// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // // BaseVector.hpp // // Common base class for vectors. A direct translation of the sangi // Vector + Vector_DIM pattern. Designed to mirror BaseMatrix. // // Design: // - No virtual functions (operator[], size, data are inline; SIMD is unimpeded). // - shared_storage_ may own dynamic storage (for the dynamic Vector subclass). // For the fixed subclass (StaticVector) and non-owning views, shared_storage_ is // nullptr and data_ points to external storage or a stack array. // - Holds stride_, allowing strided views (row/column views, etc.). // - The derived classes Vector / StaticVector configure data_, size_, stride_ in // their constructor via set_view() / set_view_nonowning(). #ifndef SANGI_BASE_VECTOR_HPP #define SANGI_BASE_VECTOR_HPP #include #include #include #include namespace sangi { template class BaseVector { public: // Compile-time size trait. // -1 = dynamic (size known only at runtime). Derived classes with statically // known size (StaticVector) shadow this with their template parameter. // Used by LinAlg algorithms to enable static_assert dimension checks. static constexpr std::ptrdiff_t static_size = -1; protected: // Ownership mode: // shared_storage_ != nullptr: BaseVector owns dynamic storage (via shared) // shared_storage_ == nullptr: data_ points to external or subclass-owned storage (non-owning view) std::shared_ptr shared_storage_; // Pointer for element access (always valid, used regardless of shared_storage_) T* data_; // Shape std::size_t size_; // stride (element address = data_[i * stride_]) // contiguous: stride_ = 1 // For column views of a matrix (BaseMatrix::col_view), stride_ = row stride std::size_t stride_; public: using value_type = T; using size_type = std::size_t; using reference = T&; using const_reference = const T&; // Empty construction (configure the view later by assignment; default = empty view) BaseVector() noexcept : shared_storage_(), data_(nullptr), size_(0), stride_(0) {} // === public: ctor for non-owning views === // Build a view that references external data directly BaseVector(T* data, std::size_t size, std::size_t stride = 1) noexcept : shared_storage_(), data_(data), size_(size), stride_(stride) {} // Implicit conversion: implicit construction (as a non-owning view) from a contiguous vector type (Vector, StaticVector, etc.) template requires std::is_same_v && (!std::is_same_v, BaseVector>) && requires(const V& v) { { v.data() } -> std::convertible_to; { v.size() } -> std::convertible_to; } BaseVector(const V& v) noexcept : shared_storage_() , data_(const_cast(v.data())) , size_(v.size()) , stride_(1) {} protected: // Derived-class only: allocate and own dynamic storage BaseVector(std::size_t size) : shared_storage_(size > 0 ? new T[size]() : nullptr) , data_(shared_storage_.get()) , size_(size), stride_(1) {} // Derived-class only: view-configuration setter (so Vector can synchronize its storage with the base) void set_view(std::shared_ptr storage, T* data, std::size_t size, std::size_t stride = 1) noexcept { shared_storage_ = std::move(storage); data_ = data; size_ = size; stride_ = stride; } // Derived-class only: lightweight sync that updates only the data pointer (no shared_storage) // (used by StaticVector to pass the address of its std::array to the base) void set_view_nonowning(T* data, std::size_t size, std::size_t stride = 1) noexcept { shared_storage_.reset(); data_ = data; size_ = size; stride_ = stride; } public: // === access === [[nodiscard]] size_type size() const noexcept { return size_; } [[nodiscard]] size_type stride() const noexcept { return stride_; } [[nodiscard]] bool empty() const noexcept { return size_ == 0; } [[nodiscard]] const T& operator[](size_type i) const noexcept { return data_[i * stride_]; } [[nodiscard]] T& operator[](size_type i) noexcept { return data_[i * stride_]; } [[nodiscard]] const T* data() const noexcept { return data_; } [[nodiscard]] T* data() noexcept { return data_; } // === Contiguity test (for the fast path) === [[nodiscard]] bool is_contiguous() const noexcept { return stride_ == 1; } // === Storage-ownership query (for debugging) === [[nodiscard]] bool owns_storage() const noexcept { return static_cast(shared_storage_); } }; } // namespace sangi #endif // SANGI_BASE_VECTOR_HPP