From ef76246a9afc12c735ea8e0317d45b9c474a3e5a Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 12 Apr 2017 01:38:59 +0200 Subject: compat/simple-mat: simplify SFINAE variable templates rock ass. --- compat/simple-mat.hpp | 284 +++++++++++++++++++++++++------------------------- 1 file 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 #include "export.hpp" +#include #include #include #include -namespace { - // last param to fool SFINAE into overloading - template - struct equals - { - enum { value = i == j }; - }; - template - struct maybe_add_swizzle - { - enum { value = (i == 1 || j == 1) && (i >= min || j >= min) }; - }; - template - struct is_vector_pair - { - enum { value = (i1 == i2 && j1 == 1 && j2 == 1) || (j1 == j2 && i1 == 1 && i2 == 1) }; - }; - template - struct vector_len - { - enum { value = i > j ? i : j }; - }; - template - 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 - struct is_arglist_correct - { - enum { value = h * w == sizeof...(ts) }; - }; -} +// `zz' param to fool into SFINAE member overload -template -class Mat -{ - static_assert(h_ > 0 && w_ > 0, "must have positive mat dimensions"); - num data[h_][w_]; +template +constexpr bool equals = ((void)zz, i == k && j != k); -public: - template typename std::enable_if::value, num>::type - inline operator()(int i) const { return data[i][0]; } +template +constexpr bool maybe_swizzle = + (i == 1 || j == 1) && (i >= min || j >= min); - template typename std::enable_if::value, num>::type - inline operator()(int i) const { return data[0][i]; } +template +constexpr bool is_vector_pair = + (i1 == i2 && j1 == 1 && j2 == 1) || (j1 == j2 && i1 == 1 && i2 == 1); - template typename std::enable_if::value, num&>::type - inline operator()(int i) { return data[i][0]; } +template +constexpr unsigned vector_len = i > j ? i : j; - template typename std::enable_if::value, num&>::type - inline operator()(int i) { return data[0][i]; } +template +constexpr bool dim3 = + (a == 3 || b == 3) && (c == 3 || d == 3) && + (a == 1 || b == 1) && (c == 1 || d == 1); - template typename std::enable_if::value, num>::type - inline operator()(unsigned i) const { return data[i][0]; } +template +constexpr bool arglist_correct = h * w == sizeof...(ts); - template typename std::enable_if::value, num>::type - inline operator()(unsigned i) const { return data[0][i]; } +template +using sfinae = typename std::enable_if::type; - template typename std::enable_if::value, num&>::type - inline operator()(unsigned i) { return data[i][0]; } +template +class Mat +{ + static_assert(h_ > 0 && w_ > 0, "must have positive mat dimensions"); + num data[h_][w_]; - template typename std::enable_if::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&& 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 typename std::enable_if::value, num>::type - x() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); } + // rebinding w_ and h_ since SFINAE requires dependent variables - template typename std::enable_if::value, num>::type - y() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); } + template sfinae, num> + OTR_FLATTEN operator()(int i) const { OTR_ASSERT_SWIZZLE; return data[i][0]; } + template sfinae, num&> + OTR_FLATTEN operator()(int i) { OTR_ASSERT_SWIZZLE; return data[i][0]; } - template typename std::enable_if::value, num>::type - z() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); } + template sfinae, num> + OTR_FLATTEN operator()(int i) const { OTR_ASSERT_SWIZZLE; return data[0][i]; } + template sfinae, num&> + OTR_FLATTEN operator()(int i) { OTR_ASSERT_SWIZZLE; return data[0][i]; } - template typename std::enable_if::value, num>::type - w() const { OPENTRACK_ASSERT_SWIZZLE; return operator()(3); } + template sfinae, num> + OTR_FLATTEN x() const { OTR_ASSERT_SWIZZLE; return operator()(0); } + template sfinae, num&> + OTR_FLATTEN x() { OTR_ASSERT_SWIZZLE; return operator()(0); } - template typename std::enable_if::value, num&>::type - x() { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); } + template sfinae, num> + OTR_FLATTEN y() const { OTR_ASSERT_SWIZZLE; return operator()(1); } + template sfinae, num&> + OTR_FLATTEN y() { OTR_ASSERT_SWIZZLE; return operator()(1); } - template typename std::enable_if::value, num&>::type - y() { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); } + template sfinae, num> + OTR_FLATTEN z() const { OTR_ASSERT_SWIZZLE; return operator()(2); } + template sfinae, num&> + OTR_FLATTEN z() { OTR_ASSERT_SWIZZLE; return operator()(2); } - template typename std::enable_if::value, num&>::type - z() { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); } + template sfinae, num> + OTR_FLATTEN w() const { OTR_ASSERT_SWIZZLE; return operator()(3); } + template sfinae, num&> + OTR_FLATTEN w() { OTR_ASSERT_SWIZZLE; return operator()(3); } + + // end sfinae-R-us block - template typename std::enable_if::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 - typename std::enable_if::value, num>::type + sfinae, num> dot(const Mat& p2) const { - static_assert(P == h_ && Q == w_, ""); + OTR_ASSERT_SWIZZLE; num ret = 0; - constexpr int len = vector_len::value; - for (int i = 0; i < len; i++) + static constexpr unsigned len = vector_len; + for (unsigned i = 0; i < len; i++) ret += operator()(i) * p2(i); return ret; } - template - typename std::enable_if::value, Mat::P, is_dim3::Q>>::type + template sfinae, Mat> cross(const Mat& p2) const { - static_assert(P == h_ && Q == w_, ""); - decltype(*this)& p1 = *this; + OTR_ASSERT_SWIZZLE; + decltype(*this)& OTR_RESTRICT p1 = *this; return Mat(p1.y() * p2.z() - p2.y() * p1.z(), p2.x() * p1.z() - p1.x() * p2.z(), @@ -153,24 +143,6 @@ public: return ret; } - Mat operator+(const num& other) const - { - Mat 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 operator-(const num& other) const - { - Mat 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 Mat operator*(const Mat& 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::value>::type> + template, void>> Mat(const ts... xs) { - static_assert(h__ == h_ && w__ == w_, ""); + OTR_ASSERT_SWIZZLE; + static_assert(arglist_correct, ""); std::initializer_list init = { static_cast(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&& 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(data); } - operator const num*() const { return reinterpret_cast(data); } + OTR_ALWAYS_INLINE operator num*() { return reinterpret_cast(data); } + OTR_ALWAYS_INLINE operator const num*() const { return reinterpret_cast(data); } // XXX add more operators as needed, third-party dependencies mostly // not needed merely for matrix algebra -sh 20141030 - template - static typename std::enable_if>::type eye() + template + static typename std::enable_if

