Something went wrong. Try again.
C++ container for matrices.
Something went wrong. Try again.
cpp-matrix array.cpp
15 kB · 536 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537/* Static Size Container Array** Wrapper class to a c-array of Tp_[n_]** @tparam Tp_ -> element type* @tparam n_ -> size of array*/template<typename Tp_, Size n_>class Array{ /* EnableCMem * check for the ability to * use `memcpy` and `memmove` * from a type Vp_ to a type Tp_ */ template<typename Vp_> using EnableCMem = meta::BoolConstant< sizeof(Vp_) == sizeof(Tp_) && std::is_pod<Tp_>::value && std::is_pod<Vp_>::value >;
/* Store size of data array in type * for zero overhead */ using DataSize = meta::SizeConstant<sizeof(Tp_) * n_>;
/* Raw Data */ Tp_ _data[n_];
public:
//============================================ // ** Initialisation ** //============================================
/* Maintain default initialisation * from compilier * * default: * ~ Default Ctor * ~ Copy Ctor * ~ Move Ctor * ~ Destructor * ~ Copy Assignment Operator * ~ Move Assignment Operator */
Array(void) = default; Array(const Array &) = default; Array(Array &&) = default; ~Array(void) = default;
Array & operator = (const Array &) = default; Array & operator = (Array &&) = default;
/* Values Constructor * * move a variadic list of values into the raw data * * enabled when exactly n_ many values are provided * * @tparam Tps_ -> parameter pack of arguments to move assign * * ASSERT: Every Tps_ is move assignable */ template<typename ... Tps_, typename = meta::EnableIf_t< meta::VariadicSize_v<Tps_ ... > == n_ >> Array(Tps_ && ... values) : _data{ std::move(values) ... } {}
//============================================ // ** Data Access ** //============================================
/* Subcript Operator * * access an individual element in the array * * @param index -> element in the array */ Tp_ & operator[] (const Size & index) { return Array::_data[index]; } const Tp_ & operator[] (const Size & index) const { return Array::_data[index]; }
/* Iterators * * access [begin, end) pointers of the array */ Tp_ * begin(void) { return Array::_data; } Tp_ * end(void) { return Array::_data + n_; }
const Tp_ * begin(void) const { return Array::_data; } const Tp_ * end(void) const { return Array::_data + n_; }
/* First and Last * * access the first and last element in array */ Tp_ & front(void) { return *Array::_data; } Tp_ & back(void) { return *(Array::_data + n_ - 1); }
const Tp_ & front(void) const { return *Array::_data; } const Tp_ & back(void) const { return *(Array::_data + n_ - 1); }
/* Raw Data * * access a pointer to the raw data */ Tp_ * data(void) { return Array::_data; } const Tp_ * data(void) const { return Array::_data; }
//============================================ // ** Utilities ** //============================================
/* Array size * * static size of array -> n_ */ static constexpr Size size(void) { return n_; }
/* Array Fill * * copy value to every element in array * * @param value -> value to copy assign * * ASSERT: copy assignable from const Vp_ to Tp_ */ template<typename Vp_> void fill(const Vp_ & value) { static_assert(meta::CopyAssignable_v<Tp_, const Vp_>, "Array<Tp_, n_>::fill(const Vp_ &) ~ Invalid Vp_, requires copy assignability from const Vp_ to Tp_ \n");
std::fill(Array::begin(), Array::end(), value); }
/* Array Copy * * copy data from rhs array to lhs * * enable if c-styled copy available between types * * @param array -> the rhs Array of any type */ template<typename Vp_> meta::EnableIf_t<EnableCMem<const Vp_>::value> copy(const Array<Vp_, n_> & array) { memcpy(Array::_data, array.begin(), DataSize::value); }
/* Array Copy * * iterate copy from rhs array to lhs * * enable if c-styled copy is NOT available between types * * @param array -> the rhs Array of any type * * ASSERT: copy assignable from const Vp_ to Tp_ */ template<typename Vp_> meta::EnableIf_t<!EnableCMem<const Vp_>::value> copy(const Array<Vp_, n_> & array) { static_assert(meta::CopyAssignable_v<Tp_, const Vp_>, "Array<Tp_, n_>::copy(const Array<Vp_, n_> &) ~ Invalid Vp_, requires copy assignability from const Vp_ to Tp_ \n");
std::copy(array.begin(), array.end(), Array::begin()); }
/* Array Move * * move data from rhs array to lhs * * enable if c-styled move available between types * * @param array -> rhs Array of any type */ template<typename Vp_> meta::EnableIf_t<EnableCMem<Vp_>::value> move(Array<Vp_, n_> && array) { memmove(Array::_data, array.begin(), DataSize::value); }
/* Array Move * * iterate move from rhs array to lhs * * enable if c-styled move NOT available between types * * @param array -> rhs Array of any type * * ASSERT: move assignable from Vp_ to Tp_ */ template<typename Vp_> meta::EnableIf_t<!EnableCMem<Vp_>::value> move(Array<Vp_, n_> && array) { static_assert(meta::MoveAssignable_v<Tp_, Vp_>, "Array<Tp_, n_>::move(Array<Vp_, n_> &&) ~ Invalid Vp_, requires move assignability from Vp_ to Tp_ \n");
std::move(array.begin(), array.end(), Array::begin()); }
/* Array Swap * * swap data betwen rhs array and lhs array * * @param array -> rhs Array to swap */ template<typename Vp_> void swap(Array<Vp_, n_> & array) { auto array_temp = std::move(array); array = std::move(*this); *this = std::move(array_temp); }
//============================================ // ** Operators ** //============================================
/* Function Operator * * call `function` for every element * * @param function -> function to call * * ASSERT: function is callable as * function(Tp_ &, const Size &) */ void operator() (auto function) { static_assert(meta::Callable_v<decltype(function), Tp_ &, const Size &>, "Array<Tp_, n_>::operator()(auto function) ~ Invalid function, requires signature function(Tp_ &, const Size &) \n");
for (Size i = 0; i != n_; ++i) function(Array::_data[i], i); }
/* Array Cast * * creates an implicit conversion from * this Array<Tp_> to an Array<Vp_> * * copies data from this to lhs */ template<typename Vp_> operator Array<Vp_, n_> (void) { Array<Vp_, n_> conversion; conversion.copy(*this); return conversion; }
/* Equality * * validate if every element in rhs array is * equal to every element in lhs array * * @param array -> rhs Array of any type * * ASSERT: equatability between Tp_ and const Vp_ */ template<typename Vp_> auto operator == (const Array<Vp_, n_> & array) { static_assert(meta::Equatable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator==(const Array<Vp_, n_> &) ~ Invalid Vp_, requires equatability between Tp_ and const Vp_ \n");
return std::equal(array.begin(), array.end(), Array::begin()); }
/* Scalar Equality * * validate if value is equal to * every element in lhs array * * @param value -> value of any type * * ASSERT: equatability between Tp_ and const Vp_ */ template<typename Vp_> auto operator == (const Vp_ & value) { static_assert(meta::Equatable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator==(const Vp_ &) ~ Invalid Vp_, requires equatability between Tp_ and const Vp_ \n");
return std::equal(Array::begin(), Array::end(), value); }
/* Inequality * * return the inverse of equality */ template<typename Vp_> auto operator != (const Array<Vp_, n_> & array) { return !(*this == array); }
/* Scalar Inequality * * return the inverse of scalar inequality */ template<typename Vp_> auto operator != (const Vp_ & value) { return !(*this == value); }
/* Addition * * assign the addition of every element * in rhs array and every element in lhs * array to a new instance and return * * @param array -> rhs Array of any type * * ASSERT: addability between Tp_ and const Vp_ */ template<typename Vp_> auto operator + (const Array<Vp_, n_> & array) { static_assert(meta::Addable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator+(const Array<Vp_, n_> &) ~ Invalid Vp_, requires addability between Tp_ and const Vp_ \n");
Array<meta::AddableTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] + array[index]; }); return result; }
/* Scalar Addition * * assign the addition of rhs value and * every element in lhs array to * a new instance and return * * @param value -> rhs value of any type * * ASSERT: addability between Tp_ and const Vp_ */ template<typename Vp_> auto operator + (const Vp_ & value) { static_assert(meta::Addable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator+(const Vp_ &) ~ Invalid Vp_, requires addability between Tp_ and const Vp_ \n");
Array<meta::AddableTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] + value; }); return result; }
/* Negation * * assign the negation of every element * in rhs array to new instance and return * * ASSERT: negatability of a const Tp_ */ auto operator - (void) { static_assert(meta::Negatable_v<Tp_>, "Array<Tp_, n_>::operator-(void) ~ Invalid Tp_, requires negatability on a Tp_ \n");
Array<meta::NegatableTest<Tp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = -(this->_data[index]); }); return result; }
/* Subtraction * * assign the subtraction of every element * in rhs array and every element in the lhs * array to a new instance and return * * @param array -> rhs Array of any type * * ASSERT: subtractability between Tp_ and const Vp_ */ template<typename Vp_> auto operator - (const Array<Vp_, n_> & array) { static_assert(meta::Subtractable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator-(const Array<Vp_, n_> &) ~ Invalid Vp_, requires subtractability between Tp_ and const Vp_ \n");
Array<meta::SubtractableTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] - array[index]; }); return result; }
/* Scalar Subtraction * * assign the subtraction of rhs value and * every element in lhs array to * a new instance and return * * @param value -> rhs value of any type * * ASSERT: subtractability between Tp_ and const Vp_ */ template<typename Vp_> auto operator - (const Vp_ & value) { static_assert(meta::Subtractable_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator-(const Vp_ &) ~ Invalid Vp_, requires subtractability between Tp_ and const Vp_ \n");
Array<meta::SubtractableTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] - value; }); return result; }
/* Product * * assign the product of every element * in rhs array and every element in the lhs * array to a new instance and return * * @param array -> rhs Array of any type * * ASSERT: multiplicativity between Tp_ and const Vp_ */ template<typename Vp_> auto operator * (const Array<Vp_, n_> & array) { static_assert(meta::Multiplicative_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator*(const Array<Vp_, n_> &) ~ Invalid Vp_, requires multiplicativity between Tp_ and const Vp_ \n");
Array<meta::MultiplicativeTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] * array[index]; }); return result; }
/* Scalar Product * * assign the product of rhs value and * every element in lhs array to * a new instance and return * * @param value -> rhs value of any type * * ASSERT: multiplicativity between Tp_ and const Vp_ */ template<typename Vp_> auto operator * (const Vp_ & value) { static_assert(meta::Multiplicative_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator*(const Vp_ &) ~ Invalid Vp_, requires multiplicativity between Tp_ and const Vp_ \n");
Array<meta::MultiplicativeTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] * value; }); return result; }
/* Quotient * * assign the quotient of every element * in rhs array and every element in the lhs * array to a new instance and return * * @param array -> rhs Array of any type * * ASSERT: divisibility between Tp_ and const Vp_ */ template<typename Vp_> auto operator / (const Array<Vp_, n_> & array) { static_assert(meta::Divisible_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator/(const Array<Vp_, n_> &) ~ Invalid Vp_, requires divisbility between Tp_ and const Vp_ \n");
Array<meta::DivisibleTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] / array[index]; }); return result; }
/* Scalar Quotient * * assign the quotient of rhs value and * every element in lhs array to * a new instance and return * * @param value -> rhs value of any type * * ASSERT: divisibility between Tp_ and const Vp_ */ template<typename Vp_> auto operator / (const Vp_ & value) { static_assert(meta::Divisible_v<Tp_, const Vp_>, "Array<Tp_, n_>::operator/(const Vp_ &) ~ Invalid Vp_, requires divisbility between Tp_ and const Vp_ \n");
Array<meta::DivisibleTest<Tp_, const Vp_>, n_> result; result([&, this](auto & elem, const auto & index) { elem = this->_data[index] / value; }); return result; }
};