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

// vector_storage.hpp
//
// ベクトルストレージクラスの定義
//
// このファイルでは、MKL代数ライブラリのベクトルクラスで使用される
// 異なるストレージ戦略を定義します。これにより、動的サイズと
// 固定サイズのベクトルで効率的なメモリ管理が可能になります。
//
// 主な機能:
// - 動的サイズのベクトルストレージ（std::vectorベース）
// - 固定サイズのベクトルストレージ（スタック割り当て）
// - 最適化された小サイズベクトルのストレージ
// - アラインメント制御

#ifndef CALX_VECTOR_STORAGE_HPP
#define CALX_VECTOR_STORAGE_HPP

#include "../common.hpp"

#include <algorithm>
#include <array>
#include <cstddef>
#include <initializer_list>
#include <memory>
#include <type_traits>
#include <vector>

namespace calx {
namespace detail {

//-----------------------------------------------------------------------------
// 動的サイズのベクトルストレージ（std::vectorベース）
//-----------------------------------------------------------------------------

template<typename T>
class DynamicVectorStorage {
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = T&;
    using const_reference = const T&;
    using pointer = T*;
    using const_pointer = const T*;
    using iterator = typename std::vector<T>::iterator;
    using const_iterator = typename std::vector<T>::const_iterator;
    
    // デフォルトコンストラクタ
    DynamicVectorStorage() = default;
    
    // サイズ指定コンストラクタ
    explicit DynamicVectorStorage(size_type size) : data_(size) {}
    
    // サイズと初期値指定コンストラクタ
    DynamicVectorStorage(size_type size, const T& value) : data_(size, value) {}
    
    // イテレータ範囲コンストラクタ
    template<typename InputIt>
    DynamicVectorStorage(InputIt first, InputIt last) : data_(first, last) {}
    
    // 初期化リストコンストラクタ
    DynamicVectorStorage(std::initializer_list<T> init) : data_(init) {}
    
    // コピー/ムーブコンストラクタとコピー/ムーブ代入演算子
    DynamicVectorStorage(const DynamicVectorStorage&) = default;
    DynamicVectorStorage(DynamicVectorStorage&&) noexcept = default;
    DynamicVectorStorage& operator=(const DynamicVectorStorage&) = default;
    DynamicVectorStorage& operator=(DynamicVectorStorage&&) noexcept = default;
    
    // デストラクタ
    ~DynamicVectorStorage() = default;
    
    // 要素アクセス
    reference operator[](size_type pos) {
        return data_[pos];
    }
    
    const_reference operator[](size_type pos) const {
        return data_[pos];
    }
    
    reference at(size_type pos) {
        return data_.at(pos);
    }
    
    const_reference at(size_type pos) const {
        return data_.at(pos);
    }
    
    reference front() {
        return data_.front();
    }
    
    const_reference front() const {
        return data_.front();
    }
    
    reference back() {
        return data_.back();
    }
    
    const_reference back() const {
        return data_.back();
    }
    
    // データアクセス
    T* data() noexcept {
        return data_.data();
    }
    
    const T* data() const noexcept {
        return data_.data();
    }
    
    // イテレータ
    iterator begin() noexcept {
        return data_.begin();
    }
    
    const_iterator begin() const noexcept {
        return data_.begin();
    }
    
    const_iterator cbegin() const noexcept {
        return data_.cbegin();
    }
    
    iterator end() noexcept {
        return data_.end();
    }
    
    const_iterator end() const noexcept {
        return data_.end();
    }
    
    const_iterator cend() const noexcept {
        return data_.cend();
    }
    
    // 容量
    bool empty() const noexcept {
        return data_.empty();
    }
    
    size_type size() const noexcept {
        return data_.size();
    }
    
    size_type max_size() const noexcept {
        return data_.max_size();
    }
    
    void reserve(size_type new_cap) {
        data_.reserve(new_cap);
    }
    
