Line data Source code
1 : /******************************************************************************
2 : * Project: GDAL Vector abstraction
3 : * Purpose:
4 : * Author: Javier Jimenez Shaw
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2024, Javier Jimenez Shaw
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #ifndef GDAL_VECTORX_H_INCLUDED
13 : #define GDAL_VECTORX_H_INCLUDED
14 :
15 : /*! @cond Doxygen_Suppress */
16 :
17 : #include <algorithm>
18 : #include <array>
19 : #include <functional>
20 :
21 : namespace gdal
22 : {
23 :
24 : /**
25 : * @brief Template class to abstract a vector
26 : *
27 : * Inspired by Eigen3 Vector class, but much simpler.
28 : * For GDAL internal use for now.
29 : *
30 : * @tparam T type of the values stored
31 : * @tparam N size of the container/vector
32 : */
33 : template <typename T, std::size_t N> class VectorX
34 : {
35 : public:
36 : using value_type = T;
37 : using size_type = std::size_t;
38 : using self_type = VectorX<T, N>;
39 :
40 : /** Size of the container */
41 7 : static constexpr size_type size() noexcept
42 : {
43 7 : return N;
44 : }
45 :
46 1776605 : VectorX()
47 1776605 : {
48 1776605 : }
49 :
50 : // cppcheck-suppress noExplicitConstructor
51 1121236 : template <typename... Args> VectorX(Args... args) : _values({args...})
52 : {
53 : static_assert(N == sizeof...(Args),
54 : "Invalid number of constructor params");
55 1121236 : }
56 :
57 : /** Container as an std::array */
58 1 : const std::array<T, N> &array() const
59 : {
60 1 : return _values;
61 : }
62 :
63 3046076 : T &operator[](const size_type &pos)
64 : {
65 3046076 : return _values[pos];
66 : }
67 :
68 1015706 : const T &operator[](const size_type &pos) const
69 : {
70 1015706 : return _values[pos];
71 : }
72 :
73 2134855 : T x() const
74 : {
75 : static_assert(N >= 1, "Invalid template size for x()");
76 2134855 : return _values[0];
77 : }
78 :
79 1796551 : T y() const
80 : {
81 : static_assert(N >= 2, "Invalid template size for y()");
82 1796551 : return _values[1];
83 : }
84 :
85 : T z() const
86 : {
87 : static_assert(N >= 3, "Invalid template size for z()");
88 : return _values[2];
89 : }
90 :
91 1521727 : T &x()
92 : {
93 : static_assert(N >= 1, "Invalid template size for x()");
94 1521727 : return _values[0];
95 : }
96 :
97 1268156 : T &y()
98 : {
99 : static_assert(N >= 2, "Invalid template size for y()");
100 1268156 : return _values[1];
101 : }
102 :
103 6 : T &z()
104 : {
105 : static_assert(N >= 3, "Invalid template size for z()");
106 6 : return _values[2];
107 : }
108 :
109 : /** Fill all elements of the vector with the same value
110 : * @return this
111 : */
112 2 : self_type &fill(T arg)
113 : {
114 8 : for (size_t i = 0; i < N; i++)
115 6 : (*this)[i] = arg;
116 :
117 2 : return *this;
118 : }
119 :
120 : /** Apply the unary operator to all the elements
121 : * @param op unary operator to apply to every element
122 : * @return a new object with the computed values
123 : */
124 253616 : template <class UnaryOp> self_type apply(UnaryOp op) const
125 : {
126 253616 : self_type res;
127 760848 : for (size_t i = 0; i < N; i++)
128 507232 : res[i] = op(_values[i]);
129 253616 : return res;
130 : }
131 :
132 253613 : self_type floor() const
133 : {
134 760839 : return apply([](const value_type &v) { return std::floor(v); });
135 : }
136 :
137 1 : self_type ceil() const
138 : {
139 3 : return apply([](const value_type &v) { return std::ceil(v); });
140 : }
141 :
142 : /** Compute the scalar product of two vectors */
143 2 : T scalarProd(const self_type &arg) const
144 : {
145 2 : T accum{};
146 6 : for (size_t i = 0; i < N; i++)
147 4 : accum += _values[i] * arg[i];
148 2 : return accum;
149 : }
150 :
151 : /** Compute the norm squared of the vector */
152 1 : T norm2() const
153 : {
154 1 : return scalarProd(*this);
155 : }
156 :
157 : /**
158 : * @brief cast the type to a different one, and convert the elements
159 : *
160 : * @tparam U output value type
161 : * @return VectorX<U, N> object of new type, where all elements are casted
162 : */
163 507911 : template <typename U> VectorX<U, N> cast() const
164 : {
165 507911 : VectorX<U, N> res;
166 1523733 : for (size_t i = 0; i < N; i++)
167 1015822 : res[i] = static_cast<U>(_values[i]);
168 507911 : return res;
169 : }
170 :
171 1 : self_type operator+(T arg) const
172 : {
173 1 : return operatorImpl(arg, std::plus());
174 : }
175 :
176 2 : self_type &operator+=(T arg)
177 : {
178 2 : return operatorEqImpl(arg, std::plus());
179 : }
180 :
181 253651 : self_type operator-(T arg) const
182 : {
183 253651 : return operatorImpl(arg, std::minus());
184 : }
185 :
186 2 : self_type &operator-=(T arg)
187 : {
188 2 : return operatorEqImpl(arg, std::minus());
189 : }
190 :
191 1 : self_type operator-() const
192 : {
193 3 : return apply([](const value_type &v) { return -v; });
194 : }
195 :
196 1 : template <typename U> self_type operator*(U arg) const
197 : {
198 1 : self_type res;
199 3 : for (size_t i = 0; i < N; i++)
200 2 : res[i] = T(_values[i] * arg);
201 1 : return res;
202 : }
203 :
204 1 : self_type operator*(T arg) const
205 : {
206 1 : return operatorImpl(arg, std::multiplies());
207 : }
208 :
209 1 : template <typename U> self_type operator/(U arg) const
210 : {
211 1 : self_type res;
212 3 : for (size_t i = 0; i < N; i++)
213 2 : res[i] = T(_values[i] / arg);
214 1 : return res;
215 : }
216 :
217 1 : self_type operator/(T arg) const
218 : {
219 1 : return operatorImpl(arg, std::divides());
220 : }
221 :
222 1 : self_type operator+(const self_type &arg) const
223 : {
224 1 : return operatorImpl(arg, std::plus());
225 : }
226 :
227 507847 : self_type operator-(const self_type &arg) const
228 : {
229 507847 : return operatorImpl(arg, std::minus());
230 : }
231 :
232 1 : friend VectorX<T, N> operator+(T t, const VectorX<T, N> &arg)
233 : {
234 1 : VectorX<T, N> res;
235 3 : for (size_t i = 0; i < N; i++)
236 2 : res._values[i] = t + arg._values[i];
237 1 : return res;
238 : }
239 :
240 253569 : friend VectorX<T, N> operator-(T t, const VectorX<T, N> &arg)
241 : {
242 253569 : VectorX<T, N> res;
243 760707 : for (size_t i = 0; i < N; i++)
244 507138 : res._values[i] = t - arg._values[i];
245 253569 : return res;
246 : }
247 :
248 : private:
249 : std::array<T, N> _values{};
250 :
251 253654 : template <class Op> self_type operatorImpl(T arg, Op op) const
252 : {
253 253654 : self_type res;
254 760962 : for (size_t i = 0; i < N; i++)
255 507308 : res[i] = op(_values[i], arg);
256 253654 : return res;
257 : }
258 :
259 4 : template <class Op> self_type &operatorEqImpl(T arg, Op op)
260 : {
261 12 : for (size_t i = 0; i < N; i++)
262 8 : _values[i] = op(_values[i], arg);
263 4 : return *this;
264 : }
265 :
266 : template <class Op>
267 507848 : self_type operatorImpl(const self_type &arg, Op op) const
268 : {
269 507848 : self_type res;
270 1523544 : for (size_t i = 0; i < N; i++)
271 1015696 : res[i] = op(_values[i], arg[i]);
272 507848 : return res;
273 : }
274 :
275 : template <class Op> self_type &operatorEqImpl(const self_type &arg, Op op)
276 : {
277 : for (size_t i = 0; i < N; i++)
278 : _values[i] = op(_values[i], arg[i]);
279 : return *this;
280 : }
281 : };
282 :
283 : using Vector2d = VectorX<double, 2>;
284 : using Vector2i = VectorX<int, 2>;
285 : using Vector3d = VectorX<double, 3>;
286 : using Vector3i = VectorX<int, 3>;
287 : } // namespace gdal
288 :
289 : /*! @endcond */
290 :
291 : #endif /* ndef GDAL_VECTORX_H_INCLUDED */
|