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