    size_type capacity() const noexcept {
        return data_.capacity();
    }
    
    void shrink_to_fit() {
        data_.shrink_to_fit();
    }
    
    // 修飾子
    void clear() noexcept {
        data_.clear();
    }
    
    void resize(size_type count) {
        data_.resize(count);
    }
    
    void resize(size_type count, const value_type& value) {
        data_.resize(count, value);
    }
    
    void push_back(const T& value) {
        data_.push_back(value);
    }
    
    void push_back(T&& value) {
        data_.push_back(std::move(value));
    }
    
    void pop_back() {
        data_.pop_back();
    }
    
private:
    std::vector<T> data_;
};

//-----------------------------------------------------------------------------
// 固定サイズのベクトルストレージ（スタック割り当て）
//-----------------------------------------------------------------------------

template<typename T, std::size_t N>
class StaticVectorStorage {
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = T&;
    using const_reference = const T&;
    using pointer = T*;
    using const_pointer = const T*;
    using iterator = T*;
    using const_iterator = const T*;
    
    // デフォルトコンストラクタ（ゼロ初期化）
    StaticVectorStorage() : data_{} {}
    
    // 値で初期化するコンストラクタ
    explicit StaticVectorStorage(const T& value) {
        std::fill(begin(), end(), value);
    }
    
    // コピー/ムーブコンストラクタとコピー/ムーブ代入演算子
    StaticVectorStorage(const StaticVectorStorage&) = default;
    StaticVectorStorage(StaticVectorStorage&&) noexcept = default;
    StaticVectorStorage& operator=(const StaticVectorStorage&) = default;
    StaticVectorStorage& operator=(StaticVectorStorage&&) noexcept = default;
    
    // デストラクタ
    ~StaticVectorStorage() = default;
    
    // 要素アクセス
    reference operator[](size_type pos) {
        return data_[pos];
    }
    
    const_reference operator[](size_type pos) const {
        return data_[pos];
    }
    
    reference at(size_type pos) {
        if (pos >= N) {
            throw IndexError("StaticVectorStorage::at: index out of range");
        }
        return data_[pos];
    }
    
    const_reference at(size_type pos) const {
        if (pos >= N) {
            throw IndexError("StaticVectorStorage::at: index out of range");
        }
        return data_[pos];
    }
    
    reference front() {
        return data_[0];
    }
    
    const_reference front() const {
        return data_[0];
    }
    
    reference back() {
        return data_[N - 1];
    }
    
    const_reference back() const {
        return data_[N - 1];
    }
    
    // データアクセス
    T* data() noexcept {
        return data_;
    }
    
    const T* data() const noexcept {
        return data_;
    }
    
    // イテレータ
    iterator begin() noexcept {
        return data_;
    }
    
    const_iterator begin() const noexcept {
        return data_;
    }
    
    const_iterator cbegin() const noexcept {
        return data_;
    }
    
    iterator end() noexcept {
        return data_ + N;
    }
    
    const_iterator end() const noexcept {
        return data_ + N;
    }
    
    const_iterator cend() const noexcept {
        return data_ + N;
    }
    
    // 容量
    constexpr bool empty() const noexcept {
        return N == 0;
    }
    
    constexpr size_type size() const noexcept {
        return N;
    }
    
    constexpr size_type max_size() const noexcept {
        return N;
    }
    
    constexpr size_type capacity() const noexcept {
        return N;
    }
    
private:
    T data_[N];
};

//-----------------------------------------------------------------------------
// アラインメント済み動的ベクトルストレージ（MKL最適化用）
//-----------------------------------------------------------------------------

template<typename T>
class AlignedVectorStorage {
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = T&;
    using const_reference = const T&;
    using pointer = T*;
    using const_pointer = const T*;
    using iterator = T*;
    using const_iterator = const T*;
    
    // アライメント値
    static constexpr size_type alignment = memory::simd_alignment();
    
