From d89da18709f920da3ebc939c6d1c83b295a20bbb Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Thu, 18 Sep 2025 14:31:33 +0200 Subject: [PATCH] Clarify single index API for data access. --- include/rotgen/common/ref.hpp | 12 ++++- include/rotgen/config.hpp | 6 +++ include/rotgen/dynamic/block.hpp | 23 ++++++--- include/rotgen/dynamic/map.hpp | 19 +++++-- include/rotgen/dynamic/matrix.hpp | 45 ++++++++++------ include/rotgen/fixed/block.hpp | 37 +++++++------- include/rotgen/fixed/map.hpp | 42 ++++++++------- include/rotgen/fixed/matrix.hpp | 76 ++++++++++++++++++---------- include/rotgen/impl/matrix_model.hpp | 3 +- src/matrix_model.cpp | 1 + test/unit/block/basic_api.cpp | 41 ++++++++++++--- test/unit/map/basic_api.cpp | 39 +++++++++++--- test/unit/matrix/basic_api.cpp | 33 ++++++------ 13 files changed, 249 insertions(+), 128 deletions(-) diff --git a/include/rotgen/common/ref.hpp b/include/rotgen/common/ref.hpp index 33f5ef3..1dff724 100644 --- a/include/rotgen/common/ref.hpp +++ b/include/rotgen/common/ref.hpp @@ -25,11 +25,15 @@ namespace rotgen using value_type = typename T::value_type; using rotgen_tag = void; - static constexpr int storage_order = T::storage_order; + static constexpr int storage_order = T::storage_order; + static constexpr int RowsAtCompileTime = T::RowsAtCompileTime; + static constexpr int ColsAtCompileTime = T::ColsAtCompileTime; + static constexpr bool IsVectorAtCompileTime = T::IsVectorAtCompileTime; using parent::evaluate; using parent::noalias; using parent::operator(); + using parent::operator[]; using parent::rows; using parent::cols; using parent::size; @@ -99,11 +103,15 @@ namespace rotgen using value_type = typename T::value_type; using rotgen_tag = void; - static constexpr int storage_order = T::storage_order; + static constexpr int storage_order = T::storage_order; + static constexpr int RowsAtCompileTime = T::RowsAtCompileTime; + static constexpr int ColsAtCompileTime = T::ColsAtCompileTime; + static constexpr bool IsVectorAtCompileTime = T::IsVectorAtCompileTime; using parent::evaluate; using parent::noalias; using parent::operator(); + using parent::operator[]; using parent::rows; using parent::cols; using parent::size; diff --git a/include/rotgen/config.hpp b/include/rotgen/config.hpp index d4f0858..4d88d99 100644 --- a/include/rotgen/config.hpp +++ b/include/rotgen/config.hpp @@ -38,6 +38,12 @@ namespace rotgen inline constexpr int Aligned = default_alignment; } +namespace rotgen::detail +{ + template + inline constexpr int force_order = AutoAlign | ((R==1 && C!=1) ? RowMajor : ColMajor); +} + #if !defined(ROTGEN_MAX_SIZE) && defined(ROTGEN_ENABLE_EXPRESSION_TEMPLATES) #define ROTGEN_MAX_SIZE 0 #endif diff --git a/include/rotgen/dynamic/block.hpp b/include/rotgen/dynamic/block.hpp index 9ffd4b8..02ae9a6 100644 --- a/include/rotgen/dynamic/block.hpp +++ b/include/rotgen/dynamic/block.hpp @@ -33,10 +33,11 @@ namespace rotgen using concrete_type = matrix; using concrete_dynamic_type = matrix; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr int Options = Ref::Options; - static constexpr bool IsRowMajor = (storage_order & RowMajor) == RowMajor; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr bool IsVectorAtCompileTime = Ref::IsVectorAtCompileTime; + static constexpr int Options = Ref::Options; + static constexpr bool IsRowMajor = (storage_order & RowMajor) == RowMajor; static constexpr bool is_defined_static = false; static constexpr bool has_static_storage = false; @@ -103,20 +104,30 @@ namespace rotgen value_type& operator()(Index i, Index j) requires(!is_immutable) { return parent::operator()(i,j); } - value_type& operator()(Index i) requires(!is_immutable) + value_type& operator()(Index i) requires(!is_immutable && IsVectorAtCompileTime) { assert(is_contiguous_linear()); return parent::operator()(i); } + value_type& operator[](Index i) requires(!is_immutable && IsVectorAtCompileTime) + { + return (*this)(i); + } + value_type operator()(Index i, Index j) const { return parent::operator()(i,j); } - value_type operator()(Index i) const + value_type operator()(Index i) const requires(IsVectorAtCompileTime) { assert(is_contiguous_linear()); return parent::operator()(i); } + value_type operator[](Index i) const requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + auto evaluate() const { return *this; } decltype(auto) noalias() const { return *this; } decltype(auto) noalias() { return *this; } diff --git a/include/rotgen/dynamic/map.hpp b/include/rotgen/dynamic/map.hpp index 545dfde..6db4423 100644 --- a/include/rotgen/dynamic/map.hpp +++ b/include/rotgen/dynamic/map.hpp @@ -37,8 +37,9 @@ namespace rotgen using ptr_type = std::conditional_t; using stride_type = Stride; - static constexpr Index RowsAtCompileTime = Ref::RowsAtCompileTime; - static constexpr Index ColsAtCompileTime = Ref::ColsAtCompileTime; + static constexpr int RowsAtCompileTime = Ref::RowsAtCompileTime; + static constexpr int ColsAtCompileTime = Ref::ColsAtCompileTime; + static constexpr bool IsVectorAtCompileTime = Ref::IsVectorAtCompileTime; map(ptr_type ptr, Index r, Index c, stride_type s) : parent(ptr, r, c, strides(s,r,c)) {} map(ptr_type ptr, Index r, Index c) @@ -91,7 +92,7 @@ namespace rotgen } value_type& operator()(Index i, Index j) requires(!is_immutable) { return parent::operator()(i,j); } - value_type& operator()(Index i) requires(!is_immutable) + value_type& operator()(Index i) requires(!is_immutable && IsVectorAtCompileTime) { assert( parent::innerStride() == 1 && parent::outerStride() ==(storage_order == RowMajor ? parent::cols() : parent::rows()) @@ -99,8 +100,13 @@ namespace rotgen return parent::operator()(i); } + value_type& operator[](Index i) requires(!is_immutable && IsVectorAtCompileTime) + { + return (*this)(i); + } + value_type operator()(Index i, Index j) const { return parent::operator()(i,j); } - value_type operator()(Index i) const + value_type operator()(Index i) const requires(IsVectorAtCompileTime) { assert( parent::innerStride() == 1 && parent::outerStride() ==(storage_order == RowMajor ? parent::cols() : parent::rows()) @@ -108,6 +114,11 @@ namespace rotgen return parent::operator()(i); } + value_type operator[](Index i) const requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + auto evaluate() const { return *this; } decltype(auto) noalias() const { return *this; } decltype(auto) noalias() { return *this; } diff --git a/include/rotgen/dynamic/matrix.hpp b/include/rotgen/dynamic/matrix.hpp index c7e65b0..e2a1877 100644 --- a/include/rotgen/dynamic/matrix.hpp +++ b/include/rotgen/dynamic/matrix.hpp @@ -15,7 +15,7 @@ namespace rotgen { template< typename Scalar , int Rows = Dynamic , int Cols = Dynamic - , int Opts = ColMajor + , int Opts = detail::force_order , int MaxRows = Rows , int MaxCols = Cols > class matrix : public find_matrix @@ -26,25 +26,32 @@ namespace rotgen using concrete_type = matrix; using value_type = Scalar; - static constexpr auto storage_order = Opts & 1; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr int Options = Opts; - static constexpr bool IsRowMajor = (Opts & RowMajor) == RowMajor; - static constexpr bool is_defined_static = false; - static constexpr bool has_static_storage = false; + static constexpr auto storage_order = Opts & 1; + static constexpr Index RowsAtCompileTime = Rows; + static constexpr Index ColsAtCompileTime = Cols; + static constexpr bool IsVectorAtCompileTime = (RowsAtCompileTime == 1) || (ColsAtCompileTime == 1); + static constexpr int Options = Opts; + static constexpr bool IsRowMajor = (Opts & RowMajor) == RowMajor; + static constexpr bool is_defined_static = false; + static constexpr bool has_static_storage = false; - matrix() : parent(Rows==-1?0:Rows,Cols==-1?0:Cols) {} + matrix() : parent(Rows==-1?0:Rows,Cols==-1?0:Cols) {} - matrix(int r, int c) : parent(r, c) + matrix(Index r, Index c) : parent(r, c) { if constexpr(Rows != -1) assert(r == Rows && "Mismatched between dynamic and static row size"); if constexpr(Cols != -1) assert(c == Cols && "Mismatched between dynamic and static column size"); } + matrix(Index n) requires(IsVectorAtCompileTime && (Rows != 1 || Cols != 1)) + : parent(Rows != -1 ? 1 : n, Cols != -1 ? 1 : n) + {} + + matrix(Scalar v) requires(Rows == 1 && Cols == 1) : parent(1,1,{v}) {} + matrix(parent const& base) : parent(base) {} - explicit matrix(std::initializer_list> init) : parent(init) + matrix(std::initializer_list> init) : parent(init) { if constexpr(Rows != -1) assert(init.size() == Rows && "Mismatched between dynamic and static row size"); if constexpr(Cols != -1) @@ -55,10 +62,8 @@ namespace rotgen } } - template... S> - explicit matrix(Scalar s0,S... init) - requires((Rows == 1 && Cols == (1+sizeof...(S))) || (Cols == 1 && Rows == (1+sizeof...(S)))) - : parent(Rows, Cols, {s0,static_cast(init)...}) + matrix(std::initializer_list init) + requires(IsVectorAtCompileTime) : parent(Rows, Cols, init) {} matrix(concepts::entity auto const& e) : parent(e.rows(),e.cols()) @@ -83,6 +88,16 @@ namespace rotgen return *this; } + value_type& operator[](Index i) requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + + value_type operator[](Index i) const requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + auto evaluate() const { return *this; } decltype(auto) noalias() const { return *this; } decltype(auto) noalias() { return *this; } diff --git a/include/rotgen/fixed/block.hpp b/include/rotgen/fixed/block.hpp index 18d199c..6173680 100644 --- a/include/rotgen/fixed/block.hpp +++ b/include/rotgen/fixed/block.hpp @@ -57,12 +57,13 @@ namespace rotgen template using as_concrete_type = as_concrete_t; - static constexpr auto Flags = Ref::Flags; - static constexpr int Options = Ref::Options; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; - static constexpr bool has_static_storage = storage_status; + static constexpr auto Flags = Ref::Flags; + static constexpr int Options = Ref::Options; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr bool IsVectorAtCompileTime = Ref::IsVectorAtCompileTime; + static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; + static constexpr bool has_static_storage = storage_status; public: @@ -91,7 +92,7 @@ namespace rotgen : parent(r.base(),i0,j0,Rows,Cols) {} - template + template block(block const& other) : parent(other.base()) {} @@ -317,29 +318,25 @@ namespace rotgen return parent::template lpNorm

