9#if SIZE_MAX == UINT64_MAX && (defined(__AVX512F__) || defined(__AVX2__))
14namespace pixie::permutations::detail {
30inline std::size_t node_select_scalar(std::span<const std::size_t> ends,
31 std::size_t index)
noexcept {
33 while (i < ends.size() && ends[i] <= index) {
51inline std::size_t node_select(std::span<const std::size_t> ends,
52 std::size_t index)
noexcept {
56#if SIZE_MAX == UINT64_MAX && defined(__AVX512F__)
58 _mm512_set1_epi64(std::bit_cast<long long>(std::uint64_t{index}));
59 for (std::size_t i = 0; i < ends.size();) {
60 const auto remaining = ends.size() - i;
61 const auto count = remaining < 8 ? remaining : 8;
62 const auto active =
static_cast<__mmask8
>((1u << count) - 1);
63 const auto values = _mm512_maskz_loadu_epi64(active, ends.data() + i);
64 const auto greater =
static_cast<unsigned>(
65 _mm512_mask_cmp_epu64_mask(active, values, query, _MM_CMPINT_GT));
67 return i + std::countr_zero(greater);
72#elif SIZE_MAX == UINT64_MAX && defined(__AVX2__)
73 const auto sign = _mm256_set1_epi64x(std::numeric_limits<long long>::min());
74 const auto query = _mm256_xor_si256(
75 _mm256_set1_epi64x(std::bit_cast<long long>(std::uint64_t{index})), sign);
77 for (; ends.size() - i >= 4; i += 4) {
79 _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(ends.data() + i));
81 static_cast<unsigned>(_mm256_movemask_pd(_mm256_castsi256_pd(
82 _mm256_cmpgt_epi64(_mm256_xor_si256(values, sign), query))));
84 return i + std::countr_zero(greater);
87 return i + node_select_scalar(ends.subspan(i), index);
89 return node_select_scalar(ends, index);