C++ container for matrices.
at main 15 kB view raw
1/* Static Size Container Array 2* 3* Wrapper class to a c-array of Tp_[n_] 4* 5* @tparam Tp_ -> element type 6* @tparam n_ -> size of array 7*/ 8template<typename Tp_, Size n_> 9class Array 10{ 11 /* EnableCMem 12 * check for the ability to 13 * use `memcpy` and `memmove` 14 * from a type Vp_ to a type Tp_ 15 */ 16 template<typename Vp_> 17 using EnableCMem = meta::BoolConstant< 18 sizeof(Vp_) == sizeof(Tp_) && 19 std::is_pod<Tp_>::value && 20 std::is_pod<Vp_>::value 21 >; 22 23 /* Store size of data array in type 24 * for zero overhead 25 */ 26 using DataSize = meta::SizeConstant<sizeof(Tp_) * n_>; 27 28 /* Raw Data 29 */ 30 Tp_ _data[n_]; 31 32public: 33 34 //============================================ 35 // ** Initialisation ** 36 //============================================ 37 38 /* Maintain default initialisation 39 * from compilier 40 * 41 * default: 42 * ~ Default Ctor 43 * ~ Copy Ctor 44 * ~ Move Ctor 45 * ~ Destructor 46 * ~ Copy Assignment Operator 47 * ~ Move Assignment Operator 48 */ 49 50 Array(void) = default; 51 Array(const Array &) = default; 52 Array(Array &&) = default; 53 ~Array(void) = default; 54 55 Array & operator = (const Array &) = default; 56 Array & operator = (Array &&) = default; 57 58 /* Values Constructor 59 * 60 * move a variadic list of values into the raw data 61 * 62 * enabled when exactly n_ many values are provided 63 * 64 * @tparam Tps_ -> parameter pack of arguments to move assign 65 * 66 * ASSERT: Every Tps_ is move assignable 67 */ 68 template<typename ... Tps_, 69 typename = meta::EnableIf_t< 70 meta::VariadicSize_v<Tps_ ... > == n_ 71 >> 72 Array(Tps_ && ... values) 73 : _data{ std::move(values) ... } 74 {} 75 76 77 //============================================ 78 // ** Data Access ** 79 //============================================ 80 81 /* Subcript Operator 82 * 83 * access an individual element in the array 84 * 85 * @param index -> element in the array 86 */ 87 Tp_ & operator[] (const Size & index) { return Array::_data[index]; } 88 const Tp_ & operator[] (const Size & index) const { return Array::_data[index]; } 89 90 /* Iterators 91 * 92 * access [begin, end) pointers of the array 93 */ 94 Tp_ * begin(void) { return Array::_data; } 95 Tp_ * end(void) { return Array::_data + n_; } 96 97 const Tp_ * begin(void) const { return Array::_data; } 98 const Tp_ * end(void) const { return Array::_data + n_; } 99 100 /* First and Last 101 * 102 * access the first and last element in array 103 */ 104 Tp_ & front(void) { return *Array::_data; } 105 Tp_ & back(void) { return *(Array::_data + n_ - 1); } 106 107 const Tp_ & front(void) const { return *Array::_data; } 108 const Tp_ & back(void) const { return *(Array::_data + n_ - 1); } 109 110 /* Raw Data 111 * 112 * access a pointer to the raw data 113 */ 114 Tp_ * data(void) { return Array::_data; } 115 const Tp_ * data(void) const { return Array::_data; } 116 117 118 //============================================ 119 // ** Utilities ** 120 //============================================ 121 122 /* Array size 123 * 124 * static size of array -> n_ 125 */ 126 static constexpr Size size(void) { return n_; } 127 128 /* Array Fill 129 * 130 * copy value to every element in array 131 * 132 * @param value -> value to copy assign 133 * 134 * ASSERT: copy assignable from const Vp_ to Tp_ 135 */ 136 template<typename Vp_> 137 void fill(const Vp_ & value) 138 { 139 static_assert(meta::CopyAssignable_v<Tp_, const Vp_>, 140 "Array<Tp_, n_>::fill(const Vp_ &) ~ Invalid Vp_, requires copy assignability from const Vp_ to Tp_ \n"); 141 142 std::fill(Array::begin(), Array::end(), value); 143 } 144 145 146 /* Array Copy 147 * 148 * copy data from rhs array to lhs 149 * 150 * enable if c-styled copy available between types 151 * 152 * @param array -> the rhs Array of any type 153 */ 154 template<typename Vp_> 155 meta::EnableIf_t<EnableCMem<const Vp_>::value> 156 copy(const Array<Vp_, n_> & array) 157 { 158 memcpy(Array::_data, array.begin(), DataSize::value); 159 } 160 161 /* Array Copy 162 * 163 * iterate copy from rhs array to lhs 164 * 165 * enable if c-styled copy is NOT available between types 166 * 167 * @param array -> the rhs Array of any type 168 * 169 * ASSERT: copy assignable from const Vp_ to Tp_ 170 */ 171 template<typename Vp_> 172 meta::EnableIf_t<!EnableCMem<const Vp_>::value> 173 copy(const Array<Vp_, n_> & array) 174 { 175 static_assert(meta::CopyAssignable_v<Tp_, const Vp_>, 176 "Array<Tp_, n_>::copy(const Array<Vp_, n_> &) ~ Invalid Vp_, requires copy assignability from const Vp_ to Tp_ \n"); 177 178 std::copy(array.begin(), array.end(), Array::begin()); 179 } 180 181 /* Array Move 182 * 183 * move data from rhs array to lhs 184 * 185 * enable if c-styled move available between types 186 * 187 * @param array -> rhs Array of any type 188 */ 189 template<typename Vp_> 190 meta::EnableIf_t<EnableCMem<Vp_>::value> 191 move(Array<Vp_, n_> && array) 192 { 193 memmove(Array::_data, array.begin(), DataSize::value); 194 } 195 196 /* Array Move 197 * 198 * iterate move from rhs array to lhs 199 * 200 * enable if c-styled move NOT available between types 201 * 202 * @param array -> rhs Array of any type 203 * 204 * ASSERT: move assignable from Vp_ to Tp_ 205 */ 206 template<typename Vp_> 207 meta::EnableIf_t<!EnableCMem<Vp_>::value> 208 move(Array<Vp_, n_> && array) 209 { 210 static_assert(meta::MoveAssignable_v<Tp_, Vp_>, 211 "Array<Tp_, n_>::move(Array<Vp_, n_> &&) ~ Invalid Vp_, requires move assignability from Vp_ to Tp_ \n"); 212 213 std::move(array.begin(), array.end(), Array::begin()); 214 } 215 216 /* Array Swap 217 * 218 * swap data betwen rhs array and lhs array 219 * 220 * @param array -> rhs Array to swap 221 */ 222 template<typename Vp_> 223 void swap(Array<Vp_, n_> & array) 224 { 225 auto array_temp = std::move(array); 226 array = std::move(*this); 227 *this = std::move(array_temp); 228 } 229 230 //============================================ 231 // ** Operators ** 232 //============================================ 233 234 /* Function Operator 235 * 236 * call `function` for every element 237 * 238 * @param function -> function to call 239 * 240 * ASSERT: function is callable as 241 * function(Tp_ &, const Size &) 242 */ 243 void operator() (auto function) 244 { 245 static_assert(meta::Callable_v<decltype(function), Tp_ &, const Size &>, 246 "Array<Tp_, n_>::operator()(auto function) ~ Invalid function, requires signature function(Tp_ &, const Size &) \n"); 247 248 for (Size i = 0; i != n_; ++i) 249 function(Array::_data[i], i); 250 } 251 252 /* Array Cast 253 * 254 * creates an implicit conversion from 255 * this Array<Tp_> to an Array<Vp_> 256 * 257 * copies data from this to lhs 258 */ 259 template<typename Vp_> 260 operator Array<Vp_, n_> (void) 261 { 262 Array<Vp_, n_> conversion; 263 conversion.copy(*this); 264 return conversion; 265 } 266 267 /* Equality 268 * 269 * validate if every element in rhs array is 270 * equal to every element in lhs array 271 * 272 * @param array -> rhs Array of any type 273 * 274 * ASSERT: equatability between Tp_ and const Vp_ 275 */ 276 template<typename Vp_> 277 auto operator == (const Array<Vp_, n_> & array) 278 { 279 static_assert(meta::Equatable_v<Tp_, const Vp_>, 280 "Array<Tp_, n_>::operator==(const Array<Vp_, n_> &) ~ Invalid Vp_, requires equatability between Tp_ and const Vp_ \n"); 281 282 return std::equal(array.begin(), array.end(), Array::begin()); 283 } 284 285 /* Scalar Equality 286 * 287 * validate if value is equal to 288 * every element in lhs array 289 * 290 * @param value -> value of any type 291 * 292 * ASSERT: equatability between Tp_ and const Vp_ 293 */ 294 template<typename Vp_> 295 auto operator == (const Vp_ & value) 296 { 297 static_assert(meta::Equatable_v<Tp_, const Vp_>, 298 "Array<Tp_, n_>::operator==(const Vp_ &) ~ Invalid Vp_, requires equatability between Tp_ and const Vp_ \n"); 299 300 return std::equal(Array::begin(), Array::end(), value); 301 } 302 303 /* Inequality 304 * 305 * return the inverse of equality 306 */ 307 template<typename Vp_> 308 auto operator != (const Array<Vp_, n_> & array) 309 { 310 return !(*this == array); 311 } 312 313 /* Scalar Inequality 314 * 315 * return the inverse of scalar inequality 316 */ 317 template<typename Vp_> 318 auto operator != (const Vp_ & value) 319 { 320 return !(*this == value); 321 } 322 323 324 /* Addition 325 * 326 * assign the addition of every element 327 * in rhs array and every element in lhs 328 * array to a new instance and return 329 * 330 * @param array -> rhs Array of any type 331 * 332 * ASSERT: addability between Tp_ and const Vp_ 333 */ 334 template<typename Vp_> 335 auto operator + (const Array<Vp_, n_> & array) 336 { 337 static_assert(meta::Addable_v<Tp_, const Vp_>, 338 "Array<Tp_, n_>::operator+(const Array<Vp_, n_> &) ~ Invalid Vp_, requires addability between Tp_ and const Vp_ \n"); 339 340 Array<meta::AddableTest<Tp_, const Vp_>, n_> result; 341 result([&, this](auto & elem, const auto & index) 342 { 343 elem = this->_data[index] + array[index]; 344 }); 345 return result; 346 } 347 348 /* Scalar Addition 349 * 350 * assign the addition of rhs value and 351 * every element in lhs array to 352 * a new instance and return 353 * 354 * @param value -> rhs value of any type 355 * 356 * ASSERT: addability between Tp_ and const Vp_ 357 */ 358 template<typename Vp_> 359 auto operator + (const Vp_ & value) 360 { 361 static_assert(meta::Addable_v<Tp_, const Vp_>, 362 "Array<Tp_, n_>::operator+(const Vp_ &) ~ Invalid Vp_, requires addability between Tp_ and const Vp_ \n"); 363 364 Array<meta::AddableTest<Tp_, const Vp_>, n_> result; 365 result([&, this](auto & elem, const auto & index) 366 { 367 elem = this->_data[index] + value; 368 }); 369 return result; 370 } 371 372 /* Negation 373 * 374 * assign the negation of every element 375 * in rhs array to new instance and return 376 * 377 * ASSERT: negatability of a const Tp_ 378 */ 379 auto operator - (void) 380 { 381 static_assert(meta::Negatable_v<Tp_>, 382 "Array<Tp_, n_>::operator-(void) ~ Invalid Tp_, requires negatability on a Tp_ \n"); 383 384 Array<meta::NegatableTest<Tp_>, n_> result; 385 result([&, this](auto & elem, const auto & index) 386 { 387 elem = -(this->_data[index]); 388 }); 389 return result; 390 } 391 392 /* Subtraction 393 * 394 * assign the subtraction of every element 395 * in rhs array and every element in the lhs 396 * array to a new instance and return 397 * 398 * @param array -> rhs Array of any type 399 * 400 * ASSERT: subtractability between Tp_ and const Vp_ 401 */ 402 template<typename Vp_> 403 auto operator - (const Array<Vp_, n_> & array) 404 { 405 static_assert(meta::Subtractable_v<Tp_, const Vp_>, 406 "Array<Tp_, n_>::operator-(const Array<Vp_, n_> &) ~ Invalid Vp_, requires subtractability between Tp_ and const Vp_ \n"); 407 408 Array<meta::SubtractableTest<Tp_, const Vp_>, n_> result; 409 result([&, this](auto & elem, const auto & index) 410 { 411 elem = this->_data[index] - array[index]; 412 }); 413 return result; 414 } 415 416 /* Scalar Subtraction 417 * 418 * assign the subtraction of rhs value and 419 * every element in lhs array to 420 * a new instance and return 421 * 422 * @param value -> rhs value of any type 423 * 424 * ASSERT: subtractability between Tp_ and const Vp_ 425 */ 426 template<typename Vp_> 427 auto operator - (const Vp_ & value) 428 { 429 static_assert(meta::Subtractable_v<Tp_, const Vp_>, 430 "Array<Tp_, n_>::operator-(const Vp_ &) ~ Invalid Vp_, requires subtractability between Tp_ and const Vp_ \n"); 431 432 Array<meta::SubtractableTest<Tp_, const Vp_>, n_> result; 433 result([&, this](auto & elem, const auto & index) 434 { 435 elem = this->_data[index] - value; 436 }); 437 return result; 438 } 439 440 /* Product 441 * 442 * assign the product of every element 443 * in rhs array and every element in the lhs 444 * array to a new instance and return 445 * 446 * @param array -> rhs Array of any type 447 * 448 * ASSERT: multiplicativity between Tp_ and const Vp_ 449 */ 450 template<typename Vp_> 451 auto operator * (const Array<Vp_, n_> & array) 452 { 453 static_assert(meta::Multiplicative_v<Tp_, const Vp_>, 454 "Array<Tp_, n_>::operator*(const Array<Vp_, n_> &) ~ Invalid Vp_, requires multiplicativity between Tp_ and const Vp_ \n"); 455 456 Array<meta::MultiplicativeTest<Tp_, const Vp_>, n_> result; 457 result([&, this](auto & elem, const auto & index) 458 { 459 elem = this->_data[index] * array[index]; 460 }); 461 return result; 462 } 463 464 /* Scalar Product 465 * 466 * assign the product of rhs value and 467 * every element in lhs array to 468 * a new instance and return 469 * 470 * @param value -> rhs value of any type 471 * 472 * ASSERT: multiplicativity between Tp_ and const Vp_ 473 */ 474 template<typename Vp_> 475 auto operator * (const Vp_ & value) 476 { 477 static_assert(meta::Multiplicative_v<Tp_, const Vp_>, 478 "Array<Tp_, n_>::operator*(const Vp_ &) ~ Invalid Vp_, requires multiplicativity between Tp_ and const Vp_ \n"); 479 480 Array<meta::MultiplicativeTest<Tp_, const Vp_>, n_> result; 481 result([&, this](auto & elem, const auto & index) 482 { 483 elem = this->_data[index] * value; 484 }); 485 return result; 486 } 487 488 /* Quotient 489 * 490 * assign the quotient of every element 491 * in rhs array and every element in the lhs 492 * array to a new instance and return 493 * 494 * @param array -> rhs Array of any type 495 * 496 * ASSERT: divisibility between Tp_ and const Vp_ 497 */ 498 template<typename Vp_> 499 auto operator / (const Array<Vp_, n_> & array) 500 { 501 static_assert(meta::Divisible_v<Tp_, const Vp_>, 502 "Array<Tp_, n_>::operator/(const Array<Vp_, n_> &) ~ Invalid Vp_, requires divisbility between Tp_ and const Vp_ \n"); 503 504 Array<meta::DivisibleTest<Tp_, const Vp_>, n_> result; 505 result([&, this](auto & elem, const auto & index) 506 { 507 elem = this->_data[index] / array[index]; 508 }); 509 return result; 510 } 511 512 /* Scalar Quotient 513 * 514 * assign the quotient of rhs value and 515 * every element in lhs array to 516 * a new instance and return 517 * 518 * @param value -> rhs value of any type 519 * 520 * ASSERT: divisibility between Tp_ and const Vp_ 521 */ 522 template<typename Vp_> 523 auto operator / (const Vp_ & value) 524 { 525 static_assert(meta::Divisible_v<Tp_, const Vp_>, 526 "Array<Tp_, n_>::operator/(const Vp_ &) ~ Invalid Vp_, requires divisbility between Tp_ and const Vp_ \n"); 527 528 Array<meta::DivisibleTest<Tp_, const Vp_>, n_> result; 529 result([&, this](auto & elem, const auto & index) 530 { 531 elem = this->_data[index] / value; 532 }); 533 return result; 534 } 535 536};