Control Surface  1.1.0
MIDI Control Surface library for Arduino
ArrayHelpers.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 "Array.hpp"
10 #include <AH/STL/algorithm>
11 
12 #if __cplusplus >= 201400L
13 #define USE_CONSTEXPR_ARRAY_HELPERS constexpr
14 #else
15 #define USE_CONSTEXPR_ARRAY_HELPERS
16 #endif
17 
19 
20 namespace detail {
21 
22 /**
23  * @brief Utility class that acts as a functor to return incremental values.
24  *
25  * @tparam T
26  * The type that will be returned by the functor, as well as the type
27  * of the initial value.
28  * @tparam V
29  * The type of the object that is added to the value on each call.
30  */
31 template <class T, class V>
32 class Incrementor {
33  public:
34  USE_CONSTEXPR_ARRAY_HELPERS Incrementor(T start = 0, V increment = 1)
35  : value(start), increment(increment) {}
37  T temp = value;
38  value += increment;
39  return temp;
40  }
41 
42  private:
43  T value;
44  const V increment;
45 };
46 
47 } // namespace detail
48 
50 /// @addtogroup AH_Containers
51 /// @{
52 
54 
55 /**
56  * @brief Generate an array using the given generator.
57  *
58  * @tparam T
59  * The type of the elements in the array.
60  * @tparam N
61  * The number of elements in the array.
62  * @tparam G
63  * The generator functor type.
64  *
65  * @param generator
66  * A functor that will be called to create each element.
67  *
68  * @return The generated array.
69  */
70 template <class T, size_t N, class G>
72  Array<T, N> array{{}};
73  std::generate(array.begin(), array.end(), generator);
74  return array;
75 }
76 
77 /**
78  * @brief Generate an array using the given generator.
79  *
80  * @tparam N
81  * The number of elements in the array.
82  * @tparam G
83  * The generator functor type.
84  *
85  * @param generator
86  * A functor that will be called to create each element.
87  *
88  * @return The generated array.
89  */
90 template <size_t N, class G>
92  -> Array<decltype(generator()), N> {
93  Array<decltype(generator()), N> array{{}};
94  std::generate(array.begin(), array.end(), generator);
95  return array;
96 }
97 
98 /**
99  * @brief Copy an Array to an Array of a different type.
100  *
101  * @tparam T
102  * The type of the new array.
103  * @tparam N
104  * The number of elements in the arrays.
105  * @tparam U
106  * The type of the source array.
107  *
108  * @param src
109  * The source array to be copied.
110  */
111 template <class T, size_t N, class U>
113  Array<T, N> dest{{}};
114  std::transform(std::begin(src), std::end(src), std::begin(dest),
115  [](const U &src) { return T(src); });
116  return dest;
117 }
118 
119 /**
120  * @brief Apply a function to all elements of the array and return a copy.
121  */
122 template <class F, class U, size_t N>
123 USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(F{}(U{})), N>
124 apply(const Array<U, N> &src, F f) {
125  Array<decltype(F{}(U{})), N> dest{{}};
126  std::transform(std::begin(src), std::end(src), std::begin(dest), f);
127  return dest;
128 }
129 
130 #if !defined(__GNUC__) || (__GNUC__ > 7) || \
131  (__GNUC__ == 7 && __GNUC_MINOR__ >= 3) || defined(DOXYGEN)
132 /**
133  * @brief Fill the array with the same value for each element.
134  */
135 template <class T, size_t N, class... Args>
137  return generateArray<N>([&]() { return T{args...}; });
138 }
139 #else
140 template <class T, size_t N, class... Args>
141 USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> fillArray(Args... args) {
142  Array<T, N> array{{}};
143  for (auto &el : array)
144  el = T{args...};
145  return array;
146 }
147 #endif
148 
149 /**
150  * @brief Generate an array where the first value is given, and the subsequent
151  * values are calculated as the previous value incremented with a given
152  * value:
153  * @f$ x[0] = \mathrm{start} @f$
154  * @f$ x[k+1] = x[k] + \mathrm{increment} @f$ .
155  *
156  * For example:
157  * ```
158  * auto x = generateIncrementalArray<unsigned int, 4>(2, 3);
159  * ```
160  * is equivalent to
161  * ```
162  * Array<unsigned int, 4> x = {2, 5, 8, 11};
163  * ```
164  *
165  * @tparam T
166  * The type of the elements in the array.
167  * @tparam N
168  * The number of elements in the array.
169  * @tparam U
170  * The type of the initial value.
171  * @tparam V
172  * The type of the value that will be added to each subsequent element.
173  *
174  * @param start
175  * The first value in the array.
176  * @param increment
177  * The value to add to each subsequent element of the array.
178  *
179  * @return The generated array.
180  */
181 template <class T, size_t N, class U, class V = U>
182 USE_CONSTEXPR_ARRAY_HELPERS Array<T, N>
183 generateIncrementalArray(U start = 0, V increment = V(1)) {
184  detail::Incrementor<U, V> g(start, increment);
185  return generateArray<T, N>(g);
186 }
187 
188 /**
189  * @brief Concatenate two arrays.
190  *
191  * @tparam T
192  * The type of the elements in the array.
193  * @tparam M
194  * The number of elements in the first array.
195  * @tparam N
196  * The number of elements in the second array.
197  * @param a
198  * The first array.
199  * @param b
200  * The second array.
201  * @return A new array containing the elements of both input arrays (in order).
202  */
203 template <class T, size_t M, size_t N>
205  const Array<T, N> &b) {
206  Array<T, M + N> result{{}};
207  size_t r = 0;
208  for (size_t i = 0; i < M; ++i, ++r)
209  result[r] = a[i];
210  for (size_t i = 0; i < N; ++i, ++r)
211  result[r] = b[i];
212  return result;
213 }
214 
215 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
216  bool Reverse2, bool Const1, bool Const2>
217 USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
220  Array<decltype(T1() * T2()), N1 + N2 - 1> result = {{}};
221  for (size_t i = 0; i < N1; ++i)
222  for (size_t j = 0; j < N2; ++j)
223  result[i + j] += a[i] * b[j];
224  return result;
225 }
226 
227 template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
228 USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
230  const Array<T2, N2> &b) {
231  return distribute(a, b.slice());
232 }
233 
234 template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
235 USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
238  return distribute(a.slice(), b);
239 }
240 
241 template <class T1, class T2, size_t N1, size_t N2>
242 USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
244  return distribute(a.slice(), b.slice());
245 }
246 
248 
249 /// @}
250 
251 #ifndef ARDUINO
252 
253 #include <ostream>
254 
255 template <class T, size_t N, bool Reverse, bool Const>
256 std::enable_if_t<std::is_arithmetic<T>::value, std::ostream &>
257 operator<<(std::ostream &os, const AH::ArraySlice<T, N, Reverse, Const> &a) {
258  for (const T &el : a.template slice<0, N - 2>())
259  os << el << ", ";
260  os << a[N - 1];
261  return os;
262 }
263 
264 template <class T, size_t N>
265 std::enable_if_t<std::is_arithmetic<T>::value, std::ostream &>
266 operator<<(std::ostream &os, const AH::Array<T, N> &a) {
267  return os << a.slice();
268 }
269 
270 #endif
271 
273 
274 template <class T, size_t N, bool Reverse, bool Const>
275 std::enable_if_t<std::is_arithmetic<T>::value, Print &>
277  for (const T &el : a.template slice<0, N - 2>())
278  os << el << ", ";
279  os << a[N - 1];
280  return os;
281 }
282 
283 template <class T, size_t N>
284 std::enable_if_t<std::is_arithmetic<T>::value, Print &>
285 operator<<(Print &os, const AH::Array<T, N> &a) {
286  return os << a.slice();
287 }
288 
AH::generateArray
auto generateArray(G generator) -> Array< decltype(generator()), N >
Generate an array using the given generator.
Definition: ArrayHelpers.hpp:91
Warnings.hpp
operator<<
std::enable_if_t< std::is_arithmetic< T >::value, Print & > operator<<(Print &os, const AH::ArraySlice< T, N, Reverse, Const > &a)
Definition: ArrayHelpers.hpp:276
MIDI_Notes::G
constexpr int8_t G
Definition: Notes.hpp:25
AH::copyAs
Array< T, N > copyAs(const Array< U, N > &src)
Copy an Array to an Array of a different type.
Definition: ArrayHelpers.hpp:112
AH::generateIncrementalArray
Array< T, N > generateIncrementalArray(U start=0, V increment=V(1))
Generate an array where the first value is given, and the subsequent values are calculated as the pre...
Definition: ArrayHelpers.hpp:183
AH::apply
Array< decltype(F{}(U{})), N > apply(const Array< U, N > &src, F f)
Apply a function to all elements of the array and return a copy.
Definition: ArrayHelpers.hpp:124
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:17
USE_CONSTEXPR_ARRAY_HELPERS
#define USE_CONSTEXPR_ARRAY_HELPERS
Definition: ArrayHelpers.hpp:15
AH::cat
Array< T, M+N > cat(const Array< T, M > &a, const Array< T, N > &b)
Concatenate two arrays.
Definition: ArrayHelpers.hpp:204
AH::detail::Incrementor::increment
const V increment
Definition: ArrayHelpers.hpp:44
AH::Array
An array wrapper for easy copying, comparing, and iterating.
Definition: Array.hpp:36
AH::detail::Incrementor::value
T value
Definition: ArrayHelpers.hpp:43
AH::distribute
Array< decltype(T1() *T2()), N1+N2 - 1 > distribute(const Array< T1, N1 > &a, const Array< T2, N2 > &b)
Definition: ArrayHelpers.hpp:243
AH::ArraySlice
Class for a view on a slice of an array.
Definition: Array.hpp:25
PrintStream.hpp
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
AH::detail::Incrementor::operator()
T operator()()
Definition: ArrayHelpers.hpp:36
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::detail::Incrementor::Incrementor
Incrementor(T start=0, V increment=1)
Definition: ArrayHelpers.hpp:34
AH::Array::slice
ArraySlice< T, abs_diff(Start, End)+1,(End< Start), false > slice()
Get a view on a slice of the Array.
AH::detail::Incrementor
Utility class that acts as a functor to return incremental values.
Definition: ArrayHelpers.hpp:32
AH::fillArray
Array< T, N > fillArray(Args... args)
Fill the array with the same value for each element.
Definition: ArrayHelpers.hpp:136
MIDI_Notes::F
constexpr int8_t F
Definition: Notes.hpp:23