| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- //
- // vector.hpp
- // vector
- //
- // Created by Sam Jaffe on 8/15/16.
- //
- #pragma once
- #include <cassert>
- #include <cmath>
- #include <cstddef>
- #include <array>
- #include <initializer_list>
- #include <stdexcept>
- #include <type_traits>
- namespace math { namespace vector {
- #define VECTOR_ENABLE_IF_LT_N(index, expr) \
- template <bool _ = true> \
- typename std::enable_if<std::size_t(index) < N && _, expr>::type
-
- #define VECTOR_ENABLE_IF_EQ_N(index, t, n) \
- template <bool _ = true> \
- typename std::enable_if<std::size_t(index) == N && _, vector<t, n> >::type
- #define VECTOR_ENABLE_IF_EQ_T(_type, t, n) \
- vector<typename std::enable_if<std::is_same<_type, T>::value,T>::type, N>
-
- #define VECTOR_ACCESS_FN(name, i) \
- VECTOR_ENABLE_IF_LT_N(i, value_type const &) name() const { return _data[i]; } \
- VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
-
- #define VECTOR_FOR_EACH(var) for (std::size_t var = 0; var < N; ++var)
-
- struct {} fill;
- using fill_t = decltype(fill);
-
- template <typename T, std::size_t N>
- struct vector {
- public:
- using value_type = T;
- private:
- using mag_t = decltype(std::sqrt(std::declval<T>()));
- template <typename M>
- using mul_t = decltype(std::declval<T>()*std::declval<M>());
- template <typename M>
- using div_t = decltype(std::declval<T>()/std::declval<M>());
- public:
-
- // Constructors
- vector() = default;
- vector(std::initializer_list<T> && init) {
- std::size_t idx = 0;
- for ( auto it = init.begin(), end = init.end(); it != end && idx < N; ++it, ++idx ) {
- _data[idx] = *it;
- }
- }
- vector(std::array<T, N> const & init) {
- for (std::size_t i = 0; i < N && i < init.size(); ++i) {
- _data[i] = init[i];
- }
- }
- vector(vector const & other) {
- *this = other;
- }
- vector(vector && other) {
- *this = std::move(other);
- }
-
- // Conversion
- template <typename T2, std::size_t N2>
- explicit vector(vector<T2, N2> const & other) {
- for (std::size_t i = 0; i < N && i < N2; ++i) {
- _data[i] = static_cast<T>(other[i]);
- }
- }
- vector(T const & v, fill_t) {
- VECTOR_FOR_EACH(i) { _data[i] = v; }
- }
-
- // Assignment
- vector& operator=(vector const & other) {
- VECTOR_FOR_EACH(i) { _data[i] = other[i]; }
- return *this;
- }
- vector& operator=(vector && other) {
- VECTOR_FOR_EACH(i) { _data[i] = std::move(other._data[i]); }
- return *this;
- }
-
- // Named Accessors
- // - Numeric Vector Accessors
- VECTOR_ACCESS_FN(x, 0)
- VECTOR_ACCESS_FN(y, 1)
- VECTOR_ACCESS_FN(z, 2)
- VECTOR_ACCESS_FN(w, 3)
-
- // - Color Vector Accessors
- VECTOR_ACCESS_FN(r, 0)
- VECTOR_ACCESS_FN(g, 1)
- VECTOR_ACCESS_FN(b, 2)
- VECTOR_ACCESS_FN(a, 3)
-
- // Unnamed Accessors
- value_type const & operator[](std::size_t idx) const { return _data[idx]; }
- value_type & operator[](std::size_t idx) { return _data[idx]; }
-
- value_type const & at(std::size_t idx) const {
- if (idx >= N) throw std::out_of_range{"index out of range"};
- assert(idx < N);
- return operator[](idx);
- }
- value_type & at(std::size_t idx) {
- if (idx >= N) throw std::out_of_range{"index out of range"};
- assert(idx < N);
- return operator[](idx);
- }
-
- // Mathematical Operations
- vector& operator+=(vector const & other) {
- VECTOR_FOR_EACH(i) {
- _data[i] += other[i];
- }
- return *this;
- }
-
- vector& operator-=(vector const & other) {
- VECTOR_FOR_EACH(i) {
- _data[i] -= other[i];
- }
- return *this;
- }
-
- template <typename M>
- VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(M c) {
- VECTOR_FOR_EACH(i) {
- _data[i] *= c;
- }
- return *this;
- }
-
- template <typename M>
- VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(M c) {
- VECTOR_FOR_EACH(i) {
- _data[i] /= c;
- }
- return *this;
- }
-
- template <typename M>
- VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(vector<M, N> c) {
- VECTOR_FOR_EACH(i) {
- _data[i] *= c[i];
- }
- return *this;
- }
-
- template <typename M>
- VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(vector<M, N> c) {
- VECTOR_FOR_EACH(i) {
- _data[i] /= c[i];
- }
- return *this;
- }
-
- vector operator+(vector const & other) const {
- return vector{*this} += other;
- }
-
- vector operator-(vector const & other) const {
- return vector{*this} -= other;
- }
-
- template <typename M>
- vector<mul_t<M>, N> scaled(vector<M, N> const & other) const {
- return vector<mul_t<M>, N>{*this} *= other;
- }
-
- template <typename M>
- vector<mul_t<M>, N> operator*(M c) const {
- return vector<mul_t<M>, N>{*this} *= c;
- }
-
- template <typename M>
- friend vector<mul_t<M>, N> operator*(M c, vector<T, N> const & v) {
- return v * c;
- }
-
- template <typename M>
- vector<div_t<M>, N> invscaled(vector<M, N> const & other) const {
- return vector<div_t<M>, N>{*this} /= other;
- }
-
- template <typename M>
- vector<div_t<M>, N> operator/(M c) const {
- return vector<div_t<M>, N>{*this} /= c;
- }
-
- vector operator-() const {
- return vector{} -= *this;
- }
-
- // Vector Operations
- value_type dot(vector const & other) const {
- value_type accum{};
- VECTOR_FOR_EACH(i) {
- accum += at(i) * other.at(i);
- }
- return accum;
- }
-
- mag_t magnitude() const {
- return std::sqrt(dot(*this));
- }
-
- vector<mag_t, N> unit() const {
- return *this / magnitude();
- }
-
- friend vector abs(vector const & self) {
- vector tmp(self);
- using std::abs;
- for (std::size_t i = 0; i < N; ++i) {
- tmp._data[i] = abs(tmp._data[i]);
- }
- return tmp;
- }
-
- friend void swap(vector & lhs, vector & rhs) {
- vector tmp(lhs);
- lhs = rhs;
- rhs = tmp;
- }
-
- VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
- return {
- y()*other.z() - z()*other.y(),
- z()*other.x() - x()*other.z(),
- x()*other.y() - y()*other.x()
- };
- }
- VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
- return { 0, 0, x()*other.y() - y()*other.x() };
- }
-
- vector<mag_t, N> projection(vector const & other) const {
- vector<mag_t, N> b_p = other.unit();
- return b_p * vector<mag_t, N>{*this}.dot(b_p);
- }
-
- friend bool operator==(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) == 0; }
- friend bool operator!=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) != 0; }
- friend bool operator< (vector const & lhs, vector const & rhs) { return lhs.compare(rhs) < 0; }
- friend bool operator<=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) <= 0; }
- friend bool operator> (vector const & lhs, vector const & rhs) { return lhs.compare(rhs) > 0; }
- friend bool operator>=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) >= 0; }
-
- private:
- int compare(vector const & other) const {
- int rv = 0;
- for (std::size_t i = 0; i < N && rv == 0; ++i) {
- if (_data[i] < other[i]) rv = -1;
- else if (_data[i] > other[i]) rv = 1;
- }
- return rv;
- }
-
- value_type _data[N] = {value_type()};
- };
- } }
|