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 using iterator = typename std::conditional<
189 Reverse, std::reverse_iterator<ElementPtrType>, ElementPtrType>::type;
190
200 ElementRefType operator[](size_t index) const {
201 if (index >= N) { // TODO
202 ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDEF);
203 index = N - 1; // LCOV_EXCL_LINE
204 } // LCOV_EXCL_LINE
205 if (Reverse)
206 return *(array - index);
207 else
208 return *(array + index);
209 }
210
211 iterator begin() const {
212 if (Reverse)
213 return iterator {array + 1};
214 else
215 return iterator {array};
216 }
217
218 iterator end() const {
219 if (Reverse)
220 return iterator {array + 1 - N};
221 else
222 return iterator {array + N};
223 }
224
225 template <size_t Start, size_t End>
226 ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
227 slice() const;
228
229 private:
231};
232
233template <class T, size_t N>
234template <size_t Start, size_t End>
235inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), false>
237 static_assert(Start < N, "");
238 static_assert(End < N, "");
239 return &(*this)[Start];
240}
241
242template <class T, size_t N>
243template <size_t Start, size_t End>
244inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true>
246 static_assert(Start < N, "");
247 static_assert(End < N, "");
248 return &(*this)[Start];
249}
250
251template <class T, size_t N, bool Reverse, bool Const>
252template <size_t Start, size_t End>
253ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
255 static_assert(Start < N, "");
256 static_assert(End < N, "");
257 return &(*this)[Start];
258}
259
261template <class T, size_t N, bool Reverse, bool Const>
265 return a + n;
266}
267
268// Equality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
269
272template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
273 bool Reverse2, bool Const1, bool Const2>
276 static_assert(N1 == N2, "Error: sizes do not match");
277 for (size_t i = 0; i < N1; ++i)
278 if (a[i] != b[i])
279 return false;
280 return true;
281}
282
285template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
288 return a.slice() == b;
289}
290
293template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
295 const Array<T2, N2> &b) {
296 return a == b.slice();
297}
298
299// Inequality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
300
303template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
304 bool Reverse2, bool Const1, bool Const2>
307 return !(a == b);
308}
309
312template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
315 return a.slice() != b;
316}
317
320template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
322 const Array<T2, N2> &b) {
323 return a != b.slice();
324}
325
326// Addition ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
327
330template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
331 bool Reverse2, bool Const1, bool Const2>
332Array<decltype(T1 {} + T2 {}), N1>
335 static_assert(N1 == N2, "Error: sizes do not match");
336 Array<decltype(T1 {} + T2 {}), N1> result = {{}};
337 for (size_t i = 0; i < N1; ++i)
338 result[i] = a[i] + b[i];
339 return result;
340}
341
344template <class T1, class T2, size_t N1, size_t N2>
345Array<decltype(T1 {} + T2 {}), N1> operator+(const Array<T1, N1> &a,
346 const Array<T2, N2> &b) {
347 return a.slice() + b.slice();
348}
349
352template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
353 bool Reverse2, bool Const1, bool Const2>
354const ArraySlice<T1, N1, Reverse1, Const1> &
357 static_assert(N1 == N2, "Error: sizes do not match");
358 for (size_t i = 0; i < N1; ++i)
359 a[i] += b[i];
360 return a;
361}
362
365template <class T1, class T2, size_t N1, size_t N2>
367 a.slice() += b.slice();
368 return a;
369}
370
371// Subtraction :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
372
375template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
376 bool Reverse2, bool Const1, bool Const2>
377Array<decltype(T1 {} - T2 {}), N1>
380 static_assert(N1 == N2, "Error: sizes do not match");
381 Array<decltype(T1 {} - T2 {}), N1> result = {{}};
382 for (size_t i = 0; i < N1; ++i)
383 result[i] = a[i] - b[i];
384 return result;
385}
386
389template <class T1, class T2, size_t N1, size_t N2>
390Array<decltype(T1 {} - T2 {}), N1> operator-(const Array<T1, N1> &a,
391 const Array<T2, N2> &b) {
392 return a.slice() - b.slice();
393}
394
397template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
398 bool Reverse2, bool Const1, bool Const2>
399const ArraySlice<T1, N1, Reverse1, Const1> &
402 static_assert(N1 == N2, "Error: sizes do not match");
403 for (size_t i = 0; i < N1; ++i)
404 a[i] -= b[i];
405 return a;
406}
407
410template <class T1, class T2, size_t N1, size_t N2>
412 a.slice() -= b.slice();
413 return a;
414}
415
416// Scalar Multiplication :::::::::::::::::::::::::::::::::::::::::::::::::::::::
417
420template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
421Array<decltype(T1 {} * T2 {}), N1>
423 Array<decltype(T1 {} * T2 {}), N1> result = {{}};
424 for (size_t i = 0; i < N1; ++i)
425 result[i] = a[i] * b;
426 return result;
427}
428
431template <class T1, class T2, size_t N1>
432Array<decltype(T1 {} * T2 {}), N1> operator*(const Array<T1, N1> &a, T2 b) {
433 return a.slice() * b;
434}
435
438template <class T1, class T2, size_t N2, bool Reverse2, bool Const2>
439Array<decltype(T1 {} * T2 {}), N2>
441 Array<decltype(T1 {} * T2 {}), N2> result = {{}};
442 for (size_t i = 0; i < N2; ++i)
443 result[i] = a * b[i];
444 return result;
445}
446
449template <class T1, class T2, size_t N2>
450Array<decltype(T1 {} * T2 {}), N2> operator*(T1 a, const Array<T2, N2> &b) {
451 return a * b.slice();
452}
453
456template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
457const ArraySlice<T1, N1, Reverse1, Const1> &
459 for (size_t i = 0; i < N1; ++i)
460 a[i] *= b;
461 return a;
462}
463
466template <class T1, class T2, size_t N1>
468 a.slice() *= b;
469 return a;
470}
471
472// Scalar Division :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
473
476template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
477Array<decltype(T1 {} / T2 {}), N1>
479 Array<decltype(T1 {} / T2 {}), N1> result = {{}};
480 for (size_t i = 0; i < N1; ++i)
481 result[i] = a[i] / b;
482 return result;
483}
484
487template <class T1, class T2, size_t N1>
488Array<decltype(T1 {} / T2 {}), N1> operator/(const Array<T1, N1> &a, T2 b) {
489 return a.slice() / b;
490}
491
494template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
495const ArraySlice<T1, N1, Reverse1, Const1> &
497 for (size_t i = 0; i < N1; ++i)
498 a[i] /= b;
499 return a;
500}
501
504template <class T1, class T2, size_t N1>
506 a.slice() /= b;
507 return a;
508}
509
510// Negation ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
511
514template <class T, size_t N, bool Reverse, bool Const>
515Array<decltype(-T {}), N> operator-(ArraySlice<T, N, Reverse, Const> a) {
516 Array<decltype(-T {}), N> result = {{}};
517 for (size_t i = 0; i < N; ++i)
518 result[i] = -a[i];
519 return result;
520}
521
524template <class T, size_t N>
525Array<decltype(-T {}), N> operator-(const Array<T, N> &a) {
526 return -a.slice();
527}
528
529// Type aliases ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
530
532template <class T, size_t NumRows, size_t NumCols>
534
536
538
#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
Class for a view on a slice of an array.
Definition: Array.hpp:168
iterator begin() const
Definition: Array.hpp:211
ElementPtrType array
Definition: Array.hpp:230
ArraySlice(ElementPtrType array)
Constructor.
Definition: Array.hpp:176
typename std::conditional< Const, const T &, T & >::type ElementRefType
Definition: Array.hpp:170
typename std::conditional< Reverse, std::reverse_iterator< ElementPtrType >, ElementPtrType >::type iterator
Definition: Array.hpp:189
iterator end() const
Definition: Array.hpp:218
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:200
Array< T, N > asArray() const
Definition: Array.hpp:181
Array< T1, N1 > & operator*=(Array< T1, N1 > &a, T2 b)
Array *= Scalar.
Definition: Array.hpp:467
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice != Slice.
Definition: Array.hpp:305
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:355
const ArraySlice< T1, N1, Reverse1, Const1 > & operator*=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, T2 b)
Slice *= Scalar.
Definition: Array.hpp:458
const ArraySlice< T1, N1, Reverse1, Const1 > & operator/=(const ArraySlice< T1, N1, Reverse1, Const1 > &a, T2 b)
Slice /= Scalar.
Definition: Array.hpp:496
bool operator!=(const Array< T1, N1 > &a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Array != Slice.
Definition: Array.hpp:313
bool operator==(const Array< T1, N1 > &a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Array == Slice.
Definition: Array.hpp:286
Array< T1, N1 > & operator+=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array += Array.
Definition: Array.hpp:366
Array< decltype(T1 {}+T2 {}), N1 > operator+(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice + Slice.
Definition: Array.hpp:333
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice == Slice.
Definition: Array.hpp:274
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice == Array.
Definition: Array.hpp:294
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:400
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:245
Array< T1, N1 > & operator/=(Array< T1, N1 > &a, T2 b)
Array /= Scalar.
Definition: Array.hpp:505
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice != Array.
Definition: Array.hpp:321
Array< T1, N1 > & operator-=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array -= Array.
Definition: Array.hpp:411
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), false > slice()
Get a view on a slice of the Array.
Definition: Array.hpp:236
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