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