HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
numeric_array.hpp
1// Copyright Take Vos 2020-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../os_detect.hpp"
8#include "../concepts.hpp"
9#include "../cast.hpp"
10#include "../type_traits.hpp"
11#if TT_PROCESSOR == TT_CPU_X64
12#include "f32x4_sse.hpp"
13#endif
14
15#include <cstdint>
16#include <ostream>
17#include <string>
18#include <array>
19#include <type_traits>
20#include <concepts>
21#include <bit>
22#include <climits>
23
24namespace tt {
25
26template<arithmetic T, ssize_t N>
28public:
29 static_assert(N >= 0);
30
32 using value_type = typename container_type::value_type;
33 using size_type = typename container_type::size_type;
34 using difference_type = typename container_type::difference_type;
35 using reference = typename container_type::reference;
36 using const_reference = typename container_type::const_reference;
37 using pointer = typename container_type::pointer;
38 using const_pointer = typename container_type::const_pointer;
39 using iterator = typename container_type::iterator;
40 using const_iterator = typename container_type::const_iterator;
41
42 constexpr numeric_array() noexcept = default;
43 constexpr numeric_array(numeric_array const &rhs) noexcept = default;
44 constexpr numeric_array(numeric_array &&rhs) noexcept = default;
45 constexpr numeric_array &operator=(numeric_array const &rhs) noexcept = default;
46 constexpr numeric_array &operator=(numeric_array &&rhs) noexcept = default;
47
48 [[nodiscard]] constexpr numeric_array(std::initializer_list<T> rhs) noexcept : v()
49 {
50 auto src = std::begin(rhs);
51 auto dst = std::begin(v);
52
53 // Copy all values from the initializer list.
54 while (src != std::end(rhs) && dst != std::end(v)) {
55 *(dst++) = *(src++);
56 }
57
58 tt_axiom(
59 dst != std::end(v) || src == std::end(rhs),
60 "Expecting the std:initializer_list size to be <= to the size of the numeric array");
61
62 // Set all other elements to zero
63 while (dst != std::end(v)) {
64 *(dst++) = {};
65 }
66 }
67
68 [[nodiscard]] constexpr numeric_array(T const &first) noexcept requires(N == 1) : numeric_array({first}) {}
69
70 template<arithmetic... Rest>
71 requires(sizeof...(Rest) + 2 <= N)
72 [[nodiscard]] constexpr numeric_array(T const &first, T const &second, Rest const &...rest) noexcept :
73 numeric_array({first, second, narrow_cast<T>(rest)...})
74 {
75 }
76
77 [[nodiscard]] static constexpr numeric_array broadcast(T rhs) noexcept
78 {
79 auto r = numeric_array{};
80 for (ssize_t i = 0; i != N; ++i) {
81 r[i] = rhs;
82 }
83 return r;
84 }
85
86 [[nodiscard]] numeric_array(std::array<T,N> const &rhs) noexcept : v(rhs) {}
87
88 numeric_array &operator=(std::array<T,N> const &rhs) noexcept
89 {
90 v = rhs;
91 return *this;
92 }
93
94 [[nodiscard]] operator std::array<T,N>() const noexcept
95 {
96 return v;
97 }
98
99 template<arithmetic U, ssize_t M>
100 [[nodiscard]] explicit constexpr numeric_array(numeric_array<U, M> const &rhs) noexcept : v()
101 {
102 auto src = std::begin(rhs);
103 auto dst = std::begin(v);
104 auto src_last = std::end(rhs);
105 auto dst_last = std::end(v);
106
107 while (src != src_last && dst != dst_last) {
108 *(dst++) = narrow_cast<T>(*(src++));
109 }
110 while (dst != dst_last) {
111 *(dst++) = T{};
112 }
113 while (src != src_last) {
114 tt_axiom(*(src++) == U{});
115 }
116 }
117
118 template<arithmetic U, ssize_t M>
119 [[nodiscard]] explicit constexpr operator numeric_array<U, M>() const noexcept
120 {
121 auto r = std::array<U, M>{};
122
123 auto src = std::begin(v);
124 auto dst = std::begin(r);
125 auto src_last = std::end(v);
126 auto dst_last = std::end(r);
127
128 while (src != src_last && dst != dst_last) {
129 *(dst++) = narrow_cast<U>(*(src++));
130 }
131 while (dst != dst_last) {
132 *(dst++) = U{};
133 }
134 while (src != src_last) {
135 tt_axiom(*(src++) == T{});
136 }
137
138 return r;
139 }
140
141 [[nodiscard]] constexpr T const &operator[](ssize_t i) const noexcept
142 {
143 tt_axiom(i < N);
144 return v[i];
145 }
146
147 [[nodiscard]] constexpr T &operator[](ssize_t i) noexcept
148 {
149 tt_axiom(i < N);
150 return v[i];
151 }
152
153 [[nodiscard]] constexpr reference front() noexcept
154 {
155 return v.front();
156 }
157
158 [[nodiscard]] constexpr const_reference front() const noexcept
159 {
160 return v.front();
161 }
162
163 [[nodiscard]] constexpr reference back() noexcept
164 {
165 return v.back();
166 }
167
168 [[nodiscard]] constexpr const_reference back() const noexcept
169 {
170 return v.back();
171 }
172
173 [[nodiscard]] constexpr pointer data() noexcept
174 {
175 return v.data();
176 }
177
178 [[nodiscard]] constexpr const_pointer data() const noexcept
179 {
180 return v.data();
181 }
182
183 [[nodiscard]] constexpr iterator begin() noexcept
184 {
185 return v.begin();
186 }
187
188 [[nodiscard]] constexpr const_iterator begin() const noexcept
189 {
190 return v.begin();
191 }
192
193 [[nodiscard]] constexpr const_iterator cbegin() const noexcept
194 {
195 return v.cbegin();
196 }
197
198 [[nodiscard]] constexpr iterator end() noexcept
199 {
200 return v.end();
201 }
202
203 [[nodiscard]] constexpr const_iterator end() const noexcept
204 {
205 return v.end();
206 }
207
208 [[nodiscard]] constexpr const_iterator cend() const noexcept
209 {
210 return v.cend();
211 }
212
213 [[nodiscard]] constexpr bool empty() const noexcept
214 {
215 return v.empty();
216 }
217
218 [[nodiscard]] constexpr size_type size() const noexcept
219 {
220 return v.size();
221 }
222
223 [[nodiscard]] constexpr size_type max_size() const noexcept
224 {
225 return v.max_size();
226 }
227
228 constexpr bool is_point() const noexcept
229 {
230 return v.back() != T{};
231 }
232
233 constexpr bool is_vector() const noexcept
234 {
235 return v.back() == T{};
236 }
237
238 constexpr bool is_opaque() const noexcept
239 {
240 return a() == T{1};
241 }
242
243 constexpr bool is_transparent() const noexcept
244 {
245 return a() == T{0};
246 }
247
248 [[nodiscard]] constexpr T const &x() const noexcept requires(N >= 1)
249 {
250 return std::get<0>(v);
251 }
252
253 [[nodiscard]] constexpr T const &y() const noexcept requires(N >= 2)
254 {
255 return std::get<1>(v);
256 }
257
258 [[nodiscard]] constexpr T const &z() const noexcept requires(N >= 3)
259 {
260 return std::get<2>(v);
261 }
262
263 [[nodiscard]] constexpr T const &w() const noexcept requires(N >= 4)
264 {
265 return std::get<3>(v);
266 }
267
268 [[nodiscard]] constexpr T &x() noexcept requires(N >= 1)
269 {
270 return std::get<0>(v);
271 }
272
273 [[nodiscard]] constexpr T &y() noexcept requires(N >= 2)
274 {
275 return std::get<1>(v);
276 }
277
278 [[nodiscard]] constexpr T &z() noexcept requires(N >= 3)
279 {
280 return std::get<2>(v);
281 }
282
283 [[nodiscard]] constexpr T &w() noexcept requires(N >= 4)
284 {
285 return std::get<3>(v);
286 }
287
288 [[nodiscard]] constexpr T const &r() const noexcept requires(N >= 1)
289 {
290 return std::get<0>(v);
291 }
292
293 [[nodiscard]] constexpr T const &g() const noexcept requires(N >= 2)
294 {
295 return std::get<1>(v);
296 }
297
298 [[nodiscard]] constexpr T const &b() const noexcept requires(N >= 3)
299 {
300 return std::get<2>(v);
301 }
302
303 [[nodiscard]] constexpr T const &a() const noexcept requires(N >= 4)
304 {
305 return std::get<3>(v);
306 }
307
308 [[nodiscard]] constexpr T &r() noexcept requires(N >= 1)
309 {
310 return std::get<0>(v);
311 }
312
313 [[nodiscard]] constexpr T &g() noexcept requires(N >= 2)
314 {
315 return std::get<1>(v);
316 }
317
318 [[nodiscard]] constexpr T &b() noexcept requires(N >= 3)
319 {
320 return std::get<2>(v);
321 }
322
323 [[nodiscard]] constexpr T &a() noexcept requires(N >= 4)
324 {
325 return std::get<3>(v);
326 }
327
328 [[nodiscard]] constexpr T const &width() const noexcept requires(N >= 1)
329 {
330 return std::get<0>(v);
331 }
332
333 [[nodiscard]] constexpr T const &height() const noexcept requires(N >= 2)
334 {
335 return std::get<1>(v);
336 }
337
338 [[nodiscard]] constexpr T const &depth() const noexcept requires(N >= 3)
339 {
340 return std::get<2>(v);
341 }
342
343 [[nodiscard]] constexpr T &width() noexcept requires(N >= 1)
344 {
345 return std::get<0>(v);
346 }
347
348 [[nodiscard]] constexpr T &height() noexcept requires(N >= 2)
349 {
350 return std::get<1>(v);
351 }
352
353 [[nodiscard]] constexpr T &depth() noexcept requires(N >= 3)
354 {
355 return std::get<2>(v);
356 }
357
358 constexpr numeric_array &operator+=(numeric_array const &rhs) noexcept
359 {
360 for (ssize_t i = 0; i != N; ++i) {
361 v[i] += rhs.v[i];
362 }
363 return *this;
364 }
365
366 constexpr numeric_array &operator+=(T const &rhs) noexcept
367 {
368 for (ssize_t i = 0; i != N; ++i) {
369 v[i] += rhs;
370 }
371 return *this;
372 }
373
374 constexpr numeric_array &operator-=(numeric_array const &rhs) noexcept
375 {
376 for (ssize_t i = 0; i != N; ++i) {
377 v[i] -= rhs.v[i];
378 }
379 return *this;
380 }
381
382 constexpr numeric_array &operator-=(T const &rhs) noexcept
383 {
384 for (ssize_t i = 0; i != N; ++i) {
385 v[i] -= rhs;
386 }
387 return *this;
388 }
389
390 constexpr numeric_array &operator*=(numeric_array const &rhs) noexcept
391 {
392 for (ssize_t i = 0; i != N; ++i) {
393 v[i] *= rhs.v[i];
394 }
395 return *this;
396 }
397
398 constexpr numeric_array &operator*=(T const &rhs) noexcept
399 {
400 for (ssize_t i = 0; i != N; ++i) {
401 v[i] *= rhs;
402 }
403 return *this;
404 }
405
406 constexpr numeric_array &operator/=(numeric_array const &rhs) noexcept
407 {
408 for (ssize_t i = 0; i != N; ++i) {
409 v[i] /= rhs.v[i];
410 }
411 return *this;
412 }
413
414 constexpr numeric_array &operator/=(T const &rhs) noexcept
415 {
416 for (ssize_t i = 0; i != N; ++i) {
417 v[i] /= rhs;
418 }
419 return *this;
420 }
421
422 constexpr numeric_array &operator%=(numeric_array const &rhs) noexcept
423 {
424 for (ssize_t i = 0; i != N; ++i) {
425 v[i] %= rhs.v[i];
426 }
427 return *this;
428 }
429
430 constexpr numeric_array &operator%=(T const &rhs) noexcept
431 {
432 for (ssize_t i = 0; i != N; ++i) {
433 v[i] %= rhs;
434 }
435 return *this;
436 }
437
438 constexpr static ssize_t get_zero = -1;
439 constexpr static ssize_t get_one = -2;
440
445 template<ssize_t I>
446 [[nodiscard]] friend constexpr T &get(numeric_array &rhs) noexcept
447 {
448 static_assert(I >= 0 && I < N, "Index out of bounds");
449 return std::get<I>(rhs.v);
450 }
451
457 template<ssize_t I>
458 [[nodiscard]] friend constexpr T get(numeric_array &&rhs) noexcept
459 {
460 static_assert(I >= -2 && I < N, "Index out of bounds");
461 if constexpr (I == get_zero) {
462 return T{0};
463 } else if constexpr (I == get_one) {
464 return T{1};
465 } else {
466 return std::get<I>(rhs.v);
467 }
468 }
469
475 template<ssize_t I>
476 [[nodiscard]] friend constexpr T get(numeric_array const &rhs) noexcept
477 {
478 static_assert(I >= -2 && I < N, "Index out of bounds");
479 if constexpr (I == get_zero) {
480 return T{0};
481 } else if constexpr (I == get_one) {
482 return T{1};
483 } else {
484 return std::get<I>(rhs.v);
485 }
486 }
487
492 template<size_t Mask = ~size_t{0}>
493 [[nodiscard]] friend constexpr numeric_array zero(numeric_array rhs) noexcept
494 {
495 if (!std::is_constant_evaluated()) {
496 if constexpr (is_f32x4 && has_sse) {
497 return numeric_array{f32x4_sse_zero<Mask & 0xf>(rhs.v)};
498 }
499 }
500
501 auto r = numeric_array{};
502 for (ssize_t i = 0; i != N; ++i) {
503 if (static_cast<bool>((Mask >> i) & 1)) {
504 r.v[i] = T{0};
505 } else {
506 r.v[i] = rhs.v[i];
507 }
508 }
509 return r;
510 }
511
516 template<size_t Mask = ~size_t{0}>
517 [[nodiscard]] friend constexpr numeric_array neg(numeric_array rhs) noexcept
518 {
519 if (!std::is_constant_evaluated()) {
520 if constexpr (is_f32x4 && has_sse) {
521 return numeric_array{f32x4_sse_neg<Mask & 0xf>(rhs.v)};
522 }
523 }
524
525 auto r = numeric_array{};
526 for (ssize_t i = 0; i != N; ++i) {
527 if (static_cast<bool>((Mask >> i) & 1)) {
528 r.v[i] = -rhs.v[i];
529 } else {
530 r.v[i] = rhs.v[i];
531 }
532 }
533 return r;
534 }
535
536 [[nodiscard]] friend constexpr numeric_array operator-(numeric_array const &rhs) noexcept
537 {
538 auto r = numeric_array{};
539 for (ssize_t i = 0; i != N; ++i) {
540 // -rhs.v[i] will cause a memory load with msvc.
541 r.v[i] = T{} - rhs.v[i];
542 }
543 return r;
544 }
545
546 [[nodiscard]] friend constexpr numeric_array abs(numeric_array const &rhs) noexcept
547 {
548 auto neg_rhs = -rhs;
549
550 auto r = numeric_array{};
551 for (ssize_t i = 0; i != N; ++i) {
552 r.v[i] = rhs.v[i] < T{} ? neg_rhs.v[i] : rhs.v[i];
553 }
554 return r;
555 }
556
557 [[nodiscard]] friend constexpr numeric_array rcp(numeric_array const &rhs) noexcept
558 {
559 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
560 return numeric_array{f32x4_sse_rcp(rhs.v)};
561 }
562
563 auto r = numeric_array{};
564 for (ssize_t i = 0; i != N; ++i) {
565 r[i] = 1.0f / rhs.v[i];
566 }
567 return r;
568 }
569
570 [[nodiscard]] friend constexpr numeric_array sqrt(numeric_array const &rhs) noexcept
571 {
572 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
573 return numeric_array{f32x4_sse_sqrt(rhs.v)};
574 }
575
576 auto r = numeric_array{};
577 for (ssize_t i = 0; i != N; ++i) {
578 r[i] = std::sqrt(rhs.v[i]);
579 }
580 return r;
581 }
582
583 [[nodiscard]] friend constexpr numeric_array rcp_sqrt(numeric_array const &rhs) noexcept
584 {
585 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
586 return numeric_array{f32x4_sse_rcp_sqrt(rhs.v)};
587 }
588
589 auto r = numeric_array{};
590 for (ssize_t i = 0; i != N; ++i) {
591 r[i] = 1.0f / std::sqrt(rhs.v[i]);
592 }
593 return r;
594 }
595
596 [[nodiscard]] friend constexpr numeric_array floor(numeric_array const &rhs) noexcept
597 {
598 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
599 return numeric_array{f32x4_sse_floor(rhs.v)};
600 }
601
602 auto r = numeric_array{};
603 for (ssize_t i = 0; i != N; ++i) {
604 r[i] = std::floor(rhs.v[i]);
605 }
606 return r;
607 }
608
609 [[nodiscard]] friend constexpr numeric_array ceil(numeric_array const &rhs) noexcept
610 {
611 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
612 return numeric_array{f32x4_sse_ceil(rhs.v)};
613 }
614
615 auto r = numeric_array{};
616 for (ssize_t i = 0; i != N; ++i) {
617 r[i] = std::ceil(rhs.v[i]);
618 }
619 return r;
620 }
621
622 [[nodiscard]] friend constexpr numeric_array round(numeric_array const &rhs) noexcept
623 {
624 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
625 return numeric_array{f32x4_sse_round(rhs.v)};
626 }
627
628 auto r = numeric_array{};
629 for (ssize_t i = 0; i != N; ++i) {
630 r[i] = std::round(rhs.v[i]);
631 }
632 return r;
633 }
634
642 template<ssize_t Mask>
643 [[nodiscard]] friend constexpr T dot(numeric_array const &lhs, numeric_array const &rhs) noexcept
644 {
645 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
646 return f32x4_sse_dot<Mask>(lhs.v, rhs.v);
647 }
648
649 auto r = T{};
650 for (ssize_t i = 0; i != N; ++i) {
651 if (static_cast<bool>(Mask & (1_uz << i))) {
652 r += lhs.v[i] * rhs.v[i];
653 }
654 }
655 return r;
656 }
657
665 template<ssize_t Mask>
666 [[nodiscard]] friend constexpr T hypot(numeric_array const &rhs) noexcept
667 {
668 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
669 return f32x4_sse_hypot<Mask>(rhs.v);
670 }
671 return std::sqrt(dot<Mask>(rhs, rhs));
672 }
673
681 template<ssize_t Mask>
682 [[nodiscard]] friend constexpr T squared_hypot(numeric_array const &rhs) noexcept
683 {
684 return dot<Mask>(rhs, rhs);
685 }
686
693 template<ssize_t Mask>
694 [[nodiscard]] friend constexpr T rcp_hypot(numeric_array const &rhs) noexcept
695 {
696 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
697 return f32x4_sse_rcp_hypot<Mask>(rhs.v);
698 }
699
700 return 1.0f / hypot<Mask>(rhs);
701 }
702
711 template<ssize_t Mask>
712 [[nodiscard]] friend constexpr numeric_array normalize(numeric_array const &rhs) noexcept
713 {
714 tt_axiom(rhs.is_vector());
715
716 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
717 return numeric_array{f32x4_sse_normalize<Mask>(rhs.v)};
718 }
719
720 ttlet rcp_hypot_ = rcp_hypot<Mask>(rhs);
721
722 auto r = numeric_array{};
723 for (size_t i = 0; i != N; ++i) {
724 if (static_cast<bool>(Mask & (1_uz << i))) {
725 r.v[i] = rhs.v[i] * rcp_hypot_;
726 }
727 }
728 return r;
729 }
730
731 [[nodiscard]] friend constexpr unsigned int eq(numeric_array const &lhs, numeric_array const &rhs) noexcept
732 requires(N <= sizeof(unsigned int) * CHAR_BIT)
733 {
734 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
735 return f32x4_sse_eq_mask(lhs.v, rhs.v);
736 } else {
737 unsigned int r = 0;
738 for (ssize_t i = 0; i != N; ++i) {
739 r |= static_cast<unsigned int>(lhs.v[i] == rhs.v[i]) << i;
740 }
741 return r;
742 }
743 }
744
745 [[nodiscard]] friend constexpr unsigned int ne(numeric_array const &lhs, numeric_array const &rhs) noexcept
746 requires(N <= sizeof(unsigned int) * CHAR_BIT)
747 {
748 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
749 return f32x4_sse_ne_mask(lhs.v, rhs.v);
750 } else {
751 unsigned int r = 0;
752 for (ssize_t i = 0; i != N; ++i) {
753 r |= static_cast<unsigned int>(lhs.v[i] != rhs.v[i]) << i;
754 }
755 return r;
756 }
757 }
758
759 [[nodiscard]] friend constexpr unsigned int lt(numeric_array const &lhs, numeric_array const &rhs) noexcept
760 requires(N <= sizeof(unsigned int) * CHAR_BIT)
761 {
762 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
763 return f32x4_sse_lt_mask(lhs.v, rhs.v);
764 } else {
765 unsigned int r = 0;
766 for (ssize_t i = 0; i != N; ++i) {
767 r |= static_cast<unsigned int>(lhs.v[i] < rhs.v[i]) << i;
768 }
769 return r;
770 }
771 }
772
773 [[nodiscard]] friend constexpr unsigned int gt(numeric_array const &lhs, numeric_array const &rhs) noexcept
774 requires(N <= sizeof(unsigned int) * CHAR_BIT)
775 {
776 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
777 return f32x4_sse_gt_mask(lhs.v, rhs.v);
778 } else {
779 unsigned int r = 0;
780 for (ssize_t i = 0; i != N; ++i) {
781 r |= static_cast<unsigned int>(lhs.v[i] > rhs.v[i]) << i;
782 }
783 return r;
784 }
785 }
786
787 [[nodiscard]] friend constexpr unsigned int le(numeric_array const &lhs, numeric_array const &rhs) noexcept
788 requires(N <= sizeof(unsigned int) * CHAR_BIT)
789 {
790 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
791 return f32x4_sse_le_mask(lhs.v, rhs.v);
792 } else {
793 unsigned int r = 0;
794 for (ssize_t i = 0; i != N; ++i) {
795 r |= static_cast<unsigned int>(lhs.v[i] <= rhs.v[i]) << i;
796 }
797 return r;
798 }
799 }
800
801 [[nodiscard]] friend constexpr unsigned int ge(numeric_array const &lhs, numeric_array const &rhs) noexcept
802 requires(N <= sizeof(unsigned int) * CHAR_BIT)
803 {
804 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
805 return f32x4_sse_ge_mask(lhs.v, rhs.v);
806 } else {
807 unsigned int r = 0;
808 for (ssize_t i = 0; i != N; ++i) {
809 r |= static_cast<unsigned int>(lhs.v[i] >= rhs.v[i]) << i;
810 }
811 return r;
812 }
813 }
814
815 [[nodiscard]] friend constexpr bool operator==(numeric_array const &lhs, numeric_array const &rhs) noexcept
816 {
817 if (!std::is_constant_evaluated()) {
818 if constexpr (is_f32x4 && has_sse) {
819 // MSVC cannot vectorize comparison.
820 return f32x4_sse_eq(lhs.v, rhs.v);
821 }
822 }
823
824 auto r = true;
825 for (ssize_t i = 0; i != N; ++i) {
826 r &= (lhs.v[i] == rhs.v[i]);
827 }
828 return r;
829 }
830
831 [[nodiscard]] friend constexpr bool operator!=(numeric_array const &lhs, numeric_array const &rhs) noexcept
832 {
833 return !(lhs == rhs);
834 }
835
836 [[nodiscard]] friend constexpr numeric_array operator+(numeric_array const &lhs, numeric_array const &rhs) noexcept
837 {
838 auto r = numeric_array{};
839 for (ssize_t i = 0; i != N; ++i) {
840 r.v[i] = lhs.v[i] + rhs.v[i];
841 }
842 return r;
843 }
844
845 [[nodiscard]] friend constexpr numeric_array operator+(numeric_array const &lhs, T const &rhs) noexcept
846 {
847 auto r = numeric_array{};
848 for (ssize_t i = 0; i != N; ++i) {
849 r.v[i] = lhs.v[i] + rhs;
850 }
851 return r;
852 }
853
854 [[nodiscard]] friend constexpr numeric_array operator+(T const &lhs, numeric_array const &rhs) noexcept
855 {
856 auto r = numeric_array{};
857 for (ssize_t i = 0; i != N; ++i) {
858 r.v[i] = lhs + rhs.v[i];
859 }
860 return r;
861 }
862
863 [[nodiscard]] friend constexpr numeric_array hadd(numeric_array const &lhs, numeric_array const &rhs) noexcept
864 {
865 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
866 return numeric_array{f32x4_sse_hadd(lhs.v, rhs.v)};
867
868 } else {
869 tt_axiom(N % 2 == 0);
870
871 auto r = numeric_array{};
872
873 ssize_t src_i = 0;
874 ssize_t dst_i = 0;
875 while (src_i != N) {
876 auto tmp = lhs[src_i++];
877 tmp += lhs[src_i++];
878 r.v[dst_i++] = tmp;
879 }
880
881 src_i = 0;
882 while (src_i != N) {
883 auto tmp = rhs[src_i++];
884 tmp += rhs[src_i++];
885 r.v[dst_i++] = tmp;
886 }
887 return r;
888 }
889 }
890
891 [[nodiscard]] friend constexpr numeric_array hsub(numeric_array const &lhs, numeric_array const &rhs) noexcept
892 {
893 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
894 return numeric_array{f32x4_sse_hsub(lhs.v, rhs.v)};
895
896 } else {
897 tt_axiom(N % 2 == 0);
898
899 auto r = numeric_array{};
900
901 ssize_t src_i = 0;
902 ssize_t dst_i = 0;
903 while (src_i != N) {
904 auto tmp = lhs[src_i++];
905 tmp -= lhs[src_i++];
906 r.v[dst_i++] = tmp;
907 }
908
909 src_i = 0;
910 while (src_i != N) {
911 auto tmp = rhs[src_i++];
912 tmp -= rhs[src_i++];
913 r.v[dst_i++] = tmp;
914 }
915 return r;
916 }
917 }
918
919 [[nodiscard]] friend constexpr numeric_array operator-(numeric_array const &lhs, numeric_array const &rhs) noexcept
920 {
921 auto r = numeric_array{};
922 for (ssize_t i = 0; i != N; ++i) {
923 r.v[i] = lhs.v[i] - rhs.v[i];
924 }
925 return r;
926 }
927
928 [[nodiscard]] friend constexpr numeric_array operator-(numeric_array const &lhs, T const &rhs) noexcept
929 {
930 auto r = numeric_array{};
931 for (ssize_t i = 0; i != N; ++i) {
932 r.v[i] = lhs.v[i] - rhs;
933 }
934 return r;
935 }
936
941 template<size_t Mask = ~size_t{0}>
942 [[nodiscard]] friend constexpr numeric_array addsub(numeric_array const &lhs, numeric_array const &rhs) noexcept
943 {
944 if (!std::is_constant_evaluated()) {
945 if constexpr (is_f32x4 && has_sse) {
946 return numeric_array{f32x4_sse_addsub<Mask & 0xf>(lhs.v, rhs.v)};
947 }
948 }
949
950 auto r = numeric_array{};
951 for (ssize_t i = 0; i != N; ++i) {
952 if (static_cast<bool>((Mask >> i) & 1)) {
953 r.v[i] = lhs.v[i] + rhs.v[i];
954 } else {
955 r.v[i] = lhs.v[i] - rhs.v[i];
956 }
957 }
958 return r;
959 }
960
961 [[nodiscard]] friend constexpr numeric_array operator-(T const &lhs, numeric_array const &rhs) noexcept
962 {
963 auto r = numeric_array{};
964 for (ssize_t i = 0; i != N; ++i) {
965 r.v[i] = lhs - rhs.v[i];
966 }
967 return r;
968 }
969
970 [[nodiscard]] friend constexpr numeric_array operator*(numeric_array const &lhs, numeric_array const &rhs) noexcept
971 {
972 auto r = numeric_array{};
973 for (ssize_t i = 0; i != N; ++i) {
974 r.v[i] = lhs.v[i] * rhs.v[i];
975 }
976 return r;
977 }
978
979 [[nodiscard]] friend constexpr numeric_array operator*(numeric_array const &lhs, T const &rhs) noexcept
980 {
981 auto r = numeric_array{};
982 for (ssize_t i = 0; i != N; ++i) {
983 r.v[i] = lhs.v[i] * rhs;
984 }
985 return r;
986 }
987
988 [[nodiscard]] friend constexpr numeric_array operator*(T const &lhs, numeric_array const &rhs) noexcept
989 {
990 auto r = numeric_array{};
991 for (ssize_t i = 0; i != N; ++i) {
992 r.v[i] = lhs * rhs.v[i];
993 }
994 return r;
995 }
996
997 [[nodiscard]] friend constexpr numeric_array operator/(numeric_array const &lhs, numeric_array const &rhs) noexcept
998 {
999 auto r = numeric_array{};
1000 for (ssize_t i = 0; i != N; ++i) {
1001 r.v[i] = lhs.v[i] / rhs.v[i];
1002 }
1003 return r;
1004 }
1005
1006 [[nodiscard]] friend constexpr numeric_array operator/(numeric_array const &lhs, T const &rhs) noexcept
1007 {
1008 auto r = numeric_array{};
1009 for (ssize_t i = 0; i != N; ++i) {
1010 r.v[i] = lhs.v[i] / rhs;
1011 }
1012 return r;
1013 }
1014
1015 [[nodiscard]] friend constexpr numeric_array operator/(T const &lhs, numeric_array const &rhs) noexcept
1016 {
1017 auto r = numeric_array{};
1018 for (ssize_t i = 0; i != N; ++i) {
1019 r.v[i] = lhs / rhs.v[i];
1020 }
1021 return r;
1022 }
1023
1024 [[nodiscard]] friend constexpr numeric_array operator%(numeric_array const &lhs, numeric_array const &rhs) noexcept
1025 {
1026 auto r = numeric_array{};
1027 for (ssize_t i = 0; i != N; ++i) {
1028 r.v[i] = lhs.v[i] % rhs.v[i];
1029 }
1030 return r;
1031 }
1032
1033 [[nodiscard]] friend constexpr numeric_array operator%(numeric_array const &lhs, T const &rhs) noexcept
1034 {
1035 auto r = numeric_array{};
1036 for (ssize_t i = 0; i != N; ++i) {
1037 r.v[i] = lhs.v[i] % rhs;
1038 }
1039 return r;
1040 }
1041
1042 [[nodiscard]] friend constexpr numeric_array operator%(T const &lhs, numeric_array const &rhs) noexcept
1043 {
1044 auto r = numeric_array{};
1045 for (ssize_t i = 0; i != N; ++i) {
1046 r.v[i] = lhs % rhs.v[i];
1047 }
1048 return r;
1049 }
1050
1051 [[nodiscard]] friend constexpr numeric_array min(numeric_array const &lhs, numeric_array const &rhs) noexcept
1052 {
1053 auto r = numeric_array{};
1054 for (ssize_t i = 0; i != N; ++i) {
1055 // std::min() causes vectorization failure with msvc
1056 r.v[i] = lhs.v[i] < rhs.v[i] ? lhs.v[i] : rhs.v[i];
1057 }
1058 return r;
1059 }
1060
1061 [[nodiscard]] friend constexpr numeric_array max(numeric_array const &lhs, numeric_array const &rhs) noexcept
1062 {
1063 auto r = numeric_array{};
1064 for (ssize_t i = 0; i != N; ++i) {
1065 // std::max() causes vectorization failure with msvc
1066 r.v[i] = lhs.v[i] > rhs.v[i] ? lhs.v[i] : rhs.v[i];
1067 }
1068 return r;
1069 }
1070
1071 [[nodiscard]] friend constexpr numeric_array
1072 clamp(numeric_array const &lhs, numeric_array const &low, numeric_array const &high) noexcept
1073 {
1074 auto r = numeric_array{};
1075 for (ssize_t i = 0; i != N; ++i) {
1076 // std::clamp() causes vectorization failure with msvc
1077 r.v[i] = lhs.v[i] < low.v[i] ? low.v[i] : lhs.v[i] > high.v[i] ? high.v[i] : lhs.v[i];
1078 }
1079 return r;
1080 }
1081
1084 [[nodiscard]] friend constexpr numeric_array cross_2D(numeric_array const &rhs) noexcept requires(N >= 2)
1085 {
1086 tt_axiom(rhs.z() == 0.0f && rhs.is_vector());
1087 return numeric_array{-rhs.y(), rhs.x()};
1088 }
1089
1092 [[nodiscard]] friend constexpr numeric_array normal_2D(numeric_array const &rhs) noexcept requires(N >= 2)
1093 {
1094 return normalize<0b0011>(cross_2D(rhs));
1095 }
1096
1099 [[nodiscard]] friend constexpr float cross_2D(numeric_array const &lhs, numeric_array const &rhs) noexcept
1100 requires(N >= 2)
1101 {
1102 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
1103 return f32x4_sse_viktor_cross(lhs.v, rhs.v);
1104
1105 } else {
1106 return lhs.x() * rhs.y() - lhs.y() * rhs.x();
1107 }
1108 }
1109
1110 // x=a.y*b.z - a.z*b.y
1111 // y=a.z*b.x - a.x*b.z
1112 // z=a.x*b.y - a.y*b.x
1113 // w=a.w*b.w - a.w*b.w
1114 [[nodiscard]] constexpr friend numeric_array cross_3D(numeric_array const &lhs, numeric_array const &rhs) noexcept
1115 {
1116 if (!std::is_constant_evaluated()) {
1117 if constexpr (is_f32x4 && has_sse) {
1118 return numeric_array{f32x4_sse_cross(lhs.v, rhs.v)};
1119 }
1120 }
1121
1122 return numeric_array{
1123 lhs.y() * rhs.z() - lhs.z() * rhs.y(),
1124 lhs.z() * rhs.x() - lhs.x() * rhs.z(),
1125 lhs.x() * rhs.y() - lhs.y() * rhs.x(),
1126 0.0f};
1127 }
1128
1129 // w + x*i + y*j + z*k
1130 //
1131 // (w1*x2 + x1*w2 + y1*z2 - z1*y2)i
1132 // + (w1*y2 - x1*z2 + y1*w2 + z1*x2)j
1133 // + (w1*z2 + x1*y2 - y1*x2 + z1*w2)k
1134 // + (w1*w2 - x1*x2 - y1*y2 - z1*z2)
1135 template<int D>
1136 requires(D == 4) [[nodiscard]] friend numeric_array
1137 hamilton_cross(numeric_array const &lhs, numeric_array const &rhs) noexcept
1138 {
1139 ttlet col0 = lhs.wwww() * rhs;
1140 ttlet col1 = lhs.xxxx() * rhs.wzyx();
1141 ttlet col2 = lhs.yyyy() * rhs.zwxy();
1142 ttlet col3 = lhs.zzzz() * rhs.yxwz();
1143
1144 ttlet col01 = addsub(col0, col1);
1145 ttlet col012 = addsub(col01.xzyw(), col2.xzyw()).xzyw();
1146
1147 return numeric_array{
1148
1149 };
1150 }
1151
1154 [[nodiscard]] friend constexpr numeric_array midpoint(numeric_array const &p1, numeric_array const &p2) noexcept
1155 {
1156 tt_axiom(p1.is_point());
1157 tt_axiom(p2.is_point());
1158 return (p1 + p2) * 0.5f;
1159 }
1160
1163 [[nodiscard]] friend constexpr numeric_array reflect_point(numeric_array const &p, numeric_array const anchor) noexcept
1164 {
1165 tt_axiom(p.is_point());
1166 tt_axiom(anchor.is_point());
1167 return anchor - (p - anchor);
1168 }
1169
1170 template<typename... Columns>
1171 [[nodiscard]] friend constexpr std::array<numeric_array, N> transpose(Columns const &...columns) noexcept
1172 {
1173 static_assert(sizeof...(Columns) == N, "Can only transpose square matrices");
1174
1176
1177 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
1178 auto tmp = f32x4_sse_transpose(columns.v...);
1179 for (int i = 0; i != N; ++i) {
1180 r[i] = numeric_array{tmp[i]};
1181 }
1182
1183 } else {
1184 transpose_detail<0, Columns...>(columns..., r);
1185 }
1186
1187 return r;
1188 }
1189
1190 [[nodiscard]] friend numeric_array composit(numeric_array const &under, numeric_array const &over) noexcept
1191 requires(N == 4 && std::is_floating_point_v<T>)
1192 {
1193 if (over.is_transparent()) {
1194 return under;
1195 }
1196 if (over.is_opaque()) {
1197 return over;
1198 }
1199
1200 ttlet over_alpha = over.wwww();
1201 ttlet under_alpha = under.wwww();
1202
1203 ttlet over_color = over.xyz1();
1204 ttlet under_color = under.xyz1();
1205
1206 ttlet output_color = over_color * over_alpha + under_color * under_alpha * (1.0 - over_alpha);
1207
1208 return output_color / output_color.www1();
1209 }
1210
1211 [[nodiscard]] friend std::string to_string(numeric_array const &rhs) noexcept
1212 {
1213 auto r = std::string{};
1214
1215 r += '(';
1216 for (ssize_t i = 0; i != N; ++i) {
1217 if (i != 0) {
1218 r += "; ";
1219 }
1220 r += fmt::format("{}", rhs[i]);
1221 }
1222 r += ')';
1223 return r;
1224 }
1225
1226 friend std::ostream &operator<<(std::ostream &lhs, numeric_array const &rhs)
1227 {
1228 return lhs << to_string(rhs);
1229 }
1230
1238 template<ssize_t... Elements>
1239 [[nodiscard]] constexpr numeric_array swizzle() const
1240 {
1241 static_assert(sizeof...(Elements) <= N);
1242
1243 if (!std::is_constant_evaluated()) {
1244 if constexpr (is_f32x4 && has_sse) {
1245 return numeric_array{f32x4_sse_swizzle<Elements...>(v)};
1246 }
1247 }
1248
1249 auto r = numeric_array{};
1250 swizzle_detail<0, Elements...>(r);
1251 return r;
1252 }
1253
1254#define SWIZZLE(swizzle_name, D, ...) \
1255 [[nodiscard]] constexpr numeric_array swizzle_name() const noexcept requires(D == N) \
1256 { \
1257 return swizzle<__VA_ARGS__>(); \
1258 }
1259
1260#define SWIZZLE_4D_GEN1(name, ...) \
1261 SWIZZLE(name##0, 4, __VA_ARGS__, get_zero) \
1262 SWIZZLE(name##1, 4, __VA_ARGS__, get_one) \
1263 SWIZZLE(name##x, 4, __VA_ARGS__, 0) \
1264 SWIZZLE(name##y, 4, __VA_ARGS__, 1) \
1265 SWIZZLE(name##z, 4, __VA_ARGS__, 2) \
1266 SWIZZLE(name##w, 4, __VA_ARGS__, 3)
1267
1268#define SWIZZLE_4D_GEN2(name, ...) \
1269 SWIZZLE_4D_GEN1(name##0, __VA_ARGS__, get_zero) \
1270 SWIZZLE_4D_GEN1(name##1, __VA_ARGS__, get_one) \
1271 SWIZZLE_4D_GEN1(name##x, __VA_ARGS__, 0) \
1272 SWIZZLE_4D_GEN1(name##y, __VA_ARGS__, 1) \
1273 SWIZZLE_4D_GEN1(name##z, __VA_ARGS__, 2) \
1274 SWIZZLE_4D_GEN1(name##w, __VA_ARGS__, 3)
1275
1276#define SWIZZLE_4D_GEN3(name, ...) \
1277 SWIZZLE_4D_GEN2(name##0, __VA_ARGS__, get_zero) \
1278 SWIZZLE_4D_GEN2(name##1, __VA_ARGS__, get_one) \
1279 SWIZZLE_4D_GEN2(name##x, __VA_ARGS__, 0) \
1280 SWIZZLE_4D_GEN2(name##y, __VA_ARGS__, 1) \
1281 SWIZZLE_4D_GEN2(name##z, __VA_ARGS__, 2) \
1282 SWIZZLE_4D_GEN2(name##w, __VA_ARGS__, 3)
1283
1284 SWIZZLE_4D_GEN3(_0, get_zero)
1285 SWIZZLE_4D_GEN3(_1, get_one)
1286 SWIZZLE_4D_GEN3(x, 0)
1287 SWIZZLE_4D_GEN3(y, 1)
1288 SWIZZLE_4D_GEN3(z, 2)
1289 SWIZZLE_4D_GEN3(w, 3)
1290
1291#define SWIZZLE_3D_GEN1(name, ...) \
1292 SWIZZLE(name##0, 3, __VA_ARGS__, get_zero) \
1293 SWIZZLE(name##1, 3, __VA_ARGS__, get_one) \
1294 SWIZZLE(name##x, 3, __VA_ARGS__, 0) \
1295 SWIZZLE(name##y, 3, __VA_ARGS__, 1) \
1296 SWIZZLE(name##z, 3, __VA_ARGS__, 2)
1297
1298#define SWIZZLE_3D_GEN2(name, ...) \
1299 SWIZZLE_3D_GEN1(name##0, __VA_ARGS__, get_zero) \
1300 SWIZZLE_3D_GEN1(name##1, __VA_ARGS__, get_one) \
1301 SWIZZLE_3D_GEN1(name##x, __VA_ARGS__, 0) \
1302 SWIZZLE_3D_GEN1(name##y, __VA_ARGS__, 1) \
1303 SWIZZLE_3D_GEN1(name##z, __VA_ARGS__, 2)
1304
1305 SWIZZLE_3D_GEN2(_0, get_zero)
1306 SWIZZLE_3D_GEN2(_1, get_one)
1307 SWIZZLE_3D_GEN2(x, 0)
1308 SWIZZLE_3D_GEN2(y, 1)
1309 SWIZZLE_3D_GEN2(z, 2)
1310
1311#define SWIZZLE_2D_GEN1(name, ...) \
1312 SWIZZLE(name##0, 2, __VA_ARGS__, get_zero) \
1313 SWIZZLE(name##1, 2, __VA_ARGS__, get_one) \
1314 SWIZZLE(name##x, 2, __VA_ARGS__, 0) \
1315 SWIZZLE(name##y, 2, __VA_ARGS__, 1)
1316
1317 SWIZZLE_2D_GEN1(_0, get_zero)
1318 SWIZZLE_2D_GEN1(_1, get_one)
1319 SWIZZLE_2D_GEN1(x, 0)
1320 SWIZZLE_2D_GEN1(y, 1)
1321
1322#undef SWIZZLE
1323#undef SWIZZLE_4D_GEN1
1324#undef SWIZZLE_4D_GEN2
1325#undef SWIZZLE_4D_GEN3
1326#undef SWIZZLE_3D_GEN1
1327#undef SWIZZLE_3D_GEN2
1328#undef SWIZZLE_2D_GEN1
1329
1330private:
1331 container_type v;
1332
1333 template<int I, typename First, typename... Rest>
1334 friend constexpr void
1335 transpose_detail(First const &first, Rest const &...rest, std::array<numeric_array, N> &r) noexcept
1336 {
1337 for (ssize_t j = 0; j != N; ++j) {
1338 r[j][I] = first[j];
1339 }
1340
1341 if constexpr (sizeof...(Rest) != 0) {
1342 transpose_detail<I + 1, Rest...>(rest..., r);
1343 }
1344 }
1345
1346 template<ssize_t I, ssize_t FirstElement, ssize_t... RestElements>
1347 constexpr void swizzle_detail(numeric_array &r) const noexcept
1348 {
1349 static_assert(I < N);
1350 static_assert(FirstElement >= -2 && FirstElement < N, "Index out of bounds");
1351
1352 get<I>(r) = get<FirstElement>(*this);
1353 if constexpr (sizeof...(RestElements) != 0) {
1354 swizzle_detail<I + 1, RestElements...>(r);
1355 }
1356 }
1357
1358 constexpr static bool is_i8x1 = std::is_same_v<T, int8_t> && N == 1;
1359 constexpr static bool is_i8x2 = std::is_same_v<T, int8_t> && N == 2;
1360 constexpr static bool is_i8x4 = std::is_same_v<T, int8_t> && N == 4;
1361 constexpr static bool is_i8x8 = std::is_same_v<T, int8_t> && N == 8;
1362 constexpr static bool is_i8x16 = std::is_same_v<T, int8_t> && N == 16;
1363 constexpr static bool is_i8x32 = std::is_same_v<T, int8_t> && N == 32;
1364 constexpr static bool is_i8x64 = std::is_same_v<T, int8_t> && N == 64;
1365 constexpr static bool is_u8x1 = std::is_same_v<T, uint8_t> && N == 1;
1366 constexpr static bool is_u8x2 = std::is_same_v<T, uint8_t> && N == 2;
1367 constexpr static bool is_u8x4 = std::is_same_v<T, uint8_t> && N == 4;
1368 constexpr static bool is_u8x8 = std::is_same_v<T, uint8_t> && N == 8;
1369 constexpr static bool is_u8x16 = std::is_same_v<T, uint8_t> && N == 16;
1370 constexpr static bool is_u8x32 = std::is_same_v<T, uint8_t> && N == 32;
1371 constexpr static bool is_u8x64 = std::is_same_v<T, uint8_t> && N == 64;
1372
1373 constexpr static bool is_i16x1 = std::is_same_v<T, int16_t> && N == 1;
1374 constexpr static bool is_i16x2 = std::is_same_v<T, int16_t> && N == 2;
1375 constexpr static bool is_i16x4 = std::is_same_v<T, int16_t> && N == 4;
1376 constexpr static bool is_i16x8 = std::is_same_v<T, int16_t> && N == 8;
1377 constexpr static bool is_i16x16 = std::is_same_v<T, int16_t> && N == 16;
1378 constexpr static bool is_i16x32 = std::is_same_v<T, int16_t> && N == 32;
1379 constexpr static bool is_u16x1 = std::is_same_v<T, uint16_t> && N == 1;
1380 constexpr static bool is_u16x2 = std::is_same_v<T, uint16_t> && N == 2;
1381 constexpr static bool is_u16x4 = std::is_same_v<T, uint16_t> && N == 4;
1382 constexpr static bool is_u16x8 = std::is_same_v<T, uint16_t> && N == 8;
1383 constexpr static bool is_u16x16 = std::is_same_v<T, uint16_t> && N == 16;
1384 constexpr static bool is_u16x32 = std::is_same_v<T, uint16_t> && N == 32;
1385
1386 constexpr static bool is_i32x1 = std::is_same_v<T, int32_t> && N == 1;
1387 constexpr static bool is_i32x2 = std::is_same_v<T, int32_t> && N == 2;
1388 constexpr static bool is_i32x4 = std::is_same_v<T, int32_t> && N == 4;
1389 constexpr static bool is_i32x8 = std::is_same_v<T, int32_t> && N == 8;
1390 constexpr static bool is_i32x16 = std::is_same_v<T, int32_t> && N == 16;
1391 constexpr static bool is_u32x1 = std::is_same_v<T, uint32_t> && N == 1;
1392 constexpr static bool is_u32x2 = std::is_same_v<T, uint32_t> && N == 2;
1393 constexpr static bool is_u32x4 = std::is_same_v<T, uint32_t> && N == 4;
1394 constexpr static bool is_u32x8 = std::is_same_v<T, uint32_t> && N == 8;
1395 constexpr static bool is_u32x16 = std::is_same_v<T, uint32_t> && N == 16;
1396 constexpr static bool is_f32x1 = std::is_same_v<T, float> && N == 1;
1397 constexpr static bool is_f32x2 = std::is_same_v<T, float> && N == 2;
1398 constexpr static bool is_f32x4 = std::is_same_v<T, float> && N == 4;
1399 constexpr static bool is_f32x8 = std::is_same_v<T, float> && N == 8;
1400 constexpr static bool is_f32x16 = std::is_same_v<T, float> && N == 16;
1401
1402 constexpr static bool is_i64x1 = std::is_same_v<T, int64_t> && N == 1;
1403 constexpr static bool is_i64x2 = std::is_same_v<T, int64_t> && N == 2;
1404 constexpr static bool is_i64x4 = std::is_same_v<T, int64_t> && N == 4;
1405 constexpr static bool is_i64x8 = std::is_same_v<T, int64_t> && N == 8;
1406 constexpr static bool is_u64x1 = std::is_same_v<T, uint64_t> && N == 1;
1407 constexpr static bool is_u64x2 = std::is_same_v<T, uint64_t> && N == 2;
1408 constexpr static bool is_u64x4 = std::is_same_v<T, uint64_t> && N == 4;
1409 constexpr static bool is_u64x8 = std::is_same_v<T, uint64_t> && N == 8;
1410 constexpr static bool is_f64x1 = std::is_same_v<T, double> && N == 1;
1411 constexpr static bool is_f64x2 = std::is_same_v<T, double> && N == 2;
1412 constexpr static bool is_f64x4 = std::is_same_v<T, double> && N == 4;
1413 constexpr static bool is_f64x8 = std::is_same_v<T, double> && N == 8;
1414};
1415
1416using i8x1 = numeric_array<int8_t, 1>;
1417using i8x2 = numeric_array<int8_t, 2>;
1418using i8x4 = numeric_array<int8_t, 4>;
1419using i8x8 = numeric_array<int8_t, 8>;
1420using i8x16 = numeric_array<int8_t, 16>;
1421using i8x32 = numeric_array<int8_t, 32>;
1422using i8x64 = numeric_array<int8_t, 64>;
1423
1424using u8x1 = numeric_array<uint8_t, 1>;
1425using u8x2 = numeric_array<uint8_t, 2>;
1426using u8x4 = numeric_array<uint8_t, 4>;
1427using u8x8 = numeric_array<uint8_t, 8>;
1428using u8x16 = numeric_array<uint8_t, 16>;
1429using u8x32 = numeric_array<uint8_t, 32>;
1430using u8x64 = numeric_array<uint8_t, 64>;
1431
1432using i16x1 = numeric_array<int16_t, 1>;
1433using i16x2 = numeric_array<int16_t, 2>;
1434using i16x4 = numeric_array<int16_t, 4>;
1435using i16x8 = numeric_array<int16_t, 8>;
1436using i16x16 = numeric_array<int16_t, 16>;
1437using i16x32 = numeric_array<int16_t, 32>;
1438
1439using u16x1 = numeric_array<uint16_t, 1>;
1440using u16x2 = numeric_array<uint16_t, 2>;
1441using u16x4 = numeric_array<uint16_t, 4>;
1442using u16x8 = numeric_array<uint16_t, 8>;
1443using u16x16 = numeric_array<uint16_t, 16>;
1444using u16x32 = numeric_array<uint16_t, 32>;
1445
1446using i32x1 = numeric_array<int32_t, 1>;
1447using i32x2 = numeric_array<int32_t, 2>;
1448using i32x4 = numeric_array<int32_t, 4>;
1449using i32x8 = numeric_array<int32_t, 8>;
1450using i32x16 = numeric_array<int32_t, 16>;
1451
1452using u32x1 = numeric_array<uint32_t, 1>;
1453using u32x2 = numeric_array<uint32_t, 2>;
1454using u32x4 = numeric_array<uint32_t, 4>;
1455using u32x8 = numeric_array<uint32_t, 8>;
1456using u32x16 = numeric_array<uint32_t, 16>;
1457
1458using f32x1 = numeric_array<float, 1>;
1459using f32x2 = numeric_array<float, 2>;
1460using f32x4 = numeric_array<float, 4>;
1461using f32x8 = numeric_array<float, 8>;
1462using f32x16 = numeric_array<float, 16>;
1463
1464using i64x1 = numeric_array<int64_t, 1>;
1465using i64x2 = numeric_array<int64_t, 2>;
1466using i64x4 = numeric_array<int64_t, 4>;
1467using i64x8 = numeric_array<int64_t, 8>;
1468
1469using u64x1 = numeric_array<uint64_t, 1>;
1470using u64x2 = numeric_array<uint64_t, 2>;
1471using u64x4 = numeric_array<uint64_t, 4>;
1472using u64x8 = numeric_array<uint64_t, 8>;
1473
1474using f64x1 = numeric_array<double, 1>;
1475using f64x2 = numeric_array<double, 2>;
1476using f64x4 = numeric_array<double, 4>;
1477using f64x8 = numeric_array<double, 8>;
1478
1479} // namespace tt
1480
1481namespace std {
1482
1483template<class T, std::size_t N>
1484struct tuple_size<tt::numeric_array<T, N>> : std::integral_constant<std::size_t, N> {
1485};
1486
1487template<std::size_t I, class T, std::size_t N>
1488struct tuple_element<I, tt::numeric_array<T, N>> {
1489 using type = T;
1490};
1491
1492} // namespace std
STL namespace.
Definition numeric_array.hpp:27
friend constexpr T get(numeric_array &&rhs) noexcept
Get a element from the numeric array.
Definition numeric_array.hpp:458
friend constexpr numeric_array neg(numeric_array rhs) noexcept
Negate individual elements.
Definition numeric_array.hpp:517
friend constexpr T get(numeric_array const &rhs) noexcept
Get a element from the numeric array.
Definition numeric_array.hpp:476
friend constexpr T squared_hypot(numeric_array const &rhs) noexcept
Take the squared length of the vector.
Definition numeric_array.hpp:682
friend constexpr numeric_array cross_2D(numeric_array const &rhs) noexcept
Calculate the 2D normal on a 2D vector.
Definition numeric_array.hpp:1084
friend constexpr numeric_array reflect_point(numeric_array const &p, numeric_array const anchor) noexcept
Find the point on the other side and at the same distance of an anchor-point.
Definition numeric_array.hpp:1163
friend constexpr numeric_array midpoint(numeric_array const &p1, numeric_array const &p2) noexcept
Find a point at the midpoint between two points.
Definition numeric_array.hpp:1154
friend constexpr T & get(numeric_array &rhs) noexcept
Get a element from the numeric array.
Definition numeric_array.hpp:446
friend constexpr T dot(numeric_array const &lhs, numeric_array const &rhs) noexcept
Take a dot product.
Definition numeric_array.hpp:643
friend constexpr T rcp_hypot(numeric_array const &rhs) noexcept
Take a reciprocal of the length.
Definition numeric_array.hpp:694
friend constexpr T hypot(numeric_array const &rhs) noexcept
Take the length of the vector.
Definition numeric_array.hpp:666
friend constexpr float cross_2D(numeric_array const &lhs, numeric_array const &rhs) noexcept
Calculate the cross-product between two 2D vectors.
Definition numeric_array.hpp:1099
friend constexpr numeric_array normal_2D(numeric_array const &rhs) noexcept
Calculate the 2D unit-normal on a 2D vector.
Definition numeric_array.hpp:1092
constexpr numeric_array swizzle() const
swizzle around the elements of the numeric array.
Definition numeric_array.hpp:1239
friend constexpr numeric_array addsub(numeric_array const &lhs, numeric_array const &rhs) noexcept
Add or subtract individual elements.
Definition numeric_array.hpp:942
friend constexpr numeric_array normalize(numeric_array const &rhs) noexcept
Normalize a vector.
Definition numeric_array.hpp:712
friend constexpr numeric_array zero(numeric_array rhs) noexcept
Set individual elements to zero.
Definition numeric_array.hpp:493
Definition concepts.hpp:15
Definition concepts.hpp:18
Definition concepts.hpp:21
T back(T... args)
T begin(T... args)
T ceil(T... args)
T data(T... args)
T empty(T... args)
T end(T... args)
T floor(T... args)
T front(T... args)
T max_size(T... args)
T round(T... args)
T size(T... args)
T sqrt(T... args)