GDAL

gdal_vectorx.h
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
17#include <algorithm>
18#include <array>
19#include <functional>
20
21 namespace gdal
22{
23
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
41 static constexpr size_type size() noexcept
42 {
43 return N;
44 }
45
46 VectorX()
47 {
48 }
49
50 // cppcheck-suppress noExplicitConstructor
51 template <typename... Args> VectorX(Args... args) : _values({args...})
52 {
53 static_assert(N == sizeof...(Args),
54 "Invalid number of constructor params");
55 }
56
58 const std::array<T, N> &array() const
59 {
60 return _values;
61 }
62
63 T &operator[](const size_type &pos)
64 {
65 return _values[pos];
66 }
67
68 const T &operator[](const size_type &pos) const
69 {
70 return _values[pos];
71 }
72
73 T x() const
74 {
75 static_assert(N >= 1, "Invalid template size for x()");
76 return _values[0];
77 }
78
79 T y() const
80 {
81 static_assert(N >= 2, "Invalid template size for y()");
82 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 T &x()
92 {
93 static_assert(N >= 1, "Invalid template size for x()");
94 return _values[0];
95 }
96
97 T &y()
98 {
99 static_assert(N >= 2, "Invalid template size for y()");
100 return _values[1];
101 }
102
103 T &z()
104 {
105 static_assert(N >= 3, "Invalid template size for z()");
106 return _values[2];
107 }
108
112 self_type &fill(T arg)
113 {
114 for (size_t i = 0; i < N; i++)
115 (*this)[i] = arg;
116
117 return *this;
118 }
119
124 template <class UnaryOp> self_type apply(UnaryOp op) const
125 {
126 self_type res;
127 for (size_t i = 0; i < N; i++)
128 res[i] = op(_values[i]);
129 return res;
130 }
131
132 self_type floor() const
133 {
134 return apply([](const value_type &v) { return std::floor(v); });
135 }
136
137 self_type ceil() const
138 {
139 return apply([](const value_type &v) { return std::ceil(v); });
140 }
141
143 T scalarProd(const self_type &arg) const
144 {
145 T accum{};
146 for (size_t i = 0; i < N; i++)
147 accum += _values[i] * arg[i];
148 return accum;
149 }
150
152 T norm2() const
153 {
154 return scalarProd(*this);
155 }
156
163 template <typename U> VectorX<U, N> cast() const
164 {
165 VectorX<U, N> res;
166 for (size_t i = 0; i < N; i++)
167 res[i] = static_cast<U>(_values[i]);
168 return res;
169 }
170
171 self_type operator+(T arg) const
172 {
173 return operatorImpl<std::plus<T>>(arg);
174 }
175
176 self_type &operator+=(T arg)
177 {
178 return operatorEqImpl<std::plus<T>>(arg);
179 }
180
181 self_type operator-(T arg) const
182 {
183 return operatorImpl<std::minus<T>>(arg);
184 }
185
186 self_type &operator-=(T arg)
187 {
188 return operatorEqImpl<std::minus<T>>(arg);
189 }
190
191 self_type operator-() const
192 {
193 return apply([](const value_type &v) { return -v; });
194 }
195
196 template <typename U> self_type operator*(U arg) const
197 {
198 self_type res;
199 for (size_t i = 0; i < N; i++)
200 res[i] = T(_values[i] * arg);
201 return res;
202 }
203
204 self_type operator*(T arg) const
205 {
206 return operatorImpl<std::multiplies<T>>(arg);
207 }
208
209 template <typename U> self_type operator/(U arg) const
210 {
211 self_type res;
212 for (size_t i = 0; i < N; i++)
213 res[i] = T(_values[i] / arg);
214 return res;
215 }
216
217 self_type operator/(T arg) const
218 {
219 return operatorImpl<std::divides<T>>(arg);
220 }
221
222 self_type operator+(const self_type &arg) const
223 {
224 return operatorImpl<std::plus<T>>(arg);
225 }
226
227 self_type operator-(const self_type &arg) const
228 {
229 return operatorImpl<std::minus<T>>(arg);
230 }
231
232 friend VectorX<T, N> operator+(T t, const VectorX<T, N> &arg)
233 {
234 VectorX<T, N> res;
235 for (size_t i = 0; i < N; i++)
236 res._values[i] = t + arg._values[i];
237 return res;
238 }
239
240 friend VectorX<T, N> operator-(T t, const VectorX<T, N> &arg)
241 {
242 VectorX<T, N> res;
243 for (size_t i = 0; i < N; i++)
244 res._values[i] = t - arg._values[i];
245 return res;
246 }
247
248 private:
249 std::array<T, N> _values{};
250
251 template <class Op> self_type operatorImpl(T arg) const
252 {
253 self_type res;
254 auto op = Op();
255 for (size_t i = 0; i < N; i++)
256 res[i] = op(_values[i], arg);
257 return res;
258 }
259
260 template <class Op> self_type &operatorEqImpl(T arg)
261 {
262 auto op = Op();
263 for (size_t i = 0; i < N; i++)
264 _values[i] = op(_values[i], arg);
265 return *this;
266 }
267
268 template <class Op> self_type operatorImpl(const self_type &arg) const
269 {
270 self_type res;
271 auto op = Op();
272 for (size_t i = 0; i < N; i++)
273 res[i] = op(_values[i], arg[i]);
274 return res;
275 }
276
277 template <class Op> self_type &operatorEqImpl(const self_type &arg)
278 {
279 auto op = Op();
280 for (size_t i = 0; i < N; i++)
281 _values[i] = op(_values[i], arg[i]);
282 return *this;
283 }
284};
285
286 using Vector2d = VectorX<double, 2>;
287 using Vector2i = VectorX<int, 2>;
288 using Vector3d = VectorX<double, 3>;
289 using Vector3i = VectorX<int, 3>;
290} // namespace gdal
291
294#endif /* ndef GDAL_VECTORX_H_INCLUDED */