xref: /aosp_15_r20/external/angle/src/common/vector_utils.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vector_utils.h: Utility classes implementing various vector operations
7 
8 #ifndef COMMON_VECTOR_UTILS_H_
9 #define COMMON_VECTOR_UTILS_H_
10 
11 #include <cmath>
12 #include <cstddef>
13 #include <ostream>
14 #include <type_traits>
15 #include "common/debug.h"
16 
17 namespace angle
18 {
19 
20 template <size_t Dimension, typename Type>
21 class Vector;
22 
23 using Vector2 = Vector<2, float>;
24 using Vector3 = Vector<3, float>;
25 using Vector4 = Vector<4, float>;
26 
27 using Vector2I = Vector<2, int>;
28 using Vector3I = Vector<3, int>;
29 using Vector4I = Vector<4, int>;
30 
31 using Vector2U = Vector<2, unsigned int>;
32 using Vector3U = Vector<3, unsigned int>;
33 using Vector4U = Vector<4, unsigned int>;
34 
35 template <size_t Dimension, typename Type>
36 class VectorBase
37 {
38   public:
39     using VectorN = Vector<Dimension, Type>;
40 
41     // Constructors
42     VectorBase() = default;
43     explicit VectorBase(Type element);
44 
45     template <typename Type2>
46     VectorBase(const VectorBase<Dimension, Type2> &other);
47 
48     template <typename Arg1, typename Arg2, typename... Args>
49     VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args);
50 
51     // Access the vector backing storage directly
data()52     const Type *data() const { return mData; }
data()53     Type *data() { return mData; }
size()54     constexpr size_t size() const { return Dimension; }
55 
56     // Load or store the pointer from / to raw data
57     static VectorN Load(const Type *source);
58     static void Store(const VectorN &source, Type *destination);
59 
60     // Index the vector
61     Type &operator[](size_t i) { return mData[i]; }
62     const Type &operator[](size_t i) const { return mData[i]; }
63 
64     // Basic arithmetic operations
65     VectorN operator+() const;
66     VectorN operator-() const;
67     VectorN operator+(const VectorN &other) const;
68     VectorN operator-(const VectorN &other) const;
69     VectorN operator*(const VectorN &other) const;
70     VectorN operator/(const VectorN &other) const;
71     VectorN operator*(Type other) const;
72     VectorN operator/(Type other) const;
73     friend VectorN operator*(Type a, const VectorN &b) { return b * a; }
74 
75     // Compound arithmetic operations
76     VectorN &operator+=(const VectorN &other);
77     VectorN &operator-=(const VectorN &other);
78     VectorN &operator*=(const VectorN &other);
79     VectorN &operator/=(const VectorN &other);
80     VectorN &operator*=(Type other);
81     VectorN &operator/=(Type other);
82 
83     // Comparison operators
84     bool operator==(const VectorBase<Dimension, Type> &other) const;
85     bool operator!=(const VectorBase<Dimension, Type> &other) const;
86 
87     // Other arithmetic operations
88     Type length() const;
89     Type lengthSquared() const;
90     Type dot(const VectorBase<Dimension, Type> &other) const;
91     VectorN normalized() const;
92 
93   protected:
94     template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
95     void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &...args);
96 
97     // Some old compilers consider this function an alternative for initWithList(Vector)
98     // when the variant above is more precise. Use SFINAE on the return value to hide
99     // this variant for non-arithmetic types. The return value is still void.
100     template <size_t CurrentIndex, typename OtherType, typename... Args>
101     typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList(
102         OtherType arg1,
103         const Args &...args);
104 
105     template <size_t CurrentIndex>
106     void initWithList() const;
107 
108     template <size_t Dimension2, typename Type2>
109     friend class VectorBase;
110 
111     Type mData[Dimension];
112 };
113 
114 template <size_t Dimension, typename Type>
115 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector);
116 
117 template <typename Type>
118 class Vector<2, Type> : public VectorBase<2, Type>
119 {
120   public:
121     // Import the constructors defined in VectorBase
122     using VectorBase<2, Type>::VectorBase;
123 
124     // Element shorthands
x()125     Type &x() { return this->mData[0]; }
y()126     Type &y() { return this->mData[1]; }
127 
x()128     const Type &x() const { return this->mData[0]; }
y()129     const Type &y() const { return this->mData[1]; }
130 };
131 
132 template <typename Type>
133 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector);
134 
135 template <typename Type>
136 class Vector<3, Type> : public VectorBase<3, Type>
137 {
138   public:
139     // Import the constructors defined in VectorBase
140     using VectorBase<3, Type>::VectorBase;
141 
142     // Additional operations
143     Vector<3, Type> cross(const Vector<3, Type> &other) const;
144 
145     // Element shorthands
x()146     Type &x() { return this->mData[0]; }
y()147     Type &y() { return this->mData[1]; }
z()148     Type &z() { return this->mData[2]; }
149 
x()150     const Type &x() const { return this->mData[0]; }
y()151     const Type &y() const { return this->mData[1]; }
z()152     const Type &z() const { return this->mData[2]; }
153 };
154 
155 template <typename Type>
156 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector);
157 
158 template <typename Type>
159 class Vector<4, Type> : public VectorBase<4, Type>
160 {
161   public:
162     // Import the constructors defined in VectorBase
163     using VectorBase<4, Type>::VectorBase;
164 
165     // Element shorthands
x()166     Type &x() { return this->mData[0]; }
y()167     Type &y() { return this->mData[1]; }
z()168     Type &z() { return this->mData[2]; }
w()169     Type &w() { return this->mData[3]; }
170 
x()171     const Type &x() const { return this->mData[0]; }
y()172     const Type &y() const { return this->mData[1]; }
z()173     const Type &z() const { return this->mData[2]; }
w()174     const Type &w() const { return this->mData[3]; }
175 };
176 
177 template <typename Type>
178 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector);
179 
180 // Implementation of constructors and misc operations
181 
182 template <size_t Dimension, typename Type>
VectorBase(Type element)183 VectorBase<Dimension, Type>::VectorBase(Type element)
184 {
185     for (size_t i = 0; i < Dimension; ++i)
186     {
187         mData[i] = element;
188     }
189 }
190 
191 template <size_t Dimension, typename Type>
192 template <typename Type2>
VectorBase(const VectorBase<Dimension,Type2> & other)193 VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other)
194 {
195     for (size_t i = 0; i < Dimension; ++i)
196     {
197         mData[i] = static_cast<Type>(other.mData[i]);
198     }
199 }
200 
201 // Ideally we would like to have only two constructors:
202 //  - a scalar constructor that takes Type as a parameter
203 //  - a compound constructor
204 // However if we define the compound constructor for when it has a single arguments, then calling
205 // Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound
206 // constructor with a single argument, which is the copy constructor. We end up with three
207 // constructors:
208 //  - the scalar constructor
209 //  - the copy constructor
210 //  - the compound constructor for two or more arguments, hence the arg1, and arg2 here.
211 template <size_t Dimension, typename Type>
212 template <typename Arg1, typename Arg2, typename... Args>
VectorBase(const Arg1 & arg1,const Arg2 & arg2,const Args &...args)213 VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args)
214 {
215     initWithList<0>(arg1, arg2, args...);
216 }
217 
218 template <size_t Dimension, typename Type>
219 template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
initWithList(const Vector<OtherDimension,OtherType> & arg1,const Args &...args)220 void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1,
221                                                const Args &...args)
222 {
223     static_assert(CurrentIndex + OtherDimension <= Dimension,
224                   "Too much data in the vector constructor.");
225     for (size_t i = 0; i < OtherDimension; ++i)
226     {
227         mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]);
228     }
229     initWithList<CurrentIndex + OtherDimension>(args...);
230 }
231 
232 template <size_t Dimension, typename Type>
233 template <size_t CurrentIndex, typename OtherType, typename... Args>
234 typename std::enable_if<std::is_arithmetic<OtherType>::value>::type
initWithList(OtherType arg1,const Args &...args)235 VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &...args)
236 {
237     static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor.");
238     mData[CurrentIndex] = static_cast<Type>(arg1);
239     initWithList<CurrentIndex + 1>(args...);
240 }
241 
242 template <size_t Dimension, typename Type>
243 template <size_t CurrentIndex>
initWithList()244 void VectorBase<Dimension, Type>::initWithList() const
245 {
246     static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor.");
247 }
248 
249 template <size_t Dimension, typename Type>
Load(const Type * source)250 Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source)
251 {
252     Vector<Dimension, Type> result;
253     for (size_t i = 0; i < Dimension; ++i)
254     {
255         result.mData[i] = source[i];
256     }
257     return result;
258 }
259 
260 template <size_t Dimension, typename Type>
Store(const Vector<Dimension,Type> & source,Type * destination)261 void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination)
262 {
263     for (size_t i = 0; i < Dimension; ++i)
264     {
265         destination[i] = source.mData[i];
266     }
267 }
268 
269 // Implementation of basic arithmetic operations
270 template <size_t Dimension, typename Type>
271 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const
272 {
273     Vector<Dimension, Type> result;
274     for (size_t i = 0; i < Dimension; ++i)
275     {
276         result.mData[i] = +mData[i];
277     }
278     return result;
279 }
280 
281 template <size_t Dimension, typename Type>
282 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const
283 {
284     Vector<Dimension, Type> result;
285     for (size_t i = 0; i < Dimension; ++i)
286     {
287         result.mData[i] = -mData[i];
288     }
289     return result;
290 }
291 
292 template <size_t Dimension, typename Type>
293 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+(
294     const Vector<Dimension, Type> &other) const
295 {
296     Vector<Dimension, Type> result;
297     for (size_t i = 0; i < Dimension; ++i)
298     {
299         result.mData[i] = mData[i] + other.mData[i];
300     }
301     return result;
302 }
303 
304 template <size_t Dimension, typename Type>
305 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-(
306     const Vector<Dimension, Type> &other) const
307 {
308     Vector<Dimension, Type> result;
309     for (size_t i = 0; i < Dimension; ++i)
310     {
311         result.mData[i] = mData[i] - other.mData[i];
312     }
313     return result;
314 }
315 
316 template <size_t Dimension, typename Type>
317 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(
318     const Vector<Dimension, Type> &other) const
319 {
320     Vector<Dimension, Type> result;
321     for (size_t i = 0; i < Dimension; ++i)
322     {
323         result.mData[i] = mData[i] * other.mData[i];
324     }
325     return result;
326 }
327 
328 template <size_t Dimension, typename Type>
329 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(
330     const Vector<Dimension, Type> &other) const
331 {
332     Vector<Dimension, Type> result;
333     for (size_t i = 0; i < Dimension; ++i)
334     {
335         result.mData[i] = mData[i] / other.mData[i];
336     }
337     return result;
338 }
339 
340 template <size_t Dimension, typename Type>
341 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const
342 {
343     Vector<Dimension, Type> result;
344     for (size_t i = 0; i < Dimension; ++i)
345     {
346         result.mData[i] = mData[i] * other;
347     }
348     return result;
349 }
350 
351 template <size_t Dimension, typename Type>
352 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const
353 {
354     Vector<Dimension, Type> result;
355     for (size_t i = 0; i < Dimension; ++i)
356     {
357         result.mData[i] = mData[i] / other;
358     }
359     return result;
360 }
361 
362 // Implementation of compound arithmetic operations
363 template <size_t Dimension, typename Type>
364 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=(
365     const Vector<Dimension, Type> &other)
366 {
367     for (size_t i = 0; i < Dimension; ++i)
368     {
369         mData[i] += other.mData[i];
370     }
371     return *static_cast<Vector<Dimension, Type> *>(this);
372 }
373 
374 template <size_t Dimension, typename Type>
375 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=(
376     const Vector<Dimension, Type> &other)
377 {
378     for (size_t i = 0; i < Dimension; ++i)
379     {
380         mData[i] -= other.mData[i];
381     }
382     return *static_cast<Vector<Dimension, Type> *>(this);
383 }
384 
385 template <size_t Dimension, typename Type>
386 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(
387     const Vector<Dimension, Type> &other)
388 {
389     for (size_t i = 0; i < Dimension; ++i)
390     {
391         mData[i] *= other.mData[i];
392     }
393     return *static_cast<Vector<Dimension, Type> *>(this);
394 }
395 
396 template <size_t Dimension, typename Type>
397 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(
398     const Vector<Dimension, Type> &other)
399 {
400     for (size_t i = 0; i < Dimension; ++i)
401     {
402         mData[i] /= other.mData[i];
403     }
404     return *static_cast<Vector<Dimension, Type> *>(this);
405 }
406 
407 template <size_t Dimension, typename Type>
408 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other)
409 {
410     for (size_t i = 0; i < Dimension; ++i)
411     {
412         mData[i] *= other;
413     }
414     return *static_cast<Vector<Dimension, Type> *>(this);
415 }
416 
417 template <size_t Dimension, typename Type>
418 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other)
419 {
420     for (size_t i = 0; i < Dimension; ++i)
421     {
422         mData[i] /= other;
423     }
424     return *static_cast<Vector<Dimension, Type> *>(this);
425 }
426 
427 // Implementation of comparison operators
428 template <size_t Dimension, typename Type>
429 bool VectorBase<Dimension, Type>::operator==(const VectorBase<Dimension, Type> &other) const
430 {
431     for (size_t i = 0; i < Dimension; ++i)
432     {
433         if (mData[i] != other.mData[i])
434         {
435             return false;
436         }
437     }
438     return true;
439 }
440 
441 template <size_t Dimension, typename Type>
442 bool VectorBase<Dimension, Type>::operator!=(const VectorBase<Dimension, Type> &other) const
443 {
444     return !(*this == other);
445 }
446 
447 // Implementation of other arithmetic operations
448 template <size_t Dimension, typename Type>
length()449 Type VectorBase<Dimension, Type>::length() const
450 {
451     static_assert(std::is_floating_point<Type>::value,
452                   "VectorN::length is only defined for floating point vectors");
453     return std::sqrt(lengthSquared());
454 }
455 
456 template <size_t Dimension, typename Type>
lengthSquared()457 Type VectorBase<Dimension, Type>::lengthSquared() const
458 {
459     return dot(*this);
460 }
461 
462 template <size_t Dimension, typename Type>
dot(const VectorBase<Dimension,Type> & other)463 Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const
464 {
465     Type sum = Type();
466     for (size_t i = 0; i < Dimension; ++i)
467     {
468         sum += mData[i] * other.mData[i];
469     }
470     return sum;
471 }
472 
473 template <size_t Dimension, typename Type>
474 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector)
475 {
476     ostream << "[ ";
477     for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++)
478     {
479         if (elementIdx > 0)
480         {
481             ostream << ", ";
482         }
483         ostream << vector.data()[elementIdx];
484     }
485     ostream << " ]";
486     return ostream;
487 }
488 
489 template <size_t Dimension, typename Type>
normalized()490 Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const
491 {
492     static_assert(std::is_floating_point<Type>::value,
493                   "VectorN::normalized is only defined for floating point vectors");
494     ASSERT(length() != Type());
495     return *this / length();
496 }
497 
498 template <typename Type>
499 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector)
500 {
501     return ostream << static_cast<const VectorBase<2, Type> &>(vector);
502 }
503 
504 template <typename Type>
cross(const Vector<3,Type> & other)505 Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const
506 {
507     return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(),
508                            x() * other.y() - y() * other.x());
509 }
510 
511 template <typename Type>
512 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector)
513 {
514     return ostream << static_cast<const VectorBase<3, Type> &>(vector);
515 }
516 
517 template <typename Type>
518 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector)
519 {
520     return ostream << static_cast<const VectorBase<4, Type> &>(vector);
521 }
522 
523 }  // namespace angle
524 
525 #endif  // COMMON_VECTOR_UTILS_H_
526