From e0f2069b19316ebd46bd6136cecb4b822e4edb60 Mon Sep 17 00:00:00 2001 From: Brett Date: Tue, 6 Feb 2024 00:00:35 -0500 Subject: [PATCH] make vec class trivially copyable. Also add a couple new useful constructors --- include/blt/math/vectors.h | 324 ++++++++++++++++++++++++------------- tests/src/main.cpp | 15 ++ 2 files changed, 225 insertions(+), 114 deletions(-) diff --git a/include/blt/math/vectors.h b/include/blt/math/vectors.h index 15232f1..72d9225 100755 --- a/include/blt/math/vectors.h +++ b/include/blt/math/vectors.h @@ -11,141 +11,185 @@ #include #include #include +#include +#include -namespace blt { +namespace blt +{ constexpr float EPSILON = 0.0001f; - static inline constexpr bool f_equal(float v1, float v2) { + static inline constexpr bool f_equal(float v1, float v2) + { return v1 >= v2 - EPSILON && v1 <= v2 + EPSILON; } #define MSVC_COMPILER (!defined(__GNUC__) && !defined(__clang__)) - - template - struct vec { + template + struct vec + { + static_assert(std::is_arithmetic_v && "blt::vec must be created using an arithmetic type!"); private: - T elements[size]; + std::array elements; public: - - vec() { - for (uint32_t i = 0; i < size; i++) - elements[i] = 0; + vec() + { + for (auto& v : elements) + v = static_cast(0); } - vec(std::initializer_list args): vec() { - for (uint32_t i = 0; i < args.size(); i++) - elements[i] = *(args.begin() + i); + /** + * Create a vector with initializer list, if the initializer list doesn't contain enough values to fill this vec, it will use t + * @param t default value to fill with + * @param args list of args + */ + vec(T t, std::initializer_list args) + { + auto b = args.begin(); + for (auto& v : elements) + { + if (b == args.end()) + { + v = t; + continue; + } + v = *b; + ++b; + } } - explicit vec(const T elem[size]) { - for (uint32_t i = 0; i < size; i++) + /** + * Create a vector from an initializer list, if the list doesn't have enough elements it will be filled with the default value (0) + * @param args + */ + vec(std::initializer_list args): vec(static_cast(0), args) + {} + + explicit vec(T t) + { + for (auto& v : elements) + v = t; + } + + explicit vec(const T elem[size]) + { + for (size_t i = 0; i < size; i++) elements[i] = elem[i]; } - vec(const vec& copy): vec(copy.elements) {} - - template - explicit vec(const vec& copy) { - for (uint32_t i = 0; i < std::min(o_size, size); i++) - elements[i] = copy[i]; + explicit vec(std::array elem) + { + auto b = elem.begin(); + for (auto& v : elements) + { + v = *b; + ++b; + } } - vec& operator=(const vec& copy) { - if (© == this) - return *this; - for (uint32_t i = 0; i < size; i++) - elements[i] = copy[i]; - return *this; - } - - [[nodiscard]] inline T x() const { + [[nodiscard]] inline T x() const + { return elements[0]; } - [[nodiscard]] inline T y() const { + [[nodiscard]] inline T y() const + { static_assert(size > 1); return elements[1]; } - [[nodiscard]] inline T z() const { + [[nodiscard]] inline T z() const + { static_assert(size > 2); return elements[2]; } - [[nodiscard]] inline T w() const { + [[nodiscard]] inline T w() const + { static_assert(size > 3); return elements[3]; } - [[nodiscard]] inline T magnitude() const { + [[nodiscard]] inline T magnitude() const + { T total = 0; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) total += elements[i] * elements[i]; return std::sqrt(total); } - [[nodiscard]] inline vec normalize() const { + [[nodiscard]] inline vec normalize() const + { T mag = this->magnitude(); if (mag == 0) return vec(*this); return *this / mag; } - inline T& operator[](int index) { + inline T& operator[](int index) + { return elements[index]; } - inline T operator[](int index) const { + inline T operator[](int index) const + { return elements[index]; } - inline vec& operator=(T v) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator=(T v) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] = v; return *this; } - inline vec operator-() { + inline vec operator-() + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = -elements[i]; return vec{initializer}; } - inline vec& operator+=(const vec& other) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator+=(const vec& other) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] += other[i]; return *this; } - inline vec& operator*=(const vec& other) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator*=(const vec& other) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] *= other[i]; return *this; } - inline vec& operator+=(T f) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator+=(T f) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] += f; return *this; } - inline vec& operator*=(T f) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator*=(T f) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] *= f; return *this; } - inline vec& operator-=(const vec& other) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator-=(const vec& other) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] -= other[i]; return *this; } - inline vec& operator-=(T f) { - for (uint32_t i = 0; i < size; i++) + inline vec& operator-=(T f) + { + for (std::uint32_t i = 0; i < size; i++) elements[i] -= f; return *this; } @@ -153,16 +197,18 @@ namespace blt { /** * performs the dot product of left * right */ - static inline constexpr T dot(const vec& left, const vec& right) { + static inline constexpr T dot(const vec& left, const vec& right) + { T dot = 0; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) dot += left[i] * right[i]; return dot; } static inline constexpr vec cross( const vec& left, const vec& right - ) { + ) + { // cross is only defined on vectors of size 3. 2D could be implemented, which is a TODO static_assert(size == 3); return {left.y() * right.z() - left.z() * right.y(), @@ -172,109 +218,153 @@ namespace blt { static inline constexpr vec project( const vec& u, const vec& v - ) { + ) + { T du = dot(u); T dv = dot(v); return (du / dv) * v; } + + auto begin() + { + return elements.begin(); + } + + auto end() + { + return elements.end(); + } + + auto rbegin() + { + return elements.rbegin(); + } + + auto rend() + { + return elements.rend(); + } + + [[nodiscard]] auto cbegin() const + { + return elements.cbegin(); + } + + [[nodiscard]] auto cend() const + { + return elements.cend(); + } }; - template - inline constexpr vec operator+(const vec& left, const vec& right) { + template + inline constexpr vec operator+(const vec& left, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] + right[i]; return initializer; } - template - inline constexpr vec operator-(const vec& left, const vec& right) { + template + inline constexpr vec operator-(const vec& left, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] - right[i]; return initializer; } - template - inline constexpr vec operator+(const vec& left, T f) { + template + inline constexpr vec operator+(const vec& left, T f) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] + f; return initializer; } - template - inline constexpr vec operator-(const vec& left, T f) { + template + inline constexpr vec operator-(const vec& left, T f) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] + f; return initializer; } - template - inline constexpr vec operator+(T f, const vec& right) { + template + inline constexpr vec operator+(T f, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = f + right[i]; return initializer; } - template - inline constexpr vec operator-(T f, const vec& right) { + template + inline constexpr vec operator-(T f, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = f - right[i]; return initializer; } - template - inline constexpr vec operator*(const vec& left, const vec& right) { + template + inline constexpr vec operator*(const vec& left, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] * right[i]; return initializer; } - template - inline constexpr vec operator*(const vec& left, T f) { + template + inline constexpr vec operator*(const vec& left, T f) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] * f; return initializer; } - template - inline constexpr vec operator*(T f, const vec& right) { + template + inline constexpr vec operator*(T f, const vec& right) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = f * right[i]; return initializer; } - template - inline constexpr vec operator/(const vec& left, T f) { + template + inline constexpr vec operator/(const vec& left, T f) + { vec initializer{}; - for (uint32_t i = 0; i < size; i++) + for (std::uint32_t i = 0; i < size; i++) initializer[i] = left[i] / f; return initializer; } - template - inline constexpr bool operator==(const vec& left, const vec& right) { - for (uint32_t i = 0; i < size; i++) + template + inline constexpr bool operator==(const vec& left, const vec& right) + { + for (std::uint32_t i = 0; i < size; i++) if (left[i] != right[i]) return false; return true; } - template - inline constexpr bool operator!=(const vec& left, const vec& right) { + template + inline constexpr bool operator!=(const vec& left, const vec& right) + { return !(left == right); } - template - inline constexpr bool operator&&(const vec& left, const vec& right) { - for (uint32_t i = 0; i < size; i++) + template + inline constexpr bool operator&&(const vec& left, const vec& right) + { + for (std::uint32_t i = 0; i < size; i++) if (!f_equal(left[i], right[i])) return false; return true; @@ -288,32 +378,35 @@ namespace blt { typedef vec vec3d; typedef vec vec4d; - typedef vec vec2i; - typedef vec vec3i; - typedef vec vec4i; + typedef vec vec2i; + typedef vec vec3i; + typedef vec vec4i; - typedef vec vec2l; - typedef vec vec3l; - typedef vec vec4l; + typedef vec vec2l; + typedef vec vec3l; + typedef vec vec4l; - typedef vec vec2ui; - typedef vec vec3ui; - typedef vec vec4ui; + typedef vec vec2ui; + typedef vec vec3ui; + typedef vec vec4ui; - typedef vec vec2ul; - typedef vec vec3ul; - typedef vec vec4ul; + typedef vec vec2ul; + typedef vec vec3ul; + typedef vec vec4ul; typedef vec2f vec2; typedef vec3f vec3; typedef vec4f vec4; - namespace vec_algorithm { - static inline void findOrthogonalBasis(const vec3& v, vec3& v1, vec3& v2, vec3& v3) { + namespace vec_algorithm + { + static inline void findOrthogonalBasis(const vec3& v, vec3& v1, vec3& v2, vec3& v3) + { v1 = v.normalize(); vec3 arbitraryVector{1, 0, 0}; - if (std::abs(vec3::dot(v, arbitraryVector)) > 0.9) { + if (std::abs(vec3::dot(v, arbitraryVector)) > 0.9) + { arbitraryVector = vec3{0, 1, 0}; } @@ -322,7 +415,8 @@ namespace blt { } // Gram-Schmidt orthonormalization algorithm - static inline void gramSchmidt(std::vector& vectors) { + static inline void gramSchmidt(std::vector& vectors) + { int n = (int) vectors.size(); std::vector basis; @@ -331,10 +425,12 @@ namespace blt { basis[0] = basis[0].normalize(); // iterate over the rest of the vectors - for (int i = 1; i < n; ++i) { + for (int i = 1; i < n; ++i) + { // subtract the projections of the vector onto the previous basis vectors vec3 new_vector = vectors[i]; - for (int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) + { float projection = vec3::dot(vectors[i], basis[j]); new_vector[0] -= projection * basis[j].x(); new_vector[1] -= projection * basis[j].y(); diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 839956a..dc0f0b2 100755 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -56,6 +56,21 @@ int (* func_func_in)(int) = &test_as_func; int main(int argc, const char** argv) { +// BLT_INFO("Is blt::vec3 trivial? %b", std::is_trivial_v); +// BLT_INFO("Is blt::vec3 trivially constructable? %b", std::is_trivially_constructible_v); +// BLT_INFO("Is blt::vec3 trivially copy constructable? %b", std::is_trivially_copy_constructible_v); +// BLT_INFO("Is blt::vec3 trivially copy assignment? %b", std::is_trivially_copy_assignable_v); +// BLT_INFO("Is blt::vec3 trivially copyable? %b", std::is_trivially_copyable_v); +// BLT_INFO("Is blt::vec3 trivially destructable? %b", std::is_trivially_destructible_v); +// BLT_INFO("Is blt::vec3 trivially move constructable? %b", std::is_trivially_move_constructible_v); +// BLT_INFO("Is blt::vec3 trivially move assignable? %b", std::is_trivially_move_assignable_v); +// +// blt::vec3 trivial; +// for (int i = 0; i < 3; i++) +// BLT_TRACE(trivial[i]); +// +// return 0; + blt::arg_parse parser; parser.addArgument(