Clarify single index API for data access.

This commit is contained in:
Joel Falcou 2025-09-18 14:31:33 +02:00
parent a50098f761
commit d89da18709
13 changed files with 249 additions and 128 deletions

View file

@ -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;

View file

@ -38,6 +38,12 @@ namespace rotgen
inline constexpr int Aligned = default_alignment;
}
namespace rotgen::detail
{
template<Index R, Index C>
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

View file

@ -33,10 +33,11 @@ namespace rotgen
using concrete_type = matrix<value_type,Rows,Cols,storage_order>;
using concrete_dynamic_type = matrix<value_type,Dynamic,Dynamic,storage_order>;
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; }

View file

@ -37,8 +37,9 @@ namespace rotgen
using ptr_type = std::conditional_t<is_immutable, value_type const*, value_type*>;
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<storage_order>(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; }

View file

@ -15,7 +15,7 @@ namespace rotgen
{
template< typename Scalar
, int Rows = Dynamic , int Cols = Dynamic
, int Opts = ColMajor
, int Opts = detail::force_order<Rows,Cols>
, int MaxRows = Rows , int MaxCols = Cols
>
class matrix : public find_matrix<Scalar,Opts>
@ -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<std::initializer_list<Scalar>> init) : parent(init)
matrix(std::initializer_list<std::initializer_list<Scalar>> 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<std::convertible_to<Scalar>... 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<Scalar>(init)...})
matrix(std::initializer_list<Scalar> 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; }

View file

