boostorg / qvm

Boost Quaternions, Vectors, Matrices library
Boost Software License 1.0
81 stars 45 forks source link

Consider adding default_qvm_traits to namespace boost::qvm #4

Closed federkamm closed 7 years ago

federkamm commented 7 years ago

I found the following code to be useful in my projects

template <typename Q, typename S> struct default_quat_traits {
    using quaternion_type = Q;
    using scalar_type = S;

    template <int I> static scalar_type read_element(quaternion_type const & q) {
      return quat_traits<quaternion_type>::template write_element<I>(const_cast<quaternion_type &>(q));
    }
};

template <typename V, typename S, int d> struct default_vec_traits {
    using vector_type = V;
    using scalar_type = S;
    static constexpr int const dim = d;

    static inline scalar_type read_element_idx (int I, vector_type const & v) {
      return vec_traits<vector_type>::write_element_idx(I, const_cast<vector_type &>(v));
    }
    template <int I> static scalar_type & write_element(vector_type & v) {
      static_assert(0 <= I && I < dim, "out of range");
      return vec_traits<vector_type>::write_element_idx(I, v);
    }
    template <int I> static scalar_type read_element (vector_type const & v) {
      return write_element<I>(const_cast<vector_type &>(v));
    }
};

template <typename M, typename S, int r, int c> struct default_mat_traits {
    using matrix_type = M;
    using scalar_type = S;
    static constexpr int const rows = r;
    static constexpr int const cols = c;

    static inline scalar_type read_element_idx (int R, int C, matrix_type const & m) {
      return mat_traits<matrix_type>::write_element_idx(R, C, const_cast<matrix_type &>(m));
    }
    template <int R, int C> static scalar_type & write_element(matrix_type & m) {
      static_assert(0 <= R && R < rows && 0 <= C && C < cols, "out of range");
      return mat_traits<matrix_type>::write_element_idx(R, C, m);
    }
    template <int R, int C> static scalar_type read_element (matrix_type const & m) {
      return write_element<R, C>(const_cast<matrix_type &>(m));
    }
};

It eases the instantiation of new qvm types:

using my_quat = std::tuple<double, double, double, double>;
template <> struct quat_traits<my_quat> : default_quat_traits<my_quat, double> {
    template <int I> static scalar_type & write_element(quaternion_type & q) { // must not modify q
      return std::get<I>(q);
    }
};

struct my_vec { double x, y, z; };
template <> struct vec_traits<my_vec> : default_vec_traits<my_vec, double, 3> {
    static inline scalar_type & write_element_idx(int i, vector_type & v) { // must not modify v
      switch (i) {
        case 0: return v.x;
        case 1: return v.y;
        case 2: return v.z;
      }
      throw std::out_of_range("");
    }
};

struct my_mat { double a, b, c, d; };
template <> struct mat_traits<my_mat> : default_mat_traits<my_mat, double, 2, 2>
{
    static inline scalar_type & write_element_idx(int r, int c, matrix_type & m) { // must not modify m
      if (0 <= r && r < rows) {
        switch (r + c * rows) {
          case 0: return m.a;
          case 1: return m.b;
          case 2: return m.c;
          case 3: return m.d;
        }
      }
      throw std::out_of_range("");
    }
};

I think most compiler should be able to generate optimal code from this.

Please think about if it is possible to add default_qvm_traits to boost::qvm.

zajo commented 7 years ago

See quat/vec/mat_traits_defaults in the develop branch.