// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later

// vector_view.hpp
//
// ベクトルビュークラスの定義
//
// このファイルでは、MKL代数ライブラリのベクトルビュークラスを定義します。
// ビュークラスは、既存のベクトルの一部または全体への参照を提供し、
// コピーなしでデータにアクセスできるようにします。
//
// 主な機能:
// - 既存のベクトルへの参照ビュー
// - ベクトルの部分ビュー（サブベクトル）
// - 読み取り専用ビュー
// - 変更可能ビュー

#ifndef CALX_VECTOR_VIEW_HPP
#define CALX_VECTOR_VIEW_HPP

#include "../common.hpp"

#include <cassert>
#include <cstddef>
#include <iterator>
#include <type_traits>

namespace calx {
namespace detail {

//-----------------------------------------------------------------------------
// ベクトルビュークラス
//-----------------------------------------------------------------------------

template<typename VectorType>
class VectorView {
public:
    // ホスト型から型定義を取得
    using value_type = typename std::remove_reference_t<VectorType>::value_type;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = value_type&;
    using const_reference = const value_type&;
    using pointer = value_type*;
    using const_pointer = const value_type*;
    using iterator = value_type*;
    using const_iterator = const value_type*;
    
    // 元のベクトルへの参照型
    using vector_reference = VectorType&;
    
    // 完全なベクトルのビューを作成
    explicit VectorView(vector_reference vector)
        : vector_(vector), offset_(0), size_(vector.size()) {}
    
    // ベクトルの部分ビューを作成
    VectorView(vector_reference vector, size_type offset, size_type size)
        : vector_(vector), offset_(offset), size_(size) {
        // 範囲チェック
        if (offset + size > vector.size()) {
            throw IndexError("VectorView: view range exceeds vector bounds");
        }
    }
    
    // コピーコンストラクタ
    VectorView(const VectorView&) = default;
    
    // コピー代入演算子
    VectorView& operator=(const VectorView&) = delete;  // ビュー自体のコピーは禁止
    
    // ビューの内容をコピーする代入
    template<typename OtherVectorType>
    VectorView& operator=(const VectorView<OtherVectorType>& other) {
        assign(other.begin(), other.end());
        return *this;
    }
    
    // ベクトルの内容をコピーする代入
    template<typename OtherVectorType>
    VectorView& operator=(const OtherVectorType& other) {
        assign(other.begin(), other.end());
        return *this;
    }
    
    // 初期化リストからの代入
    VectorView& operator=(std::initializer_list<value_type> ilist) {
        assign(ilist.begin(), ilist.end());
        return *this;
    }
    
    // 要素アクセス
    
    // 添字アクセス（非const）
    reference operator[](size_type pos) {
        assert(pos < size_ && "VectorView::operator[]: index out of range");
        return vector_[offset_ + pos];
    }

    // 添字アクセス（const）
    const_reference operator[](size_type pos) const {
        assert(pos < size_ && "VectorView::operator[]: index out of range");
        return vector_[offset_ + pos];
    }
    
    // 範囲チェック付き添字アクセス（非const）
    reference at(size_type pos) {
        if (pos >= size_) {
            throw IndexError("VectorView::at: index out of range");
        }
        return vector_[offset_ + pos];
    }
    
    // 範囲チェック付き添字アクセス（const）
    const_reference at(size_type pos) const {
        if (pos >= size_) {
            throw IndexError("VectorView::at: index out of range");
        }
        return vector_[offset_ + pos];
    }
    
    // 先頭要素アクセス（非const）
    reference front() {
        if (empty()) {
            throw IndexError("VectorView::front: empty view");
        }
        return vector_[offset_];
    }
    
    // 先頭要素アクセス（const）
    const_reference front() const {
        if (empty()) {
            throw IndexError("VectorView::front: empty view");
        }
        return vector_[offset_];
    }
    
    // 末尾要素アクセス（非const）
    reference back() {
        if (empty()) {
            throw IndexError("VectorView::back: empty view");
        }
        return vector_[offset_ + size_ - 1];
    }
    
