Переглянути джерело

Reducing amount of indirection/cleverness involved in the vector type.
Renaming test file, and removing cxxtestgen product from the tracked files.

Samuel Jaffe 9 роки тому
батько
коміт
ffcd2c1b32

+ 2 - 2
Makefile

@@ -30,8 +30,8 @@ HDRFILES := vector.hpp
 SRCFILES := 
 DEPFILES := $(patsubst %.cpp,.%.d,$(SRCFILES))
 OBJFILES := $(patsubst %.cpp,%.o,$(SRCFILES))
-TSTSUITE := vector_tc.h
-TSTFILES := $(patsubst %.h,%.cpp,$(TSTSUITE))
+TSTSUITE := vector.t.h
+TSTFILES := $(patsubst %.t.h,%.cpp,$(TSTSUITE))
 TSTDRIVR := $(patsubst %.cpp,%,$(TSTFILES))
 BINARY   :=
 

+ 196 - 214
vector.hpp

@@ -1,290 +1,272 @@
 //
-//  vector.h
-//  
-//
-//  Created by Sam Jaffe on 8/21/15.
+//  vector.hpp
+//  vector
 //
+//  Created by Sam Jaffe on 8/15/16.
 //
 
 #pragma once
 
-namespace math { namespace vector {
-  template <size_t, typename> class raw_vector;
-} }
+#include <cassert>
+#include <cmath>
+#include <cstddef>
 
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator +(T const&, math::vector::raw_vector<D, T> const&);
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator -(T const&, math::vector::raw_vector<D, T> const&);
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator *(T const&, math::vector::raw_vector<D, T> const&);
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator /(T const&, math::vector::raw_vector<D, T> const&);
+#include <array>
+#include <initializer_list>
+#include <stdexcept>
+#include <type_traits>
 
 namespace math { namespace vector {
-  struct fill_t {} fill;
+#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
 
-  template <size_t D, typename T>
-  class raw_vector {
+#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:
-    typedef T value_type;
-    typedef T& reference;
-    typedef const T& const_reference;
-    typedef raw_vector<D, T> this_type;
-    
-    typedef decltype(std::sqrt(std::declval<T>())) sqrt_type; // double or float
-    
-    T& operator [](size_t index) { return data[index]; }
-    
-    inline const T& operator [](size_t index) const { return data[index]; }
     
-    T& at(size_t index) {
-      if (index >= D) throw std::out_of_range(std::to_string(index) + " is out of range [0, " + std::to_string(D) + ")");
-      return operator [](index);
+    // 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;
+      }
     }
-    
-    const T& at(size_t index) const {
-      if (index >= D) throw std::out_of_range(std::to_string(index) + " is out of range [0, " + std::to_string(D) + ")");
-      return operator [](index);
+    vector(std::array<T, N> const & init) {
+      for (std::size_t i = 0; i < N && i < init.size(); ++i) {
+        _data[i] = init[i];
+      }
     }
-    
-    template <std::size_t Idx, typename = typename std::enable_if<Idx < D>::type>
-    inline const_reference get() const { return data[Idx]; }
-    
-    template <std::size_t Idx, typename = typename std::enable_if<Idx < D>::type>
-    inline reference get() { return data[Idx]; }
-    
-    reference x() { return get<0>(); }
-    const_reference x() const { return get<0>(); }
-    reference y() { return get<1>(); }
-    const_reference y() const { return get<1>(); }
-    reference z() { return get<2>(); }
-    const_reference z() const { return get<2>(); }
-    reference w() { return get<3>(); }
-    const_reference w() const { return get<3>(); }
-    reference r() { return get<0>(); }
-    const_reference r() const { return get<0>(); }
-    reference g() { return get<1>(); }
-    const_reference g() const { return get<1>(); }
-    reference b() { return get<2>(); }
-    const_reference b() const { return get<2>(); }
-    reference a() { return get<3>(); }
-    const_reference a() const { return get<3>(); }
-    
-    this_type& operator+=(const this_type& other) {
-      for (size_t i = 0; i < D; ++i) at(i) += other.at(i);
-      return *this;
+    vector(vector const & other) {
+      *this = other;
     }
-    
-    this_type& operator-=(const this_type& other) {
-      for (size_t i = 0; i < D; ++i) at(i) -= other.at(i);
-      return *this;
+    vector(vector && other) {
+      *this = std::move(other);
     }
     
-    this_type& operator*=(const this_type& other) {
-      for (size_t i = 0; i < D; ++i) at(i) *= other.at(i);
-      return *this;
+    // 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]);
+      }
     }
-    
-    this_type& operator/=(const this_type& other) {
-      for (size_t i = 0; i < D; ++i) at(i) /= other.at(i);
-      return *this;
+    vector(T const & v, fill_t) {
+      VECTOR_FOR_EACH(i) { _data[i] = v; }
     }
     
-    this_type& operator+=(const T& c) {
-      return operator +=(this_type{c, fill});
+    // Assignment
+    vector& operator=(vector const & other) {
+      VECTOR_FOR_EACH(i) { _data[i] = other[i]; }
+      return *this;
     }
-    
-    this_type& operator -=(const T& c) {
-      return operator -=(this_type{c, fill});
+    vector& operator=(vector && other) {
+      VECTOR_FOR_EACH(i) { _data[i] = std::move(other._data[i]); }
+      return *this;
     }
     
-    this_type& operator *=(const T& c)  {
-      return operator *=(this_type{c, fill});
-    }
+    // 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)
     
-    this_type& operator /=(const T& c) {
-      return operator /=(this_type{c, fill});
-    }
+    // - Color Vector Accessors
+    VECTOR_ACCESS_FN(r, 0)
+    VECTOR_ACCESS_FN(g, 1)
+    VECTOR_ACCESS_FN(b, 2)
+    VECTOR_ACCESS_FN(a, 3)
     
-    this_type operator +(const this_type& other) const {
-      return this_type(*this) += other;
-    }
+    // Unnamed Accessors
+    value_type const & operator[](std::size_t idx) const { return _data[idx]; }
+    value_type & operator[](std::size_t idx) { return _data[idx]; }
     
-    this_type operator -(const this_type& other) const {
-      return this_type(*this) -= other;
+    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);
     }
-    
-    this_type operator *(const this_type& other) const {
-      return this_type(*this) *= other;
+    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);
     }
     
-    this_type operator /(const this_type& other) const {
-      return this_type(*this) /= other;
+    // Mathematical Operations
+    vector& operator+=(vector const & other) {
+      VECTOR_FOR_EACH(i) {
+        _data[i] += other[i];
+      }
+      return *this;
     }
     
-    this_type operator +(const T& c) const {
-      return operator +(this_type{c, fill});
+    vector& operator-=(vector const & other) {
+      VECTOR_FOR_EACH(i) {
+        _data[i] -= other[i];
+      }
+      return *this;
     }
     
-    this_type operator -(const T& c) const {
-      return operator -(this_type{c, fill});
+    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;
     }
     
-    this_type operator *(const T& c) const {
-      return operator *(this_type{c, fill});
+    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;
     }
     
-    this_type operator /(const T& c) const {
-      return operator /(this_type{c, fill});
+    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;
     }
     
-    this_type operator -() const { return -1 * (*this); }
-    
-    bool operator ==(const this_type& other) const {
-      return !memcmp(data, other.data, D * sizeof(T));
-    } // technically wrong on float/double
-    
-    bool operator !=(const this_type& other) const {
-      return !operator==(other);
+    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;
     }
-    
-    bool operator <=(const this_type& other) const {
-      for (size_t i = 0; i < D; ++i) { if (at(i) > other.at(i)) return false; }
-      return true;
+      
+    vector operator+(vector const & other) const {
+      return vector{*this} += other;
     }
     
-    bool operator <(const this_type& other) const {
-      for (size_t i = 0; i < D; ++i) { if (at(i) >= other.at(i)) return false; }
-      return true;
+    vector operator-(vector const & other) const {
+      return vector{*this} -= other;
     }
     
-    bool operator >=(const this_type& other) const {
-      for (size_t i = 0; i < D; ++i) { if (at(i) < other.at(i)) return false; }
-      return true;
+    template <typename M>
+    vector<mul_t<M>, N> scaled(vector<M, N> const & other) const {
+      return vector<mul_t<M>, N>{*this} *= other;
     }
     
-    bool operator >(const this_type& other) const {
-      for (size_t i = 0; i < D; ++i) { if (at(i) <= other.at(i)) return false; }
-      return true;
+    template <typename M>
+    vector<mul_t<M>, N> operator*(M c) const {
+      return vector<mul_t<M>, N>{*this} *= c;
     }
     
-    template <size_t D2>
-    typename std::enable_if<(D == 2 || D == 3) && D == D2, raw_vector<3, T> >::type cross(const raw_vector<D2, T>& v) const {
-      return D == 2
-      ? raw_vector<3, T>{0, 0, at(0)*v.at(1) - at(1)*v.at(0)}
-      : raw_vector<3, T>{
-        at(1)*v.at(2) - at(2)*v.at(1),
-        at(2)*v.at(0) - at(0)*v.at(2),
-        at(0)*v.at(1) - at(1)*v.at(0)
-      };
+    template <typename M>
+    friend vector<mul_t<M>, N> operator*(M c, vector<T, N> const & v) {
+      return v * c;
     }
     
-    T dot(const this_type& v) const {
-      T accum{};
-      for (size_t i = 0; i < D; ++i) accum += data[i] * v[i];
-      return accum;
+    template <typename M>
+    vector<div_t<M>, N> invscaled(vector<M, N> const & other) const {
+      return vector<div_t<M>, N>{*this} /= other;
     }
     
-    T lengthSquared() const {
-      return dot(*this);
+    template <typename M>
+    vector<div_t<M>, N> operator/(M c) const {
+      return vector<div_t<M>, N>{*this} /= c;
     }
     
-    sqrt_type length() const {
-      return std::sqrt(lengthSquared());
+    vector operator-() const {
+      return vector{} -= *this;
     }
     
-    T distanceSquared(const this_type& other) const {
-      return operator -(other).lengthSquared();
+    // Vector Operations
+    value_type dot(vector const & other) const {
+      value_type accum{};
+      VECTOR_FOR_EACH(i) {
+        accum += at(i) * other.at(i);
+      }
+      return accum;
     }
     
-    sqrt_type distance(const this_type& other) const {
-      return std::sqrt(distanceSquared(other));
+    mag_t magnitude() const {
+      return std::sqrt(dot(*this));
     }
     
-    raw_vector<D, sqrt_type> unit() const { return raw_vector<D, sqrt_type>(*this)/length(); }
-    
-    void swap(raw_vector& that) {
-      using std::swap;
-      for (size_t i = 0; i < D; ++i) swap(data[i], that.data[i]);
+    vector<mag_t, N> unit() const {
+      return *this / magnitude();
     }
     
-    constexpr raw_vector() = default;
-    
-    raw_vector(const this_type& that) {
-      for (size_t i = 0; i < D; ++i) data[i] = that.data[i];
+    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;
     }
     
-    raw_vector(this_type&& that) {
-      for (size_t i = 0; i < D; ++i) data[i] = that.data[i];
+    friend void swap(vector & lhs, vector & rhs) {
+      vector tmp(lhs);
+      lhs = rhs;
+      rhs = tmp;
     }
     
-    raw_vector& operator=(const this_type& other) {
-      for (size_t i = 0; i < D; ++i) data[i] = other.data[i];
-      return *this;
+    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()
+      };
     }
-    
-    raw_vector& operator=(this_type&& other) {
-      for (size_t i = 0; i < D; ++i) data[i] = other.data[i];
-      return *this;
+    VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
+      return { 0, 0, x()*other.y() - y()*other.x() };
     }
     
-    raw_vector(std::initializer_list<T> vals) {
-      const size_t D2 = vals.size();
-      const T* ptr = vals.begin();
-      for (size_t i = 0; i < std::min(D, D2); ++i) data[i] = *ptr++;
-      for (size_t j = std::min(D, D2); j < std::max(D, D2); ++j) data[j] = T();
+    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);
     }
     
-    template <std::size_t D2, typename T2,
-    typename = typename std::enable_if<D2 != D || !std::is_same<T, T2>::value>::type>
-    explicit raw_vector(const raw_vector<D2, T2>& that) {
-      for (size_t i = 0; i < std::min(D, D2); ++i) data[i] = static_cast<T>(that[i]);
-      for (size_t j = std::min(D, D2); j < std::max(D, D2); ++j) data[j] = T();
-    }
+    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; }
     
-    raw_vector(T const& t, fill_t) {
-      for (size_t i = 0; i < D; ++i) data[i] = t;
+  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;
     }
     
-  private:
-    value_type data[D] = {0};
+    value_type _data[N] = {value_type()};
   };
 } }
-
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator +(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
-  return rhs + lhs;
-}
-
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator -(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
-  return math::vector::raw_vector<D, T>(lhs, math::vector::fill) - rhs;
-}
-
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator *(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
-  return rhs * lhs;
-}
-
-template <size_t D, typename T>
-math::vector::raw_vector<D, T> operator /(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
-  return math::vector::raw_vector<D, T>(lhs, math::vector::fill) / rhs;
-}
-
-template <typename CharT, typename Traits, size_t N, typename T>
-std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, const math::vector::raw_vector<N, T>& v) {
-  out << '(' << v[0];
-  for (size_t i = 1; i < N; ++i) { out << ',' << v[i]; }
-  out << ')';
-  return out;
-}
-
-namespace std {
-  template <size_t D, typename T>
-  math::vector::raw_vector<D, T> abs(math::vector::raw_vector<D, T> const& data) {
-    math::vector::raw_vector<D, T> rval;
-    for (size_t i = 0; i < D; ++i) rval[i] = std::abs(data[i]);
-    return rval;
-  }
-}

+ 39 - 35
vector_tc.h

@@ -4,10 +4,10 @@
 
 class vector_TestSuite : public CxxTest::TestSuite {
 public:
-  using vec2i = math::vector::raw_vector<2, int>;
-  using vec3  = math::vector::raw_vector<3, double>;
-  using vec3i = math::vector::raw_vector<3, int>;
-  using vec4i = math::vector::raw_vector<4, int>;
+  using vec2i = math::vector::vector<int, 2>;
+  using vec3  = math::vector::vector<double, 3>;
+  using vec3i = math::vector::vector<int, 3>;
+  using vec4i = math::vector::vector<int, 4>;
 
   void test_vector_equals() const {
     TS_ASSERT_EQUALS(iota3i(), (vec3i{1, 2, 3}));
@@ -18,14 +18,14 @@ public:
   }
   
   void test_vector_elems() const {
-    math::vector::raw_vector<3, int> viota = iota3i();
+    math::vector::vector<int, 3> viota = iota3i();
     TS_ASSERT_EQUALS(viota[0], 1);
     TS_ASSERT_EQUALS(viota[1], 2);
     TS_ASSERT_EQUALS(viota[2], 3);
   }
   
   void test_vector_oob() const {
-    TS_ASSERT_THROWS((iota<3, int>()).at(3), std::out_of_range);
+    TS_ASSERT_THROWS((iota<int, 3>()).at(3), std::out_of_range);
   }
   
   void test_default_zero() const {
@@ -53,20 +53,20 @@ public:
   }
   
   void test_vector_multiplication_vector() const {
-    TS_ASSERT_EQUALS((vec2i{1,0} * vec2i{2,1}), (vec2i{2,0}))
+    TS_ASSERT_EQUALS((vec2i{1,0}.scaled(vec2i{2,1})), (vec2i{2,0}))
   }
   
   void test_vector_divides_vector() const {
-    TS_ASSERT_EQUALS((vec2i{6,4} / vec2i{2,1}), (vec2i{3,4}))
+    TS_ASSERT_EQUALS((vec2i{6,4}.invscaled(vec2i{2,1})), (vec2i{3,4}))
   }
   
-  void test_vector_addition_value() const {
-    TS_ASSERT_EQUALS((vec2i{1,0} + 1), (vec2i{2,1}))
-  }
-  
-  void test_vector_subtraction_value() const {
-    TS_ASSERT_EQUALS((vec2i{1,0} - 1), (vec2i{0,-1}))
-  }
+//  void test_vector_addition_value() const {
+//    TS_ASSERT_EQUALS((vec2i{1,0} + 1), (vec2i{2,1}))
+//  }
+//  
+//  void test_vector_subtraction_value() const {
+//    TS_ASSERT_EQUALS((vec2i{1,0} - 1), (vec2i{0,-1}))
+//  }
   
   void test_vector_multiplication_value() const {
     TS_ASSERT_EQUALS((vec2i{1,0} * 3), (vec2i{3,0}))
@@ -76,30 +76,34 @@ public:
     TS_ASSERT_EQUALS((vec2i{6,4} / 2), (vec2i{3,2}))
   }
   
-  void test_value_addition_vector() const {
-    TS_ASSERT_EQUALS(1+iota2i(), (vec2i{2,3}));
-  }
-  
-  void test_value_subtraction_vector() const {
-    TS_ASSERT_EQUALS(4-iota2i(), (vec2i{3,2}));
-  }
+//  void test_value_addition_vector() const {
+//    TS_ASSERT_EQUALS(1+iota2i(), (vec2i{2,3}));
+//  }
+//  
+//  void test_value_subtraction_vector() const {
+//    TS_ASSERT_EQUALS(4-iota2i(), (vec2i{3,2}));
+//  }
   
   void test_value_multiplication_vector() const {
     TS_ASSERT_EQUALS(2*iota2i(), (vec2i{2,4}));
   }
   
-  void test_value_divides_vector() const {
-    TS_ASSERT_EQUALS(4/iota2i(), (vec2i{4,2}));
-  }
+//  void test_value_divides_vector() const {
+//    TS_ASSERT_EQUALS(4/iota2i(), (vec2i{4,2}));
+//  }
   
   void test_length_of_vector() const {
-    TS_ASSERT_EQUALS(iota3i().lengthSquared(), 14);
-    TS_ASSERT_DELTA(iota3i().length(), std::sqrt(14), 0.00001);
+//    TS_ASSERT_EQUALS(iota3i().lengthSquared(), 14);
+    TS_ASSERT_DELTA(iota3i().magnitude(), std::sqrt(14), 0.00001);
   }
   
   void test_distance_of_vector() const {
-    TS_ASSERT_EQUALS((iota3i().distanceSquared(vec3i{3, 1, -1})), 21);
-    TS_ASSERT_DELTA((iota3i().distance(vec3i{3, 1, -1})), std::sqrt(21), 0.00001);
+//    TS_ASSERT_EQUALS((iota3i().distanceSquared(vec3i{3, 1, -1})), 21);
+    TS_ASSERT_DELTA((iota3i() - vec3i{3, 1, -1}).magnitude(), std::sqrt(21), 0.00001);
+  }
+  
+  void test_projection_of_vector() const {
+    TS_ASSERT_DELTA((iota3i().projection(vec3i{3, 1, -1})).magnitude(), std::sqrt(4.0/11.0), 0.00001);
   }
   
   void test_dot_product() const {
@@ -119,7 +123,7 @@ public:
   void test_swap() const {
     vec2i a{1, 2}; const vec2i ac = a;
     vec2i b{5, 7}; const vec2i bc = b;
-    a.swap(b);
+    swap(a, b);
     TS_ASSERT_EQUALS(a, bc);
     TS_ASSERT_EQUALS(b, ac);
   }
@@ -129,17 +133,17 @@ public:
   }
   
   void test_absolute_value() const {
-    TS_ASSERT_EQUALS(iota3i(), std::abs(-iota3i()));
+    TS_ASSERT_EQUALS(iota3i(), abs(-iota3i()));
   }
   
 private:
   
-  template <size_t N, typename T> math::vector::raw_vector<N, T> iota() const {
-    math::vector::raw_vector<N, T> rval;
+  template <typename T, size_t N> math::vector::vector<T, N> iota() const {
+    math::vector::vector<T, N> rval;
     for (size_t i = 0; i < N; ++i) rval[i] = static_cast<T>(i+1);
     return rval;
   }
   
-  vec2i iota2i() const { return iota<2, int>(); }
-  vec3i iota3i() const { return iota<3, int>(); }
+  vec2i iota2i() const { return iota<int, 2>(); }
+  vec3i iota3i() const { return iota<int, 3>(); }
 };

+ 27 - 6
vector.xcodeproj/project.pbxproj

@@ -24,11 +24,12 @@
 
 /* Begin PBXFileReference section */
 		0E5DFDD71BB4D3360063976E /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
-		0E5DFDD81BB4D3360063976E /* vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector.hpp; sourceTree = "<group>"; };
+		0E5DFDD81BB4D3360063976E /* vector_old.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_old.hpp; sourceTree = "<group>"; };
 		0E5DFDDA1BB4D3360063976E /* vector_tc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vector_tc.cpp; sourceTree = "<group>"; };
-		0E5DFDDB1BB4D3360063976E /* vector_tc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vector_tc.h; sourceTree = "<group>"; };
+		0E5DFDDB1BB4D3360063976E /* vector.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vector.t.h; sourceTree = "<group>"; };
 		0E5DFDF31BB4D5040063976E /* vector_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vector_tc; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD97B6211CA576B7007756C8 /* vector_type_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = vector_type_generator.hpp; sourceTree = "<group>"; };
+		CDFFC7A81D62296200E9528B /* vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector.hpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -46,10 +47,11 @@
 			isa = PBXGroup;
 			children = (
 				0E5DFDD71BB4D3360063976E /* Makefile */,
-				0E5DFDD81BB4D3360063976E /* vector.hpp */,
+				0E5DFDD81BB4D3360063976E /* vector_old.hpp */,
+				CDFFC7A81D62296200E9528B /* vector.hpp */,
 				CD97B6211CA576B7007756C8 /* vector_type_generator.hpp */,
 				0E5DFDDA1BB4D3360063976E /* vector_tc.cpp */,
-				0E5DFDDB1BB4D3360063976E /* vector_tc.h */,
+				0E5DFDDB1BB4D3360063976E /* vector.t.h */,
 				0E5DFDF41BB4D5040063976E /* Products */,
 			);
 			sourceTree = "<group>";
@@ -86,6 +88,7 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 0E5DFDF81BB4D5040063976E /* Build configuration list for PBXNativeTarget "vector_tc" */;
 			buildPhases = (
+				CD35DCF11D6130E700BE3686 /* ShellScript */,
 				0E5DFDEF1BB4D5040063976E /* Sources */,
 				0E5DFDF01BB4D5040063976E /* Frameworks */,
 				0E5DFDF11BB4D5040063976E /* CopyFiles */,
@@ -130,6 +133,24 @@
 		};
 /* End PBXProject section */
 
+/* Begin PBXShellScriptBuildPhase section */
+		CD35DCF11D6130E700BE3686 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"$(SRCROOT)/vector.t.h",
+			);
+			outputPaths = (
+				"$(SRCROOT)/vector_tc.cpp",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cxxtestgen --error-printer -o vector_tc.cpp vector.t.h";
+		};
+/* End PBXShellScriptBuildPhase section */
+
 /* Begin PBXSourcesBuildPhase section */
 		0E5DFDEF1BB4D5040063976E /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
@@ -222,7 +243,7 @@
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
-				HEADER_SEARCH_PATHS = "${HOME}/Documents/Programming/cxxtest-4.4/";
+				HEADER_SEARCH_PATHS = "${HOME}/Documents/Programming/Resources/cxxtest-4.4/";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -258,7 +279,7 @@
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
-				HEADER_SEARCH_PATHS = "${HOME}/Documents/Programming/cxxtest-4.4/";
+				HEADER_SEARCH_PATHS = "${HOME}/Documents/Programming/Resources/cxxtest-4.4/";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 2 - 2
vector.xcodeproj/xcuserdata/samjaffe.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -7,12 +7,12 @@
 		<key>vector.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>2</integer>
+			<integer>1</integer>
 		</dict>
 		<key>vector_tc.xcscheme</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>3</integer>
+			<integer>2</integer>
 		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>

+ 290 - 0
vector_old.hpp

@@ -0,0 +1,290 @@
+//
+//  vector.h
+//  
+//
+//  Created by Sam Jaffe on 8/21/15.
+//
+//
+
+#pragma once
+
+namespace math { namespace vector {
+  template <size_t, typename> class raw_vector;
+} }
+
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator +(T const&, math::vector::raw_vector<D, T> const&);
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator -(T const&, math::vector::raw_vector<D, T> const&);
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator *(T const&, math::vector::raw_vector<D, T> const&);
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator /(T const&, math::vector::raw_vector<D, T> const&);
+
+namespace math { namespace vector {
+  struct fill_t {} fill;
+
+  template <size_t D, typename T>
+  class raw_vector {
+  public:
+    typedef T value_type;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef raw_vector<D, T> this_type;
+    
+    typedef decltype(std::sqrt(std::declval<T>())) sqrt_type; // double or float
+    
+    T& operator [](size_t index) { return data[index]; }
+    
+    inline const T& operator [](size_t index) const { return data[index]; }
+    
+    T& at(size_t index) {
+      if (index >= D) throw std::out_of_range(std::to_string(index) + " is out of range [0, " + std::to_string(D) + ")");
+      return operator [](index);
+    }
+    
+    const T& at(size_t index) const {
+      if (index >= D) throw std::out_of_range(std::to_string(index) + " is out of range [0, " + std::to_string(D) + ")");
+      return operator [](index);
+    }
+    
+    template <std::size_t Idx, typename = typename std::enable_if<Idx < D>::type>
+    inline const_reference get() const { return data[Idx]; }
+    
+    template <std::size_t Idx, typename = typename std::enable_if<Idx < D>::type>
+    inline reference get() { return data[Idx]; }
+    
+    reference x() { return get<0>(); }
+    const_reference x() const { return get<0>(); }
+    reference y() { return get<1>(); }
+    const_reference y() const { return get<1>(); }
+    reference z() { return get<2>(); }
+    const_reference z() const { return get<2>(); }
+    reference w() { return get<3>(); }
+    const_reference w() const { return get<3>(); }
+    reference r() { return get<0>(); }
+    const_reference r() const { return get<0>(); }
+    reference g() { return get<1>(); }
+    const_reference g() const { return get<1>(); }
+    reference b() { return get<2>(); }
+    const_reference b() const { return get<2>(); }
+    reference a() { return get<3>(); }
+    const_reference a() const { return get<3>(); }
+    
+    this_type& operator+=(const this_type& other) {
+      for (size_t i = 0; i < D; ++i) at(i) += other.at(i);
+      return *this;
+    }
+    
+    this_type& operator-=(const this_type& other) {
+      for (size_t i = 0; i < D; ++i) at(i) -= other.at(i);
+      return *this;
+    }
+    
+    this_type& operator*=(const this_type& other) {
+      for (size_t i = 0; i < D; ++i) at(i) *= other.at(i);
+      return *this;
+    }
+    
+    this_type& operator/=(const this_type& other) {
+      for (size_t i = 0; i < D; ++i) at(i) /= other.at(i);
+      return *this;
+    }
+    
+    this_type& operator+=(const T& c) {
+      return operator +=(this_type{c, fill});
+    }
+    
+    this_type& operator -=(const T& c) {
+      return operator -=(this_type{c, fill});
+    }
+    
+    this_type& operator *=(const T& c)  {
+      return operator *=(this_type{c, fill});
+    }
+    
+    this_type& operator /=(const T& c) {
+      return operator /=(this_type{c, fill});
+    }
+    
+    this_type operator +(const this_type& other) const {
+      return this_type(*this) += other;
+    }
+    
+    this_type operator -(const this_type& other) const {
+      return this_type(*this) -= other;
+    }
+    
+    this_type operator *(const this_type& other) const {
+      return this_type(*this) *= other;
+    }
+    
+    this_type operator /(const this_type& other) const {
+      return this_type(*this) /= other;
+    }
+    
+    this_type operator +(const T& c) const {
+      return operator +(this_type{c, fill});
+    }
+    
+    this_type operator -(const T& c) const {
+      return operator -(this_type{c, fill});
+    }
+    
+    this_type operator *(const T& c) const {
+      return operator *(this_type{c, fill});
+    }
+    
+    this_type operator /(const T& c) const {
+      return operator /(this_type{c, fill});
+    }
+    
+    this_type operator -() const { return -1 * (*this); }
+    
+    bool operator ==(const this_type& other) const {
+      return !memcmp(data, other.data, D * sizeof(T));
+    } // technically wrong on float/double
+    
+    bool operator !=(const this_type& other) const {
+      return !operator==(other);
+    }
+    
+    bool operator <=(const this_type& other) const {
+      for (size_t i = 0; i < D; ++i) { if (at(i) > other.at(i)) return false; }
+      return true;
+    }
+    
+    bool operator <(const this_type& other) const {
+      for (size_t i = 0; i < D; ++i) { if (at(i) >= other.at(i)) return false; }
+      return true;
+    }
+    
+    bool operator >=(const this_type& other) const {
+      for (size_t i = 0; i < D; ++i) { if (at(i) < other.at(i)) return false; }
+      return true;
+    }
+    
+    bool operator >(const this_type& other) const {
+      for (size_t i = 0; i < D; ++i) { if (at(i) <= other.at(i)) return false; }
+      return true;
+    }
+    
+    template <size_t D2>
+    typename std::enable_if<(D == 2 || D == 3) && D == D2, raw_vector<3, T> >::type cross(const raw_vector<D2, T>& v) const {
+      return D == 2
+      ? raw_vector<3, T>{0, 0, at(0)*v.at(1) - at(1)*v.at(0)}
+      : raw_vector<3, T>{
+        at(1)*v.at(2) - at(2)*v.at(1),
+        at(2)*v.at(0) - at(0)*v.at(2),
+        at(0)*v.at(1) - at(1)*v.at(0)
+      };
+    }
+    
+    T dot(const this_type& v) const {
+      T accum{};
+      for (size_t i = 0; i < D; ++i) accum += data[i] * v[i];
+      return accum;
+    }
+    
+    T lengthSquared() const {
+      return dot(*this);
+    }
+    
+    sqrt_type length() const {
+      return std::sqrt(lengthSquared());
+    }
+    
+    T distanceSquared(const this_type& other) const {
+      return operator -(other).lengthSquared();
+    }
+    
+    sqrt_type distance(const this_type& other) const {
+      return std::sqrt(distanceSquared(other));
+    }
+    
+    raw_vector<D, sqrt_type> unit() const { return raw_vector<D, sqrt_type>(*this)/length(); }
+    
+    void swap(raw_vector& that) {
+      using std::swap;
+      for (size_t i = 0; i < D; ++i) swap(data[i], that.data[i]);
+    }
+    
+    constexpr raw_vector() = default;
+    
+    raw_vector(const this_type& that) {
+      for (size_t i = 0; i < D; ++i) data[i] = that.data[i];
+    }
+    
+    raw_vector(this_type&& that) {
+      for (size_t i = 0; i < D; ++i) data[i] = that.data[i];
+    }
+    
+    raw_vector& operator=(const this_type& other) {
+      for (size_t i = 0; i < D; ++i) data[i] = other.data[i];
+      return *this;
+    }
+    
+    raw_vector& operator=(this_type&& other) {
+      for (size_t i = 0; i < D; ++i) data[i] = other.data[i];
+      return *this;
+    }
+    
+    raw_vector(std::initializer_list<T> vals) {
+      const size_t D2 = vals.size();
+      const T* ptr = vals.begin();
+      for (size_t i = 0; i < std::min(D, D2); ++i) data[i] = *ptr++;
+      for (size_t j = std::min(D, D2); j < std::max(D, D2); ++j) data[j] = T();
+    }
+    
+    template <std::size_t D2, typename T2,
+    typename = typename std::enable_if<D2 != D || !std::is_same<T, T2>::value>::type>
+    explicit raw_vector(const raw_vector<D2, T2>& that) {
+      for (size_t i = 0; i < std::min(D, D2); ++i) data[i] = static_cast<T>(that[i]);
+      for (size_t j = std::min(D, D2); j < std::max(D, D2); ++j) data[j] = T();
+    }
+    
+    raw_vector(T const& t, fill_t) {
+      for (size_t i = 0; i < D; ++i) data[i] = t;
+    }
+    
+  private:
+    value_type data[D] = {0};
+  };
+} }
+
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator +(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
+  return rhs + lhs;
+}
+
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator -(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
+  return math::vector::raw_vector<D, T>(lhs, math::vector::fill) - rhs;
+}
+
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator *(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
+  return rhs * lhs;
+}
+
+template <size_t D, typename T>
+math::vector::raw_vector<D, T> operator /(T const& lhs, math::vector::raw_vector<D, T> const& rhs) {
+  return math::vector::raw_vector<D, T>(lhs, math::vector::fill) / rhs;
+}
+
+template <typename CharT, typename Traits, size_t N, typename T>
+std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, const math::vector::raw_vector<N, T>& v) {
+  out << '(' << v[0];
+  for (size_t i = 1; i < N; ++i) { out << ',' << v[i]; }
+  out << ')';
+  return out;
+}
+
+namespace std {
+  template <size_t D, typename T>
+  math::vector::raw_vector<D, T> abs(math::vector::raw_vector<D, T> const& data) {
+    math::vector::raw_vector<D, T> rval;
+    for (size_t i = 0; i < D; ++i) rval[i] = std::abs(data[i]);
+    return rval;
+  }
+}

+ 0 - 200
vector_tc.cpp

@@ -1,200 +0,0 @@
-/* Generated file, do not edit */
-
-#ifndef CXXTEST_RUNNING
-#define CXXTEST_RUNNING
-#endif
-
-#define _CXXTEST_HAVE_STD
-#define _CXXTEST_HAVE_EH
-#include <cxxtest/TestListener.h>
-#include <cxxtest/TestTracker.h>
-#include <cxxtest/TestRunner.h>
-#include <cxxtest/RealDescriptions.h>
-#include <cxxtest/TestMain.h>
-#include <cxxtest/ErrorPrinter.h>
-
-int main( int argc, char *argv[] ) {
- int status;
-    CxxTest::ErrorPrinter tmp;
-    CxxTest::RealWorldDescription::_worldName = "cxxtest";
-    status = CxxTest::Main< CxxTest::ErrorPrinter >( tmp, argc, argv );
-    return status;
-}
-bool suite_vector_TestSuite_init = false;
-#include "vector_tc.h"
-
-static vector_TestSuite suite_vector_TestSuite;
-
-static CxxTest::List Tests_vector_TestSuite = { 0, 0 };
-CxxTest::StaticSuiteDescription suiteDescription_vector_TestSuite( "vector_tc.h", 5, "vector_TestSuite", suite_vector_TestSuite, Tests_vector_TestSuite );
-
-static class TestDescription_suite_vector_TestSuite_test_vector_equals : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_equals() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 12, "test_vector_equals" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_equals(); }
-} testDescription_suite_vector_TestSuite_test_vector_equals;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_notequals : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_notequals() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 16, "test_vector_notequals" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_notequals(); }
-} testDescription_suite_vector_TestSuite_test_vector_notequals;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_elems : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_elems() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 20, "test_vector_elems" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_elems(); }
-} testDescription_suite_vector_TestSuite_test_vector_elems;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_oob : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_oob() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 27, "test_vector_oob" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_oob(); }
-} testDescription_suite_vector_TestSuite_test_vector_oob;
-
-static class TestDescription_suite_vector_TestSuite_test_default_zero : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_default_zero() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 31, "test_default_zero" ) {}
- void runTest() { suite_vector_TestSuite.test_default_zero(); }
-} testDescription_suite_vector_TestSuite_test_default_zero;
-
-static class TestDescription_suite_vector_TestSuite_test_extends_with_zero : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_extends_with_zero() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 35, "test_extends_with_zero" ) {}
- void runTest() { suite_vector_TestSuite.test_extends_with_zero(); }
-} testDescription_suite_vector_TestSuite_test_extends_with_zero;
-
-static class TestDescription_suite_vector_TestSuite_test_vec2_cross : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vec2_cross() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 39, "test_vec2_cross" ) {}
- void runTest() { suite_vector_TestSuite.test_vec2_cross(); }
-} testDescription_suite_vector_TestSuite_test_vec2_cross;
-
-static class TestDescription_suite_vector_TestSuite_test_vec3_cross : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vec3_cross() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 43, "test_vec3_cross" ) {}
- void runTest() { suite_vector_TestSuite.test_vec3_cross(); }
-} testDescription_suite_vector_TestSuite_test_vec3_cross;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_addition_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_addition_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 47, "test_vector_addition_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_addition_vector(); }
-} testDescription_suite_vector_TestSuite_test_vector_addition_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_subtraction_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_subtraction_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 51, "test_vector_subtraction_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_subtraction_vector(); }
-} testDescription_suite_vector_TestSuite_test_vector_subtraction_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_multiplication_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_multiplication_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 55, "test_vector_multiplication_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_multiplication_vector(); }
-} testDescription_suite_vector_TestSuite_test_vector_multiplication_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_divides_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_divides_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 59, "test_vector_divides_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_divides_vector(); }
-} testDescription_suite_vector_TestSuite_test_vector_divides_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_addition_value : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_addition_value() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 63, "test_vector_addition_value" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_addition_value(); }
-} testDescription_suite_vector_TestSuite_test_vector_addition_value;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_subtraction_value : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_subtraction_value() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 67, "test_vector_subtraction_value" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_subtraction_value(); }
-} testDescription_suite_vector_TestSuite_test_vector_subtraction_value;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_multiplication_value : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_multiplication_value() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 71, "test_vector_multiplication_value" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_multiplication_value(); }
-} testDescription_suite_vector_TestSuite_test_vector_multiplication_value;
-
-static class TestDescription_suite_vector_TestSuite_test_vector_divides_value : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_vector_divides_value() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 75, "test_vector_divides_value" ) {}
- void runTest() { suite_vector_TestSuite.test_vector_divides_value(); }
-} testDescription_suite_vector_TestSuite_test_vector_divides_value;
-
-static class TestDescription_suite_vector_TestSuite_test_value_addition_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_value_addition_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 79, "test_value_addition_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_value_addition_vector(); }
-} testDescription_suite_vector_TestSuite_test_value_addition_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_value_subtraction_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_value_subtraction_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 83, "test_value_subtraction_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_value_subtraction_vector(); }
-} testDescription_suite_vector_TestSuite_test_value_subtraction_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_value_multiplication_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_value_multiplication_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 87, "test_value_multiplication_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_value_multiplication_vector(); }
-} testDescription_suite_vector_TestSuite_test_value_multiplication_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_value_divides_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_value_divides_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 91, "test_value_divides_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_value_divides_vector(); }
-} testDescription_suite_vector_TestSuite_test_value_divides_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_length_of_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_length_of_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 95, "test_length_of_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_length_of_vector(); }
-} testDescription_suite_vector_TestSuite_test_length_of_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_distance_of_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_distance_of_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 100, "test_distance_of_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_distance_of_vector(); }
-} testDescription_suite_vector_TestSuite_test_distance_of_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_dot_product : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_dot_product() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 105, "test_dot_product" ) {}
- void runTest() { suite_vector_TestSuite.test_dot_product(); }
-} testDescription_suite_vector_TestSuite_test_dot_product;
-
-static class TestDescription_suite_vector_TestSuite_test_unit_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_unit_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 109, "test_unit_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_unit_vector(); }
-} testDescription_suite_vector_TestSuite_test_unit_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_type_shift : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_type_shift() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 115, "test_type_shift" ) {}
- void runTest() { suite_vector_TestSuite.test_type_shift(); }
-} testDescription_suite_vector_TestSuite_test_type_shift;
-
-static class TestDescription_suite_vector_TestSuite_test_swap : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_swap() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 119, "test_swap" ) {}
- void runTest() { suite_vector_TestSuite.test_swap(); }
-} testDescription_suite_vector_TestSuite_test_swap;
-
-static class TestDescription_suite_vector_TestSuite_test_negate_vector : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_negate_vector() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 127, "test_negate_vector" ) {}
- void runTest() { suite_vector_TestSuite.test_negate_vector(); }
-} testDescription_suite_vector_TestSuite_test_negate_vector;
-
-static class TestDescription_suite_vector_TestSuite_test_absolute_value : public CxxTest::RealTestDescription {
-public:
- TestDescription_suite_vector_TestSuite_test_absolute_value() : CxxTest::RealTestDescription( Tests_vector_TestSuite, suiteDescription_vector_TestSuite, 131, "test_absolute_value" ) {}
- void runTest() { suite_vector_TestSuite.test_absolute_value(); }
-} testDescription_suite_vector_TestSuite_test_absolute_value;
-
-#include <cxxtest/Root.cpp>
-const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";

