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 8 : return temp;
40 4 : }
41 :
42 : private:
43 : T value;
44 : const V increment;
45 : };
46 :
47 : } // namespace detail
48 :
49 : END_AH_NAMESPACE
50 : /// @addtogroup AH_Containers
51 : /// @{
52 :
53 : BEGIN_AH_NAMESPACE
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>
71 2 : USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> generateArray(G generator) {
72 2 : Array<T, N> array{{}};
73 2 : std::generate(array.begin(), array.end(), generator);
74 2 : 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>
91 1 : USE_CONSTEXPR_ARRAY_HELPERS auto generateArray(G generator)
92 : -> Array<decltype(generator()), N> {
93 1 : Array<decltype(generator()), N> array{{}};
94 1 : std::generate(array.begin(), array.end(), generator);
95 1 : 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>
112 1 : USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> copyAs(const Array<U, N> &src) {
113 4 : Array<T, N> dest{{}};
114 1 : std::transform(std::begin(src), std::end(src), std::begin(dest),
115 4 : [](const U &src) { return T(src); });
116 1 : 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 1 : apply(const Array<U, N> &src, F f) {
125 1 : Array<decltype(F{}(U{})), N> dest{{}};
126 1 : std::transform(std::begin(src), std::end(src), std::begin(dest), f);
127 1 : 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>
136 : USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> fillArray(Args... args) {
137 : return generateArray<N>([&]() { return T{args...}; });
138 : }
139 : #else
140 : template <class T, size_t N, class... Args>
141 1 : USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> fillArray(Args... args) {
142 1 : Array<T, N> array{{}};
143 5 : for (auto &el : array)
144 4 : el = T{args...};
145 1 : 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 1 : generateIncrementalArray(U start = 0, V increment = V(1)) {
184 1 : detail::Incrementor<U, V> g(start, increment);
185 1 : return generateArray<T, N>(g);
186 1 : }
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>
204 : USE_CONSTEXPR_ARRAY_HELPERS Array<T, M + N> cat(const Array<T, M> &a,
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>
218 5 : distribute(const ArraySlice<T1, N1, Reverse1, Const1> &a,
219 : const ArraySlice<T2, N2, Reverse2, Const2> &b) {
220 5 : Array<decltype(T1() * T2()), N1 + N2 - 1> result = {{}};
221 22 : for (size_t i = 0; i < N1; ++i)
222 77 : for (size_t j = 0; j < N2; ++j)
223 77 : result[i + j] += a[i] * b[j];
224 5 : 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>
229 2 : distribute(const ArraySlice<T1, N1, Reverse1, Const1> &a,
230 : const Array<T2, N2> &b) {
231 2 : 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>
236 : distribute(const Array<T1, N1> &a,
237 : const ArraySlice<T2, N2, Reverse2, Const2> &b) {
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>
243 2 : distribute(const Array<T1, N1> &a, const Array<T2, N2> &b) {
244 2 : return distribute(a.slice(), b.slice());
245 : }
246 :
247 : END_AH_NAMESPACE
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 :
272 : #include <AH/PrintStream/PrintStream.hpp>
273 :
274 : template <class T, size_t N, bool Reverse, bool Const>
275 : std::enable_if_t<std::is_arithmetic<T>::value, Print &>
276 : operator<<(Print &os, const AH::ArraySlice<T, N, Reverse, Const> &a) {
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 :
289 : AH_DIAGNOSTIC_POP()
|