>::type eye() { - static_assert(h_ == h__, ""); + static_assert(P == h_, ""); - Mat ret; - for (int j = 0; j < h_; j++) + Mat 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 -Mat operator*(num scalar, const Mat& mat) -{ - return mat * scalar; -} - -template -Mat operator*(const Mat& self, num other) -{ - Mat 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 class Quat : Mat { @@ -287,7 +237,7 @@ class Quat : Mat } inline num elt(idx k) const { return operator()(k); } - inline num& elt(idx k) { return operator()(k); } + inline num& elt(idx k) { return Mat::operator()(int(k)); } public: Quat(num w, num x, num y, num z) : Mat(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 +using Mat = mat_detail::Mat; + +template +inline Mat operator*(num scalar, const Mat& mat) { return mat * scalar; } + +template +inline Mat operator-(num scalar, const Mat& mat) { return mat - scalar; } + +template +inline Mat operator+(num scalar, const Mat& mat) { return mat + scalar; } + +template +inline Mat operator*(const Mat& OTR_RESTRICT self, num other) +{ + Mat 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 +inline Mat operator-(const Mat& OTR_RESTRICT self, num other) +{ + Mat 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 +inline Mat operator+(const Mat& OTR_RESTRICT self, num other) +{ + Mat 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 +using Quat_ = mat_detail::Quat; + +using Quat = Quat_; + +template class mat_detail::Mat; +template class mat_detail::Mat; +template class mat_detail::Mat; + +// eof -- cgit v1.2.3