(); } - bool is_contiguous_linear() const + value_type& operator()(Index i, Index j) requires(!is_immutable) { - if(parent::innerStride() != 1) return false; - // outer‐stride must equal the “inner‐dimension length” - if constexpr(storage_order) return parent::outerStride() == parent::cols(); - else return parent::outerStride() == parent::rows(); + return base()(i,j); } - value_type& operator()(Index i, Index j) requires(!is_immutable) { return base()(i,j); } - value_type operator()(Index i, Index j) const { return base()(i,j); } - - value_type& operator()(Index i) requires(!is_immutable) + value_type& operator()(Index i) requires(!is_immutable && IsVectorAtCompileTime) { - assert(is_contiguous_linear()); return base().data()[i]; } - value_type operator()(Index i) const + value_type& operator[](Index i) requires(!is_immutable && IsVectorAtCompileTime) { - assert(is_contiguous_linear()); - return base().data()[i]; + return (*this)(i); } + value_type operator()(Index i, Index j) const { return base()(i,j); } + value_type operator()(Index i) const requires(IsVectorAtCompileTime) { return base().data()[i]; } + value_type operator[](Index i) const requires(IsVectorAtCompileTime) { return (*this)(i); } + using parent::innerStride; using parent::outerStride; using parent::rows; diff --git a/include/rotgen/fixed/map.hpp b/include/rotgen/fixed/map.hpp index 2058c56..aa8e42b 100644 --- a/include/rotgen/fixed/map.hpp +++ b/include/rotgen/fixed/map.hpp @@ -39,13 +39,14 @@ namespace rotgen using value_type = typename std::remove_const_t::value_type; using concrete_type = typename std::remove_const_t::concrete_type; - static constexpr auto Flags = Ref::Flags; - static constexpr Index RowsAtCompileTime = Ref::RowsAtCompileTime; - static constexpr Index ColsAtCompileTime = Ref::ColsAtCompileTime; - static constexpr bool has_static_storage = Ref::has_static_storage; - static constexpr int storage_order = Ref::storage_order; - static constexpr bool is_immutable = std::is_const_v; - static constexpr bool is_defined_static = Ref::is_defined_static; + static constexpr auto Flags = Ref::Flags; + static constexpr Index RowsAtCompileTime = Ref::RowsAtCompileTime; + static constexpr Index ColsAtCompileTime = Ref::ColsAtCompileTime; + static constexpr bool IsVectorAtCompileTime = Ref::IsVectorAtCompileTime; + static constexpr bool has_static_storage = Ref::has_static_storage; + static constexpr int storage_order = Ref::storage_order; + static constexpr bool is_immutable = std::is_const_v; + static constexpr bool is_defined_static = Ref::is_defined_static; template using as_concrete_type = as_concrete_t; @@ -111,21 +112,25 @@ namespace rotgen else return *this; } - value_type& operator()(Index i, Index j) { return base()(i, j); } - value_type operator()(Index i, Index j) const { return base()(i, j); } - - value_type& operator()(Index i) requires(!is_immutable) + value_type& operator()(Index i, Index j) requires(!is_immutable) + { + return base()(i,j); + } + + value_type& operator()(Index i) requires(!is_immutable && IsVectorAtCompileTime) { - assert(is_contiguous_linear()); return base().data()[i]; } - value_type operator()(Index i) const + value_type& operator[](Index i) requires(!is_immutable && IsVectorAtCompileTime) { - assert(is_contiguous_linear()); - return base().data()[i]; + return (*this)(i); } + value_type operator()(Index i, Index j) const { return base()(i,j); } + value_type operator()(Index i) const requires(IsVectorAtCompileTime) { return base().data()[i]; } + value_type operator[](Index i) const requires(IsVectorAtCompileTime) { return (*this)(i); } + map& operator+=(map const& rhs) { base() += rhs.base(); @@ -253,13 +258,6 @@ namespace rotgen return *this; } - bool is_contiguous_linear() const - { - if(base().innerStride() != 1) return false; - if constexpr(storage_order == rotgen::RowMajor) return base().outerStride() == base().cols(); - else return base().outerStride() == base().rows(); - } - using parent::innerStride; using parent::outerStride; using parent::rows; diff --git a/include/rotgen/fixed/matrix.hpp b/include/rotgen/fixed/matrix.hpp index 57afd5a..932fabe 100644 --- a/include/rotgen/fixed/matrix.hpp +++ b/include/rotgen/fixed/matrix.hpp @@ -14,7 +14,7 @@ namespace rotgen { namespace detail { - template + template using storage_type = std::conditional_t < storage_status , Eigen::Matrix , Eigen::Matrix @@ -22,9 +22,9 @@ namespace rotgen } template< typename Scalar - , int Rows = Dynamic , int Cols = Dynamic - , int Opts = ColMajor - , int MaxRows = Rows , int MaxCols = Cols + , int Rows = Dynamic , int Cols = Dynamic + , int Opts = detail::force_order + , int MaxRows = Rows, int MaxCols = Cols > class matrix : private detail::storage_type { @@ -38,17 +38,18 @@ namespace rotgen using concrete_type = matrix; using concrete_dynamic_type = matrix; - static constexpr auto Flags = parent::Flags; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr int Options = parent::Options; - static constexpr bool IsRowMajor = parent::IsRowMajor; + static constexpr auto Flags = parent::Flags; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr bool IsVectorAtCompileTime = (RowsAtCompileTime == 1) || (ColsAtCompileTime == 1); + static constexpr int Options = parent::Options; + static constexpr bool IsRowMajor = parent::IsRowMajor; template using as_concrete_type = as_concrete_t; - static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; - static constexpr bool has_static_storage = storage_status; + static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; + static constexpr bool has_static_storage = storage_status; public: @@ -64,24 +65,33 @@ namespace rotgen matrix(std::initializer_list> init) : parent(init) {} - template... S> - requires((Rows == 1 && Cols == (1+sizeof...(S))) || (Cols == 1 && Rows == (1+sizeof...(S)))) - matrix(Scalar s0,S... init) - : parent ( [&]() - { - if constexpr(has_static_storage) - return parent{static_cast(s0),static_cast(init)...}; - else return parent{Rows,Cols}; - }() - ) - { - if constexpr(!has_static_storage) + matrix(Index n) requires(IsVectorAtCompileTime && (Rows != 1 || Cols != 1)) + : matrix(Rows != -1 ? 1 : n, Cols != -1 ? 1 : n) + {} + + matrix(Scalar v) requires(Rows == 1 && Cols == 1) : parent + ( [&]() { - auto raw = {static_cast(s0),static_cast(init)...}; - auto first = raw.begin(); - for(rotgen::Index i=0; i < parent::size(); i++) - (*this)(i) = first[i]; - } + if constexpr(has_static_storage) return parent(v); + else return parent{1,1}; + }() + ) + { + if constexpr(!has_static_storage) (*this)(0) = v; + } + + explicit matrix(std::initializer_list init) + requires(IsVectorAtCompileTime) + : parent( [&]() + { + if constexpr(has_static_storage) return parent{}; + else return parent{Rows,Cols}; + }() + ) + { + auto first = init.begin(); + for(rotgen::Index i=0; i < parent::size(); i++) + (*this)(i) = first[i]; } matrix(concepts::entity auto const& other) : parent(other.base()) @@ -262,6 +272,16 @@ namespace rotgen return parent::template lpNorm

(); } + value_type& operator[](Index i) requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + + value_type operator[](Index i) const requires(IsVectorAtCompileTime) + { + return (*this)(i); + } + using parent::operator(); using parent::rows; using parent::cols; diff --git a/include/rotgen/impl/matrix_model.hpp b/include/rotgen/impl/matrix_model.hpp index 81e6beb..7912c8d 100644 --- a/include/rotgen/impl/matrix_model.hpp +++ b/include/rotgen/impl/matrix_model.hpp @@ -14,7 +14,8 @@ class ROTGEN_EXPORT CLASSNAME { public: - CLASSNAME(std::size_t rows = 0, std::size_t cols = 0); + CLASSNAME(); + CLASSNAME(std::size_t rows, std::size_t cols); CLASSNAME(std::size_t rows, std::size_t cols,std::initializer_list init); CLASSNAME(std::initializer_list> init); diff --git a/src/matrix_model.cpp b/src/matrix_model.cpp index e2b67f5..2c832d7 100644 --- a/src/matrix_model.cpp +++ b/src/matrix_model.cpp @@ -15,6 +15,7 @@ //================================================================================================== // Constructors & Special Members //================================================================================================== +CLASSNAME::CLASSNAME() : storage_(std::make_unique(0,0)) {} CLASSNAME::CLASSNAME(std::size_t r, std::size_t c) : storage_(std::make_unique(r,c)) {} CLASSNAME::CLASSNAME(std::initializer_list> init) diff --git a/test/unit/block/basic_api.cpp b/test/unit/block/basic_api.cpp index 05320a2..0b89dc9 100644 --- a/test/unit/block/basic_api.cpp +++ b/test/unit/block/basic_api.cpp @@ -85,20 +85,45 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types) TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types) ( tts::type< tts::types> ) { - using base = rotgen::matrix; + auto vs = [&]() + { + if constexpr(O::value == rotgen::ColMajor) + { + using base = rotgen::matrix; + base m(12); + for(int k=0;k<12;++k) m(k) = k+1; + return std::tuple{m,rotgen::block(m, 0, 0, 1, 12)}; + } + else + { + using base = rotgen::matrix; + base m(12); + for(int k=0;k<12;++k) m(k) = k+1; + return std::tuple{m,rotgen::block(m, 0, 0, 12, 1)}; + } + }(); - T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; - base mat(4,3); - for(int k=0;k<12;++k) mat.data()[k] = data[k]; + auto mat = get<0>(vs); + auto b = get<1>(vs); + TTS_EXPECT(b.IsVectorAtCompileTime); - auto b = rotgen::block(mat, 0, 0, 4, 3); for(rotgen::Index i=0;i( tts::type< tts::types> ) { - using base = rotgen::matrix; - T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; - rotgen::map a(data,4,3); - for(rotgen::Index i=0;i; + rotgen::map a(data,12); + return a; + } + else + { + using base = rotgen::matrix; + rotgen::map a(data,12); + return a; + } + }(); - a(1) = 42; + TTS_EXPECT(m.IsVectorAtCompileTime); + + for(rotgen::Index i=0;i( tts::type< tts::types> ) { - rotgen::matrix a(2, 4); + auto a = [&]() + { + if constexpr(O::value == rotgen::ColMajor) return rotgen::matrix(1,8); + else return rotgen::matrix(8,1); + }(); + + TTS_EXPECT(a.IsVectorAtCompileTime); + + for(rotgen::Index s=0;s