    // 末尾要素アクセス（const）
    const_reference back() const {
        if (empty()) {
            throw IndexError("VectorView::back: empty view");
        }
        return vector_[offset_ + size_ - 1];
    }
    
    // データポインタアクセス（非const）
    pointer data() noexcept {
        return &vector_[offset_];
    }
    
    // データポインタアクセス（const）
    const_pointer data() const noexcept {
        return &vector_[offset_];
    }
    
    // イテレータ
    
    // 先頭イテレータ（非const）
    iterator begin() noexcept {
        return &vector_[offset_];
    }
    
    // 先頭イテレータ（const）
    const_iterator begin() const noexcept {
        return &vector_[offset_];
    }
    
    // 先頭イテレータ（常にconst）
    const_iterator cbegin() const noexcept {
        return &vector_[offset_];
    }
    
    // 末尾イテレータ（非const）
    iterator end() noexcept {
        return &vector_[offset_ + size_];
    }
    
    // 末尾イテレータ（const）
    const_iterator end() const noexcept {
        return &vector_[offset_ + size_];
    }
    
    // 末尾イテレータ（常にconst）
    const_iterator cend() const noexcept {
        return &vector_[offset_ + size_];
    }
    
    // 容量
    
    // 空かどうかの確認
    bool empty() const noexcept {
        return size_ == 0;
    }
    
    // サイズの取得
    size_type size() const noexcept {
        return size_;
    }
    
    // 元のベクトルのサイズ
    size_type parent_size() const noexcept {
        return vector_.size();
    }
    
    // オフセットの取得
    size_type offset() const noexcept {
        return offset_;
    }
    
    // サブビューの作成
    VectorView subview(size_type sub_offset, size_type sub_size) const {
        if (sub_offset + sub_size > size_) {
            throw IndexError("VectorView::subview: subview range exceeds view bounds");
        }
        return VectorView(vector_, offset_ + sub_offset, sub_size);
    }
    
    // 全要素のスカラー値への設定
    void fill(const value_type& value) {
        std::fill(begin(), end(), value);
    }
    
    // ゼロクリア
    void zero() {
        fill(numeric_traits<value_type>::zero());
    }
    
    // イテレータによる範囲からの代入
    template<typename InputIt>
    void assign(InputIt first, InputIt last) {
        const auto count = std::distance(first, last);
        if (count > static_cast<difference_type>(size_)) {
            throw DimensionError("VectorView::assign: source range too large for view");
        }
        
        std::copy(first, last, begin());
    }
    
    // 元のベクトルへの参照の取得
    vector_reference parent() noexcept {
        return vector_;
    }
    
    const vector_reference parent() const noexcept {
        return vector_;
    }
    
private:
    vector_reference vector_;  // 元のベクトルへの参照
    size_type offset_;         // 元のベクトル内でのオフセット
    size_type size_;           // ビューのサイズ
};

//-----------------------------------------------------------------------------
// 読み取り専用ベクトルビュークラス
//-----------------------------------------------------------------------------

template<typename VectorType>
class ConstVectorView {
public:
    // ホスト型から型定義を取得
    using value_type = typename std::remove_reference_t<VectorType>::value_type;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = const value_type&;  // constリファレンス
    using const_reference = const value_type&;
    using pointer = const value_type*;    // constポインタ
    using const_pointer = const value_type*;
    using iterator = const value_type*;   // constイテレータ
    using const_iterator = const value_type*;
    
    // 元のベクトルへの参照型（常にconst）
    using vector_reference = const VectorType&;
    
    // 完全なベクトルのビューを作成
    explicit ConstVectorView(vector_reference vector)
        : vector_(vector), offset_(0), size_(vector.size()) {}
    
    // ベクトルの部分ビューを作成
    ConstVectorView(vector_reference vector, size_type offset, size_type size)
        : vector_(vector), offset_(offset), size_(size) {
        // 範囲チェック
        if (offset + size > vector.size()) {
            throw IndexError("ConstVectorView: view range exceeds vector bounds");
        }
    }
    
