From df718217d2888fdddc1fb97d07389ed1e6deb0b3 Mon Sep 17 00:00:00 2001 From: Artem Zyktin Date: Fri, 29 May 2026 21:16:48 +0800 Subject: [PATCH 1/2] Rewrite --- src/tenvex/expressions/add.h | 36 ++++++ src/tenvex/expressions/add_impl.hpp | 31 +++++ src/tenvex/expressions/concepts.h | 25 ++++ .../{internal => expressions}/defines.h | 4 +- src/tenvex/expressions/expression.h | 19 +++ src/tenvex/expressions/expression_impl.hpp | 14 +++ src/tenvex/expressions/mul.h | 48 ++++++++ src/tenvex/expressions/mul_impl.hpp | 44 +++++++ src/tenvex/expressions/scalar.h | 30 +++++ src/tenvex/expressions/scalar_impl.hpp | 20 ++++ src/tenvex/expressions/sub.h | 36 ++++++ src/tenvex/expressions/sub_impl.hpp | 30 +++++ src/tenvex/expressions/traits.h | 22 ++++ src/tenvex/expressions/vec4.h | 41 +++++++ src/tenvex/expressions/vec4_impl.hpp | 1 + src/tenvex/internal/add.h | 28 ----- src/tenvex/internal/add_impl.hpp | 30 ----- src/tenvex/internal/cross.h | 28 ----- src/tenvex/internal/cross_impl.hpp | 47 -------- src/tenvex/internal/dot.h | 39 ------- src/tenvex/internal/dot_impl.hpp | 60 ---------- src/tenvex/internal/expression.h | 47 -------- src/tenvex/internal/expression_impl.hpp | 31 ----- src/tenvex/internal/magnitude.h | 30 ----- src/tenvex/internal/magnitude_impl.hpp | 37 ------ src/tenvex/internal/mul.h | 37 ------ src/tenvex/internal/mul_impl.hpp | 44 ------- src/tenvex/internal/norm.h | 27 ----- src/tenvex/internal/norm_impl.hpp | 38 ------ src/tenvex/internal/scalar.h | 25 ---- src/tenvex/internal/scalar_impl.hpp | 26 ----- src/tenvex/internal/sub.h | 28 ----- src/tenvex/internal/sub_impl.hpp | 28 ----- src/tenvex/tenvex.h | 21 ++-- src/tenvex/vec4.h | 63 ---------- src/tenvex/vec4_impl.hpp | 108 ------------------ src/tests/vec4_tests.cpp | 15 ++- 37 files changed, 423 insertions(+), 815 deletions(-) create mode 100644 src/tenvex/expressions/add.h create mode 100644 src/tenvex/expressions/add_impl.hpp create mode 100644 src/tenvex/expressions/concepts.h rename src/tenvex/{internal => expressions}/defines.h (92%) create mode 100644 src/tenvex/expressions/expression.h create mode 100644 src/tenvex/expressions/expression_impl.hpp create mode 100644 src/tenvex/expressions/mul.h create mode 100644 src/tenvex/expressions/mul_impl.hpp create mode 100644 src/tenvex/expressions/scalar.h create mode 100644 src/tenvex/expressions/scalar_impl.hpp create mode 100644 src/tenvex/expressions/sub.h create mode 100644 src/tenvex/expressions/sub_impl.hpp create mode 100644 src/tenvex/expressions/traits.h create mode 100644 src/tenvex/expressions/vec4.h create mode 100644 src/tenvex/expressions/vec4_impl.hpp delete mode 100644 src/tenvex/internal/add.h delete mode 100644 src/tenvex/internal/add_impl.hpp delete mode 100644 src/tenvex/internal/cross.h delete mode 100644 src/tenvex/internal/cross_impl.hpp delete mode 100644 src/tenvex/internal/dot.h delete mode 100644 src/tenvex/internal/dot_impl.hpp delete mode 100644 src/tenvex/internal/expression.h delete mode 100644 src/tenvex/internal/expression_impl.hpp delete mode 100644 src/tenvex/internal/magnitude.h delete mode 100644 src/tenvex/internal/magnitude_impl.hpp delete mode 100644 src/tenvex/internal/mul.h delete mode 100644 src/tenvex/internal/mul_impl.hpp delete mode 100644 src/tenvex/internal/norm.h delete mode 100644 src/tenvex/internal/norm_impl.hpp delete mode 100644 src/tenvex/internal/scalar.h delete mode 100644 src/tenvex/internal/scalar_impl.hpp delete mode 100644 src/tenvex/internal/sub.h delete mode 100644 src/tenvex/internal/sub_impl.hpp delete mode 100644 src/tenvex/vec4.h delete mode 100644 src/tenvex/vec4_impl.hpp diff --git a/src/tenvex/expressions/add.h b/src/tenvex/expressions/add.h new file mode 100644 index 0000000..0dbb6a5 --- /dev/null +++ b/src/tenvex/expressions/add.h @@ -0,0 +1,36 @@ +#pragma once + +#include "defines.h" +#include "expression.h" +#include "concepts.h" +#include "traits.h" + +#include + +namespace tnvx +{ + +template +struct Add : Expr> +{ + TNVX_INLINE + Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + + [[nodiscard]] TNVX_INLINE + __m128 eval() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Add operator+(const L& l, const R& r) noexcept; + +template +inline constexpr bool is_vec_expr> = true; + +} + +#include "add_impl.hpp" diff --git a/src/tenvex/expressions/add_impl.hpp b/src/tenvex/expressions/add_impl.hpp new file mode 100644 index 0000000..1df6b07 --- /dev/null +++ b/src/tenvex/expressions/add_impl.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "defines.h" +#include "add.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Add::Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept + : _l(l) + , _r(r) +{ +} + +template +[[nodiscard]] TNVX_INLINE +__m128 Add::eval() const noexcept +{ + return _mm_add_ps(_l.eval(), _r.eval()); +} + +template +[[nodiscard]] TNVX_INLINE +Add operator+(const L& l, const R& r) noexcept +{ + return { l, r }; +} + +} diff --git a/src/tenvex/expressions/concepts.h b/src/tenvex/expressions/concepts.h new file mode 100644 index 0000000..59db405 --- /dev/null +++ b/src/tenvex/expressions/concepts.h @@ -0,0 +1,25 @@ +#pragma once + +#include "traits.h" +#include "expression.h" + +#include + +namespace tnvx +{ + +template +concept expression = requires (T t) +{ + { t.eval() } -> std::same_as<__m128>; + { t.self() } -> std::same_as; +} +&& std::is_base_of_v, T>; + +template +concept vec_expr = expression && is_vec_expr; + +template +concept scalar_expr = expression && is_scalar_expr; + +} diff --git a/src/tenvex/internal/defines.h b/src/tenvex/expressions/defines.h similarity index 92% rename from src/tenvex/internal/defines.h rename to src/tenvex/expressions/defines.h index 28f1b98..4eb4064 100644 --- a/src/tenvex/internal/defines.h +++ b/src/tenvex/expressions/defines.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #if defined(_MSC_VER) #define TNVX_INLINE __forceinline @@ -9,4 +9,4 @@ #else #define TNVX_INLINE inline #define TNVX_RESTRICT -#endif +#endif \ No newline at end of file diff --git a/src/tenvex/expressions/expression.h b/src/tenvex/expressions/expression.h new file mode 100644 index 0000000..f309e5e --- /dev/null +++ b/src/tenvex/expressions/expression.h @@ -0,0 +1,19 @@ +#pragma once + +#include "defines.h" + +#include + +namespace tnvx +{ + +template +struct Expr +{ + [[nodiscard]] TNVX_INLINE + const Derived& self() const noexcept; +}; + +} + +#include "expression_impl.hpp" diff --git a/src/tenvex/expressions/expression_impl.hpp b/src/tenvex/expressions/expression_impl.hpp new file mode 100644 index 0000000..c6b60ca --- /dev/null +++ b/src/tenvex/expressions/expression_impl.hpp @@ -0,0 +1,14 @@ +#include "defines.h" +#include "expression.h" + +namespace tnvx +{ + +template +TNVX_INLINE +const Derived& Expr::self() const noexcept +{ + return static_cast(*this); +} + +} diff --git a/src/tenvex/expressions/mul.h b/src/tenvex/expressions/mul.h new file mode 100644 index 0000000..b8e14b0 --- /dev/null +++ b/src/tenvex/expressions/mul.h @@ -0,0 +1,48 @@ +#pragma once + +#include "defines.h" +#include "traits.h" +#include "expression.h" +#include "concepts.h" + +#include "scalar.h" + +#include + +namespace tnvx +{ + +template +struct Mul : Expr> +{ + TNVX_INLINE + Mul(const L& l, const R& r) noexcept; + + [[nodiscard]] TNVX_INLINE + __m128 eval() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Mul operator*(const E& l, float r) noexcept; + +template +[[nodiscard]] TNVX_INLINE +Mul operator*(float l, const E& r) noexcept; + +template +[[nodiscard]] TNVX_INLINE +Mul operator*(const L& l, const R& r) noexcept; + +template inline constexpr bool is_vec_expr> = true; +template inline constexpr bool is_vec_expr> = true; + +template inline constexpr bool is_scalar_expr> = true; + +} + +#include "mul_impl.hpp" diff --git a/src/tenvex/expressions/mul_impl.hpp b/src/tenvex/expressions/mul_impl.hpp new file mode 100644 index 0000000..80278d7 --- /dev/null +++ b/src/tenvex/expressions/mul_impl.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "mul.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Mul::Mul(const L& l, const R& r) noexcept + : _l(l) + , _r(r) +{ +} + +template +TNVX_INLINE +__m128 Mul::eval() const noexcept +{ + return _mm_mul_ps(_l.eval(), _r.eval()); +} + +template +TNVX_INLINE +Mul operator*(const E& l, float r) noexcept +{ + return { l, Scalar(r) }; +} + +template +TNVX_INLINE +Mul operator*(float l, const E& r) noexcept +{ + return { Scalar(l), r }; +} + +template +TNVX_INLINE +Mul operator*(const L& l, const R& r) noexcept +{ + return { l, r }; +} + +} diff --git a/src/tenvex/expressions/scalar.h b/src/tenvex/expressions/scalar.h new file mode 100644 index 0000000..a58a36c --- /dev/null +++ b/src/tenvex/expressions/scalar.h @@ -0,0 +1,30 @@ +#pragma once + +#include "defines.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +#include + +namespace tnvx +{ + +struct Scalar : Expr +{ + TNVX_INLINE + explicit Scalar(float value) noexcept; + + [[nodiscard]] TNVX_INLINE + __m128 eval() const noexcept; + +private: + __m128 _value; +}; + +template<> +inline constexpr bool is_scalar_expr = true; + +} + +#include "scalar_impl.hpp" diff --git a/src/tenvex/expressions/scalar_impl.hpp b/src/tenvex/expressions/scalar_impl.hpp new file mode 100644 index 0000000..4db581f --- /dev/null +++ b/src/tenvex/expressions/scalar_impl.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "scalar.h" + +namespace tnvx +{ + +TNVX_INLINE +Scalar::Scalar(float value) noexcept +{ + _value = _mm_set1_ps(value); +} + +TNVX_INLINE +__m128 Scalar::eval() const noexcept +{ + return _value; +} + +} diff --git a/src/tenvex/expressions/sub.h b/src/tenvex/expressions/sub.h new file mode 100644 index 0000000..65d317f --- /dev/null +++ b/src/tenvex/expressions/sub.h @@ -0,0 +1,36 @@ +#pragma once + +#include "defines.h" +#include "expression.h" +#include "concepts.h" +#include "traits.h" + +#include + +namespace tnvx +{ + +template +struct Sub : Expr> +{ + TNVX_INLINE + Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + + [[nodiscard]] TNVX_INLINE + __m128 eval() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Sub operator-(const L& l, const R& r) noexcept; + +template +inline constexpr bool is_vec_expr> = true; + +} + +#include "sub_impl.hpp" diff --git a/src/tenvex/expressions/sub_impl.hpp b/src/tenvex/expressions/sub_impl.hpp new file mode 100644 index 0000000..eeebe9c --- /dev/null +++ b/src/tenvex/expressions/sub_impl.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "sub.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Sub::Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept + : _l(l) + , _r(r) +{ +} + +template +TNVX_INLINE +__m128 Sub::eval() const noexcept +{ + return _mm_sub_ps(_l.eval(), _r.eval()); +} + +template +TNVX_INLINE +Sub operator-(const L& l, const R& r) noexcept +{ + return { l, r }; +} + +} diff --git a/src/tenvex/expressions/traits.h b/src/tenvex/expressions/traits.h new file mode 100644 index 0000000..0a48524 --- /dev/null +++ b/src/tenvex/expressions/traits.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace tnvx +{ + +template +inline constexpr bool is_stored_by_value_v = std::is_trivially_copyable_v + && std::is_trivially_destructible_v + && sizeof(T) <= 16; + +template +using tnvx_ref_or_value_t = std::conditional_t, T, const T&>; + +template +inline constexpr bool is_scalar_expr = false; + +template +inline constexpr bool is_vec_expr = false; + +} diff --git a/src/tenvex/expressions/vec4.h b/src/tenvex/expressions/vec4.h new file mode 100644 index 0000000..b4b52ec --- /dev/null +++ b/src/tenvex/expressions/vec4.h @@ -0,0 +1,41 @@ +#pragma once + +#include "defines.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +#include + +namespace tnvx +{ + +struct alignas(16) vec4 : Expr +{ + TNVX_INLINE + vec4() noexcept = default; + + TNVX_INLINE + vec4(float x, float y, float z, float w = 0) noexcept; + + template + TNVX_INLINE + vec4(const E& e) noexcept; + + [[nodiscaed]] TNVX_INLINE + __m128 eval() const noexcept; + +private: + __m128 _data; +}; + +template<> +inline constexpr bool is_vec_expr = true; + +TNVX_INLINE +bool approx_eq(const vec4& lhs, const vec4& rhs, float eps = 1e-6f) noexcept; + +TNVX_INLINE +bool operator==(const vec4& lhs, const vec4& rhs) noexcept; + +} diff --git a/src/tenvex/expressions/vec4_impl.hpp b/src/tenvex/expressions/vec4_impl.hpp new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/src/tenvex/expressions/vec4_impl.hpp @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/tenvex/internal/add.h b/src/tenvex/internal/add.h deleted file mode 100644 index f6d52fa..0000000 --- a/src/tenvex/internal/add.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Add : Expr> -{ - inline - Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - -private: - tnvx_type_storage _l; - tnvx_type_storage _r; -}; - -template -[[nodiscard]] inline -Add operator+(const Expr& l, const Expr& r) noexcept; - -} - -#include "add_impl.hpp" diff --git a/src/tenvex/internal/add_impl.hpp b/src/tenvex/internal/add_impl.hpp deleted file mode 100644 index c124370..0000000 --- a/src/tenvex/internal/add_impl.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "add.h" - -namespace tnvx -{ - -template -Add::Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept - : _l(l) - , _r(r) -{ - -} - -template -TNVX_INLINE -__m128 Add::eval() const noexcept -{ - return _mm_add_ps(_l.eval(), _r.eval()); -} - -template -TNVX_INLINE -Add operator+(const Expr& l, const Expr& r) noexcept -{ - return { l.self(), r.self() }; -} - -} // namespace tnvx diff --git a/src/tenvex/internal/cross.h b/src/tenvex/internal/cross.h deleted file mode 100644 index c7b3e94..0000000 --- a/src/tenvex/internal/cross.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Cross : Expr> -{ - inline - Cross(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - -private: - tnvx_type_storage _l; - tnvx_type_storage _r; -}; - -template -[[nodiscard]] inline -Cross cross(const Expr& l, const Expr& r) noexcept; - -} - -#include "cross_impl.hpp" diff --git a/src/tenvex/internal/cross_impl.hpp b/src/tenvex/internal/cross_impl.hpp deleted file mode 100644 index 4f723ca..0000000 --- a/src/tenvex/internal/cross_impl.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "cross.h" - -namespace tnvx -{ - -template -TNVX_INLINE -Cross::Cross(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept - : _l(l) - , _r(r) -{ -} - -template -TNVX_INLINE -__m128 Cross::eval() const noexcept -{ - __m128 a = _l.eval(); - __m128 b = _r.eval(); - - // [ay, az, ax, 0] - __m128 a_yzx = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); - // [by, bz, bx, 0] - __m128 b_yzx = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); - - // [ay*bz, az*bx, ax*by, 0] - __m128 mul0 = _mm_mul_ps(a, b_yzx); - // [az*by, ax*bz, ay*bx, 0] - __m128 mul1 = _mm_mul_ps(a_yzx, b); - - // [ay*bz - az*by, az*bx - ax*bz, ax*by - ay*bx, 0] - __m128 sub = _mm_sub_ps(mul0, mul1); - - // shuffle обратно в [x, y, z, 0] - return _mm_shuffle_ps(sub, sub, _MM_SHUFFLE(3, 0, 2, 1)); -} - -template -Cross cross(const Expr& l, const Expr& r) noexcept -{ - return { l.self(), r.self() }; -} - - -} diff --git a/src/tenvex/internal/dot.h b/src/tenvex/internal/dot.h deleted file mode 100644 index 1727731..0000000 --- a/src/tenvex/internal/dot.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Dot : Expr> -{ - inline - Dot(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - - [[nodiscard]] inline - operator float() const noexcept; - -private: - tnvx_type_storage _l; - tnvx_type_storage _r; -}; - -template -[[nodiscard]] inline -Dot dot(const Expr& l, const Expr& r) noexcept; - -template -[[nodiscard]] inline -float operator*(const Dot& l, float r) noexcept; - -template -[[nodiscard]] inline -float operator*(float l, const Dot& r) noexcept; - -} - -#include "dot_impl.hpp" diff --git a/src/tenvex/internal/dot_impl.hpp b/src/tenvex/internal/dot_impl.hpp deleted file mode 100644 index bc3bce5..0000000 --- a/src/tenvex/internal/dot_impl.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "dot.h" - -namespace tnvx -{ - -template -TNVX_INLINE -Dot::Dot(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept - : _l(l) - , _r(r) -{ -} - -template -TNVX_INLINE -__m128 Dot::eval() const noexcept -{ - __m128 a = _l.eval(); - __m128 b = _r.eval(); - - __m128 mul = _mm_mul_ps(a, b); - __m128 shuf = _mm_shuffle_ps(mul, mul, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sum = _mm_add_ps(mul, shuf); - shuf = _mm_movehl_ps(shuf, sum); - sum = _mm_add_ss(sum, shuf); - return _mm_shuffle_ps(sum, sum, 0); -} - -template -TNVX_INLINE -Dot::operator float() const noexcept -{ - return _mm_cvtss_f32(eval()); -} - -template -TNVX_INLINE -Dot dot(const Expr& l, const Expr& r) noexcept -{ - return { l.self(), r.self() }; -} - -template -TNVX_INLINE -float operator*(const Dot& l, float r) noexcept -{ - return static_cast(l) * r; -} - -template -float operator*(float l, const Dot& r) noexcept -{ - return l * static_cast(r); -} - - - -} diff --git a/src/tenvex/internal/expression.h b/src/tenvex/internal/expression.h deleted file mode 100644 index 4c3a61e..0000000 --- a/src/tenvex/internal/expression.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "defines.h" - -#include -#include -#include - -namespace tnvx -{ - -template -struct Expr -{ - [[nodiscard]] inline - const Derived& self() const noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - - [[nodiscard]] inline - float operator[](size_t i) const noexcept; -}; - -template -concept expression = requires(T a) -{ - { a.eval() } -> std::same_as<__m128>; -} -&& std::derived_from>; - -struct Scalar; - -template -concept vector_expression = expression && !std::same_as; - -template -constexpr bool tnvx_store_by_value = std::is_trivially_copyable_v - && std::is_trivially_destructible_v - && sizeof(T) <= 16; - -template -using tnvx_type_storage = std::conditional_t, T, const T&>; - -} // namespace tnvx - -#include "expression_impl.hpp" diff --git a/src/tenvex/internal/expression_impl.hpp b/src/tenvex/internal/expression_impl.hpp deleted file mode 100644 index c52d41a..0000000 --- a/src/tenvex/internal/expression_impl.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -TNVX_INLINE -const Derived& Expr::self() const noexcept -{ - return static_cast(*this); -} - -template -TNVX_INLINE -__m128 Expr::eval() const noexcept -{ - return self().eval(); -} - -template -TNVX_INLINE -float Expr::operator[](size_t i) const noexcept -{ - alignas(16) float tmp[4]; - _mm_store_ps(tmp, eval()); - return tmp[i]; -} - -} // namespace tnvx \ No newline at end of file diff --git a/src/tenvex/internal/magnitude.h b/src/tenvex/internal/magnitude.h deleted file mode 100644 index 678c214..0000000 --- a/src/tenvex/internal/magnitude.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Magnitude : Expr> -{ - inline - Magnitude(const E& TNVX_RESTRICT e) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - - [[nodiscard]] inline - operator float() const noexcept; - -private: - tnvx_type_storage _e; -}; - -template -[[nodiscard]] inline -Magnitude magnitude(const Expr& e) noexcept; - -} - -#include "magnitude_impl.hpp" diff --git a/src/tenvex/internal/magnitude_impl.hpp b/src/tenvex/internal/magnitude_impl.hpp deleted file mode 100644 index ce2723a..0000000 --- a/src/tenvex/internal/magnitude_impl.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "magnitude.h" -#include "dot.h" - -namespace tnvx -{ - -template -TNVX_INLINE -Magnitude::Magnitude(const E& TNVX_RESTRICT e) noexcept - : _e(e) -{ -} - -template -TNVX_INLINE -__m128 Magnitude::eval() const noexcept -{ - return _mm_sqrt_ss(Dot(_e, _e).eval()); -} - -template -TNVX_INLINE -Magnitude::operator float() const noexcept -{ - return _mm_cvtss_f32(eval()); -} - -template -TNVX_INLINE -Magnitude magnitude(const Expr& e) noexcept -{ - return { e.self() }; -} - -} diff --git a/src/tenvex/internal/mul.h b/src/tenvex/internal/mul.h deleted file mode 100644 index 3d08947..0000000 --- a/src/tenvex/internal/mul.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "expression.h" -#include "scalar.h" - -namespace tnvx -{ - -template -struct Mul : Expr> -{ - inline - Mul(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - -private: - tnvx_type_storage _l; - tnvx_type_storage _r; -}; - -//template -//[[nodiscard]] inline -//Mul operator*(const Expr& l, const Expr& r) noexcept; - -template -[[nodiscard]] inline -Mul operator*(const Expr& l, float r) noexcept; - -template -[[nodiscard]] inline -Mul operator*(float l, const Expr& r) noexcept; - -} - -#include "mul_impl.hpp" diff --git a/src/tenvex/internal/mul_impl.hpp b/src/tenvex/internal/mul_impl.hpp deleted file mode 100644 index 8e6c50f..0000000 --- a/src/tenvex/internal/mul_impl.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "mul.h" - -namespace tnvx -{ - -template -TNVX_INLINE -inline Mul::Mul(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept - : _l(l) - , _r(r) -{ -} - -template -TNVX_INLINE -__m128 Mul::eval() const noexcept -{ - return _mm_mul_ps(_l.eval(), _r.eval()); -} - -//template -//TNVX_INLINE -//Mul operator*(const Expr& l, const Expr& r) noexcept -//{ -// return { l.self(), r.self() }; -//} - -template -TNVX_INLINE -Mul operator*(const Expr& l, float r) noexcept -{ - return { l.self(), Scalar(r) }; -} - -template -TNVX_INLINE -Mul operator*(float l, const Expr& r) noexcept -{ - return { Scalar(l), r.self() }; -} - -} diff --git a/src/tenvex/internal/norm.h b/src/tenvex/internal/norm.h deleted file mode 100644 index dd0432d..0000000 --- a/src/tenvex/internal/norm.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Norm : Expr> -{ - inline - Norm(const E& TNVX_RESTRICT e) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - -private: - tnvx_type_storage _e; -}; - -template -[[nodiscard]] inline -Norm norm(const Expr& e) noexcept; - -} - -#include "norm_impl.hpp" diff --git a/src/tenvex/internal/norm_impl.hpp b/src/tenvex/internal/norm_impl.hpp deleted file mode 100644 index 6ca617e..0000000 --- a/src/tenvex/internal/norm_impl.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "norm.h" -#include "dot.h" - -namespace tnvx -{ - -template -TNVX_INLINE -Norm::Norm(const E& TNVX_RESTRICT e) noexcept - : _e(e) -{ -} - -template -TNVX_INLINE -__m128 Norm::eval() const noexcept -{ - __m128 data = _e.eval(); - __m128 mul = _mm_mul_ps(data, data); - __m128 shuf = _mm_shuffle_ps(mul, mul, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sum = _mm_add_ps(mul, shuf); - shuf = _mm_movehl_ps(shuf, sum); - sum = _mm_add_ss(sum, shuf); - __m128 len = _mm_shuffle_ps(sum, sum, 0); - __m128 sqrt_len = _mm_sqrt_ps(len); - return _mm_div_ps(data, sqrt_len); -} - -template -TNVX_INLINE -Norm norm(const Expr& e) noexcept -{ - return { e.self() }; -} - -} diff --git a/src/tenvex/internal/scalar.h b/src/tenvex/internal/scalar.h deleted file mode 100644 index 2fc298c..0000000 --- a/src/tenvex/internal/scalar.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -struct Scalar : Expr -{ - inline - Scalar(float value) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - - [[nodiscard]] inline - float operator[](size_t) const noexcept; - -private: - float _value; -}; - -} - -#include "scalar_impl.hpp" diff --git a/src/tenvex/internal/scalar_impl.hpp b/src/tenvex/internal/scalar_impl.hpp deleted file mode 100644 index f4804c7..0000000 --- a/src/tenvex/internal/scalar_impl.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "scalar.h" - -namespace tnvx -{ - -TNVX_INLINE -Scalar::Scalar(float value) noexcept - : _value(value) -{ -} - -[[nodiscard]] TNVX_INLINE -__m128 Scalar::eval() const noexcept -{ - return _mm_set1_ps(_value); -} - -[[nodiscard]] TNVX_INLINE -float Scalar::operator[](size_t) const noexcept -{ - return _value; -} - -} diff --git a/src/tenvex/internal/sub.h b/src/tenvex/internal/sub.h deleted file mode 100644 index a762069..0000000 --- a/src/tenvex/internal/sub.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "expression.h" - -namespace tnvx -{ - -template -struct Sub : Expr> -{ - inline - Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - -private: - tnvx_type_storage _l; - tnvx_type_storage _r; -}; - -template -[[nodiscard]] inline -Sub operator-(const Expr& l, const Expr& r) noexcept; - -} - -#include "sub_impl.hpp" diff --git a/src/tenvex/internal/sub_impl.hpp b/src/tenvex/internal/sub_impl.hpp deleted file mode 100644 index cbf092e..0000000 --- a/src/tenvex/internal/sub_impl.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "sub.h" - -namespace tnvx -{ - -template -tnvx::Sub::Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept - : _l(l), _r(r) -{ -} - -template -TNVX_INLINE -__m128 Sub::eval() const noexcept -{ - return _mm_sub_ps(_l.eval(), _r.eval()); -} - -template -TNVX_INLINE -Sub operator-(const Expr& l, const Expr& r) noexcept -{ - return { l.self(), r.self() }; -} - -} diff --git a/src/tenvex/tenvex.h b/src/tenvex/tenvex.h index c10d5f1..b44d4ea 100644 --- a/src/tenvex/tenvex.h +++ b/src/tenvex/tenvex.h @@ -1,12 +1,11 @@ -#pragma once +#pragma once -#include "vec4.h" - -#include "internal/add.h" -#include "internal/sub.h" -#include "internal/mul.h" -#include "internal/dot.h" -#include "internal/cross.h" -#include "internal/norm.h" -#include "internal/magnitude.h" -#include "internal/scalar.h" +#include "expressions/defines.h" +#include "expressions/traits.h" +#include "expressions/expression.h" +#include "expressions/concepts.h" +#include "expressions/add.h" +#include "expressions/sub.h" +#include "expressions/scalar.h" +#include "expressions/mul.h" +#include "expressions/vec4.h" diff --git a/src/tenvex/vec4.h b/src/tenvex/vec4.h deleted file mode 100644 index 03bc9af..0000000 --- a/src/tenvex/vec4.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "internal/expression.h" - -#include - -#include - -namespace tnvx -{ - -struct alignas(16) vec4 : Expr -{ - vec4() = default; - - inline - vec4(float x, float y, float z, float w) noexcept; - - template - inline - vec4(const Expr& expr) noexcept; - - template - inline - vec4& operator=(const Expr& expr) noexcept; - - [[nodiscard]] inline - __m128 eval() const noexcept; - - [[nodiscard]] inline - auto magnitude() const noexcept; - - [[nodiscard]] inline - auto norm() const noexcept; - - [[nodiscard]] inline - float x() const noexcept; - - [[nodiscard]] inline - float y() const noexcept; - - [[nodiscard]] inline - float z() const noexcept; - - [[nodiscard]] inline - float w() const noexcept; - - [[nodiscard]] inline - std::array data() const noexcept; - -private: - __m128 _data; -}; - -inline -bool operator==(const vec4& a, const vec4& b) noexcept; - -inline -bool approx_eq(const vec4& a, const vec4& b, float eps = 1e-3f) noexcept; - -} - -#include "vec4_impl.hpp" diff --git a/src/tenvex/vec4_impl.hpp b/src/tenvex/vec4_impl.hpp deleted file mode 100644 index 133d419..0000000 --- a/src/tenvex/vec4_impl.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -#include "vec4.h" -#include "internal/magnitude.h" -#include "internal/norm.h" - -namespace tnvx -{ - -template -TNVX_INLINE -vec4::vec4(const Expr& expr) noexcept - : _data(expr.eval()) -{ -} - -template -TNVX_INLINE -vec4& vec4::operator=(const Expr& expr) noexcept -{ - _data = expr.eval(); - return *this; -} - -TNVX_INLINE -vec4::vec4(float x, float y, float z, float w) noexcept -{ - _data = _mm_set_ps(w, z, y, x); -} - -TNVX_INLINE -__m128 vec4::eval() const noexcept -{ - return _data; -} - -TNVX_INLINE -auto vec4::magnitude() const noexcept -{ - return Magnitude(*this); -} - -TNVX_INLINE -auto vec4::norm() const noexcept -{ - return Norm(*this); -} - -//TNVX_INLINE -//Magnitude vec4::magnitude() const noexcept -//{ -// return { *this }; -//} -// -//TNVX_INLINE -//Norm vec4::norm() const noexcept -//{ -// return { *this }; -//} - -TNVX_INLINE -float vec4::x() const noexcept -{ - return _mm_cvtss_f32(_data); -} - -TNVX_INLINE -float vec4::y() const noexcept -{ - return _mm_cvtss_f32(_mm_shuffle_ps(_data, _data, _MM_SHUFFLE(1, 1, 1, 1))); -} - -TNVX_INLINE -float vec4::z() const noexcept -{ - return _mm_cvtss_f32(_mm_shuffle_ps(_data, _data, _MM_SHUFFLE(2, 2, 2, 2))); -} - -TNVX_INLINE -float vec4::w() const noexcept -{ - return _mm_cvtss_f32(_mm_shuffle_ps(_data, _data, _MM_SHUFFLE(3, 3, 3, 3))); -} - -TNVX_INLINE -std::array vec4::data() const noexcept -{ - std::array result; - _mm_storeu_ps(result.data(), _data); - return result; -} - -TNVX_INLINE -bool operator==(const vec4& a, const vec4& b) noexcept -{ - return _mm_movemask_ps(_mm_cmpeq_ps(a.eval(), b.eval())) == 0xF; -} - -TNVX_INLINE -bool approx_eq(const vec4& a, const vec4& b, float eps) noexcept -{ - __m128 epsilon = _mm_set1_ps(eps); - __m128 diff = _mm_sub_ps(a.eval(), b.eval()); - __m128 abs_diff = _mm_andnot_ps(_mm_set1_ps(-0.0f), diff); - return _mm_movemask_ps(_mm_cmplt_ps(abs_diff, epsilon)) == 0xF; -} - -} diff --git a/src/tests/vec4_tests.cpp b/src/tests/vec4_tests.cpp index 5186e30..e817aef 100644 --- a/src/tests/vec4_tests.cpp +++ b/src/tests/vec4_tests.cpp @@ -9,7 +9,7 @@ TEST(vec4, add) { vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f }; vec4 b = { 4.0f, 3.0f, 2.0f, 1.0f }; - vec4 check{ 5.0f, 5.0f, 5.0f, 5.0f }; + vec4 check = { 5.0f, 5.0f, 5.0f, 5.0f }; vec4 result = a + b; EXPECT_TRUE(approx_eq(check, result)); @@ -140,6 +140,19 @@ TEST(vec4, expression_c) EXPECT_TRUE(approx_eq(check, result)); } +TEST(vec4, expression_d) +{ + vec4 a = { 1.0f, 2.0f, 3.0f, 0.0f }; + vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f }; + vec4 c = { 1.0f, 0.0f, 1.0f, 0.0f }; + + vec4 check = { 7.243f, 5.657f, 10.071f, 0.0f }; + + vec4 result = magnitude(a) * dot(b, c) + c * 3.0f; + + EXPECT_TRUE(approx_eq(check, result)); +} + TEST(vec4, cross_anticommutative) { vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; From bf74d7163f20fea6f185dc88b181a16e0ec729a3 Mon Sep 17 00:00:00 2001 From: Artem Zyktin Date: Sat, 30 May 2026 19:35:07 +0800 Subject: [PATCH 2/2] Update currenct expressions list --- src/tenvex/expressions/add.h | 8 +- src/tenvex/expressions/add_impl.hpp | 7 +- src/tenvex/expressions/concepts.h | 2 +- src/tenvex/expressions/config.h | 3 + src/tenvex/expressions/core.h | 88 ++++++++++++++++++++++ src/tenvex/expressions/cross3.h | 33 ++++++++ src/tenvex/expressions/cross3_impl.hpp | 30 ++++++++ src/tenvex/expressions/defines.h | 2 +- src/tenvex/expressions/div.h | 35 +++++++++ src/tenvex/expressions/div_impl.hpp | 30 ++++++++ src/tenvex/expressions/dot3.h | 36 +++++++++ src/tenvex/expressions/dot3_impl.h | 37 +++++++++ src/tenvex/expressions/expression.h | 4 +- src/tenvex/expressions/magnitude3.h | 35 +++++++++ src/tenvex/expressions/magnitude3_impl.hpp | 37 +++++++++ src/tenvex/expressions/mul.h | 16 ++-- src/tenvex/expressions/mul_impl.hpp | 10 +-- src/tenvex/expressions/norm3.h | 31 ++++++++ src/tenvex/expressions/norm3_impl.hpp | 29 +++++++ src/tenvex/expressions/scalar.h | 8 +- src/tenvex/expressions/scalar_impl.hpp | 4 +- src/tenvex/expressions/sub.h | 11 +-- src/tenvex/expressions/sub_impl.hpp | 6 +- src/tenvex/expressions/vec4.h | 17 ++--- src/tenvex/expressions/vec4_impl.hpp | 40 +++++++++- src/tenvex/tenvex.h | 9 ++- src/tests/vec4_tests.cpp | 71 +++++++++-------- 27 files changed, 544 insertions(+), 95 deletions(-) create mode 100644 src/tenvex/expressions/config.h create mode 100644 src/tenvex/expressions/core.h create mode 100644 src/tenvex/expressions/cross3.h create mode 100644 src/tenvex/expressions/cross3_impl.hpp create mode 100644 src/tenvex/expressions/div.h create mode 100644 src/tenvex/expressions/div_impl.hpp create mode 100644 src/tenvex/expressions/dot3.h create mode 100644 src/tenvex/expressions/dot3_impl.h create mode 100644 src/tenvex/expressions/magnitude3.h create mode 100644 src/tenvex/expressions/magnitude3_impl.hpp create mode 100644 src/tenvex/expressions/norm3.h create mode 100644 src/tenvex/expressions/norm3_impl.hpp diff --git a/src/tenvex/expressions/add.h b/src/tenvex/expressions/add.h index 0dbb6a5..e9eac64 100644 --- a/src/tenvex/expressions/add.h +++ b/src/tenvex/expressions/add.h @@ -1,12 +1,10 @@ #pragma once -#include "defines.h" +#include "core.h" #include "expression.h" #include "concepts.h" #include "traits.h" -#include - namespace tnvx { @@ -17,7 +15,7 @@ struct Add : Expr> Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; [[nodiscard]] TNVX_INLINE - __m128 eval() const noexcept; + vf4 eval() const noexcept; private: tnvx_ref_or_value_t _l; @@ -26,7 +24,7 @@ private: template [[nodiscard]] TNVX_INLINE -Add operator+(const L& l, const R& r) noexcept; +Add operator+(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; template inline constexpr bool is_vec_expr> = true; diff --git a/src/tenvex/expressions/add_impl.hpp b/src/tenvex/expressions/add_impl.hpp index 1df6b07..f5b894f 100644 --- a/src/tenvex/expressions/add_impl.hpp +++ b/src/tenvex/expressions/add_impl.hpp @@ -1,6 +1,5 @@ #pragma once -#include "defines.h" #include "add.h" namespace tnvx @@ -16,14 +15,14 @@ Add::Add(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept template [[nodiscard]] TNVX_INLINE -__m128 Add::eval() const noexcept +vf4 Add::eval() const noexcept { - return _mm_add_ps(_l.eval(), _r.eval()); + return detail::add(_l.eval(), _r.eval()); } template [[nodiscard]] TNVX_INLINE -Add operator+(const L& l, const R& r) noexcept +Add operator+(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept { return { l, r }; } diff --git a/src/tenvex/expressions/concepts.h b/src/tenvex/expressions/concepts.h index 59db405..f15b4ea 100644 --- a/src/tenvex/expressions/concepts.h +++ b/src/tenvex/expressions/concepts.h @@ -11,7 +11,7 @@ namespace tnvx template concept expression = requires (T t) { - { t.eval() } -> std::same_as<__m128>; + { t.eval() } -> std::same_as; { t.self() } -> std::same_as; } && std::is_base_of_v, T>; diff --git a/src/tenvex/expressions/config.h b/src/tenvex/expressions/config.h new file mode 100644 index 0000000..0f866cf --- /dev/null +++ b/src/tenvex/expressions/config.h @@ -0,0 +1,3 @@ +#pragma once + +#define HAS_SSE42 1 diff --git a/src/tenvex/expressions/core.h b/src/tenvex/expressions/core.h new file mode 100644 index 0000000..c95f5f2 --- /dev/null +++ b/src/tenvex/expressions/core.h @@ -0,0 +1,88 @@ +#pragma once + +#include "config.h" +#include "defines.h" + +#if defined(HAS_SSE42) +#include +using vf4 = __m128; +#else +#endif + +namespace tnvx::detail +{ + +[[nodiscard]] TNVX_INLINE +bool eq(vf4 a, vf4 b) +{ + return _mm_movemask_ps(_mm_cmpeq_ps(a, b)) == 0b1111; +} + +[[nodiscard]] TNVX_INLINE +bool approx_eq(vf4 a, vf4 b, float eps) noexcept +{ + vf4 abs_diff = _mm_andnot_ps(_mm_set1_ps(-0.0f), _mm_sub_ps(a, b)); + return _mm_movemask_ps(_mm_cmple_ps(abs_diff, _mm_set1_ps(eps))) == 0b1111; +} + +[[nodiscard]] TNVX_INLINE +vf4 scalar(float value) noexcept +{ + return _mm_set_ps1(value); +} + +[[nodiscard]] TNVX_INLINE +vf4 add(vf4 l, vf4 r) noexcept +{ + return _mm_add_ps(l, r); +} + +[[nodiscard]] TNVX_INLINE +vf4 sub(vf4 l, vf4 r) noexcept +{ + return _mm_sub_ps(l, r); +} + +[[nodiscard]] TNVX_INLINE +vf4 mul(vf4 l, vf4 r) noexcept +{ + return _mm_mul_ps(l, r); +} + +[[nodiscard]] TNVX_INLINE +vf4 div(vf4 l, vf4 r) noexcept +{ + return _mm_div_ps(l, r); +} + +[[nodiscard]] TNVX_INLINE +vf4 dot3(vf4 l, vf4 r) noexcept +{ + return _mm_dp_ps(l, r, 0b01111111); +} + +[[nodiscard]] TNVX_INLINE +vf4 magnitude3(vf4 v) noexcept +{ + return _mm_sqrt_ps(_mm_dp_ps(v, v, 0b01111111)); +} + +[[nodiscard]] TNVX_INLINE +vf4 norm3(vf4 v) noexcept +{ + return _mm_blend_ps(_mm_div_ps(v, magnitude3(v)), v, 0b1000); +} + +[[nodiscard]] TNVX_INLINE +vf4 cross3(vf4 l, vf4 r) noexcept +{ + vf4 a_yzx = _mm_shuffle_ps(l, l, _MM_SHUFFLE(3, 0, 2, 1)); + vf4 b_yzx = _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 0, 2, 1)); + + vf4 t = _mm_sub_ps(_mm_mul_ps(l, b_yzx), + _mm_mul_ps(a_yzx, r)); + + return _mm_shuffle_ps(t, t, _MM_SHUFFLE(3, 0, 2, 1)); +} + +} diff --git a/src/tenvex/expressions/cross3.h b/src/tenvex/expressions/cross3.h new file mode 100644 index 0000000..7834f00 --- /dev/null +++ b/src/tenvex/expressions/cross3.h @@ -0,0 +1,33 @@ +#pragma once + +#include "core.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +namespace tnvx +{ + +template +struct Cross3 : Expr> +{ + TNVX_INLINE + Cross3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Cross3 cross3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + +template inline constexpr bool is_vec_expr> = true; + +} + +#include "cross3_impl.hpp" diff --git a/src/tenvex/expressions/cross3_impl.hpp b/src/tenvex/expressions/cross3_impl.hpp new file mode 100644 index 0000000..cd13a74 --- /dev/null +++ b/src/tenvex/expressions/cross3_impl.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "cross3.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Cross3::Cross3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept + : _l(l) + , _r(r) +{ +} + +template +TNVX_INLINE +vf4 Cross3::eval() const noexcept +{ + return detail::cross3(_l.eval(), _r.eval()); +} + +template +TNVX_INLINE +Cross3 cross3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept +{ + return { l, r }; +} + +} diff --git a/src/tenvex/expressions/defines.h b/src/tenvex/expressions/defines.h index 4eb4064..ec5d154 100644 --- a/src/tenvex/expressions/defines.h +++ b/src/tenvex/expressions/defines.h @@ -9,4 +9,4 @@ #else #define TNVX_INLINE inline #define TNVX_RESTRICT -#endif \ No newline at end of file +#endif diff --git a/src/tenvex/expressions/div.h b/src/tenvex/expressions/div.h new file mode 100644 index 0000000..eabaf0d --- /dev/null +++ b/src/tenvex/expressions/div.h @@ -0,0 +1,35 @@ +#pragma once + +#include "core.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +#include "scalar.h" + +namespace tnvx +{ + +template +struct Div : Expr> +{ + TNVX_INLINE + Div(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Div operator/(const E& TNVX_RESTRICT l, float r) noexcept; + +template inline constexpr bool is_vec_expr> = true; + +} + +#include "div_impl.hpp" diff --git a/src/tenvex/expressions/div_impl.hpp b/src/tenvex/expressions/div_impl.hpp new file mode 100644 index 0000000..a32acf9 --- /dev/null +++ b/src/tenvex/expressions/div_impl.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "div.h" + +namespace tnvx +{ + +template +TNVX_INLINE +tnvx::Div::Div(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept + : _l(l) + , _r(r) +{ +} + +template +TNVX_INLINE +vf4 Div::eval() const noexcept +{ + return detail::div(_l.eval(), _r.eval()); +} + +template +TNVX_INLINE +Div operator/(const E& TNVX_RESTRICT l, float r) noexcept +{ + return { l, Scalar(r) }; +} + +} diff --git a/src/tenvex/expressions/dot3.h b/src/tenvex/expressions/dot3.h new file mode 100644 index 0000000..f2984d2 --- /dev/null +++ b/src/tenvex/expressions/dot3.h @@ -0,0 +1,36 @@ +#pragma once + +#include "core.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +namespace tnvx +{ + +template +struct Dot3 : Expr> +{ + TNVX_INLINE + Dot3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; + + [[nodiscard]] TNVX_INLINE + operator float() const noexcept; + +private: + tnvx_ref_or_value_t _l; + tnvx_ref_or_value_t _r; +}; + +template +[[nodiscard]] TNVX_INLINE +Dot3 dot3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; + +template inline constexpr bool is_scalar_expr> = true; + +} + +#include "dot3_impl.h" diff --git a/src/tenvex/expressions/dot3_impl.h b/src/tenvex/expressions/dot3_impl.h new file mode 100644 index 0000000..ba55fdc --- /dev/null +++ b/src/tenvex/expressions/dot3_impl.h @@ -0,0 +1,37 @@ +#pragma once + +#include "dot3.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Dot3::Dot3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept + : _l(l) + , _r(r) +{ +} + +template +TNVX_INLINE +vf4 Dot3::eval() const noexcept +{ + return detail::dot3(_l.eval(), _r.eval()); +} + +template +TNVX_INLINE +Dot3::operator float() const noexcept +{ + return _mm_cvtss_f32(eval()); +} + +template +TNVX_INLINE +Dot3 dot3(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept +{ + return { l, r }; +} + +} diff --git a/src/tenvex/expressions/expression.h b/src/tenvex/expressions/expression.h index f309e5e..14e2514 100644 --- a/src/tenvex/expressions/expression.h +++ b/src/tenvex/expressions/expression.h @@ -1,8 +1,6 @@ #pragma once -#include "defines.h" - -#include +#include "core.h" namespace tnvx { diff --git a/src/tenvex/expressions/magnitude3.h b/src/tenvex/expressions/magnitude3.h new file mode 100644 index 0000000..cc28bf2 --- /dev/null +++ b/src/tenvex/expressions/magnitude3.h @@ -0,0 +1,35 @@ +#pragma once + +#include "core.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +namespace tnvx +{ + +template +struct Magn3 : Expr> +{ + TNVX_INLINE + explicit Magn3(const E& TNVX_RESTRICT e) noexcept; + + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; + + [[nodiscard]] TNVX_INLINE + operator float() const noexcept; + +private: + tnvx_ref_or_value_t _e; +}; + +template +TNVX_INLINE +Magn3 magnitude3(const E& TNVX_RESTRICT e) noexcept; + +template inline constexpr bool is_scalar_expr> = true; + +} + +#include "magnitude3_impl.hpp" diff --git a/src/tenvex/expressions/magnitude3_impl.hpp b/src/tenvex/expressions/magnitude3_impl.hpp new file mode 100644 index 0000000..099951f --- /dev/null +++ b/src/tenvex/expressions/magnitude3_impl.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "magnitude3.h" +#include "dot3.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Magn3::Magn3(const E& TNVX_RESTRICT e) noexcept + : _e(e) +{ +} + +template +TNVX_INLINE +vf4 Magn3::eval() const noexcept +{ + return detail::magnitude3(_e.eval()); +} + +template +TNVX_INLINE +Magn3::operator float() const noexcept +{ + return _mm_cvtss_f32(eval()); +} + +template +TNVX_INLINE +Magn3 magnitude3(const E& TNVX_RESTRICT e) noexcept +{ + return Magn3(e); +} + +} diff --git a/src/tenvex/expressions/mul.h b/src/tenvex/expressions/mul.h index b8e14b0..be8478e 100644 --- a/src/tenvex/expressions/mul.h +++ b/src/tenvex/expressions/mul.h @@ -1,14 +1,12 @@ #pragma once -#include "defines.h" -#include "traits.h" +#include "core.h" #include "expression.h" +#include "traits.h" #include "concepts.h" #include "scalar.h" -#include - namespace tnvx { @@ -16,10 +14,10 @@ template struct Mul : Expr> { TNVX_INLINE - Mul(const L& l, const R& r) noexcept; + Mul(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; [[nodiscard]] TNVX_INLINE - __m128 eval() const noexcept; + vf4 eval() const noexcept; private: tnvx_ref_or_value_t _l; @@ -28,15 +26,15 @@ private: template [[nodiscard]] TNVX_INLINE -Mul operator*(const E& l, float r) noexcept; +Mul operator*(const E& TNVX_RESTRICT l, float r) noexcept; template [[nodiscard]] TNVX_INLINE -Mul operator*(float l, const E& r) noexcept; +Mul operator*(float l, const E& TNVX_RESTRICT r) noexcept; template [[nodiscard]] TNVX_INLINE -Mul operator*(const L& l, const R& r) noexcept; +Mul operator*(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; template inline constexpr bool is_vec_expr> = true; template inline constexpr bool is_vec_expr> = true; diff --git a/src/tenvex/expressions/mul_impl.hpp b/src/tenvex/expressions/mul_impl.hpp index 80278d7..efa8464 100644 --- a/src/tenvex/expressions/mul_impl.hpp +++ b/src/tenvex/expressions/mul_impl.hpp @@ -7,7 +7,7 @@ namespace tnvx template TNVX_INLINE -Mul::Mul(const L& l, const R& r) noexcept +Mul::Mul(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept : _l(l) , _r(r) { @@ -15,28 +15,28 @@ Mul::Mul(const L& l, const R& r) noexcept template TNVX_INLINE -__m128 Mul::eval() const noexcept +vf4 Mul::eval() const noexcept { return _mm_mul_ps(_l.eval(), _r.eval()); } template TNVX_INLINE -Mul operator*(const E& l, float r) noexcept +Mul operator*(const E& TNVX_RESTRICT l, float r) noexcept { return { l, Scalar(r) }; } template TNVX_INLINE -Mul operator*(float l, const E& r) noexcept +Mul operator*(float l, const E& TNVX_RESTRICT r) noexcept { return { Scalar(l), r }; } template TNVX_INLINE -Mul operator*(const L& l, const R& r) noexcept +Mul operator*(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept { return { l, r }; } diff --git a/src/tenvex/expressions/norm3.h b/src/tenvex/expressions/norm3.h new file mode 100644 index 0000000..f7a650a --- /dev/null +++ b/src/tenvex/expressions/norm3.h @@ -0,0 +1,31 @@ +#pragma once + +#include "core.h" +#include "expression.h" +#include "traits.h" +#include "concepts.h" + +namespace tnvx +{ + +template +struct Norm3 : Expr> +{ + TNVX_INLINE + explicit Norm3(const E& TNVX_RESTRICT e) noexcept; + + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; + +private: + tnvx_ref_or_value_t _e; +}; + +template +[[nodiscard]] TNVX_INLINE +Norm3 norm3(const E& TNVX_RESTRICT e) noexcept; + +template inline constexpr bool is_vec_expr> = true; + +} +#include "norm3_impl.hpp" diff --git a/src/tenvex/expressions/norm3_impl.hpp b/src/tenvex/expressions/norm3_impl.hpp new file mode 100644 index 0000000..cbf6f6a --- /dev/null +++ b/src/tenvex/expressions/norm3_impl.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "norm3.h" + +namespace tnvx +{ + +template +TNVX_INLINE +Norm3::Norm3(const E& TNVX_RESTRICT e) noexcept + : _e(e) +{ +} + +template +TNVX_INLINE +vf4 Norm3::eval() const noexcept +{ + return detail::norm3(_e.eval()); +} + +template +TNVX_INLINE +Norm3 norm3(const E& TNVX_RESTRICT e) noexcept +{ + return Norm3(e); +} + +} diff --git a/src/tenvex/expressions/scalar.h b/src/tenvex/expressions/scalar.h index a58a36c..53c97e6 100644 --- a/src/tenvex/expressions/scalar.h +++ b/src/tenvex/expressions/scalar.h @@ -1,12 +1,10 @@ #pragma once -#include "defines.h" +#include "core.h" #include "expression.h" #include "traits.h" #include "concepts.h" -#include - namespace tnvx { @@ -16,10 +14,10 @@ struct Scalar : Expr explicit Scalar(float value) noexcept; [[nodiscard]] TNVX_INLINE - __m128 eval() const noexcept; + vf4 eval() const noexcept; private: - __m128 _value; + vf4 _value; }; template<> diff --git a/src/tenvex/expressions/scalar_impl.hpp b/src/tenvex/expressions/scalar_impl.hpp index 4db581f..fe1ee34 100644 --- a/src/tenvex/expressions/scalar_impl.hpp +++ b/src/tenvex/expressions/scalar_impl.hpp @@ -8,11 +8,11 @@ namespace tnvx TNVX_INLINE Scalar::Scalar(float value) noexcept { - _value = _mm_set1_ps(value); + _value = detail::scalar(value); } TNVX_INLINE -__m128 Scalar::eval() const noexcept +vf4 Scalar::eval() const noexcept { return _value; } diff --git a/src/tenvex/expressions/sub.h b/src/tenvex/expressions/sub.h index 65d317f..d5cd754 100644 --- a/src/tenvex/expressions/sub.h +++ b/src/tenvex/expressions/sub.h @@ -1,12 +1,10 @@ #pragma once -#include "defines.h" +#include "core.h" #include "expression.h" #include "concepts.h" #include "traits.h" -#include - namespace tnvx { @@ -17,7 +15,7 @@ struct Sub : Expr> Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; [[nodiscard]] TNVX_INLINE - __m128 eval() const noexcept; + vf4 eval() const noexcept; private: tnvx_ref_or_value_t _l; @@ -26,10 +24,9 @@ private: template [[nodiscard]] TNVX_INLINE -Sub operator-(const L& l, const R& r) noexcept; +Sub operator-(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept; -template -inline constexpr bool is_vec_expr> = true; +template inline constexpr bool is_vec_expr> = true; } diff --git a/src/tenvex/expressions/sub_impl.hpp b/src/tenvex/expressions/sub_impl.hpp index eeebe9c..2864019 100644 --- a/src/tenvex/expressions/sub_impl.hpp +++ b/src/tenvex/expressions/sub_impl.hpp @@ -15,14 +15,14 @@ Sub::Sub(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept template TNVX_INLINE -__m128 Sub::eval() const noexcept +vf4 Sub::eval() const noexcept { - return _mm_sub_ps(_l.eval(), _r.eval()); + return detail::sub(_l.eval(), _r.eval()); } template TNVX_INLINE -Sub operator-(const L& l, const R& r) noexcept +Sub operator-(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept { return { l, r }; } diff --git a/src/tenvex/expressions/vec4.h b/src/tenvex/expressions/vec4.h index b4b52ec..d82f317 100644 --- a/src/tenvex/expressions/vec4.h +++ b/src/tenvex/expressions/vec4.h @@ -1,12 +1,10 @@ #pragma once -#include "defines.h" +#include "core.h" #include "expression.h" #include "traits.h" #include "concepts.h" -#include - namespace tnvx { @@ -20,17 +18,16 @@ struct alignas(16) vec4 : Expr template TNVX_INLINE - vec4(const E& e) noexcept; + vec4(const E& TNVX_RESTRICT e) noexcept; - [[nodiscaed]] TNVX_INLINE - __m128 eval() const noexcept; + [[nodiscard]] TNVX_INLINE + vf4 eval() const noexcept; private: - __m128 _data; + vf4 _data; }; -template<> -inline constexpr bool is_vec_expr = true; +template<> inline constexpr bool is_vec_expr = true; TNVX_INLINE bool approx_eq(const vec4& lhs, const vec4& rhs, float eps = 1e-6f) noexcept; @@ -39,3 +36,5 @@ TNVX_INLINE bool operator==(const vec4& lhs, const vec4& rhs) noexcept; } + +#include "vec4_impl.hpp" diff --git a/src/tenvex/expressions/vec4_impl.hpp b/src/tenvex/expressions/vec4_impl.hpp index 5f28270..73b3659 100644 --- a/src/tenvex/expressions/vec4_impl.hpp +++ b/src/tenvex/expressions/vec4_impl.hpp @@ -1 +1,39 @@ - \ No newline at end of file +#pragma once + +#include "vec4.h" + +namespace tnvx +{ + +TNVX_INLINE +vec4::vec4(float x, float y, float z, float w) noexcept + : _data(_mm_set_ps(w, z, y, x)) +{ +} + +TNVX_INLINE +__m128 vec4::eval() const noexcept +{ + return _data; +} + +template +TNVX_INLINE +vec4::vec4(const E& TNVX_RESTRICT e) noexcept + : _data(e.eval()) +{ +} + +TNVX_INLINE +bool approx_eq(const vec4& lhs, const vec4& rhs, float eps) noexcept +{ + return detail::approx_eq(lhs.eval(), rhs.eval(), eps); +} + +TNVX_INLINE +bool tnvx::operator==(const vec4& lhs, const vec4& rhs) noexcept +{ + return detail::eq(lhs.eval(), rhs.eval()); +} + +} diff --git a/src/tenvex/tenvex.h b/src/tenvex/tenvex.h index b44d4ea..f87fc6b 100644 --- a/src/tenvex/tenvex.h +++ b/src/tenvex/tenvex.h @@ -1,11 +1,12 @@ #pragma once -#include "expressions/defines.h" -#include "expressions/traits.h" -#include "expressions/expression.h" -#include "expressions/concepts.h" #include "expressions/add.h" #include "expressions/sub.h" #include "expressions/scalar.h" #include "expressions/mul.h" +#include "expressions/div.h" +#include "expressions/dot3.h" +#include "expressions/magnitude3.h" +#include "expressions/norm3.h" +#include "expressions/cross3.h" #include "expressions/vec4.h" diff --git a/src/tests/vec4_tests.cpp b/src/tests/vec4_tests.cpp index e817aef..b3e5965 100644 --- a/src/tests/vec4_tests.cpp +++ b/src/tests/vec4_tests.cpp @@ -45,12 +45,21 @@ TEST(vec4, mult_b) EXPECT_TRUE(approx_eq(check, result)); } -TEST(vec4, dot) +TEST(vec4, div) { - vec4 a = { 1.0f, 0.0f, 3.0f, 0.0f }; - vec4 b = { 1.0f, 2.0f, 3.0f, 1.0f }; + vec4 a = { 3.0f, 6.0f, 0.0f, 0.0f }; + float b = 3.0f; + vec4 check = { 1.0f, 2.0f, 0.0f, 0.0f }; + vec4 result = a / b; + EXPECT_TRUE(approx_eq(check, result)); +} + +TEST(vec4, dot3) +{ + vec4 a = { 1.0f, 0.0f, 3.0f, 1.0f }; + vec4 b = { 1.0f, 2.0f, 3.0f, 4.0f }; float check = 10.0f; - float result = dot(a, b); + float result = dot3(a, b); EXPECT_FLOAT_EQ(check, result); } @@ -60,25 +69,25 @@ TEST(vec4, cross) vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f }; vec4 check = { 0.0f, 0.0f, 1.0f, 0.0f }; - vec4 result = cross(a, b); + vec4 result = cross3(a, b); EXPECT_TRUE(approx_eq(check, result)); } TEST(vec4, norm_a) { - vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; - vec4 check = { 1.0f, 0.0f, 0.0f, 0.0f }; - vec4 result = norm(a); + vec4 a = { 1.0f, 0.0f, 0.0f, 1.0f }; + vec4 check = { 1.0f, 0.0f, 0.0f, 1.0f }; + vec4 result = norm3(a); EXPECT_TRUE(approx_eq(check, result)); } TEST(vec4, norm_b) { - vec4 a = { 1.0f, 0.0f, 1.0f, 0.0f }; - vec4 check = { 0.707106f, 0.0f, 0.707106f, 0.0f }; - vec4 result = norm(a); + vec4 a = { 1.0f, 0.0f, 1.0f, 1.0f }; + vec4 check = { 0.707106f, 0.0f, 0.707106f, 1.0f }; + vec4 result = norm3(a); EXPECT_TRUE(approx_eq(check, result)); } @@ -87,7 +96,7 @@ TEST(vec4, magnitude_a) { vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; float check = 1.0f; - float result = magnitude(a); + float result = magnitude3(a); EXPECT_FLOAT_EQ(check, result); } @@ -96,20 +105,20 @@ TEST(vec4, magnitude_b) { vec4 a = { 1.0f, 0.0f, 1.0f, 0.0f }; float check = 1.4142135f; - float result = magnitude(a); + float result = magnitude3(a); EXPECT_FLOAT_EQ(check, result); } TEST(vec4, expression_a) { - vec4 a = { 1.0f, 1.0f, 1.0f, 0.0f }; - vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f }; + vec4 a = { 1.0f, 1.0f, 1.0f, 1.0f }; + vec4 b = { 0.0f, 1.0f, 0.0f, 3.0f }; vec4 c = { 1.15f, 0.0f, 11.0f, 0.0f }; vec4 check = { 3.45f, 0.0f, 33.0f, 0.0f }; - vec4 result = dot(a, b) * 3.0f * c; + vec4 result = dot3(a, b) * 3.0f * c; EXPECT_TRUE(approx_eq(check, result)); } @@ -122,7 +131,7 @@ TEST(vec4, expression_b) vec4 check = { 33.0f, 0.0f, -3.45f, 0.0f }; - vec4 result = dot(a, b) * 3.0f * cross(b, c); + vec4 result = dot3(a, b) * 3.0f * cross3(b, c); EXPECT_TRUE(approx_eq(check, result)); } @@ -133,22 +142,12 @@ TEST(vec4, expression_c) vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f }; vec4 c = { 1.0f, 0.0f, 1.0f, 0.0f }; - vec4 check = { 7.243f, 5.657f, 10.071f, 0.0f }; + vec4 check = { 7.24264050f, 5.65685463f, 10.0710678f, 0.0f }; - vec4 result = norm(a + b * 2.0f) * dot(b, c) + c * 3.0f; + vec4 tmp1 = norm3(a + b * 2.0f) * dot3(b, c); + vec4 tmp2 = c * 3.0f; - EXPECT_TRUE(approx_eq(check, result)); -} - -TEST(vec4, expression_d) -{ - vec4 a = { 1.0f, 2.0f, 3.0f, 0.0f }; - vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f }; - vec4 c = { 1.0f, 0.0f, 1.0f, 0.0f }; - - vec4 check = { 7.243f, 5.657f, 10.071f, 0.0f }; - - vec4 result = magnitude(a) * dot(b, c) + c * 3.0f; + vec4 result = tmp1 + tmp2; EXPECT_TRUE(approx_eq(check, result)); } @@ -157,27 +156,27 @@ TEST(vec4, cross_anticommutative) { vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f }; - EXPECT_TRUE(approx_eq(cross(a, b), cross(b, a) * -1.0f)); + EXPECT_TRUE(approx_eq(cross3(a, b), cross3(b, a) * -1.0f)); } TEST(vec4, dot_commutative) { vec4 a = { 1.0f, 2.0f, 3.0f, 0.0f }; vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f }; - EXPECT_FLOAT_EQ(dot(a, b), dot(b, a)); + EXPECT_FLOAT_EQ(dot3(a, b), dot3(b, a)); } TEST(vec4, norm_magnitude) { vec4 a = { 3.0f, 1.0f, 4.0f, 0.0f }; - EXPECT_NEAR(magnitude(norm(a)), 1.0f, 1e-5f); + EXPECT_NEAR(magnitude3(norm3(a)), 1.0f, 1e-5f); } TEST(vec4, dot_perpendicular) { vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f }; - EXPECT_FLOAT_EQ(dot(a, b), 0.0f); + EXPECT_FLOAT_EQ(dot3(a, b), 0.0f); } TEST(vec4, cross_parallel) @@ -185,7 +184,7 @@ TEST(vec4, cross_parallel) vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f }; vec4 b = { 2.0f, 0.0f, 0.0f, 0.0f }; vec4 check = { 0.0f, 0.0f, 0.0f, 0.0f }; - EXPECT_TRUE(approx_eq(cross(a, b), check)); + EXPECT_TRUE(approx_eq(cross3(a, b), check)); } }