Control Surface  1.2.0
MIDI Control Surface library for Arduino
Array.hpp
Go to the documentation of this file.
1 /* ✔ */
2 
3 #pragma once
4 
6 
7 AH_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 
16 template <class T>
17 constexpr T abs_diff(const T &a, const T &b) {
18  return a < b ? b - a : a - b;
19 }
20 
23 
24 template <class T, size_t N, bool Reverse, bool Const>
25 class ArraySlice;
26 
35 template <class T, size_t N>
36 struct 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 
167 template <class T, size_t N, bool Reverse = false, bool Const = true>
168 class ArraySlice {
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 
204  Reverse ? --ptr : ++ptr;
205  return *this;
206  }
207 
209  Reverse ? ++ptr : --ptr;
210  return *this;
211  }
212 
214  return Reverse ? rhs.ptr - ptr : ptr - rhs.ptr;
215  }
216 
218  return Reverse ? ptr - rhs : ptr + rhs;
219  }
220 
222  return Reverse ? ptr + rhs : ptr - rhs;
223  }
224 
225  bool operator<(Iterator rhs) const {
226  return Reverse ? rhs.ptr < ptr : ptr < rhs.ptr;
227  }
228 
229  bool operator<=(Iterator rhs) const {
230  return Reverse ? rhs.ptr <= ptr : ptr <= rhs.ptr;
231  }
232 
233  private:
235  };
236 
246  ElementRefType operator[](size_t index) const {
247  if (index >= N) { // TODO
248  ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDEF);
249  index = N - 1; // LCOV_EXCL_LINE
250  } // LCOV_EXCL_LINE
251  if (Reverse)
252  return array[-index];
253  else
254  return array[index];
255  }
256 
257  Iterator begin() const {
258  if (Reverse)
259  return array;
260  else
261  return array;
262  }
263 
264  Iterator end() const {
265  if (Reverse)
266  return array - N;
267  else
268  return array + N;
269  }
270 
271  template <size_t Start, size_t End>
272  ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
273  slice() const;
274 
275  private:
277 };
278 
279 template <class T, size_t N>
280 template <size_t Start, size_t End>
281 inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), false>
283  static_assert(Start < N, "");
284  static_assert(End < N, "");
285  return &(*this)[Start];
286 }
287 
288 template <class T, size_t N>
289 template <size_t Start, size_t End>
290 inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true>
291 Array<T, N>::slice() const {
292  static_assert(Start < N, "");
293  static_assert(End < N, "");
294  return &(*this)[Start];
295 }
296 
297 template <class T, size_t N, bool Reverse, bool Const>
298 template <size_t Start, size_t End>
299 ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
300 ArraySlice<T, N, Reverse, Const>::slice() const {
301  static_assert(Start < N, "");
302  static_assert(End < N, "");
303  return &(*this)[Start];
304 }
305 
306 // Equality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
307 
309 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
310  bool Reverse2, bool Const1, bool Const2>
313  static_assert(N1 == N2, "Error: sizes do not match");
314  for (size_t i = 0; i < N1; ++i)
315  if (a[i] != b[i])
316  return false;
317  return true;
318 }
319 
321 template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
322 bool operator==(const Array<T1, N1> &a,
324  return a.slice() == b;
325 }
326 
328 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
330  const Array<T2, N2> &b) {
331  return a == b.slice();
332 }
333 
334 // Inequality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
335 
337 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
338  bool Reverse2, bool Const1, bool Const2>
341  return !(a == b);
342 }
343 
345 template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
346 bool operator!=(const Array<T1, N1> &a,
348  return a.slice() != b;
349 }
350 
352 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
354  const Array<T2, N2> &b) {
355  return a != b.slice();
356 }
357 
358 // Addition ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
359 
361 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
362  bool Reverse2, bool Const1, bool Const2>
363 Array<decltype(T1{} + T2{}), N1>
366  static_assert(N1 == N2, "Error: sizes do not match");
367  Array<decltype(T1{} + T2{}), N1> result = {{}};
368  for (size_t i = 0; i < N1; ++i)
369  result[i] = a[i] + b[i];
370  return result;
371 }
372 
374 template <class T1, class T2, size_t N1, size_t N2>
375 Array<decltype(T1{} + T2{}), N1> operator+(const Array<T1, N1> &a,
376  const Array<T2, N2> &b) {
377  return a.slice() + b.slice();
378 }
379 
381 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
382  bool Reverse2, bool Const1, bool Const2>
383 const ArraySlice<T1, N1, Reverse1, Const1> &
386  static_assert(N1 == N2, "Error: sizes do not match");
387  for (size_t i = 0; i < N1; ++i)
388  a[i] += b[i];
389  return a;
390 }
391 
393 template <class T1, class T2, size_t N1, size_t N2>
395  a.slice() += b.slice();
396  return a;
397 }
398 
399 // Subtraction :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
400 
402 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
403  bool Reverse2, bool Const1, bool Const2>
404 Array<decltype(T1{} - T2{}), N1>
407  static_assert(N1 == N2, "Error: sizes do not match");
408  Array<decltype(T1{} - T2{}), N1> result = {{}};
409  for (size_t i = 0; i < N1; ++i)
410  result[i] = a[i] - b[i];
411  return result;
412 }
413 
415 template <class T1, class T2, size_t N1, size_t N2>
416 Array<decltype(T1{} - T2{}), N1> operator-(const Array<T1, N1> &a,
417  const Array<T2, N2> &b) {
418  return a.slice() - b.slice();
419 }
420 
422 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
423  bool Reverse2, bool Const1, bool Const2>
424 const ArraySlice<T1, N1, Reverse1, Const1> &
427  static_assert(N1 == N2, "Error: sizes do not match");
428  for (size_t i = 0; i < N1; ++i)
429  a[i] -= b[i];
430  return a;
431 }
432 
434 template <class T1, class T2, size_t N1, size_t N2>
436  a.slice() -= b.slice();
437  return a;
438 }
439 
440 // Scalar Multiplication :::::::::::::::::::::::::::::::::::::::::::::::::::::::
441 
443 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
444 Array<decltype(T1{} * T2{}), N1>
446  Array<decltype(T1{} * T2{}), N1> result = {{}};
447  for (size_t i = 0; i < N1; ++i)
448  result[i] = a[i] * b;
449  return result;
450 }
451 
453 template <class T1, class T2, size_t N1>
454 Array<decltype(T1{} * T2{}), N1> operator*(const Array<T1, N1> &a, T2 b) {
455  return a.slice() * b;
456 }
457 
459 template <class T1, class T2, size_t N2, bool Reverse2, bool Const2>
460 Array<decltype(T1{} * T2{}), N2>
462  Array<decltype(T1{} * T2{}), N2> result = {{}};
463  for (size_t i = 0; i < N2; ++i)
464  result[i] = a * b[i];
465  return result;
466 }
467 
469 template <class T1, class T2, size_t N2>
470 Array<decltype(T1{} * T2{}), N2> operator*(T1 a, const Array<T2, N2> &b) {
471  return a * b.slice();
472 }
473 
475 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
476 const ArraySlice<T1, N1, Reverse1, Const1> &
478  for (size_t i = 0; i < N1; ++i)
479  a[i] *= b;
480  return a;
481 }
482 
484 template <class T1, class T2, size_t N1>
486  a.slice() *= b;
487  return a;
488 }
489 
490 // Scalar Division :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
491 
493 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
494 Array<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 
503 template <class T1, class T2, size_t N1>
504 Array<decltype(T1{} / T2{}), N1> operator/(const Array<T1, N1> &a, T2 b) {
505  return a.slice() / b;
506 }
507 
509 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
510 const ArraySlice<T1, N1, Reverse1, Const1> &
512  for (size_t i = 0; i < N1; ++i)
513  a[i] /= b;
514  return a;
515 }
516 
518 template <class T1, class T2, size_t N1>
520  a.slice() /= b;
521  return a;
522 }
523 
524 // Negation ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
525 
527 template <class T, size_t N, bool Reverse, bool Const>
528 Array<decltype(-T{}), N> operator-(ArraySlice<T, N, Reverse, Const> a) {
529  Array<decltype(-T{}), N> result = {{}};
530  for (size_t i = 0; i < N; ++i)
531  result[i] = -a[i];
532  return result;
533 }
534 
536 template <class T, size_t N>
537 Array<decltype(-T{}), N> operator-(const Array<T, N> &a) {
538  return -a.slice();
539 }
540 
541 // Type aliases ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
542 
544 template <class T, size_t nb_rows, size_t nb_cols>
546 
548 
550 
AH::ArraySlice::Iterator::operator++
Iterator & operator++()
Definition: Array.hpp:203
AH::ArraySlice::Iterator::operator!=
bool operator!=(Iterator rhs) const
Definition: Array.hpp:198
AH::ArraySlice::Iterator::operator-
difference_type operator-(Iterator rhs) const
Definition: Array.hpp:213
AH::ArraySlice::Iterator::operator==
bool operator==(Iterator rhs) const
Definition: Array.hpp:199
AH::ArraySlice::Iterator::value_type
T value_type
Definition: Array.hpp:193
AH::Array::end
T * end()
Get a pointer to the memory beyond the array.
Definition: Array.hpp:88
AH::ArraySlice::Iterator
Definition: Array.hpp:188
AH::ArraySlice::ElementPtrType
typename std::conditional< Const, const T *, T * >::type ElementPtrType
Definition: Array.hpp:172
AH::ArraySlice::array
ElementPtrType array
Definition: Array.hpp:276
AH::ArraySlice::Iterator::operator--
Iterator & operator--()
Definition: Array.hpp:208
Warnings.hpp
AH::ArraySlice::Iterator::pointer
ElementPtrType pointer
Definition: Array.hpp:194
AH::Array::end
const T * end() const
Get a pointer to the memory beyond the array.
Definition: Array.hpp:93
AH::ArraySlice::end
Iterator end() const
Definition: Array.hpp:264
AH::ArraySlice::Iterator::difference_type
std::ptrdiff_t difference_type
Definition: Array.hpp:192
AH::operator*=
Array< T1, N1 > & operator*=(Array< T1, N1 > &a, T2 b)
Array *= Scalar.
Definition: Array.hpp:485
AH::Button
A class for reading and debouncing buttons and switches.
Definition: Button.hpp:18
AH::ArraySlice::Iterator::operator<=
bool operator<=(Iterator rhs) const
Definition: Array.hpp:229
AH::ArraySlice::ArraySlice
ArraySlice(ElementPtrType array)
Constructor.
Definition: Array.hpp:176
AH::ArraySlice::asArray
Array< T, N > asArray() const
Definition: Array.hpp:181
AH::Array::slice
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), false > slice()
Get a view on a slice of the Array.
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
AH::Array::operator[]
const T & operator[](size_t index) const
Get the element at the given index.
Definition: Array.hpp:67
AH::ArraySlice::Iterator::ptr
ElementPtrType ptr
Definition: Array.hpp:234
AH::operator-=
Array< T1, N1 > & operator-=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array -= Array.
Definition: Array.hpp:435
AH::ArraySlice::Iterator::operator+
Iterator operator+(difference_type rhs) const
Definition: Array.hpp:217
AH::ArraySlice::Iterator::operator*
reference operator*() const
Definition: Array.hpp:201
AH::operator/=
Array< T1, N1 > & operator/=(Array< T1, N1 > &a, T2 b)
Array /= Scalar.
Definition: Array.hpp:519
ERROR
#define ERROR(msg, errc)
Print the error message and error code, and stop the execution if FATAL_ERRORS are enabled.
Definition: Error.hpp:42
AH::ArraySlice::slice
ArraySlice< T, abs_diff(End, Start)+1, Reverse ^(End< Start), Const > slice() const
AH::ArraySlice::Iterator::iterator_category
std::random_access_iterator_tag iterator_category
Definition: Array.hpp:196
AH::Array
An array wrapper for easy copying, comparing, and iterating.
Definition: Array.hpp:36
AH::ArraySlice::operator[]
ElementRefType operator[](size_t index) const
Get the element at the given index.
Definition: Array.hpp:246
AH::Array::operator==
bool operator==(const Array< T, N > &rhs) const
Check the equality of all elements in two arrays.
Definition: Array.hpp:101
AH::ArraySlice::Iterator::operator<
bool operator<(Iterator rhs) const
Definition: Array.hpp:225
AH::Array::begin
T * begin()
Get a pointer to the first element.
Definition: Array.hpp:78
AH::Array::slice
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), true > slice() const
Get a read-only view on a slice of the Array.
AH::ArraySlice::Iterator::Iterator
Iterator(ElementPtrType ptr)
Definition: Array.hpp:190
AH::Array::cslice
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
AH::operator+=
Array< T1, N1 > & operator+=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array += Array.
Definition: Array.hpp:394
AH::ArraySlice
Class for a view on a slice of an array.
Definition: Array.hpp:168
AH::ArraySlice::Iterator::operator-
Iterator operator-(difference_type rhs) const
Definition: Array.hpp:221
AH::abs_diff
constexpr T abs_diff(const T &a, const T &b)
Definition: Array.hpp:17
MIDI_Notes::F
constexpr int8_t F
Definition: Notes.hpp:23
AH::Array::operator[]
T & operator[](size_t index)
Get the element at the given index.
Definition: Array.hpp:50
AH::ArraySlice::Iterator::reference
ElementRefType reference
Definition: Array.hpp:195
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
BEGIN_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:9
END_AH_NAMESPACE
#define END_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:10
AH::operator!=
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice != Array.
Definition: Array.hpp:353
AH::Array::operator!=
bool operator!=(const Array< T, N > &rhs) const
Check the inequality of all elements in two arrays.
Definition: Array.hpp:116
AH::ArraySlice::ElementRefType
typename std::conditional< Const, const T &, T & >::type ElementRefType
Definition: Array.hpp:170
AH::Array::begin
const T * begin() const
Get a pointer to the first element.
Definition: Array.hpp:83
AH::operator==
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice == Array.
Definition: Array.hpp:329
AH::ArraySlice::begin
Iterator begin() const
Definition: Array.hpp:257