vector.hpp 9.2 KB

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