Vector.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
22 #ifndef PLAYRHO_COMMON_VECTOR_HPP
23 #define PLAYRHO_COMMON_VECTOR_HPP
24 
25 #include <cassert>
26 #include <cstddef>
27 #include <type_traits>
28 #include <iterator>
29 #include <algorithm>
30 #include <functional>
31 #include <iostream>
33 #include <PlayRho/Common/Real.hpp>
35 
36 namespace playrho {
37 
47 template <typename T, std::size_t N>
48 struct Vector
49 {
51  using value_type = T;
52 
54  using size_type = std::size_t;
55 
57  using difference_type = std::ptrdiff_t;
58 
61 
63  using const_reference = const value_type&;
64 
66  using pointer = value_type*;
67 
69  using const_pointer = const value_type*;
70 
72  using iterator = value_type*;
73 
75  using const_iterator = const value_type*;
76 
78  using reverse_iterator = std::reverse_iterator<iterator>;
79 
81  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
82 
86  PLAYRHO_CONSTEXPR inline Vector() = default;
87 
89  template<typename... Tail>
90  PLAYRHO_CONSTEXPR inline Vector(std::enable_if_t<sizeof...(Tail)+1 == N, T> head,
91  Tail... tail) noexcept: elements{head, T(tail)...}
92  {
93  // Intentionally empty.
94  }
95 
97  PLAYRHO_CONSTEXPR inline size_type max_size() const noexcept { return N; }
98 
100  PLAYRHO_CONSTEXPR inline size_type size() const noexcept { return N; }
101 
104  PLAYRHO_CONSTEXPR inline bool empty() const noexcept { return N == 0; }
105 
107  iterator begin() noexcept { return iterator(elements); }
108 
110  iterator end() noexcept { return iterator(elements + N); }
111 
113  const_iterator begin() const noexcept { return const_iterator(elements); }
114 
116  const_iterator end() const noexcept { return const_iterator(elements + N); }
117 
119  const_iterator cbegin() const noexcept { return begin(); }
120 
122  const_iterator cend() const noexcept { return end(); }
123 
125  reverse_iterator rbegin() noexcept { return reverse_iterator{elements + N}; }
126 
129 
132  {
133  return const_reverse_iterator{elements + N};
134  }
135 
137  const_reverse_iterator crend() const noexcept
138  {
140  }
141 
144  {
145  return crbegin();
146  }
147 
149  const_reverse_iterator rend() const noexcept
150  {
151  return crend();
152  }
153 
158  {
159  assert(pos < size());
160  return elements[pos];
161  }
162 
167  {
168  assert(pos < size());
169  return elements[pos];
170  }
171 
175  {
176  if (pos >= size())
177  {
178  throw InvalidArgument("Vector::at: position >= size()");
179  }
180  return elements[pos];
181  }
182 
186  {
187  if (pos >= size())
188  {
189  throw InvalidArgument("Vector::at: position >= size()");
190  }
191  return elements[pos];
192  }
193 
195  PLAYRHO_CONSTEXPR inline pointer data() noexcept
196  {
197  return elements;
198  }
199 
201  PLAYRHO_CONSTEXPR inline const_pointer data() const noexcept
202  {
203  return elements;
204  }
205 
211  value_type elements[N? N: 1]; // Never zero to avoid needing C++ extension capability.
212 };
213 
217 
226 template <typename>
227 struct IsVector: std::false_type {};
228 
237 template <typename T, std::size_t N>
238 struct IsVector<Vector<T, N>>: std::true_type {};
239 
241 
244 template <typename T, std::size_t N>
245 PLAYRHO_CONSTEXPR inline bool operator== (const Vector<T, N>& lhs, const Vector<T, N>& rhs) noexcept
246 {
247  for (auto i = decltype(N){0}; i < N; ++i)
248  {
249  if (lhs[i] != rhs[i])
250  {
251  return false;
252  }
253  }
254  return true;
255 }
256 
259 template <typename T, std::size_t N>
260 PLAYRHO_CONSTEXPR inline bool operator!= (const Vector<T, N>& lhs, const Vector<T, N>& rhs) noexcept
261 {
262  return !(lhs == rhs);
263 }
264 
267 template <typename T, std::size_t N>
268 PLAYRHO_CONSTEXPR inline
269 std::enable_if_t<std::is_same<T, decltype(+T{})>::value, Vector<T, N>>
270 operator+ (Vector<T, N> v) noexcept
271 {
272  return v;
273 }
274 
277 template <typename T, std::size_t N>
278 PLAYRHO_CONSTEXPR inline
279 std::enable_if_t<std::is_same<T, decltype(-T{})>::value, Vector<T, N>>
280 operator- (Vector<T, N> v) noexcept
281 {
282  for (auto i = decltype(N){0}; i < N; ++i)
283  {
284  v[i] = -v[i];
285  }
286  return v;
287 }
288 
291 template <typename T, std::size_t N>
292 PLAYRHO_CONSTEXPR inline
293 std::enable_if_t<std::is_same<T, decltype(T{} + T{})>::value, Vector<T, N>&>
294 operator+= (Vector<T, N>& lhs, const Vector<T, N> rhs) noexcept
295 {
296  for (auto i = decltype(N){0}; i < N; ++i)
297  {
298  lhs[i] += rhs[i];
299  }
300  return lhs;
301 }
302 
305 template <typename T, std::size_t N>
306 PLAYRHO_CONSTEXPR inline
307 std::enable_if_t<std::is_same<T, decltype(T{} - T{})>::value, Vector<T, N>&>
308 operator-= (Vector<T, N>& lhs, const Vector<T, N> rhs) noexcept
309 {
310  for (auto i = decltype(N){0}; i < N; ++i)
311  {
312  lhs[i] -= rhs[i];
313  }
314  return lhs;
315 }
316 
319 template <typename T, std::size_t N>
320 PLAYRHO_CONSTEXPR inline
321 std::enable_if_t<std::is_same<T, decltype(T{} + T{})>::value, Vector<T, N>>
322 operator+ (Vector<T, N> lhs, const Vector<T, N> rhs) noexcept
323 {
324  return lhs += rhs;
325 }
326 
329 template <typename T, std::size_t N>
330 PLAYRHO_CONSTEXPR inline
331 std::enable_if_t<std::is_same<T, decltype(T{} - T{})>::value, Vector<T, N>>
332 operator- (Vector<T, N> lhs, const Vector<T, N> rhs) noexcept
333 {
334  return lhs -= rhs;
335 }
336 
339 template <typename T1, typename T2, std::size_t N>
340 PLAYRHO_CONSTEXPR inline
341 std::enable_if_t<std::is_same<T1, decltype(T1{} * T2{})>::value, Vector<T1, N>&>
342 operator*= (Vector<T1, N>& lhs, const T2 rhs) noexcept
343 {
344  for (auto i = decltype(N){0}; i < N; ++i)
345  {
346  lhs[i] *= rhs;
347  }
348  return lhs;
349 }
350 
353 template <typename T1, typename T2, std::size_t N>
354 PLAYRHO_CONSTEXPR inline
355 std::enable_if_t<std::is_same<T1, decltype(T1{} / T2{})>::value, Vector<T1, N>&>
356 operator/= (Vector<T1, N>& lhs, const T2 rhs) noexcept
357 {
358  const auto inverseRhs = Real{1} / rhs;
359  for (auto i = decltype(N){0}; i < N; ++i)
360  {
361  lhs[i] *= inverseRhs;
362  }
363  return lhs;
364 }
365 
384 template <typename T1, typename T2, std::size_t A, std::size_t B, std::size_t C,
385  typename OT = decltype(T1{} * T2{})>
386 PLAYRHO_CONSTEXPR inline
387 std::enable_if_t<IsMultipliable<T1, T2>::value, Vector<Vector<OT, C>, A>>
388 operator* (const Vector<Vector<T1, B>, A>& lhs, const Vector<Vector<T2, C>, B>& rhs) noexcept
389 {
390  //using OT = decltype(T1{} * T2{});
391  auto result = Vector<Vector<OT, C>, A>{};
392  for (auto a = decltype(A){0}; a < A; ++a)
393  {
394  for (auto c = decltype(C){0}; c < C; ++c)
395  {
396  // So for 2x3 lhs matrix * 3*2 rhs matrix... result is 2x2 matrix:
397  // result[0][0] = lhs[0][0] * rhs[0][0] + lhs[0][1] * rhs[1][0] + lhs[0][2] * rhs[2][0]
398  // result[0][1] = lhs[0][0] * rhs[0][1] + lhs[0][1] * rhs[1][1] + lhs[0][2] * rhs[2][1]
399  // result[1][0] = lhs[1][0] * rhs[0][0] + lhs[1][1] * rhs[1][0] + lhs[1][2] * rhs[2][0]
400  // result[1][1] = lhs[1][0] * rhs[0][1] + lhs[1][1] * rhs[1][1] + lhs[1][2] * rhs[2][1]
401  // This is also: result[a][c] = row(lhs, a) * col(rhs, c)
402  auto element = OT{};
403  for (auto b = decltype(B){0}; b < B; ++b)
404  {
405  element += lhs[a][b] * rhs[b][c];
406  }
407  result[a][c] = element;
408  }
409  }
410  return result;
411 }
412 
420 template <typename T1, typename T2, std::size_t A, std::size_t B,
421  typename OT = decltype(T1{} * T2{})>
422 PLAYRHO_CONSTEXPR inline
423 std::enable_if_t<IsMultipliable<T1, T2>::value && !IsVector<T1>::value, Vector<OT, B>>
424 operator* (const Vector<T1, A>& lhs, const Vector<Vector<T2, B>, A>& rhs) noexcept
425 {
426  auto result = Vector<OT, B>{};
427  for (auto b = decltype(B){0}; b < B; ++b)
428  {
429  auto element = OT{};
430  for (auto a = decltype(A){0}; a < A; ++a)
431  {
432  element += lhs[a] * rhs[a][b];
433  }
434  result[b] = element;
435  }
436  return result;
437 }
438 
446 template <typename T1, typename T2, std::size_t A, std::size_t B,
447  typename OT = decltype(T1{} * T2{})>
448 PLAYRHO_CONSTEXPR inline
449 std::enable_if_t<IsMultipliable<T1, T2>::value && !IsVector<T2>::value, Vector<OT, B>>
450 operator* (const Vector<Vector<T1, A>, B>& lhs, const Vector<T2, A>& rhs) noexcept
451 {
452  auto result = Vector<OT, B>{};
453  for (auto b = decltype(B){0}; b < B; ++b)
454  {
455  auto element = OT{};
456  for (auto a = decltype(A){0}; a < A; ++a)
457  {
458  element += lhs[b][a] * rhs[a];
459  }
460  result[b] = element;
461  }
462  return result;
463 }
464 
469 template <std::size_t N, typename T1, typename T2, typename OT = decltype(T1{} * T2{})>
470 PLAYRHO_CONSTEXPR inline
471 std::enable_if_t<IsMultipliable<T1, T2>::value && !IsVector<T1>::value, Vector<OT, N>>
472 operator* (const T1 s, Vector<T2, N> a) noexcept
473 {
474  // Can't base this off of *= since result type in this case can be different
475  auto result = Vector<OT, N>{};
476  for (auto i = decltype(N){0}; i < N; ++i)
477  {
478  result[i] = s * a[i];
479  }
480  return result;
481 }
482 
487 template <std::size_t N, typename T1, typename T2, typename OT = decltype(T1{} * T2{})>
488 PLAYRHO_CONSTEXPR inline
489 std::enable_if_t<IsMultipliable<T1, T2>::value && !IsVector<T2>::value, Vector<OT, N>>
490 operator* (Vector<T1, N> a, const T2 s) noexcept
491 {
492  // Can't base this off of *= since result type in this case can be different
493  auto result = Vector<OT, N>{};
494  for (auto i = decltype(N){0}; i < N; ++i)
495  {
496  result[i] = a[i] * s;
497  }
498  return result;
499 }
500 
503 template <std::size_t N, typename T1, typename T2, typename OT = decltype(T1{} / T2{})>
504 PLAYRHO_CONSTEXPR inline
505 std::enable_if_t<IsDivisable<T1, T2>::value && !IsVector<T2>::value, Vector<OT, N>>
506 operator/ (Vector<T1, N> a, const T2 s) noexcept
507 {
508  // Can't base this off of /= since result type in this case can be different
509  auto result = Vector<OT, N>{};
510  const auto inverseS = Real{1} / s;
511  for (auto i = decltype(N){0}; i < N; ++i)
512  {
513  result[i] = a[i] * inverseS;
514  }
515  return result;
516 }
517 
520 template <std::size_t I, std::size_t N, typename T>
521 PLAYRHO_CONSTEXPR inline auto& get(Vector<T, N>& v) noexcept
522 {
523  static_assert(I < N, "Index out of bounds in playrho::get<> (playrho::Vector)");
524  return v[I];
525 }
526 
528 template <std::size_t I, std::size_t N, typename T>
529 PLAYRHO_CONSTEXPR inline auto get(const Vector<T, N>& v) noexcept
530 {
531  static_assert(I < N, "Index out of bounds in playrho::get<> (playrho::Vector)");
532  return v[I];
533 }
534 
537 template <typename T, std::size_t N>
538 ::std::ostream& operator<< (::std::ostream& os, const Vector<T, N>& value)
539 {
540  os << "{";
541  for (auto i = decltype(N){0}; i < N; ++i)
542  {
543  if (i > decltype(N){0})
544  {
545  os << ',';
546  }
547  os << value[i];
548  }
549  os << "}";
550  return os;
551 }
552 
553 } // namespace playrho
554 
555 namespace std {
556 
558  template<class T, std::size_t N>
559  class tuple_size< playrho::Vector<T, N> >: public std::integral_constant<std::size_t, N> {};
560 
562  template<std::size_t I, class T, std::size_t N>
563  class tuple_element<I, playrho::Vector<T, N>>
564  {
565  public:
567  using type = T;
568  };
569 
570 } // namespace std
571 
572 #endif // PLAYRHO_COMMON_VECTOR_HPP