13#if defined(PIXIE_AVX512_SUPPORT) || defined(PIXIE_AVX2_SUPPORT)
17namespace pixie::detail::compressed {
22template <
class Endpo
int>
23inline std::size_t first_metadata_ge(
const Endpoint* endpoints,
26 static_assert(std::is_unsigned_v<Endpoint> &&
27 (
sizeof(Endpoint) == 2 ||
sizeof(Endpoint) == 4 ||
28 sizeof(Endpoint) == 8));
29 assert(count <= 64 /
sizeof(Endpoint));
30 assert(key <= std::numeric_limits<Endpoint>::max());
31#ifdef PIXIE_AVX512_SUPPORT
32 if constexpr (
sizeof(Endpoint) == 2) {
33 const auto valid =
static_cast<__mmask32
>((std::uint64_t{1} << count) - 1);
34 const auto values = _mm512_maskz_loadu_epi16(valid, endpoints);
35 const std::uint32_t matches =
36 valid & _mm512_cmpge_epu16_mask(values, _mm512_set1_epi16(key));
37 return matches == 0 ? count : std::countr_zero(matches);
38 }
else if constexpr (
sizeof(Endpoint) == 4) {
39 const auto valid =
static_cast<__mmask16
>((std::uint64_t{1} << count) - 1);
40 const auto values = _mm512_maskz_loadu_epi32(valid, endpoints);
41 const std::uint32_t matches =
42 valid & _mm512_cmpge_epu32_mask(values, _mm512_set1_epi32(key));
43 return matches == 0 ? count : std::countr_zero(matches);
45 const auto valid =
static_cast<__mmask8
>((std::uint64_t{1} << count) - 1);
46 const auto values = _mm512_maskz_loadu_epi64(valid, endpoints);
47 const std::uint32_t matches =
48 valid & _mm512_cmpge_epu64_mask(values, _mm512_set1_epi64(key));
49 return matches == 0 ? count : std::countr_zero(matches);
51#elif defined(PIXIE_AVX2_SUPPORT)
52 constexpr std::size_t lanes = 32 /
sizeof(Endpoint);
53 std::size_t begin = 0;
54 while (count - begin >= lanes) {
56 _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(endpoints + begin));
57 std::uint32_t matches;
58 if constexpr (
sizeof(Endpoint) == 2) {
59 const auto sign = _mm256_set1_epi16(-32768);
61 _mm256_cmpgt_epi16(_mm256_xor_si256(_mm256_set1_epi16(key), sign),
62 _mm256_xor_si256(values, sign));
63 matches = ~static_cast<std::uint32_t>(_mm256_movemask_epi8(less));
65 return begin + std::countr_zero(matches) / 2;
67 }
else if constexpr (
sizeof(Endpoint) == 4) {
69 _mm256_set1_epi32(std::numeric_limits<std::int32_t>::min());
71 _mm256_cmpgt_epi32(_mm256_xor_si256(_mm256_set1_epi32(key), sign),
72 _mm256_xor_si256(values, sign));
73 matches = ~static_cast<std::uint32_t>(
74 _mm256_movemask_ps(_mm256_castsi256_ps(less))) &
77 return begin + std::countr_zero(matches);
81 _mm256_set1_epi64x(std::numeric_limits<std::int64_t>::min());
83 _mm256_cmpgt_epi64(_mm256_xor_si256(_mm256_set1_epi64x(key), sign),
84 _mm256_xor_si256(values, sign));
85 matches = ~static_cast<std::uint32_t>(
86 _mm256_movemask_pd(_mm256_castsi256_pd(less))) &
89 return begin + std::countr_zero(matches);
94 for (; begin < count; ++begin) {
95 if (endpoints[begin] >= key) {
101 for (std::size_t i = 0; i < count; ++i) {
102 if (endpoints[i] >= key) {
110template <
class Endpo
int>
111inline std::size_t grouped_lower_bound(
const Endpoint* endpoints,
114 constexpr std::size_t lanes = 64 /
sizeof(Endpoint);
116 std::size_t high = (count + lanes - 1) / lanes;
118 const auto mid = low + (high - low) / 2;
119 const auto end = std::min(count, (mid + 1) * lanes);
120 if (endpoints[end - 1] < key) {
126 const auto begin = low * lanes;
127 return begin >= count
129 : begin + first_metadata_ge(endpoints + begin,
130 std::min(lanes, count - begin), key);