sandbox
Loading...
Searching...
No Matches
vector.hpp
1#ifndef LIBSBX_MATH_VECTOR_HPP_
2#define LIBSBX_MATH_VECTOR_HPP_
3
4#include <array>
5#include <cmath>
6#include <ranges>
7
8#include <libsbx/utility/make_array.hpp>
9#include <libsbx/utility/assert.hpp>
10#include <libsbx/utility/zip.hpp>
12
13#include <libsbx/math/concepts.hpp>
14
15namespace sbx::math {
16
17template<std::size_t Size, scalar Type>
18requires (Size > 1u)
20
21 template<std::size_t S, scalar T>
22 requires (S > 1u)
23 friend class basic_vector;
24
25public:
26
27 using value_type = Type;
28 using reference = value_type&;
29 using const_reference = const value_type&;
30 using size_type = std::size_t;
31 using length_type = std::float_t;
32
33 template<scalar Other = value_type>
34 constexpr basic_vector(Other value = Other{0}) noexcept
35 : _components{utility::make_array<value_type, Size>(value)} { }
36
37 template<scalar Other = value_type>
38 constexpr basic_vector(const basic_vector<Size, Other>& other) noexcept
39 : _components{utility::make_array<value_type, Size>(other._components)} { }
40
41 constexpr auto data() noexcept -> value_type* {
42 return _components.data();
43 }
44
45 [[nodiscard]] constexpr auto operator[](size_type index) noexcept -> reference {
46 return _components[index];
47 }
48
49 [[nodiscard]] constexpr auto operator[](size_type index) const noexcept -> const_reference {
50 return _components[index];
51 }
52
53 template<scalar Other>
54 constexpr auto operator+=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
55 for (auto i : std::views::iota(0u, Size)) {
56 _components[i] += static_cast<value_type>(other[i]);
57 }
58
59 return *this;
60 }
61
62 template<scalar Other>
63 constexpr auto operator-=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
64 for (auto i : std::views::iota(0u, Size)) {
65 _components[i] -= static_cast<value_type>(other[i]);
66 }
67
68 return *this;
69 }
70
71 template<scalar Other>
72 constexpr auto operator*=(Other scalar) noexcept -> basic_vector& {
73 for (auto i : std::views::iota(0u, Size)) {
74 _components[i] *= static_cast<value_type>(scalar);
75 }
76
77 return *this;
78 }
79
80 template<scalar Other>
81 constexpr auto operator*=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
82 for (auto i : std::views::iota(0u, Size)) {
83 _components[i] *= static_cast<value_type>(other[i]);
84 }
85
86 return *this;
87 }
88
89 template<scalar Other>
90 constexpr auto operator/=(Other scalar) noexcept -> basic_vector& {
91 utility::assert_that(!comparision_traits<Other>::equal(scalar, static_cast<Other>(0)), "Division by zero");
92
93 for (auto i : std::views::iota(0u, Size)) {
94 _components[i] /= static_cast<value_type>(scalar);
95 }
96
97 return *this;
98 }
99
100 [[nodiscard]] constexpr auto length_squared() const noexcept -> length_type {
101 auto result = static_cast<length_type>(0);
102
103 for (auto i : std::views::iota(0u, Size)) {
104 result += static_cast<length_type>(_components[i] * _components[i]);
105 }
106
107 return result;
108 }
109
110 [[nodiscard]] constexpr auto length() const noexcept -> length_type {
111 return std::sqrt(length_squared());
112 }
113
114 constexpr auto normalize() noexcept -> basic_vector& {
115 const auto length_squared = this->length_squared();
116
117 if (!comparision_traits<length_type>::equal(length_squared, static_cast<length_type>(0))) {
118 *this /= std::sqrt(length_squared);
119 }
120
121 return *this;
122 }
123
124protected:
125
126 template<std::convertible_to<value_type>... Args>
127 requires (sizeof...(Args) == Size)
128 constexpr basic_vector(Args&&... args) noexcept
129 : _components{utility::make_array<value_type, Size>(std::forward<Args>(args)...)} { }
130
131 constexpr basic_vector(std::array<value_type, Size>&& components) noexcept
132 : _components{std::move(components)} { }
133
134 template<scalar Other>
135 [[nodiscard]] static constexpr auto fill(Other value) noexcept -> basic_vector {
136 return basic_vector{value};
137 }
138
139 template<std::size_t Index, scalar Other>
140 [[nodiscard]] static constexpr auto axis(Other value) noexcept -> basic_vector {
141 return basic_vector{utility::make_array<value_type, Size, Index>(value)};
142 }
143
144private:
145
146 std::array<Type, Size> _components;
147
148}; // class basic_vector
149
150template<std::size_t Size, scalar Lhs, scalar Rhs>
151[[nodiscard]] constexpr auto operator==(const basic_vector<Size, Lhs>& lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> bool {
152 for (auto i : std::views::iota(0u, Size)) {
153 if (!comparision_traits<Lhs>::equal(lhs[i], rhs[i])) {
154 return false;
155 }
156 }
157
158 return true;
159}
160
161template<std::size_t Size, scalar Lhs, scalar Rhs>
162[[nodiscard]] constexpr auto operator+(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
163 return lhs += rhs;
164}
165
166template<std::size_t Size, scalar Lhs, scalar Rhs>
167[[nodiscard]] constexpr auto operator-(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
168 return lhs -= rhs;
169}
170
171template<std::size_t Size, scalar Lhs, scalar Rhs>
172[[nodiscard]] constexpr auto operator*(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
173 return lhs *= scalar;
174}
175
176template<std::size_t Size, scalar Lhs, scalar Rhs>
177[[nodiscard]] constexpr auto operator/(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
178 return lhs /= scalar;
179}
180
181} // namespace sbx::math
182
183#endif // LIBSBX_MATH_VECTOR_HPP_
Definition: vector.hpp:19
Definition: concepts.hpp:59