29 static_assert(std::has_single_bit(N));
37 std::conditional_t<
sizeof(T) *
CHAR_BIT == 8, uint8_t,
38 std::conditional_t<
sizeof(T) *
CHAR_BIT == 16, uint16_t,
39 std::conditional_t<
sizeof(T) *
CHAR_BIT == 32, uint32_t,
40 std::conditional_t<
sizeof(T) *
CHAR_BIT == 64, uint64_t,
void>>>>;
42 using signed_mask_type = std::make_signed_t<mask_type>;
44 [[
nodiscard]] hi_force_inline
constexpr static mask_type to_mask(value_type a)
noexcept
46 return std::bit_cast<mask_type>(a);
49 [[
nodiscard]] hi_force_inline
constexpr static signed_mask_type to_signed_mask(value_type a)
noexcept
51 return std::bit_cast<signed_mask_type>(a);
54 template<std::
unsigned_
integral M>
55 [[
nodiscard]] hi_force_inline
constexpr static value_type to_value(M a)
noexcept
57 return std::bit_cast<value_type>(
static_cast<mask_type
>(a));
60 template<std::
signed_
integral M>
61 [[
nodiscard]] hi_force_inline
constexpr static value_type to_value(M a)
noexcept
63 return std::bit_cast<value_type>(
static_cast<signed_mask_type
>(a));
66 constexpr static value_type _zero_mask = to_value(mask_type{0});
67 constexpr static value_type _ones_mask = to_value(~mask_type{0});
69 [[
nodiscard]] hi_force_inline
static array_type undefined()
noexcept
71 if (
not std::is_constant_evaluated()) {
72 if constexpr (
requires { intrinsic_type::undefined(); }) {
73 return intrinsic_type::undefined();
80 template<std::same_as<T>... Args>
81 [[
nodiscard]] hi_force_inline
constexpr static array_type set(
Args...
args)
noexcept
82 requires(
sizeof...(Args) == N)
84 if (
not std::is_constant_evaluated()) {
85 if constexpr (
requires { intrinsic_type::set(
args...); }) {
86 return intrinsic_type::set(
args...);
89 return array_type{
args...};
92 [[
nodiscard]] hi_force_inline
constexpr static array_type set(value_type value)
noexcept
94 if (
not std::is_constant_evaluated()) {
95 if constexpr (
requires { intrinsic_type::set(value); }) {
96 return intrinsic_type::set(value);
99 auto r = array_type{};
100 std::get<0>(r) = value;
104 [[
nodiscard]] hi_force_inline
constexpr static array_type set_zero()
noexcept
106 if (
not std::is_constant_evaluated()) {
107 if constexpr (
requires { intrinsic_type::set_zero(); }) {
108 return intrinsic_type::set_zero();
111 auto r = array_type{};
118 [[
nodiscard]] hi_force_inline
constexpr static array_type set_all_ones()
noexcept
120 if (
not std::is_constant_evaluated()) {
121 if constexpr (
requires { intrinsic_type::set_all_ones(); }) {
122 return intrinsic_type::set_all_ones();
125 auto r = array_type{};
132 [[
nodiscard]] hi_force_inline
constexpr static array_type set_one()
noexcept
134 if (
not std::is_constant_evaluated()) {
135 if constexpr (
requires { intrinsic_type::set_one(); }) {
136 return intrinsic_type::set_one();
139 auto r = array_type{};
141 r[i] = value_type{1};
146 [[
nodiscard]] hi_force_inline
constexpr static array_type broadcast(value_type a)
noexcept
148 if (
not std::is_constant_evaluated()) {
149 if constexpr (
requires { intrinsic_type::broadcast(a); }) {
150 return intrinsic_type::broadcast(a);
153 auto r = array_type{};
160 [[
nodiscard]] hi_force_inline
constexpr static array_type broadcast(array_type a)
noexcept
162 if (
not std::is_constant_evaluated()) {
163 if constexpr (
requires { intrinsic_type::broadcast(a); }) {
164 return intrinsic_type::broadcast(a);
167 auto r = array_type{};
169 r[i] = std::get<0>(a);
175 [[
nodiscard]] hi_force_inline
constexpr static value_type get(array_type a)
noexcept
177 if (
not std::is_constant_evaluated()) {
178 if constexpr (
requires { intrinsic_type::template
get<I>(a); }) {
179 return intrinsic_type::template
get<I>(a);
182 return std::get<I>(a);
191 if (
not std::is_constant_evaluated()) {
192 if constexpr (
requires { intrinsic_type::set_mask(mask); }) {
193 return intrinsic_type::set_mask(mask);
198 r[i] = mask & 1 ? _ones_mask : _zero_mask;
210 if (
not std::is_constant_evaluated()) {
211 if constexpr (
requires { intrinsic_type::get_mask(a); }) {
212 return intrinsic_type::get_mask(a);
217 auto const tmp = to_signed_mask(a[i]) < 0 ?
size_t{1} :
size_t{0};
226 if (
not std::is_constant_evaluated()) {
227 if constexpr (
requires { intrinsic_type::convert(a); }) {
228 return intrinsic_type::convert(a);
232 auto r = array_type{};
234 r[i] =
static_cast<value_type
>(a[i]);
239 [[
nodiscard]] hi_force_inline
constexpr static array_type neg(array_type a)
noexcept
241 if (
not std::is_constant_evaluated()) {
242 if constexpr (
requires { intrinsic_type::neg(a); }) {
243 return intrinsic_type::neg(a);
253 template<std::
size_t Mask>
254 [[
nodiscard]] hi_force_inline
constexpr static array_type neg_mask(array_type a)
noexcept
256 if (
not std::is_constant_evaluated()) {
257 if constexpr (
requires { intrinsic_type::template
neg_mask<Mask>(a); }) {
265 [[
nodiscard]] hi_force_inline
constexpr static array_type inv(array_type a)
noexcept
267 if (
not std::is_constant_evaluated()) {
268 if constexpr (
requires { intrinsic_type::inv(a); }) {
269 return intrinsic_type::inv(a);
274 a[i] = to_value(~to_mask(a[i]));
279 [[
nodiscard]] hi_force_inline
constexpr static array_type rcp(array_type a)
noexcept
281 if (
not std::is_constant_evaluated()) {
282 if constexpr (
requires { intrinsic_type::rcp(a); }) {
283 return intrinsic_type::rcp(a);
288 a[i] = value_type{1} / a[i];
293 [[
nodiscard]] hi_force_inline
static array_type sqrt(array_type a)
noexcept
295 if (
not std::is_constant_evaluated()) {
296 if constexpr (
requires { intrinsic_type::sqrt(a); }) {
297 return intrinsic_type::sqrt(a);
307 [[
nodiscard]] hi_force_inline
static array_type rsqrt(array_type a)
noexcept
309 if (
not std::is_constant_evaluated()) {
310 if constexpr (
requires { intrinsic_type::rsqrt(a); }) {
311 return intrinsic_type::rsqrt(a);
321 [[
nodiscard]] hi_force_inline
constexpr static array_type abs(array_type a)
noexcept
323 if (
not std::is_constant_evaluated()) {
324 if constexpr (
requires { intrinsic_type::abs(a); }) {
325 return intrinsic_type::abs(a);
330 a[i] = std::abs(a[i]);
335 [[
nodiscard]] hi_force_inline
constexpr static array_type
round(array_type a)
noexcept
337 if (
not std::is_constant_evaluated()) {
338 if constexpr (
requires { intrinsic_type::round(a); }) {
339 return intrinsic_type::round(a);
349 [[
nodiscard]] hi_force_inline
constexpr static array_type floor(array_type a)
noexcept
351 if (
not std::is_constant_evaluated()) {
352 if constexpr (
requires { intrinsic_type::floor(a); }) {
353 return intrinsic_type::floor(a);
363 [[
nodiscard]] hi_force_inline
constexpr static array_type ceil(array_type a)
noexcept
365 if (
not std::is_constant_evaluated()) {
366 if constexpr (
requires { intrinsic_type::ceil(a); }) {
367 return intrinsic_type::ceil(a);
377 [[
nodiscard]] hi_force_inline
constexpr static array_type add(array_type a, array_type b)
noexcept
379 if (
not std::is_constant_evaluated()) {
380 if constexpr (
requires { intrinsic_type::add(a, b); }) {
381 return intrinsic_type::add(a, b);
391 [[
nodiscard]] hi_force_inline
constexpr static array_type sub(array_type a, array_type b)
noexcept
393 if (
not std::is_constant_evaluated()) {
394 if constexpr (
requires { intrinsic_type::sub(a, b); }) {
395 return intrinsic_type::sub(a, b);
409 template<std::
size_t Mask>
412 if (
not std::is_constant_evaluated()) {
421 [[
nodiscard]] hi_force_inline
constexpr static array_type mul(array_type a, array_type b)
noexcept
423 if (
not std::is_constant_evaluated()) {
424 if constexpr (
requires { intrinsic_type::mul(a, b); }) {
425 return intrinsic_type::mul(a, b);
435 [[
nodiscard]] hi_force_inline
constexpr static array_type div(array_type a, array_type b)
noexcept
437 if (
not std::is_constant_evaluated()) {
438 if constexpr (
requires { intrinsic_type::div(a, b); }) {
439 return intrinsic_type::div(a, b);
449 [[
nodiscard]] hi_force_inline
constexpr static array_type mod(array_type a, array_type b)
noexcept
451 if (
not std::is_constant_evaluated()) {
452 if constexpr (
requires { intrinsic_type::mod(a, b); }) {
453 return intrinsic_type::mod(a, b);
458 if constexpr (std::floating_point<T>) {
467 [[
nodiscard]] hi_force_inline
constexpr static array_type eq(array_type a, array_type b)
noexcept
469 if (
not std::is_constant_evaluated()) {
470 if constexpr (
requires { intrinsic_type::eq(a, b); }) {
471 return intrinsic_type::eq(a, b);
476 a[i] = a[i] == b[i] ? _ones_mask : _zero_mask;
481 [[
nodiscard]] hi_force_inline
constexpr static array_type ne(array_type a, array_type b)
noexcept
483 if (
not std::is_constant_evaluated()) {
484 if constexpr (
requires { intrinsic_type::ne(a, b); }) {
485 return intrinsic_type::ne(a, b);
490 a[i] = a[i] != b[i] ? _ones_mask : _zero_mask;
495 [[
nodiscard]] hi_force_inline
constexpr static array_type lt(array_type a, array_type b)
noexcept
497 if (
not std::is_constant_evaluated()) {
498 if constexpr (
requires { intrinsic_type::lt(a, b); }) {
499 return intrinsic_type::lt(a, b);
504 a[i] = a[i] < b[i] ? _ones_mask : _zero_mask;
509 [[
nodiscard]] hi_force_inline
constexpr static array_type gt(array_type a, array_type b)
noexcept
511 if (
not std::is_constant_evaluated()) {
512 if constexpr (
requires { intrinsic_type::gt(a, b); }) {
513 return intrinsic_type::gt(a, b);
518 a[i] = a[i] > b[i] ? _ones_mask : _zero_mask;
523 [[
nodiscard]] hi_force_inline
constexpr static array_type le(array_type a, array_type b)
noexcept
525 if (
not std::is_constant_evaluated()) {
526 if constexpr (
requires { intrinsic_type::le(a, b); }) {
527 return intrinsic_type::le(a, b);
532 a[i] = a[i] <= b[i] ? _ones_mask : _zero_mask;
537 [[
nodiscard]] hi_force_inline
constexpr static array_type ge(array_type a, array_type b)
noexcept
539 if (
not std::is_constant_evaluated()) {
540 if constexpr (
requires { intrinsic_type::ge(a, b); }) {
541 return intrinsic_type::ge(a, b);
546 a[i] = a[i] >= b[i] ? _ones_mask : _zero_mask;
558 if (
not std::is_constant_evaluated()) {
559 if constexpr (
requires { intrinsic_type::test(a, b); }) {
560 return intrinsic_type::test(a, b);
564 auto r = mask_type{0};
566 r |= to_mask(a[i]) & to_mask(b[i]);
578 auto const tmp = ne(a, b);
583 [[
nodiscard]] hi_force_inline
constexpr static array_type max(array_type a, array_type b)
noexcept
585 if (
not std::is_constant_evaluated()) {
586 if constexpr (
requires { intrinsic_type::max(a, b); }) {
587 return intrinsic_type::max(a, b);
597 [[
nodiscard]] hi_force_inline
constexpr static array_type min(array_type a, array_type b)
noexcept
599 if (
not std::is_constant_evaluated()) {
600 if constexpr (
requires { intrinsic_type::min(a, b); }) {
601 return intrinsic_type::min(a, b);
611 [[
nodiscard]] hi_force_inline
constexpr static array_type clamp(array_type v, array_type
lo, array_type
hi)
noexcept
613 if (
not std::is_constant_evaluated()) {
614 if constexpr (
requires { intrinsic_type::clamp(v,
lo,
hi); }) {
615 return intrinsic_type::clamp(v,
lo,
hi);
620 v[i] = std::clamp(v[i],
lo[i],
hi[i]);
625 [[
nodiscard]] hi_force_inline
constexpr static array_type _or(array_type a, array_type b)
noexcept
627 if (
not std::is_constant_evaluated()) {
628 if constexpr (
requires { intrinsic_type::_or(a, b); }) {
629 return intrinsic_type::_or(a, b);
634 a[i] = to_value(to_mask(a[i]) | to_mask(b[i]));
639 [[
nodiscard]] hi_force_inline
constexpr static array_type _and(array_type a, array_type b)
noexcept
641 if (
not std::is_constant_evaluated()) {
642 if constexpr (
requires { intrinsic_type::_and(a, b); }) {
643 return intrinsic_type::_and(a, b);
648 a[i] = to_value(to_mask(a[i]) & to_mask(b[i]));
653 [[
nodiscard]] hi_force_inline
constexpr static array_type _xor(array_type a, array_type b)
noexcept
655 if (
not std::is_constant_evaluated()) {
656 if constexpr (
requires { intrinsic_type::_xor(a, b); }) {
657 return intrinsic_type::_xor(a, b);
662 a[i] = to_value(to_mask(a[i]) ^ to_mask(b[i]));
675 if (
not std::is_constant_evaluated()) {
676 if constexpr (
requires { intrinsic_type::andnot(a, b); }) {
677 return intrinsic_type::andnot(a, b);
682 a[i] = to_value(~to_mask(a[i]) & to_mask(b[i]));
687 [[
nodiscard]] hi_force_inline
constexpr static array_type sll(array_type a,
unsigned int b)
noexcept
689 if (
not std::is_constant_evaluated()) {
690 if constexpr (
requires { intrinsic_type::sll(a, b); }) {
691 return intrinsic_type::sll(a, b);
695 if (b >=
sizeof(value_type) *
CHAR_BIT) {
699 a[i] = to_value(to_mask(a[0]) << b);
705 [[
nodiscard]] hi_force_inline
constexpr static array_type srl(array_type a,
unsigned int b)
noexcept
707 if (
not std::is_constant_evaluated()) {
708 if constexpr (
requires { intrinsic_type::srl(a, b); }) {
709 return intrinsic_type::srl(a, b);
713 if (b >=
sizeof(value_type) *
CHAR_BIT) {
717 a[i] = to_value(to_mask(a[0]) >> b);
723 [[
nodiscard]] hi_force_inline
constexpr static array_type sra(array_type a,
unsigned int b)
noexcept
725 if (
not std::is_constant_evaluated()) {
726 if constexpr (
requires { intrinsic_type::sra(a, b); }) {
727 return intrinsic_type::sra(a, b);
731 if (b >=
sizeof(value_type) *
CHAR_BIT) {
732 b =
sizeof(value_type) *
CHAR_BIT - 1;
736 a[i] = to_value(to_signed_mask(a[0]) >> b);
746 if (
not std::is_constant_evaluated()) {
747 if constexpr (
requires { intrinsic_type::hadd(a, b); }) {
748 return intrinsic_type::hadd(a, b);
765 [[
nodiscard]] hi_force_inline
constexpr static array_type hsub(array_type a, array_type b)
noexcept
767 if (
not std::is_constant_evaluated()) {
768 if constexpr (
requires { intrinsic_type::hsub(a, b); }) {
769 return intrinsic_type::hsub(a, b);
773 auto r = array_type{};
786 template<
size_t I,
int First,
int...
Rest>
787 hi_force_inline
constexpr static void _shuffle(array_type& r, array_type a)
noexcept
789 static_assert(std::cmp_less(
First, N));
791 if constexpr (
First < 0) {
792 std::get<I>(r) = std::get<I>(a);
794 std::get<I>(r) = std::get<First>(a);
797 if constexpr (
sizeof...(Rest)) {
798 _shuffle<I + 1,
Rest...>(r, a);
802 template<
size_t I,
int First,
int...
Rest>
805 static_assert(std::cmp_less(
First, N));
811 if constexpr (
sizeof...(Rest)) {
812 return _have_to_shuffle<I + 1,
Rest...>();
819 [[
nodiscard]] hi_force_inline
constexpr static array_type shuffle(array_type a)
noexcept
821 static_assert(
sizeof...(Indices) == N);
823 if constexpr (
not _have_to_shuffle<0,
Indices...>()) {
828 if (
not std::is_constant_evaluated()) {
829 if constexpr (
requires { intrinsic_type::template shuffle<
Indices...>(a); }) {
830 return intrinsic_type::template shuffle<
Indices...>(a);
834 auto r = array_type{};
839 template<
size_t Mask>
840 [[
nodiscard]] hi_force_inline
constexpr static array_type blend(array_type a, array_type b)
noexcept
842 if constexpr (
Mask == 0) {
845 }
else if constexpr (
Mask == (1ULL << N) - 1) {
850 if (
not std::is_constant_evaluated()) {
851 if constexpr (
requires { intrinsic_type::template
blend<Mask>(a, b); }) {
858 a[i] = mask & 1 ? b[i] : a[i];
867 hi_warning_ignore_msvc(26494);
868 template<std::derived_from<array_type>... Columns>
870 requires(
sizeof...(Columns) == N)
872 if (
not std::is_constant_evaluated()) {
873 if constexpr (
requires { intrinsic_type::transpose(columns...); }) {
874 return intrinsic_type::transpose(columns...);
881 auto tf = [&r](
auto i,
auto v) {
887 static_cast<void>((
tf(
Ints, columns) + ...));
889 f(std::make_index_sequence<
sizeof...(columns)>{});
895 constexpr static void _make_swizzle_blend_mask(
std::size_t& r)
noexcept
901 if constexpr (
sizeof...(Rest)) {
902 _make_swizzle_blend_mask<I + 1,
Value,
Rest...>(r);
940 [[
nodiscard]] hi_force_inline
constexpr static array_type sum(array_type a)
noexcept
942 if (
not std::is_constant_evaluated()) {
943 if constexpr (
requires { intrinsic_type::sum(a); }) {
944 return intrinsic_type::sum(a);
948 auto r = value_type{0};
955 template<
size_t Mask>
956 [[
nodiscard]] hi_force_inline
constexpr static array_type dot(array_type a, array_type b)
noexcept
958 if (
not std::is_constant_evaluated()) {
959 if constexpr (
requires { intrinsic_type::template
dot<Mask>(a, b); }) {
960 return intrinsic_type::template
dot<Mask>(a, b);
964 auto const tmp1 = mul(a, b);
969 template<
size_t Mask>
970 [[
nodiscard]] hi_force_inline
constexpr static array_type hypot(array_type a)
noexcept
972 if (
not std::is_constant_evaluated()) {
973 if constexpr (
requires { intrinsic_type::template
hypot<Mask>(a); }) {
981 template<
size_t Mask>
982 [[
nodiscard]] hi_force_inline
constexpr static array_type rhypot(array_type a)
noexcept
984 if (
not std::is_constant_evaluated()) {
985 if constexpr (
requires { intrinsic_type::template
rhypot<Mask>(a); }) {
993 template<
size_t Mask>
994 [[
nodiscard]] hi_force_inline
constexpr static array_type normalize(array_type a)
noexcept
996 if (
not std::is_constant_evaluated()) {
997 if constexpr (
requires { intrinsic_type::template
normalize<Mask>(a); }) {