Control Surface  1.1.1
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 {
169  using ElementRefType =
170  typename std::conditional<Const, const T &, T &>::type;
171  using ElementPtrType =
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  private:
231  };
232 
242  ElementRefType operator[](size_t index) const {
243  if (index >= N) { // TODO
244  ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDEF);
245  index = N - 1; // LCOV_EXCL_LINE
246  } // LCOV_EXCL_LINE
247  if (Reverse)
248  return array[-index];
249  else
250  return array[index];
251  }
252 
253  Iterator begin() const {
254  if (Reverse)
255  return array;
256  else
257  return array;
258  }
259 
260  Iterator end() const {
261  if (Reverse)
262  return array - N;
263  else
264  return array + N;
265  }
266 
267  template <size_t Start, size_t End>
268  ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
269  slice() const;
270 
271  private:
273 };
274 
275 template <class T, size_t N>
276 template <size_t Start, size_t End>
277 inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), false>
279  static_assert(Start < N, "");
280  static_assert(End < N, "");
281  return &(*this)[Start];
282 }
283 
284 template <class T, size_t N>
285 template <size_t Start, size_t End>
286 inline ArraySlice<T, abs_diff(Start, End) + 1, (End < Start), true>
287 Array<T, N>::slice() const {
288  static_assert(Start < N, "");
289  static_assert(End < N, "");
290  return &(*this)[Start];
291 }
292 
293 template <class T, size_t N, bool Reverse, bool Const>
294 template <size_t Start, size_t End>
295 ArraySlice<T, abs_diff(End, Start) + 1, Reverse ^ (End < Start), Const>
296 ArraySlice<T, N, Reverse, Const>::slice() const {
297  static_assert(Start < N, "");
298  static_assert(End < N, "");
299  return &(*this)[Start];
300 }
301 
302 // Equality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
303 
305 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
306  bool Reverse2, bool Const1, bool Const2>
309  static_assert(N1 == N2, "Error: sizes do not match");
310  for (size_t i = 0; i < N1; ++i)
311  if (a[i] != b[i])
312  return false;
313  return true;
314 }
315 
317 template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
318 bool operator==(const Array<T1, N1> &a,
320  return a.slice() == b;
321 }
322 
324 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
326  const Array<T2, N2> &b) {
327  return a == b.slice();
328 }
329 
330 // Inequality ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
331 
333 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
334  bool Reverse2, bool Const1, bool Const2>
337  return !(a == b);
338 }
339 
341 template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
342 bool operator!=(const Array<T1, N1> &a,
344  return a.slice() != b;
345 }
346 
348 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
350  const Array<T2, N2> &b) {
351  return a != b.slice();
352 }
353 
354 // Addition ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
355 
357 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
358  bool Reverse2, bool Const1, bool Const2>
359 Array<decltype(T1{} + T2{}), N1>
362  static_assert(N1 == N2, "Error: sizes do not match");
363  Array<decltype(T1{} + T2{}), N1> result = {{}};
364  for (size_t i = 0; i < N1; ++i)
365  result[i] = a[i] + b[i];
366  return result;
367 }
368 
370 template <class T1, class T2, size_t N1, size_t N2>
371 Array<decltype(T1{} + T2{}), N1> operator+(const Array<T1, N1> &a,
372  const Array<T2, N2> &b) {
373  return a.slice() + b.slice();
374 }
375 
377 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
378  bool Reverse2, bool Const1, bool Const2>
379 const ArraySlice<T1, N1, Reverse1, Const1> &
382  static_assert(N1 == N2, "Error: sizes do not match");
383  for (size_t i = 0; i < N1; ++i)
384  a[i] += b[i];
385  return a;
386 }
387 
389 template <class T1, class T2, size_t N1, size_t N2>
391  a.slice() += b.slice();
392  return a;
393 }
394 
395 // Subtraction :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
396 
398 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
399  bool Reverse2, bool Const1, bool Const2>
400 Array<decltype(T1{} - T2{}), N1>
403  static_assert(N1 == N2, "Error: sizes do not match");
404  Array<decltype(T1{} - T2{}), N1> result = {{}};
405  for (size_t i = 0; i < N1; ++i)
406  result[i] = a[i] - b[i];
407  return result;
408 }
409 
411 template <class T1, class T2, size_t N1, size_t N2>
412 Array<decltype(T1{} - T2{}), N1> operator-(const Array<T1, N1> &a,
413  const Array<T2, N2> &b) {
414  return a.slice() - b.slice();
415 }
416 
418 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
419  bool Reverse2, bool Const1, bool Const2>
420 const ArraySlice<T1, N1, Reverse1, Const1> &
423  static_assert(N1 == N2, "Error: sizes do not match");
424  for (size_t i = 0; i < N1; ++i)
425  a[i] -= b[i];
426  return a;
427 }
428 
430 template <class T1, class T2, size_t N1, size_t N2>
432  a.slice() -= b.slice();
433  return a;
434 }
435 
436 // Scalar Multiplication :::::::::::::::::::::::::::::::::::::::::::::::::::::::
437 
439 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
440 Array<decltype(T1{} * T2{}), N1>
442  Array<decltype(T1{} * T2{}), N1> result = {{}};
443  for (size_t i = 0; i < N1; ++i)
444  result[i] = a[i] * b;
445  return result;
446 }
447 
449 template <class T1, class T2, size_t N1>
450 Array<decltype(T1{} * T2{}), N1> operator*(const Array<T1, N1> &a, T2 b) {
451  return a.slice() * b;
452 }
453 
455 template <class T1, class T2, size_t N2, bool Reverse2, bool Const2>
456 Array<decltype(T1{} * T2{}), N2>
458  Array<decltype(T1{} * T2{}), N2> result = {{}};
459  for (size_t i = 0; i < N2; ++i)
460  result[i] = a * b[i];
461  return result;
462 }
463 
465 template <class T1, class T2, size_t N2>
466 Array<decltype(T1{} * T2{}), N2> operator*(T1 a, const Array<T2, N2> &b) {
467  return a * b.slice();
468 }
469 
471 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
472 const ArraySlice<T1, N1, Reverse1, Const1> &
474  for (size_t i = 0; i < N1; ++i)
475  a[i] *= b;
476  return a;
477 }
478 
480 template <class T1, class T2, size_t N1>
482  a.slice() *= b;
483  return a;
484 }
485 
486 // Scalar Division :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
487 
489 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
490 Array<decltype(T1{} / T2{}), N1>
492  Array<decltype(T1{} / T2{}), N1> result = {{}};
493  for (size_t i = 0; i < N1; ++i)
494  result[i] = a[i] / b;
495  return result;
496 }
497 
499 template <class T1, class T2, size_t N1>
500 Array<decltype(T1{} / T2{}), N1> operator/(const Array<T1, N1> &a, T2 b) {
501  return a.slice() / b;
502 }
503 
505 template <class T1, class T2, size_t N1, bool Reverse1, bool Const1>
506 const ArraySlice<T1, N1, Reverse1, Const1> &
508  for (size_t i = 0; i < N1; ++i)
509  a[i] /= b;
510  return a;
511 }
512 
514 template <class T1, class T2, size_t N1>
516  a.slice() /= b;
517  return a;
518 }
519 
520 // Negation ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
521 
523 template <class T, size_t N, bool Reverse, bool Const>
524 Array<decltype(-T{}), N> operator-(ArraySlice<T, N, Reverse, Const> a) {
525  Array<decltype(-T{}), N> result = {{}};
526  for (size_t i = 0; i < N; ++i)
527  result[i] = -a[i];
528  return result;
529 }
530 
532 template <class T, size_t N>
533 Array<decltype(-T{}), N> operator-(const Array<T, N> &a) {
534  return -a.slice();
535 }
536 
537 // Type aliases ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
538 
540 template <class T, size_t nb_rows, size_t nb_cols>
542 
544 
546 
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:272
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:260
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:481
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:17
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:230
AH::operator-=
Array< T1, N1 > & operator-=(Array< T1, N1 > &a, const Array< T2, N2 > &b)
Array -= Array.
Definition: Array.hpp:431
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:515
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::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:242
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::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:390
AH::ArraySlice
Class for a view on a slice of an array.
Definition: Array.hpp:25
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:16
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::Array< AddressMatrix< nb_rows, nb_cols >, NumBanks >::type
AddressMatrix< nb_rows, nb_cols > type
Definition: Array.hpp:38
AH::operator!=
bool operator!=(ArraySlice< T1, N1, Reverse1, Const1 > a, const Array< T2, N2 > &b)
Slice != Array.
Definition: Array.hpp:349
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:325
AH::ArraySlice::begin
Iterator begin() const
Definition: Array.hpp:253