    // デフォルトコンストラクタ
    AlignedVectorStorage() : data_(nullptr), size_(0), capacity_(0) {}
    
    // サイズ指定コンストラクタ
    explicit AlignedVectorStorage(size_type size) : size_(size), capacity_(size) {
        if (size_ > 0) {
            data_ = memory::aligned_alloc<T>(size_, alignment);
            std::uninitialized_default_construct_n(data_, size_);
        } else {
            data_ = nullptr;
        }
    }
    
    // サイズと初期値指定コンストラクタ
    AlignedVectorStorage(size_type size, const T& value) : size_(size), capacity_(size) {
        if (size_ > 0) {
            data_ = memory::aligned_alloc<T>(size_, alignment);
            std::uninitialized_fill_n(data_, size_, value);
        } else {
            data_ = nullptr;
        }
    }
    
    // イテレータ範囲コンストラクタ
    template<typename InputIt>
    AlignedVectorStorage(InputIt first, InputIt last) {
        const auto count = std::distance(first, last);
        size_ = count;
        capacity_ = count;
        
        if (size_ > 0) {
            data_ = memory::aligned_alloc<T>(size_, alignment);
            std::uninitialized_copy(first, last, data_);
        } else {
            data_ = nullptr;
        }
    }
    
    // 初期化リストコンストラクタ
    AlignedVectorStorage(std::initializer_list<T> init) 
        : AlignedVectorStorage(init.begin(), init.end()) {}
    
    // コピーコンストラクタ
    AlignedVectorStorage(const AlignedVectorStorage& other) 
        : size_(other.size_), capacity_(other.size_) {
        if (size_ > 0) {
            data_ = memory::aligned_alloc<T>(size_, alignment);
            std::uninitialized_copy_n(other.data_, size_, data_);
        } else {
            data_ = nullptr;
        }
    }
    
    // ムーブコンストラクタ
    AlignedVectorStorage(AlignedVectorStorage&& other) noexcept 
        : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
        other.data_ = nullptr;
        other.size_ = 0;
        other.capacity_ = 0;
    }
    
    // コピー代入演算子
    AlignedVectorStorage& operator=(const AlignedVectorStorage& other) {
        if (this != &other) {
            // 古いデータの破棄
            clear();
            if (data_) {
                memory::aligned_free(data_);
            }
            
            // 新しいデータの確保とコピー
            size_ = other.size_;
            capacity_ = other.size_;
            
            if (size_ > 0) {
                data_ = memory::aligned_alloc<T>(size_, alignment);
                std::uninitialized_copy_n(other.data_, size_, data_);
            } else {
                data_ = nullptr;
            }
        }
        return *this;
    }
    
    // ムーブ代入演算子
    AlignedVectorStorage& operator=(AlignedVectorStorage&& other) noexcept {
        if (this != &other) {
            // 古いデータの破棄
            clear();
            if (data_) {
                memory::aligned_free(data_);
            }
            
            // 他方のデータの移動
            data_ = other.data_;
            size_ = other.size_;
            capacity_ = other.capacity_;
            
            other.data_ = nullptr;
            other.size_ = 0;
            other.capacity_ = 0;
        }
        return *this;
    }
    
    // デストラクタ
    ~AlignedVectorStorage() {
        clear();
        if (data_) {
            memory::aligned_free(data_);
        }
    }
    
    // 要素アクセス
    reference operator[](size_type pos) {
        return data_[pos];
    }
    
    const_reference operator[](size_type pos) const {
        return data_[pos];
    }
    
    reference at(size_type pos) {
        if (pos >= size_) {
            throw IndexError("AlignedVectorStorage::at: index out of range");
        }
        return data_[pos];
    }
    
    const_reference at(size_type pos) const {
        if (pos >= size_) {
            throw IndexError("AlignedVectorStorage::at: index out of range");
        }
        return data_[pos];
    }
    
