diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2017-04-12 01:38:59 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2017-04-12 01:47:44 +0200 |
commit | ef76246a9afc12c735ea8e0317d45b9c474a3e5a (patch) | |
tree | 3b075996b75a1ddc47bb03ba2b0004e241e654c0 /compat/simple-mat.hpp | |
parent | 1e54ac6cf9751c417e5eb675e8d79a280661d921 (diff) |
compat/simple-mat: simplify SFINAE
variable templates rock ass.
Diffstat (limited to 'compat/simple-mat.hpp')
-rw-r--r-- | compat/simple-mat.hpp | 284 |
1 files changed, 144 insertions, 140 deletions
diff --git a/compat/simple-mat.hpp b/compat/simple-mat.hpp index 906c0969..1146984a 100644 --- a/compat/simple-mat.hpp +++ b/compat/simple-mat.hpp @@ -8,127 +8,117 @@ #pragma once +#include <cmath> #include "export.hpp" +#include <compat/util.hpp> #include <initializer_list> #include <type_traits> #include <utility> -namespace { - // last param to fool SFINAE into overloading - template<int i, int j, int> - struct equals - { - enum { value = i == j }; - }; - template<int i, int j, int min> - struct maybe_add_swizzle - { - enum { value = (i == 1 || j == 1) && (i >= min || j >= min) }; - }; - template<int i1, int j1, int i2, int j2> - struct is_vector_pair - { - enum { value = (i1 == i2 && j1 == 1 && j2 == 1) || (j1 == j2 && i1 == 1 && i2 == 1) }; - }; - template<int i, int j> - struct vector_len - { - enum { value = i > j ? i : j }; - }; - template<int a, int b, int c, int d> - struct is_dim3 - { - enum { value = (a == 1 && c == 1 && b == 3 && d == 3) || (a == 3 && c == 3 && b == 1 && d == 1) }; - enum { P = a == 1 ? 1 : 3 }; - enum { Q = a == 1 ? 3 : 1 }; - }; +namespace mat_detail { - template<typename num, int h, int w, typename...ts> - struct is_arglist_correct - { - enum { value = h * w == sizeof...(ts) }; - }; -} +// `zz' param to fool into SFINAE member overload -template<typename num, int h_, int w_> -class Mat -{ - static_assert(h_ > 0 && w_ > 0, "must have positive mat dimensions"); - num data[h_][w_]; +template<int i, int j, int k, int zz> +constexpr bool equals = ((void)zz, i == k && j != k); -public: - template<int Q = w_> typename std::enable_if<equals<Q, 1, 0>::value, num>::type - inline operator()(int i) const { return data[i][0]; } +template<int i, int j, int min> +constexpr bool maybe_swizzle = + (i == 1 || j == 1) && (i >= min || j >= min); - template<int P = h_> typename std::enable_if<equals<P, 1, 1>::value, num>::type - inline operator()(int i) const { return data[0][i]; } +template<int i1, int j1, int i2, int j2> +constexpr bool is_vector_pair = + (i1 == i2 && j1 == 1 && j2 == 1) || (j1 == j2 && i1 == 1 && i2 == 1); - template<int Q = w_> typename std::enable_if<equals<Q, 1, 2>::value, num&>::type - inline operator()(int i) { return data[i][0]; } +template<int i, int j> +constexpr unsigned vector_len = i > j ? i : j; - template<int P = h_> typename std::enable_if<equals<P, 1, 3>::value, num&>::type - inline operator()(int i) { return data[0][i]; } +template<int a, int b, int c, int d> +constexpr bool dim3 = + (a == 3 || b == 3) && (c == 3 || d == 3) && + (a == 1 || b == 1) && (c == 1 || d == 1); - template<int Q = w_> typename std::enable_if<equals<Q, 1, 0>::value, num>::type - inline operator()(unsigned i) const { return data[i][0]; } +template<int h, int w, typename... ts> +constexpr bool arglist_correct = h * w == sizeof...(ts); - template<int P = h_> typename std::enable_if<equals<P, 1, 1>::value, num>::type - inline operator()(unsigned i) const { return data[0][i]; } +template<bool x, typename t> +using sfinae = typename std::enable_if<x, t>::type; - template<int Q = w_> typename std::enable_if<equals<Q, 1, 2>::value, num&>::type - inline operator()(unsigned i) { return data[i][0]; } +template<typename num, int h_, int w_> +class Mat +{ + static_assert(h_ > 0 && w_ > 0, "must have positive mat dimensions"); + num data[h_][w_]; - template<int P = h_> typename std::enable_if<equals<P, 1, 3>::value, num&>::type - inline operator()(unsigned i) { return data[0][i]; } +#define OTR_ASSERT_SWIZZLE static_assert(P == h_ && Q == w_, "") -#define OPENTRACK_ASSERT_SWIZZLE static_assert(P == h_ && Q == w_, "") + Mat(std::initializer_list<num>&& init) + { + auto iter = init.begin(); + for (int j = 0; j < h_; j++) + for (int i = 0; i < w_; i++) + data[j][i] = *iter++; + } + +public: + // start sfinae-R-us block - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 1>::value, num>::type - x() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); } + // rebinding w_ and h_ since SFINAE requires dependent variables - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 2>::value, num>::type - y() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); } + template<int P = h_, int Q = w_> sfinae<equals<Q, P, 1, 0>, num> + OTR_FLATTEN operator()(int i) const { OTR_ASSERT_SWIZZLE; return data[i][0]; } + template<int P = h_, int Q = w_> sfinae<equals<Q, 0, 1, 0>, num&> + OTR_FLATTEN operator()(int i) { OTR_ASSERT_SWIZZLE; return data[i][0]; } - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 3>::value, num>::type - z() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); } + template<int P = h_, int Q = w_> sfinae<equals<P, Q, 1, 1>, num> + OTR_FLATTEN operator()(int i) const { OTR_ASSERT_SWIZZLE; return data[0][i]; } + template<int P = h_, int Q = w_> sfinae<equals<P, Q, 1, 1>, num&> + OTR_FLATTEN operator()(int i) { OTR_ASSERT_SWIZZLE; return data[0][i]; } - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 4>::value, num>::type - w() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(3); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 1>, num> + OTR_FLATTEN x() const { OTR_ASSERT_SWIZZLE; return operator()(0); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 1>, num&> + OTR_FLATTEN x() { OTR_ASSERT_SWIZZLE; return operator()(0); } - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 1>::value, num&>::type - x() { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 2>, num> + OTR_FLATTEN y() const { OTR_ASSERT_SWIZZLE; return operator()(1); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 2>, num&> + OTR_FLATTEN y() { OTR_ASSERT_SWIZZLE; return operator()(1); } - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 2>::value, num&>::type - y() { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 3>, num> + OTR_FLATTEN z() const { OTR_ASSERT_SWIZZLE; return operator()(2); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 3>, num&> + OTR_FLATTEN z() { OTR_ASSERT_SWIZZLE; return operator()(2); } - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 3>::value, num&>::type - z() { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 4>, num> + OTR_FLATTEN w() const { OTR_ASSERT_SWIZZLE; return operator()(3); } + template<int P = h_, int Q = w_> sfinae<maybe_swizzle<P, Q, 4>, num&> + OTR_FLATTEN w() { OTR_ASSERT_SWIZZLE; return operator()(3); } + + // end sfinae-R-us block - template<int P = h_, int Q = w_> typename std::enable_if<maybe_add_swizzle<P, Q, 4>::value, num&>::type - w() { OPENTRACK_ASSERT_SWIZZLE; return operator()(3); } // parameters w_ and h_ are rebound so that SFINAE occurs // removing them causes a compile-time error -sh 20150811 template<int R, int S, int P = h_, int Q = w_> - typename std::enable_if<is_vector_pair<R, S, P, Q>::value, num>::type + sfinae<is_vector_pair<R, S, P, Q>, num> dot(const Mat<num, R, S>& p2) const { - static_assert(P == h_ && Q == w_, ""); + OTR_ASSERT_SWIZZLE; num ret = 0; - constexpr int len = vector_len<R, S>::value; - for (int i = 0; i < len; i++) + static constexpr unsigned len = vector_len<R, S>; + for (unsigned i = 0; i < len; i++) ret += operator()(i) * p2(i); return ret; } - template<int R, int S, int P = h_, int Q = w_> - typename std::enable_if<is_dim3<P, Q, R, S>::value, Mat<num, is_dim3<P, Q, R, S>::P, is_dim3<P, Q, R, S>::Q>>::type + template<int R, int S, int P = h_, int Q = w_> sfinae<dim3<P, Q, R, S>, Mat<num, 3, 1>> cross(const Mat<num, R, S>& p2) const { - static_assert(P == h_ && Q == w_, ""); - decltype(*this)& p1 = *this; + OTR_ASSERT_SWIZZLE; + decltype(*this)& OTR_RESTRICT p1 = *this; return Mat<num, R, S>(p1.y() * p2.z() - p2.y() * p1.z(), p2.x() * p1.z() - p1.x() * p2.z(), @@ -153,24 +143,6 @@ public: return ret; } - Mat<num, h_, w_> operator+(const num& other) const - { - Mat<num, h_, w_> ret; - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - ret(j, i) = data[j][i] + other; - return ret; - } - - Mat<num, h_, w_> operator-(const num& other) const - { - Mat<num, h_, w_> ret; - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - ret(j, i) = data[j][i] - other; - return ret; - } - template<int p> Mat<num, h_, p> operator*(const Mat<num, w_, p>& other) const { @@ -191,11 +163,12 @@ public: inline num operator()(unsigned j, unsigned i) const { return data[j][i]; } inline num& operator()(unsigned j, unsigned i) { return data[j][i]; } - template<typename... ts, int h__ = h_, int w__ = w_, - typename = typename std::enable_if<is_arglist_correct<num, h__, w__, ts...>::value>::type> + template<typename... ts, int P = h_, int Q = w_, + typename = sfinae<arglist_correct<P, Q, ts...>, void>> Mat(const ts... xs) { - static_assert(h__ == h_ && w__ == w_, ""); + OTR_ASSERT_SWIZZLE; + static_assert(arglist_correct<P, Q, ts...>, ""); std::initializer_list<num> init = { static_cast<num>(xs)... }; @@ -209,38 +182,31 @@ public: data[j][i] = num(0); } - Mat(const num* mem) + Mat(const num* OTR_RESTRICT mem) { for (int j = 0; j < h_; j++) for (int i = 0; i < w_; i++) data[j][i] = mem[i*h_+j]; } - Mat(std::initializer_list<num>&& init) - { - auto iter = init.begin(); - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - data[j][i] = *iter++; - } - - operator num*() { return reinterpret_cast<num*>(data); } - operator const num*() const { return reinterpret_cast<const num*>(data); } + OTR_ALWAYS_INLINE operator num*() { return reinterpret_cast<num*>(data); } + OTR_ALWAYS_INLINE operator const num*() const { return reinterpret_cast<const num*>(data); } // XXX add more operators as needed, third-party dependencies mostly // not needed merely for matrix algebra -sh 20141030 - template<int h__ = h_> - static typename std::enable_if<h_ == w_, Mat<num, h__, h__>>::type eye() + template<int P = h_> + static typename std::enable_if<P == w_, Mat<num, P, P>>::type eye() { - static_assert(h_ == h__, ""); + static_assert(P == h_, ""); - Mat<num, h_, h_> ret; - for (int j = 0; j < h_; j++) + Mat<num, P, P> ret; + + for (int j = 0; j < P; j++) for (int i = 0; i < w_; i++) ret.data[j][i] = 0; - for (int i = 0; i < h_; i++) + for (int i = 0; i < P; i++) ret.data[i][i] = 1; return ret; @@ -258,22 +224,6 @@ public: } }; -template<typename num, int h, int w> -Mat<num, h, w> operator*(num scalar, const Mat<num, h, w>& mat) -{ - return mat * scalar; -} - -template<typename num, int h_, int w_> -Mat<num, h_, w_> operator*(const Mat<num, h_, w_>& self, num other) -{ - Mat<num, h_, w_> ret; - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - ret(j, i) = self(j, i) * other; - return ret; -} - template<typename num> class Quat : Mat<num, 4, 1> { @@ -287,7 +237,7 @@ class Quat : Mat<num, 4, 1> } inline num elt(idx k) const { return operator()(k); } - inline num& elt(idx k) { return operator()(k); } + inline num& elt(idx k) { return Mat<num, 4, 1>::operator()(int(k)); } public: Quat(num w, num x, num y, num z) : Mat<num, 4, 1>(w, x, y, z) { @@ -320,12 +270,11 @@ public: { const quat& OTR_RESTRICT q1 = *this; return quat(-q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z() + q1.w() * q2.w(), - q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y() + q1.w() * q2.x(), + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y() + q1.w() * q2.x(), -q1.x() * q2.z() + q1.y() * q2.w() + q1.z() * q2.x() + q1.w() * q2.y(), - q1.x() * q2.y() - q1.y() * q2.x() + q1.z() * q2.w() + q1.w() * q2.z()); + q1.x() * q2.y() - q1.y() * q2.x() + q1.z() * q2.w() + q1.w() * q2.z()); } - inline num w() const { return elt(qw); } inline num x() const { return elt(qx); } inline num y() const { return elt(qy); } @@ -336,3 +285,58 @@ public: inline num& y() { return elt(qy); } inline num& z() { return elt(qz); } }; + +} // ns detail + +template<typename num, int h, int w> +using Mat = mat_detail::Mat<num, h, w>; + +template<typename num, int h, int w> +inline Mat<num, h, w> operator*(num scalar, const Mat<num, h, w>& mat) { return mat * scalar; } + +template<typename num, int h, int w> +inline Mat<num, h, w> operator-(num scalar, const Mat<num, h, w>& mat) { return mat - scalar; } + +template<typename num, int h, int w> +inline Mat<num, h, w> operator+(num scalar, const Mat<num, h, w>& mat) { return mat + scalar; } + +template<typename num, int h_, int w_> +inline Mat<num, h_, w_> operator*(const Mat<num, h_, w_>& OTR_RESTRICT self, num other) +{ + Mat<num, h_, w_> ret; + for (int j = 0; j < h_; j++) + for (int i = 0; i < w_; i++) + ret(j, i) = self(j, i) * other; + return ret; +} + +template<typename num, int h_, int w_> +inline Mat<num, h_, w_> operator-(const Mat<num, h_, w_>& OTR_RESTRICT self, num other) +{ + Mat<num, h_, w_> ret; + for (int j = 0; j < h_; j++) + for (int i = 0; i < w_; i++) + ret(j, i) = self(j, i) - other; + return ret; +} + +template<typename num, int h_, int w_> +inline Mat<num, h_, w_> operator+(const Mat<num, h_, w_>& OTR_RESTRICT self, num other) +{ + Mat<num, h_, w_> ret; + for (int j = 0; j < h_; j++) + for (int i = 0; i < w_; i++) + ret(j, i) = self(j, i) + other; + return ret; +} + +template<typename num> +using Quat_ = mat_detail::Quat<num>; + +using Quat = Quat_<double>; + +template class mat_detail::Mat<float, 3, 3>; +template class mat_detail::Mat<float, 6, 1>; +template class mat_detail::Mat<float, 3, 1>; + +// eof |