diff options
Diffstat (limited to 'source/blender/blenlib/BLI_math_vec_types.hh')
-rw-r--r-- | source/blender/blenlib/BLI_math_vec_types.hh | 243 |
1 files changed, 152 insertions, 91 deletions
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh index 7f20881dfa3..0387d0b0440 100644 --- a/source/blender/blenlib/BLI_math_vec_types.hh +++ b/source/blender/blenlib/BLI_math_vec_types.hh @@ -40,6 +40,21 @@ template<typename T> struct vec_struct_base<T, 4> { T x, y, z, w; }; +template<class Fn, size_t... I> void unroll_impl(Fn fn, std::index_sequence<I...> /*indices*/) +{ + (fn(I), ...); +} + +/** + * Variadic templates are used to unroll loops manually. This helps GCC avoid branching during math + * operations and makes the code generation more explicit and predictable. Unrolling should always + * be worth it because the vector size is expected to be small. + */ +template<int N, class Fn> void unroll(Fn fn) +{ + unroll_impl(fn, std::make_index_sequence<N>()); +} + namespace math { template<typename T> uint64_t vector_hash(const T &vec) @@ -74,28 +89,28 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> explicit vec_base(uint value) { for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(value); + (*this)[i] = T(value); } } explicit vec_base(int value) { for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(value); + (*this)[i] = T(value); } } explicit vec_base(float value) { for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(value); + (*this)[i] = T(value); } } explicit vec_base(double value) { for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(value); + (*this)[i] = T(value); } } @@ -126,53 +141,42 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> /** Mixed scalar-vector constructors. */ template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)> - constexpr vec_base(const vec_base<U, 2> &xy, T z) - : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), z) + constexpr vec_base(const vec_base<U, 2> &xy, T z) : vec_base(T(xy.x), T(xy.y), z) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)> - constexpr vec_base(T x, const vec_base<U, 2> &yz) - : vec_base(x, static_cast<T>(yz.x), static_cast<T>(yz.y)) + constexpr vec_base(T x, const vec_base<U, 2> &yz) : vec_base(x, T(yz.x), T(yz.y)) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(vec_base<U, 3> xyz, T w) - : vec_base( - static_cast<T>(xyz.x), static_cast<T>(xyz.y), static_cast<T>(xyz.z), static_cast<T>(w)) + vec_base(vec_base<U, 3> xyz, T w) : vec_base(T(xyz.x), T(xyz.y), T(xyz.z), T(w)) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(T x, vec_base<U, 3> yzw) - : vec_base( - static_cast<T>(x), static_cast<T>(yzw.x), static_cast<T>(yzw.y), static_cast<T>(yzw.z)) + vec_base(T x, vec_base<U, 3> yzw) : vec_base(T(x), T(yzw.x), T(yzw.y), T(yzw.z)) { } template<typename U, typename V, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(vec_base<U, 2> xy, vec_base<V, 2> zw) - : vec_base( - static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(zw.x), static_cast<T>(zw.y)) + vec_base(vec_base<U, 2> xy, vec_base<V, 2> zw) : vec_base(T(xy.x), T(xy.y), T(zw.x), T(zw.y)) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(vec_base<U, 2> xy, T z, T w) - : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(z), static_cast<T>(w)) + vec_base(vec_base<U, 2> xy, T z, T w) : vec_base(T(xy.x), T(xy.y), T(z), T(w)) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(T x, vec_base<U, 2> yz, T w) - : vec_base(static_cast<T>(x), static_cast<T>(yz.x), static_cast<T>(yz.y), static_cast<T>(w)) + vec_base(T x, vec_base<U, 2> yz, T w) : vec_base(T(x), T(yz.x), T(yz.y), T(w)) { } template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)> - vec_base(T x, T y, vec_base<U, 2> zw) - : vec_base(static_cast<T>(x), static_cast<T>(y), static_cast<T>(zw.x), static_cast<T>(zw.y)) + vec_base(T x, T y, vec_base<U, 2> zw) : vec_base(T(x), T(y), T(zw.x), T(zw.y)) { } @@ -182,7 +186,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> explicit vec_base(const vec_base<U, OtherSize> &other) { for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(other[i]); + (*this)[i] = T(other[i]); } } @@ -192,17 +196,13 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> vec_base(const T *ptr) { - for (int i = 0; i < Size; i++) { - (*this)[i] = ptr[i]; - } + unroll<Size>([&](auto i) { (*this)[i] = ptr[i]; }); } template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))> explicit vec_base(const U *ptr) { - for (int i = 0; i < Size; i++) { - (*this)[i] = ptr[i]; - } + unroll<Size>([&](auto i) { (*this)[i] = ptr[i]; }); } vec_base(const T (*ptr)[Size]) : vec_base(static_cast<const T *>(ptr[0])) @@ -213,9 +213,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> template<typename U> explicit vec_base(const vec_base<U, Size> &vec) { - for (int i = 0; i < Size; i++) { - (*this)[i] = static_cast<T>(vec[i]); - } + unroll<Size>([&](auto i) { (*this)[i] = T(vec[i]); }); } /** C-style pointer dereference. */ @@ -250,29 +248,20 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> #define BLI_INT_OP(_T) template<typename U = _T, BLI_ENABLE_IF((std::is_integral_v<U>))> -#define BLI_VEC_OP_IMPL(_result, _i, _op) \ - vec_base _result; \ - for (int _i = 0; _i < Size; _i++) { \ - _op; \ - } \ - return _result; - -#define BLI_VEC_OP_IMPL_SELF(_i, _op) \ - for (int _i = 0; _i < Size; _i++) { \ - _op; \ - } \ - return *this; - /** Arithmetic operators. */ friend vec_base operator+(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] + b[i]; }); + return result; } friend vec_base operator+(const vec_base &a, const T &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] + b; }); + return result; } friend vec_base operator+(const T &a, const vec_base &b) @@ -282,52 +271,69 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> vec_base &operator+=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b[i]); + unroll<Size>([&](auto i) { (*this)[i] += b[i]; }); + return *this; } vec_base &operator+=(const T &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b); + vec_base result; + unroll<Size>([&](auto i) { (*this)[i] += b; }); + return result; } friend vec_base operator-(const vec_base &a) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = -a[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = -a[i]; }); + return result; } friend vec_base operator-(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] - b[i]; }); + return result; } friend vec_base operator-(const vec_base &a, const T &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] - b; }); + return result; } friend vec_base operator-(const T &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a - b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a - b[i]; }); + return result; } vec_base &operator-=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b[i]); + unroll<Size>([&](auto i) { (*this)[i] -= b[i]; }); + return *this; } vec_base &operator-=(const T &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b); + unroll<Size>([&](auto i) { (*this)[i] -= b; }); + return *this; } friend vec_base operator*(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] * b[i]; }); + return result; } template<typename FactorT> friend vec_base operator*(const vec_base &a, FactorT b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] * b; }); + return result; } friend vec_base operator*(T a, const vec_base &b) @@ -337,12 +343,14 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> vec_base &operator*=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b); + unroll<Size>([&](auto i) { (*this)[i] *= b; }); + return *this; } vec_base &operator*=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b[i]); + unroll<Size>([&](auto i) { (*this)[i] *= b[i]; }); + return *this; } friend vec_base operator/(const vec_base &a, const vec_base &b) @@ -350,13 +358,17 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> for (int i = 0; i < Size; i++) { BLI_assert(b[i] != T(0)); } - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] / b[i]; }); + return result; } friend vec_base operator/(const vec_base &a, T b) { BLI_assert(b != T(0)); - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] / b; }); + return result; } friend vec_base operator/(T a, const vec_base &b) @@ -364,31 +376,39 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> for (int i = 0; i < Size; i++) { BLI_assert(b[i] != T(0)); } - BLI_VEC_OP_IMPL(ret, i, ret[i] = a / b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a / b[i]; }); + return result; } vec_base &operator/=(T b) { BLI_assert(b != T(0)); - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b); + unroll<Size>([&](auto i) { (*this)[i] /= b; }); + return *this; } vec_base &operator/=(const vec_base &b) { BLI_assert(b != T(0)); - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b[i]); + unroll<Size>([&](auto i) { (*this)[i] /= b[i]; }); + return *this; } /** Binary operators. */ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] & b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, T b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] & b; }); + return result; } BLI_INT_OP(T) friend vec_base operator&(T a, const vec_base &b) @@ -398,22 +418,28 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> BLI_INT_OP(T) vec_base &operator&=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b); + unroll<Size>([&](auto i) { (*this)[i] &= b; }); + return *this; } BLI_INT_OP(T) vec_base &operator&=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b[i]); + unroll<Size>([&](auto i) { (*this)[i] &= b[i]; }); + return *this; } BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] | b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, T b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] | b; }); + return result; } BLI_INT_OP(T) friend vec_base operator|(T a, const vec_base &b) @@ -423,22 +449,28 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> BLI_INT_OP(T) vec_base &operator|=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b); + unroll<Size>([&](auto i) { (*this)[i] |= b; }); + return *this; } BLI_INT_OP(T) vec_base &operator|=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b[i]); + unroll<Size>([&](auto i) { (*this)[i] |= b[i]; }); + return *this; } BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] ^ b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, T b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] ^ b; }); + return result; } BLI_INT_OP(T) friend vec_base operator^(T a, const vec_base &b) @@ -448,59 +480,75 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> BLI_INT_OP(T) vec_base &operator^=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b); + unroll<Size>([&](auto i) { (*this)[i] ^= b; }); + return *this; } BLI_INT_OP(T) vec_base &operator^=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b[i]); + unroll<Size>([&](auto i) { (*this)[i] ^= b[i]; }); + return *this; } BLI_INT_OP(T) friend vec_base operator~(const vec_base &a) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = ~a[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = ~a[i]; }); + return result; } /** Bit-shift operators. */ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] << b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, T b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] << b; }); + return result; } BLI_INT_OP(T) vec_base &operator<<=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b); + unroll<Size>([&](auto i) { (*this)[i] <<= b; }); + return *this; } BLI_INT_OP(T) vec_base &operator<<=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b[i]); + unroll<Size>([&](auto i) { (*this)[i] <<= b[i]; }); + return *this; } BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, const vec_base &b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] >> b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, T b) { - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] >> b; }); + return result; } BLI_INT_OP(T) vec_base &operator>>=(T b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b); + unroll<Size>([&](auto i) { (*this)[i] >>= b; }); + return *this; } BLI_INT_OP(T) vec_base &operator>>=(const vec_base &b) { - BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b[i]); + unroll<Size>([&](auto i) { (*this)[i] >>= b[i]; }); + return *this; } /** Modulo operators. */ @@ -510,24 +558,28 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> for (int i = 0; i < Size; i++) { BLI_assert(b[i] != T(0)); } - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] % b[i]; }); + return result; } BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, T b) { BLI_assert(b != 0); - BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a[i] % b; }); + return result; } BLI_INT_OP(T) friend vec_base operator%(T a, const vec_base &b) { BLI_assert(b != T(0)); - BLI_VEC_OP_IMPL(ret, i, ret[i] = a % b[i]); + vec_base result; + unroll<Size>([&](auto i) { result[i] = a % b[i]; }); + return result; } #undef BLI_INT_OP -#undef BLI_VEC_OP_IMPL -#undef BLI_VEC_OP_IMPL_SELF /** Compare. */ @@ -567,6 +619,11 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> } }; +using char3 = blender::vec_base<int8_t, 3>; + +using uchar3 = blender::vec_base<uint8_t, 3>; +using uchar4 = blender::vec_base<uint8_t, 4>; + using int2 = vec_base<int32_t, 2>; using int3 = vec_base<int32_t, 3>; using int4 = vec_base<int32_t, 4>; @@ -575,7 +632,11 @@ using uint2 = vec_base<uint32_t, 2>; using uint3 = vec_base<uint32_t, 3>; using uint4 = vec_base<uint32_t, 4>; +using short3 = blender::vec_base<int16_t, 3>; + using ushort2 = vec_base<uint16_t, 2>; +using ushort3 = blender::vec_base<uint16_t, 3>; +using ushort4 = blender::vec_base<uint16_t, 4>; using float2 = vec_base<float, 2>; using float3 = vec_base<float, 3>; |