vector.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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/traits.hpp"
  18. #define VECTOR_ENABLE_IF_LT_N(index, expr) \
  19. template <bool _ = true> \
  20. typename std::enable_if<std::size_t(index) < N && _, expr>::type
  21. #define VECTOR_ENABLE_IF_EQ_N(index, t, n) \
  22. template <bool _ = true> \
  23. typename std::enable_if<std::size_t(index) == N && _, vector<t, n>>::type
  24. #define VECTOR_ENABLE_IF_EQ_T(_type, t, n) \
  25. typename std::enable_if<std::is_same<_type, t>::value, vector<t, n>>::type
  26. #define VECTOR_DISABLE_IF_VECTOR(_type, t, n) \
  27. typename std::enable_if<!is_vector<_type>::value, vector<t, n>>::type
  28. #define VECTOR_ACCESS_FN(name, i) \
  29. VECTOR_ENABLE_IF_LT_N(i, value_type const &) name() const { \
  30. return _data[i]; \
  31. } \
  32. VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
  33. #define VECTOR_FOR_EACH_RANGE(var, end) \
  34. for (std::size_t var = 0; var < end; ++var)
  35. #define VECTOR_FOR_EACH(var) VECTOR_FOR_EACH_RANGE(var, N)
  36. namespace math::vector {
  37. template <typename T, std::size_t N> class vector {
  38. public:
  39. using value_type = T;
  40. private:
  41. using mag_t = decltype(std::sqrt(std::declval<T>()));
  42. template <typename M>
  43. using mul_t = decltype(std::declval<T>() * std::declval<M>());
  44. template <typename M>
  45. using div_t = decltype(std::declval<T>() / std::declval<M>());
  46. public:
  47. // Constructors
  48. vector() = default;
  49. template <typename... Us> vector(T arg0, Us... args) {
  50. static_assert(std::is_same_v<std::common_type_t<T, Us...>, T>,
  51. "must be type compatible");
  52. static_assert(sizeof...(Us) + 1 == N, "size mismatch");
  53. *this = vector(std::array<T, N>{arg0, static_cast<T>(args)...});
  54. }
  55. vector(std::array<T, N> const & init) {
  56. VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
  57. }
  58. // Conversion
  59. template <typename T2, std::size_t N2>
  60. explicit vector(vector<T2, N2> const & other) {
  61. VECTOR_FOR_EACH_RANGE(i, std::min(N, N2)) {
  62. _data[i] = static_cast<T>(other[i]);
  63. }
  64. }
  65. vector(T const & v, fill_t) {
  66. VECTOR_FOR_EACH(i) { _data[i] = v; }
  67. }
  68. // Named Accessors
  69. // - Numeric Vector Accessors
  70. VECTOR_ACCESS_FN(x, 0)
  71. VECTOR_ACCESS_FN(y, 1)
  72. VECTOR_ACCESS_FN(z, 2)
  73. VECTOR_ACCESS_FN(w, 3)
  74. // - Color Vector Accessors
  75. VECTOR_ACCESS_FN(r, 0)
  76. VECTOR_ACCESS_FN(g, 1)
  77. VECTOR_ACCESS_FN(b, 2)
  78. VECTOR_ACCESS_FN(a, 3)
  79. // Unnamed Accessors
  80. constexpr value_type const & operator[](std::size_t idx) const {
  81. return _data[idx];
  82. }
  83. constexpr value_type & operator[](std::size_t idx) { return _data[idx]; }
  84. value_type const & at(std::size_t idx) const {
  85. expects(idx < N, std::out_of_range, "index out of range");
  86. return _data[idx];
  87. }
  88. value_type & at(std::size_t idx) {
  89. expects(idx < N, std::out_of_range, "index out of range");
  90. return _data[idx];
  91. }
  92. // Mathematical Operations
  93. vector & operator+=(vector const & other) {
  94. VECTOR_FOR_EACH(i) { _data[i] += other[i]; }
  95. return *this;
  96. }
  97. vector & operator+=(T const & other) {
  98. return operator+=(vector(other, fill));
  99. }
  100. vector operator+(vector const & other) const {
  101. return vector{*this} += other;
  102. }
  103. vector operator+(T const & other) const {
  104. return operator+(vector(other, fill));
  105. }
  106. friend vector operator+(T const & lhs, vector const & rhs) {
  107. return rhs + lhs;
  108. }
  109. vector & operator-=(vector const & other) {
  110. VECTOR_FOR_EACH(i) { _data[i] -= other[i]; }
  111. return *this;
  112. }
  113. vector & operator-=(T const & other) {
  114. return operator-=(vector(other, fill));
  115. }
  116. vector operator-(vector const & other) const {
  117. return vector{*this} -= other;
  118. }
  119. vector operator-(T const & other) const {
  120. return operator-(vector(other, fill));
  121. }
  122. friend vector operator-(T const & lhs, vector const & rhs) {
  123. return vector(lhs, fill) - rhs;
  124. }
  125. vector operator-() const { return vector{} -= *this; }
  126. template <typename M>
  127. VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(M c) {
  128. VECTOR_FOR_EACH(i) { _data[i] *= c; }
  129. return *this;
  130. }
  131. template <typename M>
  132. VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
  133. operator*(M c) const {
  134. return vector<mul_t<M>, N>{*this} *= c;
  135. }
  136. template <typename M>
  137. friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
  138. operator*(M c, vector<T, N> const & v) {
  139. return v * c;
  140. }
  141. template <typename M>
  142. VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(vector<M, N> c) {
  143. VECTOR_FOR_EACH(i) { _data[i] *= c[i]; }
  144. return *this;
  145. }
  146. template <typename M>
  147. vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
  148. return vector<mul_t<M>, N>{*this} *= other;
  149. }
  150. template <typename M>
  151. VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(M c) {
  152. expects(c != 0, std::domain_error, "divide by zero");
  153. VECTOR_FOR_EACH(i) { _data[i] /= c; }
  154. return *this;
  155. }
  156. template <typename M>
  157. VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N)
  158. operator/(M c) const {
  159. return vector<div_t<M>, N>{*this} /= c;
  160. }
  161. template <typename M>
  162. VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(vector<M, N> c) {
  163. VECTOR_FOR_EACH(i) {
  164. expects(c[i] != 0, std::domain_error, "divide by zero");
  165. }
  166. VECTOR_FOR_EACH(i) { _data[i] /= c[i]; }
  167. return *this;
  168. }
  169. template <typename M>
  170. vector<div_t<M>, N> operator/(vector<M, N> const & other) const {
  171. return vector<div_t<M>, N>{*this} /= other;
  172. }
  173. // Vector Operations
  174. value_type dot(vector const & other) const {
  175. value_type accum{};
  176. VECTOR_FOR_EACH(i) { accum += at(i) * other.at(i); }
  177. return accum;
  178. }
  179. mag_t magnitude() const { return std::sqrt(dot(*this)); }
  180. vector<mag_t, N> unit() const { return *this / magnitude(); }
  181. VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
  182. return {{y() * other.z() - z() * other.y(),
  183. z() * other.x() - x() * other.z(),
  184. x() * other.y() - y() * other.x()}};
  185. }
  186. VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
  187. return {{0, 0, x() * other.y() - y() * other.x()}};
  188. }
  189. vector<mag_t, N> projection(vector const & other) const {
  190. vector<mag_t, N> b_p = other.unit();
  191. return b_p * vector<mag_t, N>{*this}.dot(b_p);
  192. }
  193. private:
  194. value_type _data[N] = {value_type()};
  195. };
  196. template <typename T, typename... Us>
  197. vector(T, Us...) -> vector<T, sizeof...(Us) + 1>;
  198. template <typename T, std::size_t N>
  199. vector<T, N> abs(vector<T, N> const & self) {
  200. vector<T, N> tmp(self);
  201. using std::abs;
  202. VECTOR_FOR_EACH(i) { tmp[i] = abs(tmp[i]); }
  203. return tmp;
  204. }
  205. template <typename T, std::size_t N>
  206. int compare(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  207. VECTOR_FOR_EACH(i) {
  208. if (lhs[i] < rhs[i])
  209. return -1;
  210. else if (lhs[i] > rhs[i])
  211. return 1;
  212. }
  213. return 0;
  214. }
  215. template <typename T, std::size_t N>
  216. bool operator==(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  217. return compare(lhs, rhs) == 0;
  218. }
  219. template <typename T, std::size_t N>
  220. bool operator!=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  221. return compare(lhs, rhs) != 0;
  222. }
  223. template <typename T, std::size_t N>
  224. bool operator<(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  225. return compare(lhs, rhs) < 0;
  226. }
  227. template <typename T, std::size_t N>
  228. bool operator<=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  229. return compare(lhs, rhs) <= 0;
  230. }
  231. template <typename T, std::size_t N>
  232. bool operator>(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  233. return compare(lhs, rhs) > 0;
  234. }
  235. template <typename T, std::size_t N>
  236. bool operator>=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
  237. return compare(lhs, rhs) >= 0;
  238. }
  239. }
  240. using math::vector::abs;