vector.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. //
  2. // vector.hpp
  3. // vector
  4. //
  5. // Created by Sam Jaffe on 8/15/16.
  6. //
  7. #pragma once
  8. #include <cassert>
  9. #include <cmath>
  10. #include <cstddef>
  11. #include <array>
  12. #include <initializer_list>
  13. #include <stdexcept>
  14. #include <type_traits>
  15. #include <expect/expect.hpp>
  16. #include "math/vector/forward.h"
  17. #include "math/vector/macro.h"
  18. #include "math/vector/traits.hpp"
  19. namespace math::vector {
  20. template <typename T, std::size_t N> class vector {
  21. public:
  22. using value_type = T;
  23. private:
  24. using mag_t = decltype(std::sqrt(std::declval<T>()));
  25. template <typename M>
  26. using mul_t = decltype(std::declval<T>() * std::declval<M>());
  27. template <typename M>
  28. using div_t = decltype(std::declval<T>() / std::declval<M>());
  29. public:
  30. // Constructors
  31. vector() = default;
  32. VECTOR_CTOR_N_ARGS(1) {}
  33. VECTOR_CTOR_N_ARGS(2) {}
  34. VECTOR_CTOR_N_ARGS(3) {}
  35. VECTOR_CTOR_N_ARGS(4) {}
  36. vector(std::array<T, N> const & init) {
  37. VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
  38. }
  39. // Conversion
  40. template <typename T2, std::size_t N2>
  41. explicit vector(vector<T2, N2> const & other) {
  42. VECTOR_FOR_EACH_RANGE(i, std::min(N, N2)) {
  43. _data[i] = static_cast<T>(other[i]);
  44. }
  45. }
  46. vector(T const & v, fill_t) {
  47. VECTOR_FOR_EACH(i) { _data[i] = v; }
  48. }
  49. // Named Accessors
  50. // - Numeric Vector Accessors
  51. VECTOR_ACCESS_FN(x, 0)
  52. VECTOR_ACCESS_FN(y, 1)
  53. VECTOR_ACCESS_FN(z, 2)
  54. VECTOR_ACCESS_FN(w, 3)
  55. // - Color Vector Accessors
  56. VECTOR_ACCESS_FN(r, 0)
  57. VECTOR_ACCESS_FN(g, 1)
  58. VECTOR_ACCESS_FN(b, 2)
  59. VECTOR_ACCESS_FN(a, 3)
  60. // Unnamed Accessors
  61. constexpr value_type const & operator[](std::size_t idx) const {
  62. return _data[idx];
  63. }
  64. constexpr value_type & operator[](std::size_t idx) { return _data[idx]; }
  65. value_type const & at(std::size_t idx) const {
  66. expects(idx < N, std::out_of_range, "index out of range");
  67. return _data[idx];
  68. }
  69. value_type & at(std::size_t idx) {
  70. expects(idx < N, std::out_of_range, "index out of range");
  71. return _data[idx];
  72. }
  73. // Mathematical Operations
  74. vector & operator+=(vector const & other) {
  75. VECTOR_FOR_EACH(i) { _data[i] += other[i]; }
  76. return *this;
  77. }
  78. vector & operator+=(T const & other) {
  79. return operator+=(vector(other, fill));
  80. }
  81. vector operator+(vector const & other) const {
  82. return vector{*this} += other;
  83. }
  84. vector operator+(T const & other) const {
  85. return operator+(vector(other, fill));
  86. }
  87. friend vector operator+(T const & lhs, vector const & rhs) {
  88. return rhs + lhs;
  89. }
  90. vector & operator-=(vector const & other) {
  91. VECTOR_FOR_EACH(i) { _data[i] -= other[i]; }
  92. return *this;
  93. }
  94. vector & operator-=(T const & other) {
  95. return operator-=(vector(other, fill));
  96. }
  97. vector operator-(vector const & other) const {
  98. return vector{*this} -= other;
  99. }
  100. vector operator-(T const & other) const {
  101. return operator-(vector(other, fill));
  102. }
  103. friend vector operator-(T const & lhs, vector const & rhs) {
  104. return vector(lhs, fill) - rhs;
  105. }
  106. vector operator-() const { return vector{} -= *this; }
  107. template <typename M>
  108. VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(M c) {
  109. VECTOR_FOR_EACH(i) { _data[i] *= c; }
  110. return *this;
  111. }
  112. template <typename M>
  113. VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
  114. operator*(M c) const {
  115. return vector<mul_t<M>, N>{*this} *= c;
  116. }
  117. template <typename M>
  118. friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
  119. operator*(M c, vector<T, N> const & v) {
  120. return v * c;
  121. }
  122. template <typename M>
  123. VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(vector<M, N> c) {
  124. VECTOR_FOR_EACH(i) { _data[i] *= c[i]; }
  125. return *this;
  126. }
  127. template <typename M>
  128. vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
  129. return vector<mul_t<M>, N>{*this} *= other;
  130. }
  131. template <typename M>
  132. VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(M c) {
  133. expects(c != 0, std::domain_error, "divide by zero");
  134. VECTOR_FOR_EACH(i) { _data[i] /= c; }
  135. return *this;
  136. }
  137. template <typename M>
  138. VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N)
  139. operator/(M c) const {
  140. return vector<div_t<M>, N>{*this} /= c;
  141. }
  142. template <typename M>
  143. VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(vector<M, N> c) {
  144. VECTOR_FOR_EACH(i) {
  145. expects(c[i] != 0, std::domain_error, "divide by zero");
  146. }
  147. VECTOR_FOR_EACH(i) { _data[i] /= c[i]; }
  148. return *this;
  149. }
  150. template <typename M>
  151. vector<div_t<M>, N> operator/(vector<M, N> const & other) const {
  152. return vector<div_t<M>, N>{*this} /= other;
  153. }
  154. // Vector Operations
  155. value_type dot(vector const & other) const {
  156. value_type accum{};
  157. VECTOR_FOR_EACH(i) { accum += at(i) * other.at(i); }
  158. return accum;
  159. }
  160. mag_t magnitude() const { return std::sqrt(dot(*this)); }
  161. vector<mag_t, N> unit() const { return *this / magnitude(); }
  162. VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
  163. return {{y() * other.z() - z() * other.y(),
  164. z() * other.x() - x() * other.z(),
  165. x() * other.y() - y() * other.x()}};
  166. }
  167. VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
  168. return {{0, 0, x() * other.y() - y() * other.x()}};
  169. }
  170. vector<mag_t, N> projection(vector const & other) const {
  171. vector<mag_t, N> b_p = other.unit();
  172. return b_p * vector<mag_t, N>{*this}.dot(b_p);
  173. }
  174. private:
  175. value_type _data[N] = {value_type()};
  176. };
  177. template <typename T, typename... Us>
  178. vector(T, Us...) -> vector<T, sizeof...(Us) + 1>;
  179. template <typename T, std::size_t N>
  180. vector<T, N> abs(vector<T, N> const & self) {
  181. vector<T, N> tmp(self);
  182. using std::abs;
  183. VECTOR_FOR_EACH(i) { tmp[i] = abs(tmp[i]); }
  184. return tmp;
  185. }
  186. template <typename T, std::size_t N>
  187. int compare(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  188. VECTOR_FOR_EACH(i) {
  189. if (lhs[i] < rhs[i])
  190. return -1;
  191. else if (lhs[i] > rhs[i])
  192. return 1;
  193. }
  194. return 0;
  195. }
  196. template <typename T, std::size_t N>
  197. bool operator==(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  198. return compare(lhs, rhs) == 0;
  199. }
  200. template <typename T, std::size_t N>
  201. bool operator!=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  202. return compare(lhs, rhs) != 0;
  203. }
  204. template <typename T, std::size_t N>
  205. bool operator<(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  206. return compare(lhs, rhs) < 0;
  207. }
  208. template <typename T, std::size_t N>
  209. bool operator<=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  210. return compare(lhs, rhs) <= 0;
  211. }
  212. template <typename T, std::size_t N>
  213. bool operator>(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  214. return compare(lhs, rhs) > 0;
  215. }
  216. template <typename T, std::size_t N>
  217. bool operator>=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  218. return compare(lhs, rhs) >= 0;
  219. }
  220. }
  221. using math::vector::abs;
  222. #include "math/vector/undef.h"