C++ container for matrices.
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};