    // VectorViewからの変換コンストラクタ
    explicit ConstVectorView(const VectorView<VectorType>& view)
        : vector_(view.parent()), offset_(view.offset()), size_(view.size()) {}
    
    // コピーコンストラクタ
    ConstVectorView(const ConstVectorView&) = default;
    
    // コピー代入演算子
    ConstVectorView& operator=(const ConstVectorView&) = delete;  // ビュー自体のコピーは禁止
    
    // 要素アクセス
    
    // 添字アクセス（常にconst）
    const_reference operator[](size_type pos) const {
        assert(pos < size_ && "ConstVectorView::operator[]: index out of range");
        return vector_[offset_ + pos];
    }
    
    // 範囲チェック付き添字アクセス（常にconst）
    const_reference at(size_type pos) const {
        if (pos >= size_) {
            throw IndexError("ConstVectorView::at: index out of range");
        }
        return vector_[offset_ + pos];
    }
    
    // 先頭要素アクセス（常にconst）
    const_reference front() const {
        if (empty()) {
            throw IndexError("ConstVectorView::front: empty view");
        }
        return vector_[offset_];
    }
    
    // 末尾要素アクセス（常にconst）
    const_reference back() const {
        if (empty()) {
            throw IndexError("ConstVectorView::back: empty view");
        }
        return vector_[offset_ + size_ - 1];
    }
    
    // データポインタアクセス（常にconst）
    const_pointer data() const noexcept {
        return &vector_[offset_];
    }
    
    // イテレータ（すべてconst）
    
    // 先頭イテレータ
    const_iterator begin() const noexcept {
        return &vector_[offset_];
    }
    
    const_iterator cbegin() const noexcept {
        return &vector_[offset_];
    }
    
    // 末尾イテレータ
    const_iterator end() const noexcept {
        return &vector_[offset_ + size_];
    }
    
    const_iterator cend() const noexcept {
        return &vector_[offset_ + size_];
    }
    
    // 容量
    
    // 空かどうかの確認
    bool empty() const noexcept {
        return size_ == 0;
    }
    
    // サイズの取得
    size_type size() const noexcept {
        return size_;
    }
    
    // 元のベクトルのサイズ
    size_type parent_size() const noexcept {
        return vector_.size();
    }
    
    // オフセットの取得
    size_type offset() const noexcept {
        return offset_;
    }
    
    // サブビューの作成
    ConstVectorView subview(size_type sub_offset, size_type sub_size) const {
        if (sub_offset + sub_size > size_) {
            throw IndexError("ConstVectorView::subview: subview range exceeds view bounds");
        }
        return ConstVectorView(vector_, offset_ + sub_offset, sub_size);
    }
    
    // 元のベクトルへの参照の取得
    vector_reference parent() const noexcept {
        return vector_;
    }
    
private:
    vector_reference vector_;  // 元のベクトルへの参照（const）
    size_type offset_;         // 元のベクトル内でのオフセット
    size_type size_;           // ビューのサイズ
};

// ビュー作成のためのヘルパー関数

// ベクトル全体のビューを作成
template<typename VectorType>
VectorView<VectorType> make_vector_view(VectorType& vector) {
    return VectorView<VectorType>(vector);
}

// ベクトルの部分ビューを作成
template<typename VectorType>
VectorView<VectorType> make_vector_view(VectorType& vector, 
                                       std::size_t offset, 
                                       std::size_t size) {
    return VectorView<VectorType>(vector, offset, size);
}

// ベクトル全体の読み取り専用ビューを作成
template<typename VectorType>
ConstVectorView<VectorType> make_const_vector_view(const VectorType& vector) {
    return ConstVectorView<VectorType>(vector);
}

// ベクトルの部分的な読み取り専用ビューを作成
template<typename VectorType>
ConstVectorView<VectorType> make_const_vector_view(const VectorType& vector, 
                                                  std::size_t offset, 
                                                  std::size_t size) {
    return ConstVectorView<VectorType>(vector, offset, size);
}

} // namespace detail
} // namespace calx

#endif // CALX_VECTOR_VIEW_HPP