    reference front() {
        if (empty()) {
            throw IndexError("AlignedVectorStorage::front: empty container");
        }
        return data_[0];
    }
    
    const_reference front() const {
        if (empty()) {
            throw IndexError("AlignedVectorStorage::front: empty container");
        }
        return data_[0];
    }
    
    reference back() {
        if (empty()) {
            throw IndexError("AlignedVectorStorage::back: empty container");
        }
        return data_[size_ - 1];
    }
    
    const_reference back() const {
        if (empty()) {
            throw IndexError("AlignedVectorStorage::back: empty container");
        }
        return data_[size_ - 1];
    }
    
    // データアクセス
    T* data() noexcept {
        return data_;
    }
    
    const T* data() const noexcept {
        return data_;
    }
    
    // イテレータ
    iterator begin() noexcept {
        return data_;
    }
    
    const_iterator begin() const noexcept {
        return data_;
    }
    
    const_iterator cbegin() const noexcept {
        return data_;
    }
    
    iterator end() noexcept {
        return data_ + size_;
    }
    
    const_iterator end() const noexcept {
        return data_ + size_;
    }
    
    const_iterator cend() const noexcept {
        return data_ + size_;
    }
    
    // 容量
    bool empty() const noexcept {
        return size_ == 0;
    }
    
    size_type size() const noexcept {
        return size_;
    }
    
    size_type capacity() const noexcept {
        return capacity_;
    }
    
    void reserve(size_type new_cap) {
        if (new_cap <= capacity_) {
            return;
        }
        
        // 新しいメモリの確保
        T* new_data = memory::aligned_alloc<T>(new_cap, alignment);
        
        // 古いデータの移動
        if (size_ > 0) {
            std::uninitialized_move_n(data_, size_, new_data);
            // 古いオブジェクトの破棄
            std::destroy_n(data_, size_);
        }
        
        // 古いメモリの解放
        if (data_) {
            memory::aligned_free(data_);
        }
        
        // 新しいメモリの設定
        data_ = new_data;
        capacity_ = new_cap;
    }
    
    // 修飾子
    void clear() noexcept {
        if (data_) {
            std::destroy_n(data_, size_);
        }
        size_ = 0;
    }
    
    void resize(size_type count) {
        if (count > size_) {
            // 拡大
            reserve(count);
            // 新しい要素の初期化
            std::uninitialized_default_construct_n(data_ + size_, count - size_);
        } else if (count < size_) {
            // 縮小
            std::destroy_n(data_ + count, size_ - count);
        }
        size_ = count;
    }
    
    void resize(size_type count, const value_type& value) {
        if (count > size_) {
            // 拡大
            reserve(count);
            // 新しい要素の初期化
            std::uninitialized_fill_n(data_ + size_, count - size_, value);
        } else if (count < size_) {
            // 縮小
            std::destroy_n(data_ + count, size_ - count);
        }
        size_ = count;
    }
    
    void push_back(const T& value) {
        if (size_ == capacity_) {
            // 容量の拡大
            const size_type new_capacity = capacity_ == 0 ? 1 : capacity_ * 2;
            reserve(new_capacity);
        }
        
        // 新しい要素の追加
        new (data_ + size_) T(value);
        ++size_;
    }
    
    void push_back(T&& value) {
        if (size_ == capacity_) {
            // 容量の拡大
            const size_type new_capacity = capacity_ == 0 ? 1 : capacity_ * 2;
            reserve(new_capacity);
        }
        
        // 新しい要素の追加
        new (data_ + size_) T(std::move(value));
        ++size_;
    }
    
    void pop_back() {
        if (empty()) {
            throw IndexError("AlignedVectorStorage::pop_back: empty container");
        }
        
        --size_;
        std::destroy_at(data_ + size_);
    }
    
private:
    T* data_;
    size_type size_;
    size_type capacity_;
};

} // namespace detail
} // namespace calx

#endif // CALX_VECTOR_STORAGE_HPP