Mathter
A configurable 3D math library for game developers.
VectorImpl.hpp
Go to the documentation of this file.
1 //==============================================================================
2 // This software is distributed under The Unlicense.
3 // For more information, please refer to <http://unlicense.org/>
4 //==============================================================================
5 
6 #pragma once
7 
8 #include "../Common/Definitions.hpp"
9 #include "../Common/Traits.hpp"
10 #include "../SIMD/Simd.hpp"
11 #include "../Common/MathUtil.hpp"
12 
13 #include <algorithm>
14 #include <array>
15 #include <cassert>
16 #include <cmath>
17 #include <type_traits>
18 
19 
20 namespace mathter {
21 
22 
23 //------------------------------------------------------------------------------
24 // Swizzle
25 //------------------------------------------------------------------------------
26 
27 
34 template <class T, int... Indices>
35 class Swizzle {
36  static constexpr int IndexTable[] = { Indices... };
37  static constexpr int Dim = sizeof...(Indices);
38  T* data() { return reinterpret_cast<T*>(this); }
39  const T* data() const { return reinterpret_cast<const T*>(this); }
40 
41 public:
43  operator Vector<T, sizeof...(Indices), false>() const;
45  operator Vector<T, sizeof...(Indices), true>() const;
46 
52  Swizzle& operator=(const Vector<T, sizeof...(Indices), false>& rhs);
58  Swizzle& operator=(const Vector<T, sizeof...(Indices), true>& rhs);
59 
65  template <class T2, int... Indices2, typename std::enable_if<sizeof...(Indices) == sizeof...(Indices2), int>::type = 0>
67  *this = Vector<T, sizeof...(Indices2), false>(rhs);
68  return *this;
69  }
70 
72  T& operator[](int idx) {
73  assert(idx < Dim);
74  return data()[IndexTable[idx]];
75  }
77  T operator[](int idx) const {
78  assert(idx < Dim);
79  return data()[IndexTable[idx]];
80  }
81 
83  T& operator()(int idx) {
84  assert(idx < Dim);
85  return data()[IndexTable[idx]];
86  }
88  T operator()(int idx) const {
89  assert(idx < Dim);
90  return data()[IndexTable[idx]];
91  }
92 
94  template <bool Packed = false>
95  const auto ToVector() const {
96  return Vector<T, Dim, Packed>(*this);
97  }
98 
99 protected:
100  template <int... Rest, class = typename std::enable_if<sizeof...(Rest) == 0>::type>
101  void Assign(const T*) {}
102 
103  template <int Index, int... Rest>
104  void Assign(const T* rhs) {
105  data()[Index] = *rhs;
106  return Assign<Rest...>(rhs + 1);
107  }
108 };
109 
110 template <class T, int... Indices>
111 constexpr int Swizzle<T, Indices...>::IndexTable[];
112 
113 
114 //------------------------------------------------------------------------------
115 // VectorData
116 //------------------------------------------------------------------------------
117 
118 // General
119 template <class T, int Dim, bool Packed>
120 class VectorData {
121 public:
123  T data[Dim];
124 };
125 
126 
127 // Small vectors with x,y,z,w members
128 template <class T, bool Packed>
129 class VectorData<T, 2, Packed> {
130  using ST = T;
131 
132 public:
133  VectorData() {}
134  VectorData(const VectorData& rhs) {
135  for (int i = 0; i < 2; ++i) {
136  data[i] = rhs.data[i];
137  }
138  }
139  VectorData& operator=(const VectorData& rhs) {
140  for (int i = 0; i < 2; ++i) {
141  data[i] = rhs.data[i];
142  }
143  return *this;
144  }
145  union {
146  struct {
147  T x, y;
148  };
150  T data[2];
151 #include "../Swizzle/Swizzle_2.inc.hpp"
152  };
153 };
154 
155 template <class T, bool Packed>
156 class VectorData<T, 3, Packed> {
157  using ST = T;
158 
159 public:
160  VectorData() {}
161  VectorData(const VectorData& rhs) {
162  for (int i = 0; i < 3; ++i) {
163  data[i] = rhs.data[i];
164  }
165  }
166  VectorData& operator=(const VectorData& rhs) {
167  for (int i = 0; i < 3; ++i) {
168  data[i] = rhs.data[i];
169  }
170  return *this;
171  }
172  union {
173  struct {
174  T x, y, z;
175  };
177  T data[3];
178 #include "../Swizzle/Swizzle_3.inc.hpp"
179  };
180 };
181 
182 template <class T, bool Packed>
183 class VectorData<T, 4, Packed> {
184  using ST = T;
185 
186 public:
187  VectorData() {}
188  VectorData(const VectorData& rhs) {
189  for (int i = 0; i < 4; ++i) {
190  data[i] = rhs.data[i];
191  }
192  }
193  VectorData& operator=(const VectorData& rhs) {
194  for (int i = 0; i < 4; ++i) {
195  data[i] = rhs.data[i];
196  }
197  return *this;
198  }
199  union {
200  struct {
201  T x, y, z, w;
202  };
204  T data[4];
205 #include "../Swizzle/Swizzle_4.inc.hpp"
206  };
207 };
208 
209 
210 // Small SIMD fp32 vectors
211 template <>
212 class VectorData<float, 2, false> {
213  using ST = float;
214 
215 public:
216  VectorData() {}
217  VectorData(const VectorData& rhs) { simd = rhs.simd; }
218  VectorData& operator=(const VectorData& rhs) {
219  simd = rhs.simd;
220  return *this;
221  }
222  union {
224  Simd<float, 2> simd;
225  struct {
226  float x, y;
227  };
229  float data[2];
230 #include "../Swizzle/Swizzle_2.inc.hpp"
231  };
232 };
233 
234 template <>
235 class VectorData<float, 3, false> {
236  using ST = float;
237 
238 public:
239  VectorData() {}
240  VectorData(const VectorData& rhs) { simd = rhs.simd; }
241  VectorData& operator=(const VectorData& rhs) {
242  simd = rhs.simd;
243  return *this;
244  }
245  union {
247  Simd<float, 4> simd;
248  struct {
249  float x, y, z;
250  };
252  float data[3];
253 #include "../Swizzle/Swizzle_3.inc.hpp"
254  };
255 };
256 
257 template <>
258 class VectorData<float, 4, false> {
259  using ST = float;
260 
261 public:
262  VectorData() {}
263  VectorData(const VectorData& rhs) { simd = rhs.simd; }
264  VectorData& operator=(const VectorData& rhs) {
265  simd = rhs.simd;
266  return *this;
267  }
268  union {
270  Simd<float, 4> simd;
271  struct {
272  float x, y, z, w;
273  };
275  float data[4];
276 #include "../Swizzle/Swizzle_4.inc.hpp"
277  };
278 };
279 
280 template <>
281 class VectorData<float, 8, false> {
282 public:
283  VectorData() {}
284  VectorData(const VectorData& rhs) { simd = rhs.simd; }
285  VectorData& operator=(const VectorData& rhs) {
286  simd = rhs.simd;
287  return *this;
288  }
289  union {
291  Simd<float, 8> simd;
293  float data[8];
294  };
295 };
296 
297 
298 // Small SIMD fp64 vectors
299 template <>
300 class VectorData<double, 2, false> {
301  using ST = double;
302 
303 public:
304  VectorData() {}
305  VectorData(const VectorData& rhs) { simd = rhs.simd; }
306  VectorData& operator=(const VectorData& rhs) {
307  simd = rhs.simd;
308  return *this;
309  }
310  union {
312  Simd<double, 2> simd;
313  struct {
314  double x, y;
315  };
317  double data[2];
318 #include "../Swizzle/Swizzle_2.inc.hpp"
319  };
320 };
321 
322 template <>
323 class VectorData<double, 3, false> {
324  using ST = double;
325 
326 public:
327  VectorData() {}
328  VectorData(const VectorData& rhs) { simd = rhs.simd; }
329  VectorData& operator=(const VectorData& rhs) {
330  simd = rhs.simd;
331  return *this;
332  }
333  union {
335  Simd<double, 4> simd;
336  struct {
337  double x, y, z;
338  };
340  double data[3];
341 #include "../Swizzle/Swizzle_3.inc.hpp"
342  };
343 };
344 
345 template <>
346 class VectorData<double, 4, false> {
347  using ST = double;
348 
349 public:
350  VectorData() {}
351  VectorData(const VectorData& rhs) { simd = rhs.simd; }
352  VectorData& operator=(const VectorData& rhs) {
353  simd = rhs.simd;
354  return *this;
355  }
356  union {
358  Simd<double, 4> simd;
359  struct {
360  double x, y, z, w;
361  };
363  double data[4];
364 #include "../Swizzle/Swizzle_4.inc.hpp"
365  };
366 };
367 
368 
369 //------------------------------------------------------------------------------
370 // General vector class
371 //------------------------------------------------------------------------------
372 
373 
390 template <class T, int Dim, bool Packed = false>
391 class Vector : public VectorData<T, Dim, Packed> {
392  static_assert(Dim >= 1, "Dimension must be positive integer.");
393 
394 public:
395  using VectorData<T, Dim, Packed>::data;
396 
397  //--------------------------------------------
398  // Properties
399  //--------------------------------------------
400 
402  constexpr int Dimension() const {
403  return Dim;
404  }
405 
406  //--------------------------------------------
407  // Data constructors
408  //--------------------------------------------
409 
411  Vector() = default;
412  Vector(const Vector&) = default;
413  Vector& operator=(const Vector&) = default;
414 
416  explicit Vector(T all) {
417  if constexpr (!traits::HasSimd<Vector>::value) {
418  for (auto& v : *this) {
419  v = all;
420  }
421  }
422  else {
423  using SimdT = decltype(VectorData<T, Dim, Packed>::simd);
424  this->simd = SimdT::spread(all);
425  }
426  }
427 
430  template <class U>
431  explicit Vector(const U* data) {
432  for (int i = 0; i < Dim; ++i) {
433  this->data[i] = data[i];
434  }
435  }
436 
437  //--------------------------------------------
438  // Homogeneous up- and downcast
439  //--------------------------------------------
440 
442  template <class T2, bool Packed2, class = typename std::enable_if<(Dim >= 2), T2>::type>
443  explicit Vector(const Vector<T2, Dim - 1, Packed2>& rhs) : Vector(rhs, 1) {}
444 
446  template <class T2, bool Packed2>
447  explicit Vector(const Vector<T2, Dim + 1, Packed2>& rhs) : Vector(rhs.data) {}
448 
449 
450  //--------------------------------------------
451  // Copy, assignment, set
452  //--------------------------------------------
453 
454  // NOTE: somehow msvc 2015 is buggy and cannot compile sizeof... checks for ctors as in Set
455 
459  template <class H1, class H2, class... Scalars, typename std::enable_if<traits::All<traits::IsScalar, H1, H2, Scalars...>::value && traits::SumDimensions<H1, H2, Scalars...>::value == Dim, int>::type = 0>
460  Vector(H1 h1, H2 h2, Scalars... scalars) {
461  Assign(0, h1, h2, scalars...);
462  }
463 
467  template <class H1, class... Mixed, typename std::enable_if<traits::Any<traits::IsVectorOrSwizzle, H1, Mixed...>::value && traits::SumDimensions<H1, Mixed...>::value == Dim, int>::type = 0>
468  Vector(const H1& h1, const Mixed&... mixed) {
469  Assign(0, h1, mixed...);
470  }
471 
475  template <class... Scalars, typename std::enable_if<((sizeof...(Scalars) > 1) && traits::All<traits::IsScalar, Scalars...>::value), int>::type = 0>
476  Vector& Set(Scalars... scalars) {
477  static_assert(traits::SumDimensions<Scalars...>::value == Dim, "Arguments must match vector dimension.");
478  Assign(0, scalars...);
479  return *this;
480  }
481 
485  template <class... Mixed, typename std::enable_if<(sizeof...(Mixed) > 0) && traits::Any<traits::IsVectorOrSwizzle, Mixed...>::value, int>::type = 0>
486  Vector& Set(const Mixed&... mixed) {
487  static_assert(traits::SumDimensions<Mixed...>::value == Dim, "Arguments must match vector dimension.");
488  Assign(0, mixed...);
489  return *this;
490  }
491 
492 
493  //--------------------------------------------
494  // Accessors
495  //--------------------------------------------
496 
498  T operator[](int idx) const {
499  assert(idx < Dimension());
500  return data[idx];
501  }
503  T& operator[](int idx) {
504  assert(idx < Dimension());
505  return data[idx];
506  }
507 
509  T operator()(int idx) const {
510  assert(idx < Dimension());
511  return data[idx];
512  }
514  T& operator()(int idx) {
515  assert(idx < Dimension());
516  return data[idx];
517  }
518 
520  const T* cbegin() const {
521  return data;
522  }
524  const T* begin() const {
525  return data;
526  }
528  T* begin() {
529  return data;
530  }
532  const T* cend() const {
533  return data + Dim;
534  }
536  const T* end() const {
537  return data + Dim;
538  }
540  T* end() {
541  return data + Dim;
542  }
543 
545  const T* Data() const {
546  return data;
547  }
549  T* Data() {
550  return data;
551  }
552 
553 protected:
554  //--------------------------------------------
555  // Helpers
556  //--------------------------------------------
557 
558  // Get nth element of an argument
559  template <class U>
560  struct GetVectorElement {
561  static U Get(const U& u, int idx) { return u; }
562  };
563  template <class T2, int D2, bool P2>
564  struct GetVectorElement<Vector<T2, D2, P2>> {
565  static T2 Get(const Vector<T2, D2, P2>& u, int idx) { return u.data[idx]; }
566  };
567  template <class U, int... Indices>
568  struct GetVectorElement<Swizzle<U, Indices...>> {
569  static U Get(const Swizzle<T, Indices...>& u, int idx) { return u[idx]; }
570  };
571 
572  // Assign
573  // Scalar concat assign
574  template <class Head, class... Scalars, typename std::enable_if<traits::All<traits::IsScalar, Head, Scalars...>::value, int>::type = 0>
575  void Assign(int idx, Head head, Scalars... scalars) {
576  data[idx] = (T)head;
577  Assign(idx + 1, scalars...);
578  }
579 
580  // Generalized concat assign
581  template <class Head, class... Mixed, typename std::enable_if<traits::Any<traits::IsVectorOrSwizzle, Head, Mixed...>::value, int>::type = 0>
582  void Assign(int idx, const Head& head, const Mixed&... mixed) {
583  for (int i = 0; i < traits::DimensionOf<Head>::value; ++i) {
584  data[idx] = (T)GetVectorElement<Head>::Get(head, i);
585  ++idx;
586  }
587  Assign(idx, mixed...);
588  }
589 
590  // Assign terminator, fill stuff with zeros
591  void Assign(int idx) {
592  for (; idx < Dim; idx++) {
593  data[idx] = T(0);
594  }
595  }
596 };
597 
598 
599 template <class T, int... Indices>
600 Swizzle<T, Indices...>::operator Vector<T, sizeof...(Indices), false>() const {
601  return Vector<T, sizeof...(Indices), false>(data()[Indices]...);
602 }
603 template <class T, int... Indices>
604 Swizzle<T, Indices...>::operator Vector<T, sizeof...(Indices), true>() const {
605  return Vector<T, sizeof...(Indices), true>(data()[Indices]...);
606 }
607 
608 template <class T, int... Indices>
609 Swizzle<T, Indices...>& Swizzle<T, Indices...>::operator=(const Vector<T, sizeof...(Indices), false>& rhs) {
610  if (data() != rhs.data) {
611  Assign<Indices...>(rhs.data);
612  }
613  else {
614  Vector<T, sizeof...(Indices), false> tmp = rhs;
615  *this = tmp;
616  }
617  return *this;
618 }
619 template <class T, int... Indices>
620 Swizzle<T, Indices...>& Swizzle<T, Indices...>::operator=(const Vector<T, sizeof...(Indices), true>& rhs) {
621  if (data() != rhs.data) {
622  Assign<Indices...>(rhs.data);
623  }
624  else {
625  Vector<T, sizeof...(Indices), false> tmp = rhs;
626  *this = tmp;
627  }
628  return *this;
629 }
630 
631 
632 
633 } // namespace mathter
const T * end() const
Returns an iterator to the end of the vector (works like STL).
Definition: VectorImpl.hpp:536
Swizzle & operator=(const Swizzle< T2, Indices2... > &rhs)
Sets the parent vector&#39;s elements from the right-side argument.
Definition: VectorImpl.hpp:66
Definition: Simd_SSE2.hpp:115
Vector(const H1 &h1, const Mixed &... mixed)
Initializes the vector by concatenating given scalar and vector arguments.
Definition: VectorImpl.hpp:468
T * end()
Returns an iterator to the end of the vector (works like STL).
Definition: VectorImpl.hpp:540
T & operator[](int idx)
Returns the nth element of the vector.
Definition: VectorImpl.hpp:503
Represents a vector in N-dimensional space.
Definition: Definitions.hpp:57
Enables element swizzling (reordering elements) for vectors.
Definition: Definitions.hpp:60
T & operator()(int idx)
Returns the nth element of the swizzled vector. Example: v.zxy(2) returns y.
Definition: VectorImpl.hpp:83
const auto ToVector() const
Builds the swizzled vector object.
Definition: VectorImpl.hpp:95
Vector & Set(Scalars... scalars)
Sets the vector&#39;s elements to the given scalars.
Definition: VectorImpl.hpp:476
Definition: Simd_SSE2.hpp:249
Vector & Set(const Mixed &... mixed)
Sets the vector&#39;s elements by concatenating given scalar and vector arguments.
Definition: VectorImpl.hpp:486
Swizzle & operator=(const Vector< T, sizeof...(Indices), false > &rhs)
Sets the parent vector&#39;s elements from the right-side argument.
Definition: VectorImpl.hpp:609
Definition: Traits.hpp:66
Definition: Approx.hpp:11
Vector(const U *data)
Constructs the vector from an array of elements.
Definition: VectorImpl.hpp:431
T & operator()(int idx)
Returns the nth element of the vector.
Definition: VectorImpl.hpp:514
Definition: Traits.hpp:139
Vector(T all)
Sets all elements to the same value.
Definition: VectorImpl.hpp:416
Vector(H1 h1, H2 h2, Scalars... scalars)
Initializes the vector to the given scalar elements.
Definition: VectorImpl.hpp:460
T * Data()
Returns a pointer to the underlying array of elements.
Definition: VectorImpl.hpp:549
const T * Data() const
Returns a pointer to the underlying array of elements.
Definition: VectorImpl.hpp:545
T operator[](int idx) const
Returns the nth element of the swizzled vector. Example: v.zxy[2] returns y.
Definition: VectorImpl.hpp:77
T * begin()
Returns an iterator to the first element.
Definition: VectorImpl.hpp:528
const T * cend() const
Returns an iterator to the end of the vector (works like STL).
Definition: VectorImpl.hpp:532
Definition: Simd_SSE2.hpp:347
T operator[](int idx) const
Returns the nth element of the vector.
Definition: VectorImpl.hpp:498
Definition: Traits.hpp:184
Definition: Traits.hpp:204
Definition: Traits.hpp:80
Vector(const Vector< T2, Dim+1, Packed2 > &rhs)
Truncates last coordinate of homogenous vector to create non-homogeneous.
Definition: VectorImpl.hpp:447
Vector(const Vector< T2, Dim - 1, Packed2 > &rhs)
Creates a homogeneous vector by appending a 1.
Definition: VectorImpl.hpp:443
constexpr int Dimension() const
Returns the number of dimensions of the vector.
Definition: VectorImpl.hpp:402
T operator()(int idx) const
Returns the nth element of the swizzled vector. Example: v.zxy(2) returns y.
Definition: VectorImpl.hpp:88
2,4 or 8 dimension float or double parameters accepted. Uses SSE2 or AVX acceleration if enabled in t...
Definition: Simd.hpp:22
T operator()(int idx) const
Returns the nth element of the vector.
Definition: VectorImpl.hpp:509
const T * cbegin() const
Returns an iterator to the first element.
Definition: VectorImpl.hpp:520
Definition: Simd_SSE2.hpp:17
Definition: Traits.hpp:218
T & operator[](int idx)
Returns the nth element of the swizzled vector. Example: v.zxy[2] returns y.
Definition: VectorImpl.hpp:72
const T * begin() const
Returns an iterator to the first element.
Definition: VectorImpl.hpp:524