29 static_assert(N >= 0);
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;
60 "Expecting the std:initializer_list size to be <= to the size of the numeric array");
71 requires(
sizeof...(Rest) + 2 <= N)
72 [[nodiscard]]
constexpr numeric_array(T
const &first, T
const &second, Rest
const &...rest) noexcept :
77 [[nodiscard]]
static constexpr numeric_array broadcast(T rhs)
noexcept
80 for (
ssize_t i = 0; i != N; ++i) {
99 template<arithmetic U, s
size_t M>
107 while (src != src_last && dst != dst_last) {
108 *(dst++) = narrow_cast<T>(*(src++));
110 while (dst != dst_last) {
113 while (src != src_last) {
114 tt_axiom(*(src++) == U{});
118 template<arithmetic U, s
size_t M>
128 while (src != src_last && dst != dst_last) {
129 *(dst++) = narrow_cast<U>(*(src++));
131 while (dst != dst_last) {
134 while (src != src_last) {
135 tt_axiom(*(src++) == T{});
141 [[nodiscard]]
constexpr T
const &operator[](
ssize_t i)
const noexcept
147 [[nodiscard]]
constexpr T &operator[](
ssize_t i)
noexcept
153 [[nodiscard]]
constexpr reference front()
noexcept
158 [[nodiscard]]
constexpr const_reference front()
const noexcept
163 [[nodiscard]]
constexpr reference back()
noexcept
168 [[nodiscard]]
constexpr const_reference back()
const noexcept
173 [[nodiscard]]
constexpr pointer data()
noexcept
178 [[nodiscard]]
constexpr const_pointer data()
const noexcept
183 [[nodiscard]]
constexpr iterator begin()
noexcept
188 [[nodiscard]]
constexpr const_iterator begin()
const noexcept
193 [[nodiscard]]
constexpr const_iterator cbegin()
const noexcept
198 [[nodiscard]]
constexpr iterator end()
noexcept
203 [[nodiscard]]
constexpr const_iterator end()
const noexcept
208 [[nodiscard]]
constexpr const_iterator cend()
const noexcept
213 [[nodiscard]]
constexpr bool empty()
const noexcept
218 [[nodiscard]]
constexpr size_type size()
const noexcept
223 [[nodiscard]]
constexpr size_type max_size()
const noexcept
228 constexpr bool is_point()
const noexcept
230 return v.
back() != T{};
233 constexpr bool is_vector()
const noexcept
235 return v.
back() == T{};
238 constexpr bool is_opaque()
const noexcept
243 constexpr bool is_transparent()
const noexcept
248 [[nodiscard]]
constexpr T
const &x()
const noexcept requires(N >= 1)
250 return std::get<0>(v);
253 [[nodiscard]]
constexpr T
const &y()
const noexcept requires(N >= 2)
255 return std::get<1>(v);
258 [[nodiscard]]
constexpr T
const &z()
const noexcept requires(N >= 3)
260 return std::get<2>(v);
263 [[nodiscard]]
constexpr T
const &w()
const noexcept requires(N >= 4)
265 return std::get<3>(v);
268 [[nodiscard]]
constexpr T &x()
noexcept requires(N >= 1)
270 return std::get<0>(v);
273 [[nodiscard]]
constexpr T &y()
noexcept requires(N >= 2)
275 return std::get<1>(v);
278 [[nodiscard]]
constexpr T &z()
noexcept requires(N >= 3)
280 return std::get<2>(v);
283 [[nodiscard]]
constexpr T &w()
noexcept requires(N >= 4)
285 return std::get<3>(v);
288 [[nodiscard]]
constexpr T
const &r()
const noexcept requires(N >= 1)
290 return std::get<0>(v);
293 [[nodiscard]]
constexpr T
const &g()
const noexcept requires(N >= 2)
295 return std::get<1>(v);
298 [[nodiscard]]
constexpr T
const &b()
const noexcept requires(N >= 3)
300 return std::get<2>(v);
303 [[nodiscard]]
constexpr T
const &a()
const noexcept requires(N >= 4)
305 return std::get<3>(v);
308 [[nodiscard]]
constexpr T &r()
noexcept requires(N >= 1)
310 return std::get<0>(v);
313 [[nodiscard]]
constexpr T &g()
noexcept requires(N >= 2)
315 return std::get<1>(v);
318 [[nodiscard]]
constexpr T &b()
noexcept requires(N >= 3)
320 return std::get<2>(v);
323 [[nodiscard]]
constexpr T &a()
noexcept requires(N >= 4)
325 return std::get<3>(v);
328 [[nodiscard]]
constexpr T
const &width()
const noexcept requires(N >= 1)
330 return std::get<0>(v);
333 [[nodiscard]]
constexpr T
const &height()
const noexcept requires(N >= 2)
335 return std::get<1>(v);
338 [[nodiscard]]
constexpr T
const &depth()
const noexcept requires(N >= 3)
340 return std::get<2>(v);
343 [[nodiscard]]
constexpr T &width()
noexcept requires(N >= 1)
345 return std::get<0>(v);
348 [[nodiscard]]
constexpr T &height()
noexcept requires(N >= 2)
350 return std::get<1>(v);
353 [[nodiscard]]
constexpr T &depth()
noexcept requires(N >= 3)
355 return std::get<2>(v);
360 for (
ssize_t i = 0; i != N; ++i) {
368 for (
ssize_t i = 0; i != N; ++i) {
376 for (
ssize_t i = 0; i != N; ++i) {
384 for (
ssize_t i = 0; i != N; ++i) {
392 for (
ssize_t i = 0; i != N; ++i) {
400 for (
ssize_t i = 0; i != N; ++i) {
408 for (
ssize_t i = 0; i != N; ++i) {
416 for (
ssize_t i = 0; i != N; ++i) {
424 for (
ssize_t i = 0; i != N; ++i) {
432 for (
ssize_t i = 0; i != N; ++i) {
438 constexpr static ssize_t get_zero = -1;
439 constexpr static ssize_t get_one = -2;
448 static_assert(I >= 0 && I < N,
"Index out of bounds");
449 return std::get<I>(rhs.v);
460 static_assert(I >= -2 && I < N,
"Index out of bounds");
461 if constexpr (I == get_zero) {
463 }
else if constexpr (I == get_one) {
466 return std::get<I>(rhs.v);
478 static_assert(I >= -2 && I < N,
"Index out of bounds");
479 if constexpr (I == get_zero) {
481 }
else if constexpr (I == get_one) {
484 return std::get<I>(rhs.v);
492 template<
size_t Mask = ~size_t{0}>
495 if (!std::is_constant_evaluated()) {
496 if constexpr (is_f32x4 && has_sse) {
502 for (
ssize_t i = 0; i != N; ++i) {
503 if (
static_cast<bool>((Mask >> i) & 1)) {
516 template<
size_t Mask = ~size_t{0}>
519 if (!std::is_constant_evaluated()) {
520 if constexpr (is_f32x4 && has_sse) {
526 for (
ssize_t i = 0; i != N; ++i) {
527 if (
static_cast<bool>((Mask >> i) & 1)) {
539 for (ssize_t i = 0; i != N; ++i) {
541 r.v[i] = T{} - rhs.v[i];
546 [[nodiscard]]
friend constexpr numeric_array abs(numeric_array
const &rhs)
noexcept
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];
557 [[nodiscard]]
friend constexpr numeric_array rcp(numeric_array
const &rhs)
noexcept
559 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
560 return numeric_array{f32x4_sse_rcp(rhs.v)};
563 auto r = numeric_array{};
564 for (ssize_t i = 0; i != N; ++i) {
565 r[i] = 1.0f / rhs.v[i];
570 [[nodiscard]]
friend constexpr numeric_array sqrt(numeric_array
const &rhs)
noexcept
572 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
573 return numeric_array{f32x4_sse_sqrt(rhs.v)};
576 auto r = numeric_array{};
577 for (ssize_t i = 0; i != N; ++i) {
583 [[nodiscard]]
friend constexpr numeric_array rcp_sqrt(numeric_array
const &rhs)
noexcept
585 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
586 return numeric_array{f32x4_sse_rcp_sqrt(rhs.v)};
589 auto r = numeric_array{};
590 for (ssize_t i = 0; i != N; ++i) {
596 [[nodiscard]]
friend constexpr numeric_array floor(numeric_array
const &rhs)
noexcept
598 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
599 return numeric_array{f32x4_sse_floor(rhs.v)};
602 auto r = numeric_array{};
603 for (ssize_t i = 0; i != N; ++i) {
609 [[nodiscard]]
friend constexpr numeric_array ceil(numeric_array
const &rhs)
noexcept
611 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
612 return numeric_array{f32x4_sse_ceil(rhs.v)};
615 auto r = numeric_array{};
616 for (ssize_t i = 0; i != N; ++i) {
622 [[nodiscard]]
friend constexpr numeric_array round(numeric_array
const &rhs)
noexcept
624 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
625 return numeric_array{f32x4_sse_round(rhs.v)};
628 auto r = numeric_array{};
629 for (ssize_t i = 0; i != N; ++i) {
642 template<s
size_t Mask>
645 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
646 return f32x4_sse_dot<Mask>(lhs.v, rhs.v);
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];
665 template<s
size_t Mask>
668 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
669 return f32x4_sse_hypot<Mask>(rhs.v);
681 template<s
size_t Mask>
684 return dot<Mask>(rhs, rhs);
693 template<s
size_t Mask>
696 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
697 return f32x4_sse_rcp_hypot<Mask>(rhs.v);
700 return 1.0f / hypot<Mask>(rhs);
711 template<s
size_t Mask>
714 tt_axiom(rhs.is_vector());
716 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
720 ttlet rcp_hypot_ = rcp_hypot<Mask>(rhs);
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_;
732 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
734 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
735 return f32x4_sse_eq_mask(lhs.v, rhs.v);
738 for (ssize_t i = 0; i != N; ++i) {
739 r |=
static_cast<unsigned int>(lhs.v[i] == rhs.v[i]) << i;
745 [[nodiscard]]
friend constexpr unsigned int ne(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
746 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
748 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
749 return f32x4_sse_ne_mask(lhs.v, rhs.v);
752 for (ssize_t i = 0; i != N; ++i) {
753 r |=
static_cast<unsigned int>(lhs.v[i] != rhs.v[i]) << i;
759 [[nodiscard]]
friend constexpr unsigned int lt(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
760 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
762 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
763 return f32x4_sse_lt_mask(lhs.v, rhs.v);
766 for (ssize_t i = 0; i != N; ++i) {
767 r |=
static_cast<unsigned int>(lhs.v[i] < rhs.v[i]) << i;
773 [[nodiscard]]
friend constexpr unsigned int gt(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
774 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
776 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
777 return f32x4_sse_gt_mask(lhs.v, rhs.v);
780 for (ssize_t i = 0; i != N; ++i) {
781 r |=
static_cast<unsigned int>(lhs.v[i] > rhs.v[i]) << i;
787 [[nodiscard]]
friend constexpr unsigned int le(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
788 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
790 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
791 return f32x4_sse_le_mask(lhs.v, rhs.v);
794 for (ssize_t i = 0; i != N; ++i) {
795 r |=
static_cast<unsigned int>(lhs.v[i] <= rhs.v[i]) << i;
801 [[nodiscard]]
friend constexpr unsigned int ge(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
802 requires(N <=
sizeof(
unsigned int) * CHAR_BIT)
804 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
805 return f32x4_sse_ge_mask(lhs.v, rhs.v);
808 for (ssize_t i = 0; i != N; ++i) {
809 r |=
static_cast<unsigned int>(lhs.v[i] >= rhs.v[i]) << i;
815 [[nodiscard]]
friend constexpr bool operator==(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
817 if (!std::is_constant_evaluated()) {
818 if constexpr (is_f32x4 && has_sse) {
820 return f32x4_sse_eq(lhs.v, rhs.v);
825 for (ssize_t i = 0; i != N; ++i) {
826 r &= (lhs.v[i] == rhs.v[i]);
831 [[nodiscard]]
friend constexpr bool operator!=(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
833 return !(lhs == rhs);
836 [[nodiscard]]
friend constexpr numeric_array operator+(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
838 auto r = numeric_array{};
839 for (ssize_t i = 0; i != N; ++i) {
840 r.v[i] = lhs.v[i] + rhs.v[i];
845 [[nodiscard]]
friend constexpr numeric_array operator+(numeric_array
const &lhs, T
const &rhs)
noexcept
847 auto r = numeric_array{};
848 for (ssize_t i = 0; i != N; ++i) {
849 r.v[i] = lhs.v[i] + rhs;
854 [[nodiscard]]
friend constexpr numeric_array operator+(T
const &lhs, numeric_array
const &rhs)
noexcept
856 auto r = numeric_array{};
857 for (ssize_t i = 0; i != N; ++i) {
858 r.v[i] = lhs + rhs.v[i];
863 [[nodiscard]]
friend constexpr numeric_array hadd(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
865 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
866 return numeric_array{f32x4_sse_hadd(lhs.v, rhs.v)};
869 tt_axiom(N % 2 == 0);
871 auto r = numeric_array{};
876 auto tmp = lhs[src_i++];
883 auto tmp = rhs[src_i++];
891 [[nodiscard]]
friend constexpr numeric_array hsub(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
893 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
894 return numeric_array{f32x4_sse_hsub(lhs.v, rhs.v)};
897 tt_axiom(N % 2 == 0);
899 auto r = numeric_array{};
904 auto tmp = lhs[src_i++];
911 auto tmp = rhs[src_i++];
919 [[nodiscard]]
friend constexpr numeric_array operator-(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
921 auto r = numeric_array{};
922 for (ssize_t i = 0; i != N; ++i) {
923 r.v[i] = lhs.v[i] - rhs.v[i];
928 [[nodiscard]]
friend constexpr numeric_array operator-(numeric_array
const &lhs, T
const &rhs)
noexcept
930 auto r = numeric_array{};
931 for (ssize_t i = 0; i != N; ++i) {
932 r.v[i] = lhs.v[i] - rhs;
941 template<
size_t Mask = ~size_t{0}>
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)};
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];
955 r.v[i] = lhs.v[i] - rhs.v[i];
964 for (ssize_t i = 0; i != N; ++i) {
965 r.v[i] = lhs - rhs.v[i];
970 [[nodiscard]]
friend constexpr numeric_array operator*(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
972 auto r = numeric_array{};
973 for (ssize_t i = 0; i != N; ++i) {
974 r.v[i] = lhs.v[i] * rhs.v[i];
979 [[nodiscard]]
friend constexpr numeric_array operator*(numeric_array
const &lhs, T
const &rhs)
noexcept
981 auto r = numeric_array{};
982 for (ssize_t i = 0; i != N; ++i) {
983 r.v[i] = lhs.v[i] * rhs;
988 [[nodiscard]]
friend constexpr numeric_array operator*(T
const &lhs, numeric_array
const &rhs)
noexcept
990 auto r = numeric_array{};
991 for (ssize_t i = 0; i != N; ++i) {
992 r.v[i] = lhs * rhs.v[i];
997 [[nodiscard]]
friend constexpr numeric_array operator/(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
999 auto r = numeric_array{};
1000 for (ssize_t i = 0; i != N; ++i) {
1001 r.v[i] = lhs.v[i] / rhs.v[i];
1006 [[nodiscard]]
friend constexpr numeric_array operator/(numeric_array
const &lhs, T
const &rhs)
noexcept
1008 auto r = numeric_array{};
1009 for (ssize_t i = 0; i != N; ++i) {
1010 r.v[i] = lhs.v[i] / rhs;
1015 [[nodiscard]]
friend constexpr numeric_array operator/(T
const &lhs, numeric_array
const &rhs)
noexcept
1017 auto r = numeric_array{};
1018 for (ssize_t i = 0; i != N; ++i) {
1019 r.v[i] = lhs / rhs.v[i];
1024 [[nodiscard]]
friend constexpr numeric_array operator%(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
1026 auto r = numeric_array{};
1027 for (ssize_t i = 0; i != N; ++i) {
1028 r.v[i] = lhs.v[i] % rhs.v[i];
1033 [[nodiscard]]
friend constexpr numeric_array operator%(numeric_array
const &lhs, T
const &rhs)
noexcept
1035 auto r = numeric_array{};
1036 for (ssize_t i = 0; i != N; ++i) {
1037 r.v[i] = lhs.v[i] % rhs;
1042 [[nodiscard]]
friend constexpr numeric_array operator%(T
const &lhs, numeric_array
const &rhs)
noexcept
1044 auto r = numeric_array{};
1045 for (ssize_t i = 0; i != N; ++i) {
1046 r.v[i] = lhs % rhs.v[i];
1051 [[nodiscard]]
friend constexpr numeric_array min(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
1053 auto r = numeric_array{};
1054 for (ssize_t i = 0; i != N; ++i) {
1056 r.v[i] = lhs.v[i] < rhs.v[i] ? lhs.v[i] : rhs.v[i];
1061 [[nodiscard]]
friend constexpr numeric_array max(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
1063 auto r = numeric_array{};
1064 for (ssize_t i = 0; i != N; ++i) {
1066 r.v[i] = lhs.v[i] > rhs.v[i] ? lhs.v[i] : rhs.v[i];
1071 [[nodiscard]]
friend constexpr numeric_array
1072 clamp(numeric_array
const &lhs, numeric_array
const &low, numeric_array
const &high)
noexcept
1074 auto r = numeric_array{};
1075 for (ssize_t i = 0; i != N; ++i) {
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];
1086 tt_axiom(rhs.z() == 0.0f && rhs.is_vector());
1094 return normalize<0b0011>(
cross_2D(rhs));
1102 if (is_f32x4 && has_sse && !std::is_constant_evaluated()) {
1103 return f32x4_sse_viktor_cross(lhs.v, rhs.v);
1106 return lhs.x() * rhs.y() - lhs.y() * rhs.x();
1116 if (!std::is_constant_evaluated()) {
1117 if constexpr (is_f32x4 && has_sse) {
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(),
1136 requires(D == 4) [[nodiscard]]
friend numeric_array
1137 hamilton_cross(numeric_array
const &lhs, numeric_array
const &rhs)
noexcept
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();
1144 ttlet col01 =
addsub(col0, col1);
1145 ttlet col012 =
addsub(col01.xzyw(), col2.xzyw()).xzyw();
1147 return numeric_array{
1156 tt_axiom(p1.is_point());
1157 tt_axiom(p2.is_point());
1158 return (p1 + p2) * 0.5f;
1165 tt_axiom(p.is_point());
1166 tt_axiom(anchor.is_point());
1167 return anchor - (p - anchor);
1170 template<
typename... Columns>
1173 static_assert(
sizeof...(Columns) == N,
"Can only transpose square matrices");
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]};
1184 transpose_detail<0, Columns...>(columns..., r);
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>)
1193 if (over.is_transparent()) {
1196 if (over.is_opaque()) {
1200 ttlet over_alpha = over.wwww();
1201 ttlet under_alpha = under.wwww();
1203 ttlet over_color = over.xyz1();
1204 ttlet under_color = under.xyz1();
1206 ttlet output_color = over_color * over_alpha + under_color * under_alpha * (1.0 - over_alpha);
1208 return output_color / output_color.www1();
1211 [[nodiscard]]
friend std::string to_string(numeric_array
const &rhs)
noexcept
1216 for (ssize_t i = 0; i != N; ++i) {
1220 r += fmt::format(
"{}", rhs[i]);
1228 return lhs << to_string(rhs);
1238 template<ssize_t... Elements>
1241 static_assert(
sizeof...(Elements) <= N);
1243 if (!std::is_constant_evaluated()) {
1244 if constexpr (is_f32x4 && has_sse) {
1250 swizzle_detail<0, Elements...>(r);
1254#define SWIZZLE(swizzle_name, D, ...) \
1255 [[nodiscard]] constexpr numeric_array swizzle_name() const noexcept requires(D == N) \
1257 return swizzle<__VA_ARGS__>(); \
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)
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)
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)
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)
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)
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)
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)
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)
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)
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
1333 template<
int I,
typename First,
typename... Rest>
1334 friend constexpr void
1337 for (
ssize_t j = 0; j != N; ++j) {
1341 if constexpr (
sizeof...(Rest) != 0) {
1342 transpose_detail<I + 1, Rest...>(rest..., r);
1346 template<ssize_t I, ssize_t FirstElement, ssize_t... RestElements>
1347 constexpr void swizzle_detail(numeric_array &r)
const noexcept
1349 static_assert(I < N);
1350 static_assert(FirstElement >= -2 && FirstElement < N,
"Index out of bounds");
1352 get<I>(r) = get<FirstElement>(*
this);
1353 if constexpr (
sizeof...(RestElements) != 0) {
1354 swizzle_detail<I + 1, RestElements...>(r);
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;
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;
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;
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;