+ 28 - 6
vector_type_generator.hpp

@@ -8,15 +8,15 @@
 #include <boost/preprocessor/list/for_each.hpp>
 
 #define APPLY_BINARY_OPERATOR(z, op, field)\
-  lhs.field op rhs.field;
+  field op rhs.field;
 
 #define DEFINE_BINARY_OPERATOR(left_t, right_t, op, fields)\
-  left_t& operator op##=(left_t && lhs, right_t const& rhs) {\
+  left_t& operator op##=(right_t const& rhs) {\
     BOOST_PP_SEQ_FOR_EACH(APPLY_BINARY_OPERATOR, op##=, fields)\
-    return lhs;\
+    return *this;\
   }\
-  left_t operator op(left_t const& lhs, right_t const& rhs) {\
-    return left_t{lhs} op##= rhs;\
+  left_t operator op(right_t const& rhs) {\
+    return left_t{*this} op##= rhs;\
   }
 
 #define DEFINE_SELF_BINARY_OPERATOR(type, op, fields)\
@@ -31,12 +31,34 @@ DEFINE_SELF_BINARY_OPERATOR(type, op, fields)
 #define DEFINE_VECTOR_OPERATOR(z, tup, op)\
   DEFINE_VECTOR_OPERATOR2(BOOST_PP_TUPLE_ELEM(2, 0, tup), op, BOOST_PP_TUPLE_ELEM(2, 1, tup))
 
+#define DEFINE_VECTOR_OPERATIONS(type, fields, operators)\
+  BOOST_PP_LIST_FOR_EACH(DEFINE_VECTOR_OPERATOR, (type, fields),BOOST_PP_TUPLE_TO_LIST(BOOST_PP_SEQ_SIZE(operators), BOOST_PP_SEQ_TO_TUPLE(operators)))\
+
+#define DEF_VEC_CTR_ARG_2(elem_t, field) elem_t _##field
+#define DEF_VEC_CTR_ARG_1(elem_t, field) DEF_VEC_CTR_ARG_2(elem_t, field)
+#define DEF_VEC_CTR_ARG(z, elem_t, field) ,DEF_VEC_CTR_ARG_1(elem_t, field)
+#define DEFINE_VECTOR_CONSTRUCTOR_ARGS(elem_t, fields)\
+  DEF_VEC_CTR_ARG_1(elem_t, BOOST_PP_SEQ_HEAD(fields)) \
+  BOOST_PP_SEQ_FOR_EACH(DEF_VEC_CTR_ARG, elem_t, BOOST_PP_SEQ_TAIL(fields))
+
+#define DEF_VEC_CTR_INIT_2(field) field(_##field)
+#define DEF_VEC_CTR_INIT_1(field) DEF_VEC_CTR_INIT_2(field)
+#define DEF_VEC_CTR_ARG_1(elem_t, field) DEF_VEC_CTR_ARG_2(elem_t, field)
+#define DEF_VEC_CTR_INIT(z, _, field) ,DEF_VEC_CTR_INIT_1(field)
+#define DEFINE_VECTOR_CONSTRUCTOR_INIT(fields)\
+  DEF_VEC_CTR_INIT_1(BOOST_PP_SEQ_HEAD(fields)) \
+  BOOST_PP_SEQ_FOR_EACH(DEF_VEC_CTR_INIT, _, BOOST_PP_SEQ_TAIL(fields))
+
+#define DEFINE_VECTOR_CONSTRUCTOR(type, elem_t, fields)\
+  type(DEFINE_VECTOR_CONSTRUCTOR_ARGS(elem_t, fields)) : DEFINE_VECTOR_CONSTRUCTOR_INIT(fields) {}
+
 // We convert to a list because recursive calls to BOOST_PP_SEQ_FOR_EACH don't work
 #define MAKE_VECTOR_TYPE(type, elem_t, fields, operators)\
   struct type {\
+    DEFINE_VECTOR_CONSTRUCTOR(type, elem_t, fields)\
     BOOST_PP_SEQ_FOR_EACH(DEFINE_VECTOR_MEMVAR, elem_t, fields)\
+    DEFINE_VECTOR_OPERATIONS(type, fields, operators)\
   };\
-  BOOST_PP_LIST_FOR_EACH(DEFINE_VECTOR_OPERATOR, (type, fields), BOOST_PP_TUPLE_TO_LIST(BOOST_PP_SEQ_SIZE(operators), BOOST_PP_SEQ_TO_TUPLE(operators)))
 
 #define VECTOR_XY   (x)(y)
 #define VECTOR_XYZ  (x)(y)(z)