@ -57,12 +57,13 @@ namespace rotgen
template<typename ET>
using as_concrete_type = as_concrete_t<ET, matrix>;
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<Rows,Cols,Rows,Cols>;
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<Rows,Cols,Rows,Cols>;
public:
@ -91,7 +92,7 @@ namespace rotgen
: parent(r.base(),i0,j0,Rows,Cols)
{}
template<typename B, int R, int C, bool I, int FS>
template<typename B, Index R, Index C, bool I, int FS>
block(block<B,R,C,I,FS> const& other) : parent(other.base())
{}
@ -317,29 +318,25 @@ namespace rotgen
return parent::template lpNorm<P>();
}
bool is_contiguous_linear() const
value_type& operator()(Index i, Index j) requires(!is_immutable)
{
if(parent::innerStride() != 1) return false;
// outerstride must equal the “innerdimension 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;

View file

@ -39,13 +39,14 @@ namespace rotgen
using value_type = typename std::remove_const_t<Ref>::value_type;
using concrete_type = typename std::remove_const_t<Ref>::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<Ref>;
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<Ref>;
static constexpr bool is_defined_static = Ref::is_defined_static;
template<typename ET>
using as_concrete_type = as_concrete_t<ET, matrix>;
@ -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;

View file

@ -14,7 +14,7 @@ namespace rotgen
{
namespace detail
{
template<typename Scalar, int Rows, int Cols, int Opts,int MaxRows, int MaxCols>
template<typename Scalar, int Rows, int Cols, int Opts, int MaxRows, int MaxCols>
using storage_type = std::conditional_t < storage_status<Rows,Cols,MaxRows,MaxCols>
, Eigen::Matrix<Scalar, Rows, Cols, Opts, MaxRows, MaxCols>
, Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Opts>
@ -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<Rows,Cols>
, int MaxRows = Rows, int MaxCols = Cols
>
class matrix : private detail::storage_type<Scalar, Rows, Cols, Opts, MaxRows, MaxCols>
{
@ -38,17 +38,18 @@ namespace rotgen
using concrete_type = matrix;
using concrete_dynamic_type = matrix<value_type>;
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<typename ET>
using as_concrete_type = as_concrete_t<ET, matrix>;
static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1;
static constexpr bool has_static_storage = storage_status<Rows,Cols,MaxRows,MaxCols>;
static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1;
static constexpr bool has_static_storage = storage_status<Rows,Cols,MaxRows,MaxCols>;
public:
@ -64,24 +65,33 @@ namespace rotgen
matrix(std::initializer_list<std::initializer_list<Scalar>> init) : parent(init)
{}
template<std::convertible_to<Scalar>... 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<Scalar>(s0),static_cast<Scalar>(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<Scalar>(s0),static_cast<Scalar>(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<Scalar> 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<P>();
}
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;

View file

@ -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<TYPE> init);
CLASSNAME(std::initializer_list<std::initializer_list<TYPE>> init);

View file

@ -15,6 +15,7 @@
//==================================================================================================
// Constructors & Special Members
//==================================================================================================
CLASSNAME::CLASSNAME() : storage_(std::make_unique<payload>(0,0)) {}
CLASSNAME::CLASSNAME(std::size_t r, std::size_t c) : storage_(std::make_unique<payload>(r,c)) {}
CLASSNAME::CLASSNAME(std::initializer_list<std::initializer_list<TYPE>> init)

View file

@ -85,20 +85,45 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types)
TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types)
<typename T, typename O>( tts::type< tts::types<T,O>> )
{
using base = rotgen::matrix<T,rotgen::Dynamic,rotgen::Dynamic,O::value>;
auto vs = [&]()
{
if constexpr(O::value == rotgen::ColMajor)
{
using base = rotgen::matrix<T,1,rotgen::Dynamic>;
base m(12);
for(int k=0;k<12;++k) m(k) = k+1;
return std::tuple{m,rotgen::block<base,1,rotgen::Dynamic>(m, 0, 0, 1, 12)};
}
else
{
using base = rotgen::matrix<T,rotgen::Dynamic,1>;
base m(12);
for(int k=0;k<12;++k) m(k) = k+1;
return std::tuple{m,rotgen::block<base,rotgen::Dynamic,1>(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<base,rotgen::Dynamic,rotgen::Dynamic>(mat, 0, 0, 4, 3);
for(rotgen::Index i=0;i<b.size();i++)
TTS_EQUAL(b(i), data[i]) << "Index: " << i << "\n";
TTS_EQUAL(b(i), mat(i)) << "Index: " << i << "\n";
for(rotgen::Index i=0;i<b.size();i++)
TTS_EQUAL(b[i], mat(i)) << "Index: " << i << "\n";
b(1) = 42;
TTS_EQUAL(mat.data()[1], 42);
TTS_EQUAL(mat(1), 42);
T& ref = b(2);
ref = 17;
TTS_EQUAL(mat.data()[2], 17);
TTS_EQUAL(mat(2), 17);
b[1] = 77;
TTS_EQUAL(mat(1), 77);
T& bref = b[3];
bref = 331;
TTS_EQUAL(mat(3), 331);
};

View file

@ -66,18 +66,43 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types)
TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types)
<typename T, typename O>( tts::type< tts::types<T,O>> )
{
using base = rotgen::matrix<T,rotgen::Dynamic,rotgen::Dynamic,O::value>;
T data[] = {1,2,3,4,5,6,7,8,9,10,11,12};
rotgen::map<base> a(data,4,3);
for(rotgen::Index i=0;i<a.size();i++)
TTS_EQUAL(a(i), data[i]) << "Index: " << i << "\n";
auto m = [&]()
{
if constexpr(O::value == rotgen::ColMajor)
{
using base = rotgen::matrix<T,1,rotgen::Dynamic>;
rotgen::map<base> a(data,12);
return a;
}
else
{
using base = rotgen::matrix<T,rotgen::Dynamic,1>;
rotgen::map<base> a(data,12);
return a;
}
}();
a(1) = 42;
TTS_EXPECT(m.IsVectorAtCompileTime);
for(rotgen::Index i=0;i<m.size();i++)
TTS_EQUAL(m(i), data[i]) << "Index: " << i << "\n";
for(rotgen::Index i=0;i<m.size();i++)
TTS_EQUAL(m[i], data[i]) << "Index: " << i << "\n";
m(1) = 42;
TTS_EQUAL(data[1], 42);
T& ref = a(2);
T& ref = m(2);
ref = 17;
TTS_EQUAL(data[2], 17);
m[1] = 77;
TTS_EQUAL(data[1], 77);
T& bref = m[3];
bref = 331;
TTS_EQUAL(data[3], 331);
};

View file

@ -138,27 +138,30 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types)
TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types)
<typename T, typename O>( tts::type< tts::types<T,O>> )
{
rotgen::matrix<T,rotgen::Dynamic,rotgen::Dynamic,O::value> a(2, 4);
auto a = [&]()
{
if constexpr(O::value == rotgen::ColMajor) return rotgen::matrix<T,1,rotgen::Dynamic>(1,8);
else return rotgen::matrix<T,rotgen::Dynamic,1>(8,1);
}();
TTS_EXPECT(a.IsVectorAtCompileTime);
for(rotgen::Index s=0;s<a.size();++s)
a(s) = s+1;
int i = 1;
if constexpr(!O::value)
{
for(rotgen::Index c=0;c<a.cols();++c)
for(rotgen::Index r=0;r<a.rows();++r)
a(r, c) = i++;
}
else
{
for(rotgen::Index r=0;r<a.rows();++r)
for(rotgen::Index c=0;c<a.cols();++c)
a(r, c) = i++;
}
for(rotgen::Index s=0;s<a.size();++s)
TTS_EQUAL(a(s), i++) << a;
i = 1;
for(rotgen::Index r=0;r<a.rows()*a.cols();++r)
TTS_EQUAL(a(r), i++) << a;
for(rotgen::Index s=0;s<a.size();++s)
TTS_EQUAL(a[s], i++) << a;
T& ref = a(2);
ref = 999.5;
TTS_EQUAL(a(2), 999.5);
T& bref = a[3];
bref = 42.5;
TTS_EQUAL(a[3], 42.5);
};