7#include "native_f32x4_sse.hpp"
8#include "native_f64x4_avx.hpp"
9#include "native_i32x4_sse2.hpp"
10#include "native_i64x4_avx2.hpp"
11#include "native_u32x4_sse2.hpp"
12#include "native_simd_conversions_x86.hpp"
14#include "../utility/utility.hpp"
15#include "../macros.hpp"
30hi_warning_ignore_msvc(4702);
33hi_warning_ignore_msvc(26467);
36hi_warning_ignore_msvc(26472)
38#define HI_X_runtime_evaluate_if_valid(...) \
40 if (not std::is_constant_evaluated()) { \
41 if constexpr (requires { __VA_ARGS__; }) { \
47#define HI_X_accessor(index, name) \
48 [[nodiscard]] constexpr T name() const noexcept \
51 HI_X_runtime_evaluate_if_valid(get<index>(reg())); \
52 return std::get<index>(v); \
55 [[nodiscard]] constexpr T& name() noexcept \
58 return std::get<index>(v); \
61#define HI_X_binary_math_op(op) \
62 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
63 requires(requires(value_type a, value_type b) { a op b; }) \
65 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
68 for (std::size_t i = 0; i != N; ++i) { \
69 r[i] = lhs[i] op rhs[i]; \
74#define HI_X_binary_bit_op(op) \
75 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
77 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
80 for (std::size_t i = 0; i != N; ++i) { \
81 hilet lhs_vi = std::bit_cast<unsigned_type>(lhs[i]); \
82 hilet rhs_vi = std::bit_cast<unsigned_type>(rhs[i]); \
83 hilet r_vi = static_cast<unsigned_type>(lhs_vi op rhs_vi); \
84 r[i] = std::bit_cast<value_type>(r_vi); \
89#define HI_X_binary_shift_op(op) \
90 [[nodiscard]] friend constexpr simd operator op(simd const& lhs, unsigned int rhs) noexcept \
92 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs}); \
95 for (std::size_t i = 0; i != N; ++i) { \
96 r.v[i] = lhs.v[i] op rhs; \
101#define HI_X_binary_cmp_op(op) \
102 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
103 requires(requires(value_type a, value_type b) { a op b; }) \
105 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
108 for (std::size_t i = 0; i != N; ++i) { \
109 r[i] = lhs[i] op rhs[i] ? ones_value : zero_value; \
114#define HI_X_binary_op_broadcast(op) \
115 [[nodiscard]] friend constexpr auto operator op(value_type lhs, simd rhs) noexcept \
116 requires(requires(value_type a, value_type b) { a op b; }) \
118 return broadcast(lhs) op rhs; \
121 [[nodiscard]] friend constexpr auto operator op(simd lhs, value_type rhs) noexcept \
122 requires(requires(value_type a, value_type b) { a op b; }) \
124 return lhs op broadcast(rhs); \
127#define HI_X_inplace_op(long_op, short_op) \
128 constexpr simd& operator long_op(auto rhs) noexcept \
129 requires(requires { *this short_op rhs; }) \
131 return *this = *this short_op rhs; \
136template<numeric_limited T, std::
size_t N>
138 using value_type = T;
139 constexpr static size_t size = N;
141 using unsigned_type = make_uintxx_t<
sizeof(value_type) * CHAR_BIT>;
143 constexpr static bool has_native_type =
requires {
typename native_simd<value_type, size>::value_type; };
144 using native_type = native_simd<value_type, size>;
147 using size_type =
typename array_type::size_type;
148 using difference_type =
typename array_type::difference_type;
149 using reference =
typename array_type::reference;
150 using const_reference =
typename array_type::const_reference;
151 using pointer =
typename array_type::pointer;
152 using const_pointer =
typename array_type::const_pointer;
153 using iterator =
typename array_type::iterator;
154 using const_iterator =
typename array_type::const_iterator;
156 constexpr static value_type zero_value = value_type{};
161 constexpr simd() noexcept
163 if (not std::is_constant_evaluated()) {
164 if constexpr (
requires { *
this = simd{native_type{}}; }) {
165 *
this = simd{native_type{}};
171 constexpr simd(simd
const& rhs)
noexcept =
default;
172 constexpr simd(simd&& rhs)
noexcept =
default;
173 constexpr simd& operator=(simd
const& rhs)
noexcept =
default;
174 constexpr simd& operator=(simd&& rhs)
noexcept =
default;
176 template<numeric_limited U>
177 [[nodiscard]]
constexpr explicit simd(simd<U, N>
const& other)
noexcept
179 if (not std::is_constant_evaluated()) {
180 if constexpr (
requires { *
this = simd{native_type{
other.reg()}}; }) {
181 *
this = simd{native_type{
other.reg()}};
187 if constexpr (std::is_integral_v<T> and std::is_floating_point_v<U>) {
189 v[i] =
static_cast<value_type
>(
std::round(other[i]));
191 v[i] =
static_cast<value_type
>(
other[i]);
196 template<numeric_limited U>
197 [[nodiscard]]
constexpr explicit simd(simd<U, size / 2>
const& a, simd<U, size / 2>
const& b)
noexcept
199 if (not std::is_constant_evaluated()) {
200 if constexpr (
requires { simd{native_type{a.reg(), b.reg()}}; }) {
201 *
this = simd{native_type{a.reg(), b.reg()}};
207 hilet tmp = i < (size / 2) ? a[i] : b[i];
208 if constexpr (std::is_integral_v<T> and std::is_floating_point_v<U>) {
210 v[i] =
static_cast<value_type
>(
std::round(tmp));
212 v[i] =
static_cast<value_type
>(tmp);
217 template<std::convertible_to<value_type>... Args>
218 [[nodiscard]]
constexpr explicit simd(value_type first, Args... args)
noexcept
220 if (not std::is_constant_evaluated()) {
221 if constexpr (
requires { simd{native_type{first,
static_cast<value_type
>(args)...}}; }) {
222 *
this = simd{native_type{first,
static_cast<value_type
>(args)...}};
227 v = array_type{first,
static_cast<value_type
>(args)...};
230 [[nodiscard]]
constexpr static simd broadcast(T rhs)
noexcept
232 HI_X_runtime_evaluate_if_valid(simd{native_type::broadcast(rhs)});
241 [[nodiscard]]
constexpr static simd epsilon() noexcept
243 if constexpr (std::is_floating_point_v<T>) {
246 return broadcast(T{0});
263 [[nodiscard]]
explicit simd(native_type rhs)
noexcept
264 requires(
requires {
typename native_type::value_type; })
265 : v(static_cast<array_type>(rhs))
269 [[nodiscard]]
auto reg() const noexcept
270 requires(requires {
typename native_type::value_type; })
272 return native_type{v};
275 template<numeric_limited O,
size_t M>
276 [[nodiscard]]
constexpr static simd cast_from(simd<O, M>
const& rhs)
noexcept
277 requires(
sizeof(simd<O, M>) ==
sizeof(simd))
279 HI_X_runtime_evaluate_if_valid(simd{native_type::cast_from(rhs.reg())});
281 return std::bit_cast<simd>(rhs);
288 template<std::
size_t S>
289 [[nodiscard]]
constexpr static simd
load(std::byte
const *ptr)
noexcept
291 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
302 [[nodiscard]]
constexpr static simd
load(std::byte
const *ptr)
noexcept
304 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
315 [[nodiscard]]
constexpr static simd
load(T
const *ptr)
noexcept
317 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
324 template<std::
size_t S>
325 constexpr void store(std::byte *ptr)
const noexcept
327 HI_X_runtime_evaluate_if_valid(reg().store(ptr));
334 constexpr void store(std::byte *ptr)
const noexcept
336 HI_X_runtime_evaluate_if_valid(reg().store(ptr));
337 store<sizeof(*this)>(ptr);
340 [[nodiscard]]
constexpr size_t mask() const noexcept
342 HI_X_runtime_evaluate_if_valid(reg().mask());
345 for (
auto i = N; i != 0; --i) {
347 r |= std::bit_cast<unsigned_type>(v[i - 1]) >> (
sizeof(unsigned_type) * CHAR_BIT - 1);
352 [[nodiscard]]
constexpr T
const& operator[](
std::size_t i)
const noexcept
354 static_assert(std::endian::native == std::endian::little,
"Indices need to be reversed on big endian machines");
359 [[nodiscard]]
constexpr T& operator[](
std::size_t i)
noexcept
361 static_assert(std::endian::native == std::endian::little,
"Indices need to be reversed on big endian machines");
366 [[nodiscard]]
constexpr reference front() noexcept
371 [[nodiscard]]
constexpr const_reference front() const noexcept
376 [[nodiscard]]
constexpr reference back() noexcept
381 [[nodiscard]]
constexpr const_reference back() const noexcept
386 [[nodiscard]]
constexpr pointer data() noexcept
391 [[nodiscard]]
constexpr const_pointer data() const noexcept
396 [[nodiscard]]
constexpr iterator
begin() noexcept
401 [[nodiscard]]
constexpr const_iterator
begin() const noexcept
406 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
411 [[nodiscard]]
constexpr iterator
end() noexcept
416 [[nodiscard]]
constexpr const_iterator
end() const noexcept
421 [[nodiscard]]
constexpr const_iterator cend() const noexcept
426 [[nodiscard]]
constexpr bool empty() const noexcept
439 HI_X_accessor(0, width);
440 HI_X_accessor(1, height);
441 HI_X_accessor(2, depth);
443 HI_X_binary_math_op(+);
444 HI_X_binary_math_op(-);
445 HI_X_binary_math_op(*);
446 HI_X_binary_math_op(/);
447 HI_X_binary_math_op(%);
449 HI_X_binary_cmp_op(==);
450 HI_X_binary_cmp_op(!=);
451 HI_X_binary_cmp_op(<);
452 HI_X_binary_cmp_op(>);
453 HI_X_binary_cmp_op(<=);
454 HI_X_binary_cmp_op(>=);
456 HI_X_binary_bit_op(^);
457 HI_X_binary_bit_op(&);
458 HI_X_binary_bit_op(|);
459 HI_X_binary_shift_op(<<);
460 HI_X_binary_shift_op(>>);
462 [[nodiscard]]
friend constexpr bool equal(simd lhs, simd rhs)
noexcept
464 HI_X_runtime_evaluate_if_valid(
equal(lhs.reg(), rhs.reg()));
466 for (
auto i = 0_uz; i != N; ++i) {
467 if (lhs.v[i] != rhs.v[i]) {
474 HI_X_binary_op_broadcast(==);
475 HI_X_binary_op_broadcast(!=);
476 HI_X_binary_op_broadcast(<);
477 HI_X_binary_op_broadcast(>);
478 HI_X_binary_op_broadcast(<=);
479 HI_X_binary_op_broadcast(>=);
480 HI_X_binary_op_broadcast(+);
481 HI_X_binary_op_broadcast(-);
482 HI_X_binary_op_broadcast(*);
483 HI_X_binary_op_broadcast(/);
484 HI_X_binary_op_broadcast(%);
485 HI_X_binary_op_broadcast(&);
486 HI_X_binary_op_broadcast(|);
487 HI_X_binary_op_broadcast(^);
489 HI_X_inplace_op(+=, +);
490 HI_X_inplace_op(-=, -);
491 HI_X_inplace_op(*=, *);
492 HI_X_inplace_op(/=, /);
493 HI_X_inplace_op(%=, %);
494 HI_X_inplace_op(|=, |);
495 HI_X_inplace_op(&=, &);
496 HI_X_inplace_op(^=, ^);
497 HI_X_inplace_op(<<=, <<);
498 HI_X_inplace_op(>>=, >>);
504 template<std::
size_t I>
505 [[nodiscard]]
friend constexpr T& get(simd& rhs)
noexcept
507 static_assert(I < N,
"Index out of bounds");
508 return std::get<I>(rhs.v);
515 template<std::
size_t I>
516 [[nodiscard]]
friend constexpr T get(simd
const& rhs)
noexcept
518 static_assert(I < N,
"Index out of bounds");
519 HI_X_runtime_evaluate_if_valid(get<I>(rhs.reg()));
520 return std::get<I>(rhs.v);
530 template<std::
size_t I>
531 [[nodiscard]]
constexpr friend simd insert(simd
const& lhs, value_type rhs)
noexcept
533 static_assert(I < size);
534 HI_X_runtime_evaluate_if_valid(simd{insert<I>(lhs.reg(), rhs)});
537 std::get<I>(r.v) = rhs;
546 [[nodiscard]]
friend constexpr simd set_zero(simd rhs)
noexcept
548 HI_X_runtime_evaluate_if_valid(simd{set_zero<Mask>(rhs.reg())});
552 if (to_bool((Mask >> i) & 1)) {
568 template<std::
size_t Mask>
569 [[nodiscard]]
friend constexpr simd blend(simd
const& lhs, simd
const& rhs)
noexcept
571 HI_X_runtime_evaluate_if_valid(simd{blend<Mask>(lhs.reg(), rhs.reg())});
575 r[i] = to_bool((Mask >> i) & 1) ? rhs[i] : lhs[i];
582 [[nodiscard]]
friend constexpr simd blend(simd
const& a, simd
const& b, simd
const& mask)
584 HI_X_runtime_evaluate_if_valid(simd{blend(a.reg(), b.reg(), mask.reg())});
588 r[i] = mask[i] != T{0} ? b[i] : a[i];
597 template<std::
size_t Mask>
598 [[nodiscard]]
friend constexpr simd neg(simd rhs)
noexcept
600 return blend<Mask>(rhs, -rhs);
603 [[nodiscard]]
friend constexpr simd operator-(simd
const& rhs)
noexcept
605 HI_X_runtime_evaluate_if_valid(simd{-rhs.reg()});
609 [[nodiscard]]
friend constexpr simd abs(simd
const& rhs)
noexcept
611 HI_X_runtime_evaluate_if_valid(simd{abs(rhs.reg())});
612 return max(rhs, -rhs);
615 [[nodiscard]]
friend constexpr simd rcp(simd
const& rhs)
noexcept
617 HI_X_runtime_evaluate_if_valid(simd{rcp(rhs.reg())});
621 [[nodiscard]]
friend constexpr simd
sqrt(simd
const& rhs)
noexcept
623 HI_X_runtime_evaluate_if_valid(simd{
sqrt(rhs.reg())});
632 [[nodiscard]]
friend constexpr simd rcp_sqrt(simd
const& rhs)
noexcept
634 HI_X_runtime_evaluate_if_valid(simd{rcp_sqrt(rhs.reg())});
635 return rcp(
sqrt(rhs));
638 [[nodiscard]]
friend constexpr simd
floor(simd
const& rhs)
noexcept
639 requires(std::is_floating_point_v<value_type>)
641 HI_X_runtime_evaluate_if_valid(simd{
floor(rhs.reg())});
650 [[nodiscard]]
friend constexpr simd
ceil(simd
const& rhs)
noexcept
651 requires(std::is_floating_point_v<value_type>)
653 HI_X_runtime_evaluate_if_valid(simd{
ceil(rhs.reg())});
662 [[nodiscard]]
friend constexpr simd
round(simd
const& rhs)
noexcept
663 requires(std::is_floating_point_v<value_type>)
665 HI_X_runtime_evaluate_if_valid(simd{
round(rhs.reg())});
681 template<std::
size_t Mask>
682 [[nodiscard]] hi_force_inline
friend constexpr T dot(simd
const& lhs, simd
const& rhs)
noexcept
684 HI_X_runtime_evaluate_if_valid(get<0>(dot<Mask>(lhs.reg(), rhs.reg())));
688 if (to_bool(Mask & (1_uz << i))) {
689 r += lhs.v[i] * rhs.v[i];
701 template<std::
size_t Mask>
702 [[nodiscard]]
friend T
hypot(simd
const& rhs)
noexcept
703 requires(std::is_floating_point_v<value_type>)
705 HI_X_runtime_evaluate_if_valid(get<0>(
sqrt(dot<Mask>(rhs.reg(), rhs.reg()))));
715 template<std::
size_t Mask>
716 [[nodiscard]] hi_force_inline
friend constexpr T squared_hypot(simd
const& rhs)
noexcept
718 HI_X_runtime_evaluate_if_valid(get<0>(dot<Mask>(rhs.reg(), rhs.reg())));
719 return dot<Mask>(rhs, rhs);
727 template<std::
size_t Mask>
728 [[nodiscard]]
friend constexpr T rcp_hypot(simd
const& rhs)
noexcept
730 HI_X_runtime_evaluate_if_valid(get<0>(rcp_sqrt(dot<Mask>(rhs.reg(), rhs.reg()))));
731 return 1.0f / hypot<Mask>(rhs);
741 template<std::
size_t Mask>
742 [[nodiscard]]
friend constexpr simd normalize(simd
const& rhs)
noexcept
744 HI_X_runtime_evaluate_if_valid(simd{rhs * rcp_sqrt(dot<Mask>(rhs.reg(), rhs.reg()))});
746 hilet rcp_hypot_ = rcp_hypot<Mask>(rhs);
750 if (to_bool(Mask & (1_uz << i))) {
751 r.v[i] = rhs.v[i] * rcp_hypot_;
761 [[nodiscard]]
friend constexpr simd rotl(simd
const& lhs,
unsigned int rhs)
noexcept
763 hi_axiom(rhs > 0 and rhs <
sizeof(value_type) * CHAR_BIT);
765 hilet
remainder = narrow_cast<unsigned int>(
sizeof(value_type) * CHAR_BIT - rhs);
767 return (lhs << rhs) | (lhs >>
remainder);
774 [[nodiscard]]
friend constexpr simd rotr(simd
const& lhs,
unsigned int rhs)
noexcept
776 hi_axiom(rhs > 0 and rhs <
sizeof(value_type) * CHAR_BIT);
778 hilet
remainder = narrow_cast<unsigned int>(
sizeof(value_type) * CHAR_BIT - rhs);
780 return (lhs >> rhs) | (lhs <<
remainder);
783 [[nodiscard]]
friend constexpr simd
min(simd
const& lhs, simd
const& rhs)
noexcept
785 HI_X_runtime_evaluate_if_valid(simd{
min(lhs.reg(), rhs.reg())});
789 r.v[i] =
std::min(lhs.v[i], rhs.v[i]);
794 [[nodiscard]]
friend constexpr simd
max(simd
const& lhs, simd
const& rhs)
noexcept
796 HI_X_runtime_evaluate_if_valid(simd{
max(lhs.reg(), rhs.reg())});
800 r.v[i] =
std::max(lhs.v[i], rhs.v[i]);
805 [[nodiscard]]
friend constexpr simd clamp(simd
const& lhs, simd
const& low, simd
const& high)
noexcept
807 return min(
max(lhs, low), high);
810 [[nodiscard]]
friend constexpr simd hadd(simd
const& lhs, simd
const& rhs)
noexcept
812 HI_X_runtime_evaluate_if_valid(simd{horizontal_add(lhs.reg(), rhs.reg())});
814 hi_axiom(N % 2 == 0);
821 auto tmp = lhs[src_i++];
828 auto tmp = rhs[src_i++];
835 [[nodiscard]]
friend constexpr simd hsub(simd
const& lhs, simd
const& rhs)
noexcept
837 HI_X_runtime_evaluate_if_valid(simd{horizontal_sub(lhs.reg(), rhs.reg())});
839 hi_axiom(N % 2 == 0);
846 auto tmp = lhs[src_i++];
853 auto tmp = rhs[src_i++];
864 template<std::
size_t Mask>
865 [[nodiscard]]
friend constexpr simd addsub(simd
const& lhs, simd
const& rhs)
noexcept
868 return lhs + neg<Mask ^ not_mask>(rhs);
873 [[nodiscard]]
friend constexpr simd cross_2D(simd
const& rhs)
noexcept
876 return simd{-rhs.y(), rhs.x()};
881 [[nodiscard]]
friend constexpr simd normal_2D(simd
const& rhs)
noexcept
884 return normalize<0b0011>(cross_2D(rhs));
890 [[nodiscard]]
friend constexpr float cross_2D(simd
const& lhs, simd
const& rhs)
noexcept
893 hilet tmp1 = rhs.yxwz();
894 hilet tmp2 = lhs * tmp1;
895 hilet tmp3 = hsub(tmp2, tmp2);
903 [[nodiscard]]
constexpr friend simd cross_3D(simd
const& lhs, simd
const& rhs)
noexcept
906 hilet a_left = lhs.yzxw();
907 hilet b_left = rhs.zxyw();
908 hilet
left = a_left * b_left;
910 hilet a_right = lhs.zxyw();
911 hilet b_right = rhs.yzxw();
912 hilet
right = a_right * b_right;
916 [[nodiscard]]
constexpr static simd byte_srl_shuffle_indices(
unsigned int rhs)
917 requires(std::is_same_v<value_type, int8_t> and size == 16)
919 static_assert(std::endian::native == std::endian::little);
922 for (
auto i = 0; i != 16; ++i) {
923 if ((i + rhs) < 16) {
924 r[i] = narrow_cast<int8_t>(i + rhs);
933 [[nodiscard]]
constexpr static simd byte_sll_shuffle_indices(
unsigned int rhs)
934 requires(std::is_same_v<value_type, int8_t> and size == 16)
936 static_assert(std::endian::native == std::endian::little);
939 for (
auto i = 0; i != 16; ++i) {
940 if ((i - rhs) >= 0) {
941 r[i] = narrow_cast<int8_t>(i - rhs);
952 [[nodiscard]]
friend constexpr simd permute(simd
const& lhs, simd
const& rhs)
noexcept
953 requires(std::is_integral_v<value_type>)
955 HI_X_runtime_evaluate_if_valid(simd{permute(lhs.reg(), rhs.reg())});
960 r[i] = lhs[rhs[i] & 0xf];
971 [[nodiscard]]
friend constexpr simd midpoint(simd
const& p1, simd
const& p2)
noexcept
973 return (p1 + p2) * 0.5f;
978 [[nodiscard]]
friend constexpr simd reflect_point(simd
const& p, simd
const anchor)
noexcept
980 return anchor - (p - anchor);
986 hi_warning_ignore_msvc(26494);
987 template<
typename... Columns>
990 static_assert(
sizeof...(Columns) == size,
"Can only transpose square matrices");
992 if (not std::is_constant_evaluated()) {
993 if constexpr (
requires { transpose(columns.reg()...); }) {
994 hilet tmp = transpose(columns.reg()...);
996 for (
auto i = 0_uz; i != size; ++i) {
1004 auto f = [&r, &columns... ]<
std::size_t... Ints>(std::index_sequence<Ints...>)
1006 auto tf = [&r](
auto i,
auto v) {
1012 static_cast<void>((tf(Ints, columns) + ...));
1014 f(std::make_index_sequence<
sizeof...(columns)>{});
1019 [[nodiscard]]
constexpr friend simd
composit(simd
const& under, simd
const& over)
noexcept
1020 requires(N == 4 && std::is_floating_point_v<T>)
1022 if (get<3>(over) <= value_type{0}) {
1026 if (get<3>(over) >= value_type{1}) {
1031 hilet over_alpha = over.wwww();
1032 hilet under_alpha = under.wwww();
1034 hilet over_color = over.xyz1();
1035 hilet under_color = under.xyz1();
1037 hilet output_color = over_color * over_alpha + under_color * under_alpha * (T{1} - over_alpha);
1039 return output_color / output_color.www1();
1042 [[nodiscard]]
constexpr friend simd
composit(simd
const& under, simd
const& over)
noexcept
1043 requires(std::is_same_v<value_type, float16> and size == 4)
1045 return simd{
composit(
static_cast<simd<float, 4>
>(under),
static_cast<simd<float, 4>
>(over))};
1057 r += std::format(
"{}", rhs[i]);
1072 template<std::
size_t FromElement, std::
size_t ToElement>
1073 [[nodiscard]]
constexpr friend simd insert(simd
const& lhs, simd
const& rhs)
1075 HI_X_runtime_evaluate_if_valid(simd{insert<FromElement, ToElement>(lhs.reg(), rhs.reg())});
1079 r[i] = (i == ToElement) ? rhs[FromElement] : lhs[i];
1092 template<fixed_
string Order>
1093 [[nodiscard]]
constexpr simd swizzle()
const
1095 static_assert(Order.size() <= N);
1097 HI_X_runtime_evaluate_if_valid(simd{reg().swizzle<Order>()});
1100 swizzle_detail<0, Order>(r);
1104#define SWIZZLE(name, str) \
1105 [[nodiscard]] constexpr simd name() const noexcept \
1106 requires(sizeof(str) - 1 <= N) \
1108 return swizzle<str>(); \
1111#define SWIZZLE_4D(name, str) \
1112 SWIZZLE(name##0, str "0") \
1113 SWIZZLE(name##1, str "1") \
1114 SWIZZLE(name##x, str "a") \
1115 SWIZZLE(name##y, str "b") \
1116 SWIZZLE(name##z, str "c") \
1117 SWIZZLE(name##w, str "d")
1119#define SWIZZLE_3D(name, str) \
1120 SWIZZLE_4D(name##0, str "0") \
1121 SWIZZLE_4D(name##1, str "1") \
1122 SWIZZLE_4D(name##x, str "a") \
1123 SWIZZLE_4D(name##y, str "b") \
1124 SWIZZLE_4D(name##z, str "c") \
1125 SWIZZLE_4D(name##w, str "d") \
1126 SWIZZLE(name##0, str "0") \
1127 SWIZZLE(name##1, str "1") \
1128 SWIZZLE(name##x, str "a") \
1129 SWIZZLE(name##y, str "b") \
1130 SWIZZLE(name##z, str "c") \
1131 SWIZZLE(name##w, str "d")
1133#define SWIZZLE_2D(name, str) \
1134 SWIZZLE_3D(name##0, str "0") \
1135 SWIZZLE_3D(name##1, str "1") \
1136 SWIZZLE_3D(name##x, str "a") \
1137 SWIZZLE_3D(name##y, str "b") \
1138 SWIZZLE_3D(name##z, str "c") \
1139 SWIZZLE_3D(name##w, str "d") \
1140 SWIZZLE(name##0, str "0") \
1141 SWIZZLE(name##1, str "1") \
1142 SWIZZLE(name##x, str "a") \
1143 SWIZZLE(name##y, str "b") \
1144 SWIZZLE(name##z, str "c") \
1145 SWIZZLE(name##w, str "d")
1159 template<
size_t I, fixed_
string Order>
1160 constexpr void swizzle_detail(simd& r)
const noexcept
1162 static_assert(I < size);
1165 constexpr char c = I < Order.size() ? get<I>(Order) :
'0';
1167 if constexpr (c ==
'1') {
1168 r = insert<I>(r, value_type{1});
1170 }
else if constexpr (c ==
'0') {
1171 r = insert<I>(r, value_type{0});
1173 }
else if constexpr (c >=
'a' and c <=
'v') {
1174 constexpr size_t src_index = c -
'a';
1175 static_assert(src_index < size);
1177 r = insert<I>(r, get<src_index>(*
this));
1179 }
else if constexpr (c >=
'w' and c <=
'z') {
1180 constexpr size_t src_index = c ==
'x' ? 0 : c ==
'y' ? 1 : c ==
'z' ? 2 : 3;
1181 static_assert(src_index < size);
1183 r = insert<I>(r, get<src_index>(*
this));
1186 hi_static_no_default();
1189 if constexpr (I + 1 < size) {
1190 swizzle_detail<I + 1, Order>(r);
1262template<
class T, std::
size_t N>
1265template<std::
size_t I,
class T, std::
size_t N>
1266struct std::tuple_element<I,
hi::simd<T, N>> {
1270template<
typename T,
size_t N>
1274 return equal(lhs, rhs);
1279template<
typename T,
size_t N>
1286template<
typename T,
size_t N>
1293#undef HI_X_binary_cmp_op
1294#undef HI_X_binary_math_op
1295#undef HI_X_binary_bit_op
1296#undef HI_X_binary_shift_op
1297#undef HI_X_binary_op_broadcast
1298#undef HI_X_inplace_op
1299#undef HI_X_runtime_evaluate_if_valid
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
hi_export void composit(pixmap_span< sfloat_rgba16 > dst, hi::color color, graphic_path const &mask) noexcept
Composit color onto the destination image where the mask is solid.
Definition graphic_path.hpp:667
constexpr Out load(In const *src) noexcept
Unaligned Load of a numeric value from an array.
Definition endian.hpp:93
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377