Control Surface main
MIDI Control Surface library for Arduino
Array.hpp
Go to the documentation of this file.
1/* ✔ */
2
3#pragma once
4
6
7AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
8
9#include <AH/Error/Error.hpp>
10#include <AH/STL/iterator>
11#include <AH/STL/type_traits> // conditional
12#include <stddef.h> // size_t
13
15
16template <class T>
17constexpr T abs_diff(const T &a, const T &b) {
18 return a < b ? b - a : a - b;
19}
20
23
24template <class T, size_t N, bool Reverse, bool Const>
25class ArraySlice;
26
35template <class T, size_t N>
36struct Array {
37 T data[N];
38 using type = T;
39 constexpr static size_t length = N;
40
50 T &operator[](size_t index) {
51 if (index >= N) { // TODO
52 ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDED);
53 index = N - 1; // LCOV_EXCL_LINE
54 } // LCOV_EXCL_LINE
55 return data[index];
56 }
57
67 const T &operator[](size_t index) const {
68 if (index >= N) { // TODO
69 ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDED);
70 index = N - 1; // LCOV_EXCL_LINE
71 } // LCOV_EXCL_LINE
72 return data[index];
73 }
74
78 T *begin() { return &data[0]; }
79
83 const T *begin() const { return &data[0]; }
84
88 T *end() { return &data[N]; }
89
93 const T *end() const { return &data[N]; }
94
101 bool operator==(const Array<T, N> &rhs) const {
102 if (this == &rhs)
103 return true;
104 for (size_t i = 0; i < N; i++)
105 if ((*this)[i] != rhs[i])
106 return false;
107 return true;
108 }
109
116 bool operator!=(const Array<T, N> &rhs) const { return !(*this == rhs); }
117
118 public:
130 template <size_t Start = 0, size_t End = N - 1>
131 ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), false> slice();
132
137 template <size_t Start = 0, size_t End = N - 1>
138 ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true> slice() const;
139
144 template <size_t Start = 0, size_t End = N - 1>
145 ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true>
146 cslice() const {
147 const Array<T, N> *This = this;
148 return This->slice();
149 }
150};
151
167template <class T, size_t N, bool Reverse = false, bool Const = true>
170 typename std::conditional<Const, const T &, T &>::type;
172 typename std::conditional<Const, const T *, T *>::type;
173
174 public:
176 ArraySlice(ElementPtrType array) : array{array} {}
177
179 operator Array<T, N>() const { return asArray(); }
180
182 Array<T, N> slice = {{}};
183 for (size_t i = 0; i < N; ++i)
184 slice[i] = (*this)[i];
185 return slice;
186 }
187
188 class Iterator {
189 public:
190 Iterator(ElementPtrType ptr) : ptr(ptr) {}
191
192 using difference_type = std::ptrdiff_t;
193 using value_type = T;
196 using iterator_category = std::random_access_iterator_tag;
197
198 bool operator==(Iterator rhs) const { return ptr == rhs.ptr; }
199 bool operator!=(Iterator rhs) const { return ptr != rhs.ptr; }
200
201 reference operator*() const { return *ptr; }
202 pointer operator->() const { return ptr; }
203
204 reference operator[](difference_type n) const { return ptr[n]; }
205
207 Reverse ? --ptr : ++ptr;
208 return *this;
209 }
210
212 Reverse ? ++ptr : --ptr;
213 return *this;
214 }
215
217 Iterator ret = *this;
218 ++(*this);
219 return ret;
220 }
221
223 Iterator ret = *this;
224 --(*this);
225 return ret;
226 }
227
229 Reverse ? (ptr -= n) : (ptr += n);
230 return *this;
231 }
232
234 Reverse ? (ptr += n) : (ptr -= n);
235 return *this;
236 }
237
239 return Reverse ? rhs.ptr - ptr : ptr - rhs.ptr;
240 }
241
243 return Reverse ? ptr - rhs : ptr + rhs;
244 }
245
247 return Reverse ? ptr + rhs : ptr - rhs;
248 }
249
250 bool operator<(Iterator rhs) const {
251 return Reverse ? rhs.ptr < ptr : ptr < rhs.ptr;
252 }
253
254 bool operator>(Iterator rhs) const { return rhs < *this; }
255
256 bool operator<=(Iterator rhs) const { return !(*this > rhs); }
257
258 bool operator>=(Iterator rhs) const { return !(*this < rhs); }
259
260 private:
262 };
263
273 ElementRefType operator[](size_t index) const {
274 if (index >= N) { // TODO
275 ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDEF);
276 index = N - 1; // LCOV_EXCL_LINE
277 } // LCOV_EXCL_LINE
278 if (Reverse)
279 return *(array - index);
280 else
281 return *(array + index);
282 }
283
284 Iterator begin() const {
285 if (Reverse)
286 return array;
287 else
288 return array;
289 }
290
291 Iterator end() const {
292 if (Reverse)
293 return array - N;
294 else
295 return array + N;
296 }
297
298 template <size_t Start, size_t End>
299 ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
300 slice() const;
301
302 private:
304};
305
306template <class T, size_t N>
307template <size_t Start, size_t End>
308inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), false>
310 static_assert(Start < N, "");
311 static_assert(End < N, "");
312 return &(*this)[Start];
313}
314
315template <class T, size_t N>
316template <size_t Start, size_t End>
317inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true>
319 static_assert(Start < N, "");
320 static_assert(End < N, "");
321 return &(*this)[Start];
322}
323
324template <class T, size_t N, bool Reverse, bool Const>
325template <size_t Start, size_t End>
326ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
328 static_assert(Start < N, "");
329 static_assert(End < N, "");
330 return &(*this)[Start];
331}
332
334template <class T, size_t N, bool Reverse, bool Const>
338 return a + n;
339}
340
341// Equality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
342
345template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
346 bool Reverse2, bool Const1, bool Const2>
349 static_assert(N1 == N2, "Error: sizes do not match");
350 for (size_t i = 0; i < N1; ++i)
351 if (a[i] != b[i])
352 return false;
353 return true;
354}
355
358template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
361 return a.slice() == b;
362}
363
366template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
368 const Array<T2, N2> &b) {
369 return a == b.slice();
370}
371
372// Inequality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
373
376template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
377 bool Reverse2, bool Const1, bool Const2>
380 return !(a == b);
381}
382
385template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
388 return a.slice() != b;
389}
390
393template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
395 const Array<T2, N2> &b) {
396 return a != b.slice();
397}
398
399// Addition ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
400
403template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
404 bool Reverse2, bool Const1, bool Const2>
405Array<decltype(T1{} + T2{}), N1>
408 static_assert(N1 == N2, "Error: sizes do not match");
409 Array<decltype(T1{} + T2{}), N1> result = {{}};
410 for (size_t i = 0; i < N1; ++i)
411 result[i] = a[i] + b[i];
412 return result;
413}
414
417template <class T1, class T2, size_t N1, size_t N2>
418Array<decltype(T1{} + T2{}), N1> operator+(const Array<T1, N1> &a,
419 const Array<T2, N2> &b) {
420 return a.slice() + b.slice();
421}
422
425template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
426 bool Reverse2, bool Const1, bool Const2>
427const ArraySlice<T1, N1, Reverse1, Const1> &
430 static_assert(N1 == N2, "Error: sizes do not match");
431 for (size_t i = 0; i < N1; ++i)
432 a[i] += b[i];
433 return a;
434}
435
438template <class T1, class T2, size_t N1, size_t N2>
440 a.slice() += b.slice();
441 return a;
442}
443
444// Subtraction :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
445
448template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
449 bool Reverse2, bool Const1, bool Const2>
450Array<decltype(T1{} - T2{}), N1>
453 static_assert(N1 == N2, "Error: sizes do not match");
454 Array<decltype(T1{} - T2{}), N1> result = {{}};
455 for (size_t i = 0; i < N1; ++i)
456 result[i] = a[i] - b[i];
457 return result;
458}
459
462template <class T1, class T2, size_t N1, size_t N2>
463Array<decltype(T1{} - T2{}), N1> operator-(const Array<T1, N1> &a,
464 const Array<T2, N2> &b) {
465 return a.slice() - b.slice();
466}
467
470template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
471 bool Reverse2, bool Const1, bool Const2>
472const ArraySlice<T1, N1, Reverse1, Const1> &
475 static_assert(N1 == N2, "Error: sizes do not match");
476 for (size_t i = 0; i < N1; ++i)
477 a[i] -= b[i];
478 return a;
479}
480
483template <class T1, class T2, size_t N1, size_t N2>
485 a.slice() -= b.slice();
486 return a;
487}
488
489// Scalar Multiplication :::::::::::::::::::::::::::::::::::::::::::::::::::::::
490
493template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
494Array<decltype(T1{} * T2{}), N1>
496 Array<decltype(T1{} * T2{}), N1> result = {{}};
497 for (size_t i = 0; i < N1; ++i)
498 result[i] = a[i] * b;
499 return result;
500}
501
504template <class T1, class T2, size_t N1>
505Array<decltype(T1{} * T2{}), N1> operator*(const Array<T1, N1> &a, T2 b) {
506 return a.slice() * b;
507}
508
511template <class T1, class T2, size_t N2, bool Reverse2, bool Const2>
512Array<decltype(T1{} * T2{}), N2>
514 Array<decltype(T1{} * T2{}), N2> result = {{}};
515 for (size_t i = 0; i < N2; ++i)
516 result[i] = a * b[i];
517 return result;
518}
519
522template <class T1, class T2, size_t N2>
523Array<decltype(T1{} * T2{}), N2> operator*(T1 a, const Array<T2, N2> &b) {
524 return a * b.slice();
525}
526
529template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
530const ArraySlice<T1, N1, Reverse1, Const1> &
532 for (size_t i = 0; i < N1; ++i)
533 a[i] *= b;
534 return a;
535}
536
539template <class T1, class T2, size_t N1>
541 a.slice() *= b;
542 return a;
543}
544
545// Scalar Division :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
546
549template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
550Array<decltype(T1{} / T2{}), N1>
552 Array<decltype(T1{} / T2{}), N1> result = {{}};
553 for (size_t i = 0; i < N1; ++i)
554 result[i] = a[i] / b;
555 return result;
556}
557
560template <class T1, class T2, size_t N1>
561Array<decltype(T1{} / T2{}), N1> operator/(const Array<T1, N1> &a, T2 b) {
562 return a.slice() / b;
563}
564
567template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
568const ArraySlice<T1, N1, Reverse1, Const1> &
570 for (size_t i = 0; i < N1; ++i)
571 a[i] /= b;
572 return a;
573}
574
577template <class T1, class T2, size_t N1>
579 a.slice() /= b;
580 return a;
581}
582
583// Negation ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
584
587template <class T, size_t N, bool Reverse, bool Const>
588Array<decltype(-T{}), N> operator-(ArraySlice<T, N, Reverse, Const> a) {
589 Array<decltype(-T{}), N> result = {{}};
590 for (size_t i = 0; i < N; ++i)
591 result[i] = -a[i];
592 return result;
593}
594
597template <class T, size_t N>
598Array<decltype(-T{}), N> operator-(const Array<T, N> &a) {
599 return -a.slice();
600}
601
602// Type aliases ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
603
605template <class T, size_t NumRows, size_t NumCols>
607
609
611
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
#define ERROR(msg, errc)
Definition: Error.hpp:22
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:37
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:36
ElementRefType reference
Definition: Array.hpp:195
ElementPtrType pointer
Definition: Array.hpp:194
bool operator!=(Iterator rhs) const
Definition: Array.hpp:199
bool operator<=(Iterator rhs) const
Definition: Array.hpp:256
Iterator & operator-=(difference_type n)
Definition: Array.hpp:233
bool operator>=(Iterator rhs) const
Definition: Array.hpp:258
reference operator[](difference_type n) const
Definition: Array.hpp:204
difference_type operator-(Iterator rhs) const
Definition: Array.hpp:238
Iterator operator--(int)
Definition: Array.hpp:222
Iterator(ElementPtrType ptr)
Definition: Array.hpp:190
std::random_access_iterator_tag iterator_category
Definition: Array.hpp:196
Iterator & operator+=(difference_type n)
Definition: Array.hpp:228
Iterator operator-(difference_type rhs) const
Definition: Array.hpp:246
bool operator==(Iterator rhs) const
Definition: Array.hpp:198
bool operator<(Iterator rhs) const
Definition: Array.hpp:250
reference operator*() const
Definition: Array.hpp:201
ElementPtrType ptr
Definition: Array.hpp:261
Iterator operator++(int)
Definition: Array.hpp:216
Iterator operator+(difference_type rhs) const
Definition: Array.hpp:242
std::ptrdiff_t difference_type
Definition: Array.hpp:192
Iterator & operator++()
Definition: Array.hpp:206
Iterator & operator--()
Definition: Array.hpp:211
bool operator>(Iterator rhs) const
Definition: Array.hpp:254
pointer operator->() const
Definition: Array.hpp:202
Class for a view on a slice of an array.
Definition: Array.hpp:168
Iterator begin() const
Definition: Array.hpp:284
ElementPtrType array
Definition: Array.hpp:303
ArraySlice(ElementPtrType array)
Constructor.
Definition: Array.hpp:176
typename std::conditional< Const, const T &, T & >::type ElementRefType
Definition: Array.hpp:170
Iterator end() const
Definition: Array.hpp:291
typename std::conditional< Const, const T *, T * >::type ElementPtrType
Definition: Array.hpp:172
ElementRefType operator[](size_t index) const
Get the element at the given index.
Definition: Array.hpp:273
Array< T, N > asArray() const
Definition: Array.hpp:181
Array< T1, N1 > & operator*=(Array< T1, N1 > &a, T2 b)
Array *= Scalar.
Definition: Array.hpp:540
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice != Slice.
Definition: Array.hpp:378
const ArraySlice< T1, N1, Reverse1, Const1 > & operator+=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, const ArraySlice< T2, N2, Reverse2, Const2 > &b)
Slice += Slice.
Definition: Array.hpp:428
const ArraySlice< T1, N1, Reverse1, Const1 > & operator*=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, T2 b)
Slice *= Scalar.
Definition: Array.hpp:531
const ArraySlice< T1, N1, Reverse1, Const1 > & operator/=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, T2 b)
Slice /= Scalar.
Definition: Array.hpp:569
bool operator!=(const Array< T1, N1 > &a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Array != Slice.
Definition: Array.hpp:386
bool operator==(const Array< T1, N1 > &a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Array == Slice.
Definition: Array.hpp:359
Array< T1, N1 > & operator+=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array += Array.
Definition: Array.hpp:439
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice == Slice.
Definition: Array.hpp:347
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice == Array.
Definition: Array.hpp:367
const ArraySlice< T1, N1, Reverse1, Const1 > & operator-=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, const ArraySlice< T2, N2, Reverse2, Const2 > &b)
Slice -= Slice.
Definition: Array.hpp:473
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), true > slice() const
Get a read-only view on a slice of the Array.
Definition: Array.hpp:318
Array< T1, N1 > & operator/=(Array< T1, N1 > &a, T2 b)
Array /= Scalar.
Definition: Array.hpp:578
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice != Array.
Definition: Array.hpp:394
Array< T1, N1 > & operator-=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array -= Array.
Definition: Array.hpp:484
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), false > slice()
Get a view on a slice of the Array.
Definition: Array.hpp:309
ArraySlice< T, N, Reverse, Const >::Iterator operator+(typename ArraySlice< T, N, Reverse, Const >::Iterator::difference_type n, typename ArraySlice< T, N, Reverse, Const >::Iterator a)
Definition: Array.hpp:335
constexpr T abs_diff(const T &a, const T &b)
Definition: Array.hpp:17
An array wrapper for easy copying, comparing, and iterating.
Definition: Array.hpp:36
const T * end() const
Get a pointer to the memory beyond the array.
Definition: Array.hpp:93
T & operator[](size_t index)
Get the element at the given index.
Definition: Array.hpp:50
bool operator==(const Array< T, N > &rhs) const
Check the equality of all elements in two arrays.
Definition: Array.hpp:101
bool operator!=(const Array< T, N > &rhs) const
Check the inequality of all elements in two arrays.
Definition: Array.hpp:116
T type
Definition: Array.hpp:38
T * begin()
Get a pointer to the first element.
Definition: Array.hpp:78
T * end()
Get a pointer to the memory beyond the array.
Definition: Array.hpp:88
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), true > cslice() const
Get a read-only view on a slice of the Array.
Definition: Array.hpp:146
const T * begin() const
Get a pointer to the first element.
Definition: Array.hpp:83
const T & operator[](size_t index) const
Get the element at the given index.
Definition: Array.hpp:67