Line data Source code
1 : #pragma once
2 :
3 : #include "IntegerCast.h"
4 :
5 : #include <absl/hash/hash.h>
6 :
7 : #include <algorithm>
8 : #include <array>
9 : #include <functional>
10 : #include <ranges>
11 :
12 : template <size_t N, typename T> class Vector {
13 : public:
14 : using ElementType = T;
15 : using IndexType = int;
16 :
17 7658 : constexpr Vector() : _data{} {};
18 :
19 : explicit constexpr Vector(ElementType const &init)
20 : requires(N > 1u)
21 4 : {
22 4 : std::fill(_data.begin(), _data.end(), init);
23 4 : }
24 :
25 : template <typename... Ts>
26 : constexpr Vector(Ts &&...vals)
27 : requires(sizeof...(Ts) == N)
28 37756 : : _data{std::forward<Ts>(vals)...} {}
29 :
30 : template <typename U>
31 : explicit constexpr Vector(Vector<N, U> const &other)
32 : requires(!std::is_same_v<T, U>)
33 1920 : {
34 1920 : std::ranges::copy(other, begin());
35 1920 : }
36 :
37 : template <typename U>
38 : explicit constexpr Vector(Vector<N, U> &&other)
39 : requires(!std::is_same_v<T, U>)
40 : {
41 : std::ranges::move(std::move(other), begin());
42 : }
43 :
44 25655872 : [[nodiscard]] constexpr ElementType &operator[](auto const i) {
45 25655872 : ASSUME(integerCast<IndexType>(i) < size());
46 25655872 : return _data[integerCast<size_t>(i)];
47 25655872 : }
48 :
49 102962494 : [[nodiscard]] constexpr ElementType const &operator[](auto const i) const {
50 102962494 : ASSUME(integerCast<IndexType>(i) < size());
51 102962494 : return _data[integerCast<size_t>(i)];
52 102962494 : }
53 :
54 13927726 : [[nodiscard]] constexpr ElementType &x() { return (*this)[0]; }
55 47045507 : [[nodiscard]] constexpr ElementType const &x() const { return (*this)[0]; }
56 : [[nodiscard]] constexpr ElementType &y()
57 : requires(N >= 2)
58 11304098 : {
59 11304098 : return (*this)[1];
60 11304098 : }
61 :
62 : [[nodiscard]] constexpr ElementType const &y() const
63 : requires(N >= 2)
64 46978844 : {
65 46978844 : return (*this)[1];
66 46978844 : }
67 :
68 : [[nodiscard]] constexpr ElementType &z()
69 : requires(N >= 3)
70 32010 : {
71 32010 : return (*this)[2];
72 32010 : }
73 :
74 : [[nodiscard]] constexpr ElementType const &z() const
75 : requires(N >= 3)
76 8549160 : {
77 8549160 : return (*this)[2];
78 8549160 : }
79 :
80 : [[nodiscard]] constexpr T *data() { return _data.data(); }
81 : [[nodiscard]] constexpr T const *data() const { return _data.data(); }
82 190166609 : [[nodiscard]] constexpr size_t size() const { return N; }
83 :
84 9864334 : [[nodiscard]] constexpr auto begin() { return _data.begin(); }
85 4945274 : [[nodiscard]] constexpr auto end() { return _data.end(); }
86 70904194 : [[nodiscard]] constexpr auto begin() const { return _data.begin(); }
87 9409750 : [[nodiscard]] constexpr auto end() const { return _data.end(); }
88 : [[nodiscard]] constexpr auto cbegin() const { return _data.cbegin(); }
89 : [[nodiscard]] constexpr auto cend() const { return _data.cend(); }
90 : [[nodiscard]] constexpr auto rbegin() { return _data.rbegin(); }
91 : [[nodiscard]] constexpr auto rend() { return _data.rend(); }
92 : [[nodiscard]] constexpr auto rbegin() const { return _data.rbegin(); }
93 : [[nodiscard]] constexpr auto rend() const { return _data.rend(); }
94 : [[nodiscard]] constexpr auto crbegin() const { return _data.crbegin(); }
95 : [[nodiscard]] constexpr auto crend() const { return _data.crend(); }
96 :
97 10934467 : [[nodiscard]] friend constexpr Vector operator+(Vector const &lhs, Vector const &rhs) {
98 10934467 : return {std::views::zip_transform(std::plus{}, lhs, rhs)};
99 10934467 : }
100 :
101 4413411 : [[nodiscard]] friend constexpr Vector operator-(Vector const &lhs, Vector const &rhs) {
102 4413411 : return {std::views::zip_transform(std::minus{}, lhs, rhs)};
103 4413411 : }
104 :
105 : [[nodiscard]] friend constexpr Vector operator*(Vector const &lhs, Vector const &rhs) {
106 : return {std::views::zip_transform(std::multiplies{}, lhs, rhs)};
107 : }
108 :
109 18830 : [[nodiscard]] friend constexpr Vector operator/(Vector const &lhs, Vector const &rhs) {
110 18830 : return {std::views::zip_transform(std::divides{}, lhs, rhs)};
111 18830 : }
112 :
113 1000 : [[nodiscard]] friend constexpr Vector operator%(Vector const &lhs, Vector const &rhs) {
114 1000 : return {std::views::zip_transform(std::modulus{}, lhs, rhs)};
115 1000 : }
116 :
117 2 : [[nodiscard]] friend constexpr Vector operator-(Vector const &v) {
118 2 : return {std::views::transform(v, std::negate{})};
119 2 : }
120 :
121 4894452 : constexpr Vector &operator+=(Vector const &other) {
122 4894452 : std::ranges::transform(*this, other, this->begin(), std::plus{});
123 4894452 : return *this;
124 4894452 : }
125 :
126 47311 : constexpr Vector &operator-=(Vector const &other) {
127 47311 : std::ranges::transform(*this, other, this->begin(), std::minus{});
128 47311 : return *this;
129 47311 : }
130 :
131 : constexpr Vector &operator*=(Vector const &other) {
132 : std::ranges::transform(*this, other, this->begin(), std::multiplies{});
133 : return *this;
134 : }
135 :
136 : constexpr Vector &operator/=(Vector const &other) {
137 : std::ranges::transform(*this, other, this->begin(), std::divides{});
138 : return *this;
139 : }
140 :
141 : constexpr Vector &operator%=(Vector const &other) {
142 : std::ranges::transform(*this, other, this->begin(), std::modulus{});
143 : return *this;
144 : }
145 :
146 2 : [[nodiscard]] constexpr friend Vector operator+(Vector const &lhs, ElementType const &rhs) {
147 4 : return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e + rhs; })};
148 2 : }
149 :
150 4 : [[nodiscard]] constexpr friend Vector operator-(Vector const &lhs, ElementType const &rhs) {
151 8 : return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e - rhs; })};
152 4 : }
153 :
154 24547 : [[nodiscard]] constexpr friend Vector operator*(Vector const &lhs, ElementType const &rhs) {
155 49094 : return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e * rhs; })};
156 24547 : }
157 :
158 640 : [[nodiscard]] constexpr friend Vector operator/(Vector const &lhs, ElementType const &rhs) {
159 1280 : return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e / rhs; })};
160 640 : }
161 :
162 : [[nodiscard]] constexpr friend Vector operator%(Vector const &lhs, ElementType const &rhs) {
163 : return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e % rhs; })};
164 : }
165 :
166 2 : [[nodiscard]] constexpr friend Vector operator+(ElementType const &lhs, Vector const &rhs) {
167 4 : return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs + e; })};
168 2 : }
169 :
170 : [[nodiscard]] constexpr friend Vector operator-(ElementType const &lhs, Vector const &rhs) {
171 : return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs - e; })};
172 : }
173 :
174 50295 : [[nodiscard]] constexpr friend Vector operator*(ElementType const &lhs, Vector const &rhs) {
175 100590 : return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs * e; })};
176 50295 : }
177 :
178 : [[nodiscard]] constexpr friend Vector operator/(ElementType const &lhs, Vector const &rhs) {
179 : return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs / e; })};
180 : }
181 :
182 : [[nodiscard]] constexpr friend Vector operator%(ElementType const &lhs, Vector const &rhs) {
183 : return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs % e; })};
184 : }
185 :
186 153746 : constexpr auto operator<=>(Vector const &other) const = default;
187 :
188 69398 : template <typename H> [[nodiscard]] friend constexpr H AbslHashValue(H h, Vector const &v) {
189 69398 : return H::combine(std::move(h), v._data);
190 69398 : }
191 :
192 3316 : [[nodiscard]] constexpr friend Vector elementwiseMin(Vector const &lhs, Vector const &rhs) {
193 3316 : return {std::views::zip_transform(
194 6632 : [](ElementType const &l, ElementType const &r) { return std::min(l, r); }, lhs, rhs)};
195 3316 : }
196 :
197 3316 : [[nodiscard]] constexpr friend Vector elementwiseMax(Vector const &lhs, Vector const &rhs) {
198 3316 : return {std::views::zip_transform(
199 6632 : [](ElementType const &l, ElementType const &r) { return std::max(l, r); }, lhs, rhs)};
200 3316 : }
201 :
202 4362915 : [[nodiscard]] constexpr ElementType l1norm() const {
203 4362915 : return std::ranges::fold_left(
204 8725830 : *this | std::views::transform([](auto const &x) { return std::abs(x); }), ElementType{0},
205 4362915 : std::plus{});
206 4362915 : }
207 :
208 : private:
209 : template <std::ranges::sized_range R>
210 : constexpr Vector(R const &r)
211 : requires(!std::is_same_v<std::remove_cvref_t<R>, Vector<N, T>>)
212 : {
213 : DEBUG_ASSERT(std::ranges::size(r) == N);
214 : std::ranges::copy(r, _data.begin());
215 : };
216 :
217 : template <std::ranges::sized_range R>
218 : constexpr Vector(R &&r)
219 : requires(!std::is_same_v<std::remove_cvref_t<R>, Vector<N, T>>)
220 15449836 : {
221 15449836 : DEBUG_ASSERT(std::ranges::size(r) == N);
222 15449836 : std::ranges::move(std::forward<R>(r), _data.begin());
223 15449836 : };
224 :
225 : std::array<ElementType, N> _data;
226 : };
227 :
228 : // Custom specialization of std::hash can be injected in namespace std.
229 : template <size_t N, typename T> struct std::hash<Vector<N, T>> : public absl::Hash<Vector<N, T>> {};
230 :
231 : // Making Vector "tuple-like" to enable structured bindings
232 : template <size_t N, typename T>
233 : struct std::tuple_size<Vector<N, T>> : public integral_constant<std::size_t, N> {};
234 :
235 : template <std::size_t I, size_t N, typename T>
236 : requires(I < N)
237 : struct std::tuple_element<I, Vector<N, T>> {
238 : using type = T;
239 : };
240 :
241 : template <std::size_t I, size_t N, typename T>
242 : requires(I < N)
243 8 : constexpr T &get(Vector<N, T> &v) {
244 8 : return v[I];
245 8 : }
246 :
247 : template <std::size_t I, size_t N, typename T>
248 : requires(I < N)
249 : constexpr T const &get(Vector<N, T> const &v) {
250 : return v[I];
251 : }
252 :
253 : template <std::size_t I, size_t N, typename T>
254 : requires(I < N)
255 8 : constexpr T &&get(Vector<N, T> &&v) {
256 8 : return std::move(get<I>(v));
257 8 : }
258 :
259 : template <std::size_t I, size_t N, typename T>
260 : requires(I < N)
261 : constexpr T const &&get(Vector<N, T> const &&v) {
262 : return std::move(get<I>(v));
263 : }
264 :
265 : template <typename T> using Vec2 = Vector<2u, T>;
266 : template <typename T> using Vec3 = Vector<3u, T>;
|