diff options
author | Sven Göthel <[email protected]> | 2024-05-13 19:40:52 +0200 |
---|---|---|
committer | Sven Göthel <[email protected]> | 2024-05-13 19:40:52 +0200 |
commit | 95c151d99c5c90263f07059eca4c5b7abdd1f3ef (patch) | |
tree | bab9ca27ab1672318959bda3fa5d0a91685a963b | |
parent | e35c1f0276e785627634c08c8d6088a8e5bf1a30 (diff) |
math vec*/rect* alignment: Use (and validate) natural alignment to sizeof(value_type)
-rw-r--r-- | include/jau/math/recti.hpp | 23 | ||||
-rw-r--r-- | include/jau/math/vec2f.hpp | 82 | ||||
-rw-r--r-- | include/jau/math/vec2i.hpp | 31 | ||||
-rw-r--r-- | include/jau/math/vec3f.hpp | 98 | ||||
-rw-r--r-- | include/jau/math/vec4f.hpp | 116 |
5 files changed, 227 insertions, 123 deletions
diff --git a/include/jau/math/recti.hpp b/include/jau/math/recti.hpp index bb24822..e16cc24 100644 --- a/include/jau/math/recti.hpp +++ b/include/jau/math/recti.hpp @@ -36,11 +36,15 @@ namespace jau::math { */ /** - * Rectangle with x, y, width and height integer components. + * Rectangle with x, y, width and height value_type components. + * + * Component and overall alignment is natural as sizeof(value_type), + * i.e. sizeof(value_type) == alignof(value_type) */ template<typename Value_type, - std::enable_if_t<std::is_integral_v<Value_type>, bool> = true> - class RectI { + std::enable_if_t<std::is_integral_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) RectI { public: typedef Value_type value_type; typedef value_type* pointer; @@ -50,6 +54,15 @@ namespace jau::math { typedef value_type* iterator; typedef const value_type* const_iterator; + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 4; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + private: value_type m_x; value_type m_y; @@ -124,7 +137,9 @@ namespace jau::math { } typedef RectI<int> Recti; - static_assert(alignof(int) == alignof(Recti)); + static_assert(4 == Recti::components); + static_assert(sizeof(int) == Recti::value_alignment); + static_assert(sizeof(int) == alignof(Recti)); static_assert(sizeof(int)*4 == sizeof(Recti)); /**@}*/ diff --git a/include/jau/math/vec2f.hpp b/include/jau/math/vec2f.hpp index 915208d..e3c45db 100644 --- a/include/jau/math/vec2f.hpp +++ b/include/jau/math/vec2f.hpp @@ -42,11 +42,15 @@ namespace jau::math { */ /** - * 2D vector using two value_type components. + * 2D vector using two value_type components. + * + * Component and overall alignment is natural as sizeof(value_type), + * i.e. sizeof(value_type) == alignof(value_type) */ template<typename Value_type, - std::enable_if_t<std::is_floating_point_v<Value_type>, bool> = true> - class alignas(Value_type) Vector2F { + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) Vector2F { public: typedef Value_type value_type; typedef value_type* pointer; @@ -56,15 +60,18 @@ namespace jau::math { typedef value_type* iterator; typedef const value_type* const_iterator; - constexpr static const value_type zero = value_type(0); - constexpr static const value_type one = value_type(1); + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); - /** Number of components */ + /** Number of value_type components */ constexpr static const size_t components = 2; - - /** Size in bytes (aligned) */ + + /** Size in bytes with value_alignment */ constexpr static const size_t byte_size = components * sizeof(value_type); - + + constexpr static const value_type zero = value_type(0); + constexpr static const value_type one = value_type(1); + value_type x; value_type y; @@ -353,41 +360,65 @@ namespace jau::math { return out << v.toString(); } + static_assert(sizeof(float) == alignof(float)); // natural alignment (reconsider otherwise) + typedef Vector2F<float> Vec2f; - static_assert(alignof(float) == alignof(Vec2f)); + static_assert(2 == Vec2f::components); + static_assert(sizeof(float) == Vec2f::value_alignment); + static_assert(sizeof(float) == alignof(Vec2f)); + static_assert(sizeof(float)*2 == Vec2f::byte_size); static_assert(sizeof(float)*2 == sizeof(Vec2f)); /** * Point2F alias of Vector2F */ - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - using Point2F = Vector2F<T>; + template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + using Point2F = Vector2F<Value_type>; typedef Point2F<float> Point2f; - static_assert(alignof(float) == alignof(Point2f)); + static_assert(2 == Point2f::components); + static_assert(sizeof(float) == Point2f::value_alignment); + static_assert(sizeof(float) == alignof(Point2f)); + static_assert(sizeof(float)*2 == Point2f::byte_size); static_assert(sizeof(float)*2 == sizeof(Point2f)); /** * Simple compound denoting a ray. - * <p> + * + * Component and overall alignment is as sizeof(value_type), i.e. packed. + * * A ray, also known as a half line, consists out of it's <i>origin</i> * and <i>direction</i>. Hence it is bound to only the <i>origin</i> side, * where the other end is +infinitive. * <pre> * R(t) = R0 + Rd * t with R0 origin, Rd direction and t > 0.0 * </pre> - * </p> */ - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - class alignas(T) Ray2F { - public: + template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) Ray2F { + public: + typedef Value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 4; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + /** Origin of Ray. */ - Point2F<T> orig; + alignas(value_alignment) Point2F<value_type> orig; /** Normalized direction vector of ray. */ - Vector2F<T> dir; + alignas(value_alignment) Vector2F<value_type> dir; std::string toString() const noexcept { return "Ray[orig "+orig.toString()+", dir "+dir.toString() +"]"; } }; @@ -399,9 +430,12 @@ namespace jau::math { } typedef Ray2F<float> Ray2f; - static_assert(alignof(float) == alignof(Ray2f)); + static_assert(4 == Ray2f::components); + static_assert(sizeof(float) == Ray2f::value_alignment); + static_assert(sizeof(float) == alignof(Ray2f)); + static_assert(sizeof(float)*4 == Ray2f::byte_size); static_assert(sizeof(float)*4 == sizeof(Ray2f)); - + /**@}*/ } // namespace jau::math diff --git a/include/jau/math/vec2i.hpp b/include/jau/math/vec2i.hpp index 2fa861f..d3f935a 100644 --- a/include/jau/math/vec2i.hpp +++ b/include/jau/math/vec2i.hpp @@ -42,11 +42,16 @@ namespace jau::math { */ /** - * 2D vector using two integer components. + * 2D vector using two value_type components. + * + * Component and overall alignment is natural as sizeof(value_type), + * i.e. sizeof(value_type) == alignof(value_type) */ template<typename Value_type, - std::enable_if_t<std::is_integral_v<Value_type>, bool> = true> - struct alignas(Value_type) Vector2I { + std::enable_if_t<std::is_integral_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) Vector2I { + public: typedef Value_type value_type; typedef value_type* pointer; typedef const value_type* const_pointer; @@ -55,17 +60,20 @@ namespace jau::math { typedef value_type* iterator; typedef const value_type* const_iterator; + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 2; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + typedef typename jau::float_bytes<sizeof(value_type)>::type float_type; constexpr static const value_type zero = value_type(0); constexpr static const value_type one = value_type(1); - /** Number of components */ - constexpr static const size_t components = 2; - - /** Size in bytes (aligned) */ - constexpr static const size_t byte_size = components * sizeof(value_type); - value_type x; value_type y; @@ -267,7 +275,10 @@ namespace jau::math { } typedef Vector2I<int> Vec2i; - static_assert(alignof(int) == alignof(Vec2i)); + static_assert(2 == Vec2i::components); + static_assert(sizeof(int) == Vec2i::value_alignment); + static_assert(sizeof(int) == alignof(Vec2i)); + static_assert(sizeof(int)*2 == Vec2i::byte_size); static_assert(sizeof(int)*2 == sizeof(Vec2i)); /**@}*/ diff --git a/include/jau/math/vec3f.hpp b/include/jau/math/vec3f.hpp index 5e3b7b9..b4522e7 100644 --- a/include/jau/math/vec3f.hpp +++ b/include/jau/math/vec3f.hpp @@ -30,10 +30,12 @@ #include <cassert> #include <limits> #include <string> + +#include <jau/float_math.hpp> + #include <initializer_list> #include <iostream> -#include <jau/float_math.hpp> #include <jau/math/vec2f.hpp> namespace jau::math { @@ -45,10 +47,14 @@ namespace jau::math { /** * 3D vector using three value_type components. + * + * Component and overall alignment is natural as sizeof(value_type), + * i.e. sizeof(value_type) == alignof(value_type) */ - template<typename Value_type, - std::enable_if_t<std::is_floating_point_v<Value_type>, bool> = true> - class alignas(Value_type) Vector3F { + template <typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) Vector3F { public: typedef Value_type value_type; typedef value_type* pointer; @@ -58,17 +64,20 @@ namespace jau::math { typedef value_type* iterator; typedef const value_type* const_iterator; + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 3; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + typedef Vector2F<value_type, std::is_floating_point_v<Value_type>> Vec2; constexpr static const value_type zero = value_type(0); - constexpr static const value_type one = value_type(1); + constexpr static const value_type one = value_type(1); - /** Number of components */ - constexpr static const size_t components = 3; - - /** Size in bytes (aligned) */ - constexpr static const size_t byte_size = components * sizeof(value_type); - value_type x; value_type y; value_type z; @@ -115,12 +124,8 @@ namespace jau::math { constexpr iterator begin() noexcept { return &x; } /** xyz = this, returns xyz. */ - constexpr iterator get(iterator xyz) const noexcept { - xyz[0] = x; - xyz[1] = y; - xyz[2] = z; - return xyz; - } + constexpr iterator get(iterator xyz) const noexcept + { xyz[0] = x; xyz[1] = y; xyz[2] = z; return xyz; } constexpr bool equals(const Vector3F& o, const value_type epsilon=std::numeric_limits<value_type>::epsilon()) const noexcept { if( this == &o ) { @@ -368,40 +373,68 @@ namespace jau::math { return out << v.toString(); } + static_assert(3 == Vector3F<double>::components); + static_assert(sizeof(double) == Vector3F<double>::value_alignment); + static_assert(sizeof(double) == alignof(Vector3F<double>)); + static_assert(sizeof(double)*3 == Vector3F<double>::byte_size); + static_assert(sizeof(double)*3 == sizeof(Vector3F<double>)); + typedef Vector3F<float> Vec3f; - static_assert(alignof(float) == alignof(Vec3f)); + static_assert(3 == Vec3f::components); + static_assert(sizeof(float) == Vec3f::value_alignment); + static_assert(sizeof(float) == alignof(Vec3f)); + static_assert(sizeof(float)*3 == Vec3f::byte_size); static_assert(sizeof(float)*3 == sizeof(Vec3f)); /** * Point3F alias of Vector3F */ - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - using Point3F = Vector3F<T>; + template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + using Point3F = Vector3F<Value_type>; typedef Point3F<float> Point3f; - static_assert(alignof(float) == alignof(Point3f)); + static_assert(3 == Point3f::components); + static_assert(sizeof(float) == Point3f::value_alignment); + static_assert(sizeof(float) == alignof(Point3f)); + static_assert(sizeof(float)*3 == Point3f::byte_size); static_assert(sizeof(float)*3 == sizeof(Point3f)); /** * Simple compound denoting a ray. - * <p> + * + * Component and overall alignment is as sizeof(value_type), i.e. packed. + * * A ray, also known as a half line, consists out of it's <i>origin</i> * and <i>direction</i>. Hence it is bound to only the <i>origin</i> side, * where the other end is +infinitive. * <pre> * R(t) = R0 + Rd * t with R0 origin, Rd direction and t > 0.0 * </pre> - * </p> */ - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - struct alignas(T) Ray3F { + template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type>, bool> = true> + class alignas(sizeof(Value_type)) Ray3F { + public: + typedef Value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 6; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + /** Origin of Ray. */ - Point3F<T> orig; + alignas(value_alignment) Point3F<value_type> orig; /** Normalized direction vector of ray. */ - Vector3F<T> dir; + alignas(value_alignment) Vector3F<value_type> dir; std::string toString() const noexcept { return "Ray[orig "+orig.toString()+", dir "+dir.toString() +"]"; } }; @@ -413,9 +446,12 @@ namespace jau::math { } typedef Ray3F<float> Ray3f; - static_assert(alignof(float) == alignof(Ray3f)); + static_assert(6 == Ray3f::components); + static_assert(sizeof(float) == Ray3f::value_alignment); + static_assert(sizeof(float) == alignof(Ray3f)); + static_assert(sizeof(float)*6 == Ray3f::byte_size); static_assert(sizeof(float)*6 == sizeof(Ray3f)); - + /**@}*/ } // namespace jau::math diff --git a/include/jau/math/vec4f.hpp b/include/jau/math/vec4f.hpp index f0e89c5..8c9ef7d 100644 --- a/include/jau/math/vec4f.hpp +++ b/include/jau/math/vec4f.hpp @@ -31,9 +31,11 @@ #include <limits> #include <string> #include <initializer_list> -#include <iostream> #include <jau/float_math.hpp> + +#include <iostream> + #include <jau/math/vec3f.hpp> namespace jau::math { @@ -45,10 +47,14 @@ namespace jau::math { /** * 4D vector using four value_type components. + * + * Component and overall alignment is natural as sizeof(value_type), + * i.e. sizeof(value_type) == alignof(value_type) */ - template<typename Value_type, - std::enable_if_t<std::is_floating_point_v<Value_type>, bool> = true> - class alignas(Value_type) Vector4F { + template <typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + class alignas(sizeof(Value_type)) Vector4F { public: typedef Value_type value_type; typedef value_type* pointer; @@ -58,17 +64,20 @@ namespace jau::math { typedef value_type* iterator; typedef const value_type* const_iterator; + /** value alignment is sizeof(value_type) */ + constexpr static int value_alignment = sizeof(value_type); + + /** Number of value_type components */ + constexpr static const size_t components = 4; + + /** Size in bytes with value_alignment */ + constexpr static const size_t byte_size = components * sizeof(value_type); + typedef Vector3F<value_type, std::is_floating_point_v<Value_type>> Vec3; constexpr static const value_type zero = value_type(0); - constexpr static const value_type one = value_type(1); + constexpr static const value_type one = value_type(1); - /** Number of components */ - constexpr static const size_t components = 4; - - /** Size in bytes (aligned) */ - constexpr static const size_t byte_size = components * sizeof(value_type); - value_type x; value_type y; value_type z; @@ -116,24 +125,15 @@ namespace jau::math { constexpr iterator begin() noexcept { return &x; } /** xyzw = this, returns xyzw. */ - constexpr iterator get(iterator xyzw) const noexcept { - xyzw[0] = x; - xyzw[1] = y; - xyzw[2] = z; - xyzw[3] = w; - return xyzw; - } + constexpr iterator get(iterator xyzw) const noexcept + { xyzw[0] = x; xyzw[1] = y; xyzw[2] = z; xyzw[3] = w; return xyzw; } /** out = { this.x, this.y, this.z } dropping w, returns out. */ - constexpr Vec3& getVec3(Vec3& out) const noexcept { - out.x = x; - out.y = y; - out.z = z; - return out; - } + constexpr Vec3& getVec3(Vec3& out) const noexcept + { out.x = x; out.y = y; out.z = z; return out; } - constexpr bool operator==(const Vector4F& rhs ) const noexcept { - if( this == &rhs ) { + constexpr bool operator==(const Vector4F& rhs) const noexcept { + if (this == &rhs) { return true; } return jau::is_zero(x - rhs.x) && jau::is_zero(y - rhs.y) && @@ -174,9 +174,8 @@ namespace jau::math { } /** this = this - rhs, returns this. */ - constexpr Vector4F& operator-=(const Vector4F& rhs ) noexcept { - x-=rhs.x; y-=rhs.y; z-=rhs.z; w-=rhs.w; - return *this; + constexpr Vector4F& operator-=(const Vector4F& rhs ) noexcept + { x-=rhs.x; y-=rhs.y; z-=rhs.z; w-=rhs.w; return *this; } /** @@ -184,22 +183,18 @@ namespace jau::math { * @param s scale factor * @return this instance */ - constexpr Vector4F& operator*=(const value_type s ) noexcept { - x*=s; y*=s; z*=s; w*=s; - return *this; - } + constexpr Vector4F& operator*=(const value_type s ) noexcept + { x*=s; y*=s; z*=s; w*=s; return *this; } /** * Divide this vector with given scale factor * @param s scale factor * @return this instance */ - constexpr Vector4F& operator/=(const value_type s ) noexcept { - x/=s; y/=s; z/=s; w/=s; - return *this; - } + constexpr Vector4F& operator/=(const value_type s ) noexcept + { x/=s; y/=s; z/=s; w/=s; return *this; } - std::string toString() const noexcept { return std::to_string(x)+" / "+std::to_string(y)+" / "+std::to_string(z)+" / "+std::to_string(w); } + std::string toString() const noexcept { return std::to_string(x) + " / " + std::to_string(y) + " / " + std::to_string(z) + " / " + std::to_string(w); } constexpr bool is_zero() const noexcept { return jau::is_zero(x) && jau::is_zero(y) && jau::is_zero(z) && jau::is_zero(w); @@ -224,7 +219,7 @@ namespace jau::math { */ constexpr Vector4F& normalize() noexcept { const value_type lengthSq = length_sq(); - if ( jau::is_zero( lengthSq ) ) { + if (jau::is_zero(lengthSq)) { x = zero; y = zero; z = zero; @@ -263,17 +258,17 @@ namespace jau::math { constexpr_cxx23 bool intersects(const Vector4F& o) const noexcept { const value_type eps = std::numeric_limits<value_type>::epsilon(); - if( std::abs(x-o.x) >= eps || std::abs(y-o.y) >= eps || - std::abs(z-o.z) >= eps || std::abs(w-o.w) >= eps ) { + if (std::abs(x - o.x) >= eps || std::abs(y - o.y) >= eps || + std::abs(z - o.z) >= eps || std::abs(w - o.w) >= eps) { return false; } return true; } }; - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - constexpr Vector4F<T> operator+(const Vector4F<T>& lhs, const Vector4F<T>& rhs ) noexcept { + template <typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> + constexpr Vector4F<T> operator+(const Vector4F<T>& lhs, const Vector4F<T>& rhs) noexcept { // Returning a Vector4 object from the returned reference of operator+=() // may hinder copy-elision or "named return value optimization" (NRVO). // return Vector4<T>(lhs) += rhs; @@ -314,29 +309,42 @@ namespace jau::math { Vector3F<T> r; v.getVec3(r); return r; } - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> + template <typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> std::ostream& operator<<(std::ostream& out, const Vector4F<T>& v) noexcept { return out << v.toString(); } + static_assert(4 == Vector4F<double>::components); + static_assert(sizeof(double) == Vector4F<double>::value_alignment); + static_assert(sizeof(double) == alignof(Vector4F<double>)); + static_assert(sizeof(double) * 4 == Vector4F<double>::byte_size); + static_assert(sizeof(double) * 4 == sizeof(Vector4F<double>)); + typedef Vector4F<float> Vec4f; - static_assert(alignof(float) == alignof(Vec4f)); - static_assert(sizeof(float)*4 == sizeof(Vec4f)); + static_assert(4 == Vec4f::components); + static_assert(sizeof(float) == Vec4f::value_alignment); + static_assert(sizeof(float) == alignof(Vec4f)); + static_assert(sizeof(float) * 4 == Vec4f::byte_size); + static_assert(sizeof(float) * 4 == sizeof(Vec4f)); /** * Point4F alias of Vector4F */ - template<typename T, - std::enable_if_t<std::is_floating_point_v<T>, bool> = true> - using Point4F = Vector4F<T>; + template <typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type> && + sizeof(Value_type) == alignof(Value_type), bool> = true> + using Point4F = Vector4F<Value_type>; typedef Point4F<float> Point4f; - static_assert(alignof(float) == alignof(Point4f)); - static_assert(sizeof(float)*4 == sizeof(Point4f)); + static_assert(4 == Point4f::components); + static_assert(sizeof(float) == Point4f::value_alignment); + static_assert(sizeof(float) == alignof(Point4f)); + static_assert(sizeof(float) * 4 == Point4f::byte_size); + static_assert(sizeof(float) * 4 == sizeof(Point4f)); /**@}*/ -} // namespace jau::math +} // namespace jau::math #endif /* JAU_VEC4F_HPP_ */ |