mirror of
https://github.com/azahar-emu/mcl
synced 2025-11-06 23:20:08 +01:00
mcl: meta_byte: Split off meta_byte_group
This commit is contained in:
parent
d3ae1ae47c
commit
b468a2ab5f
@ -4,24 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
|
||||
#include "mcl/assert.hpp"
|
||||
#include "mcl/bitsizeof.hpp"
|
||||
#include "mcl/macro/architecture.hpp"
|
||||
#include "mcl/stdint.hpp"
|
||||
|
||||
#if defined(MCL_ARCHITECTURE_ARM64)
|
||||
# include <arm_neon.h>
|
||||
#elif defined(MCL_ARCHITECTURE_X86_64)
|
||||
# include <emmintrin.h>
|
||||
|
||||
# include "mcl/bit_cast.hpp"
|
||||
#else
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
namespace mcl::detail {
|
||||
|
||||
/// if MSB is 0, this is a full slot. remaining 7 bits is a partial hash of the key.
|
||||
@ -47,240 +32,4 @@ inline size_t group_index_from_hash(size_t hash, size_t group_index_mask)
|
||||
return hash & group_index_mask;
|
||||
}
|
||||
|
||||
#if defined(MCL_ARCHITECTURE_ARM64)
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
: data{vld1q_u8(reinterpret_cast<u8*>(ptr))}
|
||||
{}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{vld1q_u8(reinterpret_cast<const u8*>(array.data()))}
|
||||
{}
|
||||
|
||||
uint64x2_t match(meta_byte cmp) const
|
||||
{
|
||||
return vreinterpretq_u64_u8(vandq_u8(vceqq_u8(data,
|
||||
vdupq_n_u8(static_cast<u8>(cmp))),
|
||||
vdupq_n_u8(0x80)));
|
||||
}
|
||||
|
||||
uint64x2_t match_empty_or_tombstone() const
|
||||
{
|
||||
return vreinterpretq_u64_u8(vandq_u8(data,
|
||||
vdupq_n_u8(0x80)));
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
static_assert(meta_byte::empty == static_cast<meta_byte>(0xff), "empty must be maximal u8 value");
|
||||
return vmaxvq_u8(data) == 0xff;
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return vminvq_u8(vandq_u8(data, vdupq_n_u8(0x80))) == 0x80;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return static_cast<meta_byte>(data[index]);
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
data[index] = static_cast<u8>(value);
|
||||
}
|
||||
|
||||
uint8x16_t data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
const uint64x2_t match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
const uint64x2_t match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1] & 0x00ffffffffffffff}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#elif defined(MCL_ARCHITECTURE_X86_64)
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
: data{_mm_load_si128(reinterpret_cast<__m128i const*>(ptr))}
|
||||
{}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{_mm_loadu_si128(reinterpret_cast<__m128i const*>(array.data()))}
|
||||
{}
|
||||
|
||||
u16 match(meta_byte cmp) const
|
||||
{
|
||||
return _mm_movemask_epi8(_mm_cmpeq_epi8(data, _mm_set1_epi8(static_cast<u8>(cmp))));
|
||||
}
|
||||
|
||||
u16 match_empty_or_tombstone() const
|
||||
{
|
||||
return _mm_movemask_epi8(data);
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
return match(meta_byte::empty);
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return match_empty_or_tombstone() const == 0xffff;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return mcl::bit_cast<std::array<meta_byte, max_group_size>>(data)[index];
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
auto array = mcl::bit_cast<std::array<meta_byte, max_group_size>>(data);
|
||||
array[index] = value;
|
||||
data = mcl::bit_cast<__m128i>(array);
|
||||
}
|
||||
|
||||
__m128i data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
for (const u32 match_result{MATCH}; match_result != 0; match_result &= match_result - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result))}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
for (const u32 match_result{(MATCH) & (0x7fff)}; match_result != 0; match_result &= match_result - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result))}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
static constexpr u64 msb{0x8080808080808080};
|
||||
static constexpr u64 lsb{0x0101010101010101};
|
||||
static constexpr u64 not_msb{0x7f7f7f7f7f7f7f7f};
|
||||
static constexpr u64 not_lsb{0xfefefefefefefefe};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
{
|
||||
std::memcpy(data.data(), ptr, sizeof(data));
|
||||
}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{array}
|
||||
{}
|
||||
|
||||
std::array<u64, 2> match(meta_byte cmp) const
|
||||
{
|
||||
DEBUG_ASSERT(is_full(cmp));
|
||||
|
||||
const u64 vcmp{lsb * static_cast<u64>(cmp)};
|
||||
return {(msb - ((data[0] ^ vcmp) & not_msb)) & ~data[0] & msb, (msb - ((data[1] ^ vcmp) & not_msb)) & ~data[1] & msb};
|
||||
}
|
||||
|
||||
std::array<u64, 2> match_empty_or_tombstone() const
|
||||
{
|
||||
return {data[0] & msb, data[1] & msb};
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
static_assert((static_cast<u8>(meta_byte::empty) & 0xc0) == 0xc0);
|
||||
static_assert((static_cast<u8>(meta_byte::tombstone) & 0xc0) == 0x80);
|
||||
|
||||
return (data[0] & (data[0] << 1) & msb) || (data[1] & (data[1] << 1) & msb);
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return (data[0] & data[1] & msb) == msb;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return mcl::bit_cast<std::array<meta_byte, max_group_size>>(data)[index];
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
auto array = mcl::bit_cast<std::array<meta_byte, max_group_size>>(data);
|
||||
array[index] = value;
|
||||
data = mcl::bit_cast<std::array<u64, 2>>(array);
|
||||
}
|
||||
|
||||
std::array<u64, 2> data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
const std::array<u64, 2> match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
const std::array<u64, 2> match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1] & 0x00ffffffffffffff}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mcl::detail
|
||||
|
||||
263
include/mcl/container/detail/meta_byte_group.hpp
Normal file
263
include/mcl/container/detail/meta_byte_group.hpp
Normal file
@ -0,0 +1,263 @@
|
||||
// This file is part of the mcl project.
|
||||
// Copyright (c) 2022 merryhime
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
|
||||
#include "mcl/assert.hpp"
|
||||
#include "mcl/container/detail/meta_byte.hpp"
|
||||
#include "mcl/macro/architecture.hpp"
|
||||
#include "mcl/stdint.hpp"
|
||||
|
||||
#if defined(MCL_ARCHITECTURE_ARM64)
|
||||
# include <arm_neon.h>
|
||||
#elif defined(MCL_ARCHITECTURE_X86_64)
|
||||
# include <emmintrin.h>
|
||||
|
||||
# include "mcl/bit_cast.hpp"
|
||||
#else
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
namespace mcl::detail {
|
||||
|
||||
#if defined(MCL_ARCHITECTURE_ARM64)
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
: data{vld1q_u8(reinterpret_cast<u8*>(ptr))}
|
||||
{}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{vld1q_u8(reinterpret_cast<const u8*>(array.data()))}
|
||||
{}
|
||||
|
||||
uint64x2_t match(meta_byte cmp) const
|
||||
{
|
||||
return vreinterpretq_u64_u8(vandq_u8(vceqq_u8(data,
|
||||
vdupq_n_u8(static_cast<u8>(cmp))),
|
||||
vdupq_n_u8(0x80)));
|
||||
}
|
||||
|
||||
uint64x2_t match_empty_or_tombstone() const
|
||||
{
|
||||
return vreinterpretq_u64_u8(vandq_u8(data,
|
||||
vdupq_n_u8(0x80)));
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
static_assert(meta_byte::empty == static_cast<meta_byte>(0xff), "empty must be maximal u8 value");
|
||||
return vmaxvq_u8(data) == 0xff;
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return vminvq_u8(vandq_u8(data, vdupq_n_u8(0x80))) == 0x80;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return static_cast<meta_byte>(data[index]);
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
data[index] = static_cast<u8>(value);
|
||||
}
|
||||
|
||||
uint8x16_t data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
const uint64x2_t match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
const uint64x2_t match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1] & 0x00ffffffffffffff}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#elif defined(MCL_ARCHITECTURE_X86_64)
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
: data{_mm_load_si128(reinterpret_cast<__m128i const*>(ptr))}
|
||||
{}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{_mm_loadu_si128(reinterpret_cast<__m128i const*>(array.data()))}
|
||||
{}
|
||||
|
||||
u16 match(meta_byte cmp) const
|
||||
{
|
||||
return _mm_movemask_epi8(_mm_cmpeq_epi8(data, _mm_set1_epi8(static_cast<u8>(cmp))));
|
||||
}
|
||||
|
||||
u16 match_empty_or_tombstone() const
|
||||
{
|
||||
return _mm_movemask_epi8(data);
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
return match(meta_byte::empty);
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return match_empty_or_tombstone() const == 0xffff;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return mcl::bit_cast<std::array<meta_byte, max_group_size>>(data)[index];
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
auto array = mcl::bit_cast<std::array<meta_byte, max_group_size>>(data);
|
||||
array[index] = value;
|
||||
data = mcl::bit_cast<__m128i>(array);
|
||||
}
|
||||
|
||||
__m128i data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
for (const u32 match_result{MATCH}; match_result != 0; match_result &= match_result - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result))}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
for (const u32 match_result{(MATCH) & (0x7fff)}; match_result != 0; match_result &= match_result - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result))}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct meta_byte_group {
|
||||
static constexpr size_t max_group_size{16};
|
||||
|
||||
static constexpr u64 msb{0x8080808080808080};
|
||||
static constexpr u64 lsb{0x0101010101010101};
|
||||
static constexpr u64 not_msb{0x7f7f7f7f7f7f7f7f};
|
||||
static constexpr u64 not_lsb{0xfefefefefefefefe};
|
||||
|
||||
explicit meta_byte_group(meta_byte* ptr)
|
||||
{
|
||||
std::memcpy(data.data(), ptr, sizeof(data));
|
||||
}
|
||||
|
||||
explicit meta_byte_group(const std::array<meta_byte, 16>& array)
|
||||
: data{array}
|
||||
{}
|
||||
|
||||
std::array<u64, 2> match(meta_byte cmp) const
|
||||
{
|
||||
DEBUG_ASSERT(is_full(cmp));
|
||||
|
||||
const u64 vcmp{lsb * static_cast<u64>(cmp)};
|
||||
return {(msb - ((data[0] ^ vcmp) & not_msb)) & ~data[0] & msb, (msb - ((data[1] ^ vcmp) & not_msb)) & ~data[1] & msb};
|
||||
}
|
||||
|
||||
std::array<u64, 2> match_empty_or_tombstone() const
|
||||
{
|
||||
return {data[0] & msb, data[1] & msb};
|
||||
}
|
||||
|
||||
bool is_any_empty() const
|
||||
{
|
||||
static_assert((static_cast<u8>(meta_byte::empty) & 0xc0) == 0xc0);
|
||||
static_assert((static_cast<u8>(meta_byte::tombstone) & 0xc0) == 0x80);
|
||||
|
||||
return (data[0] & (data[0] << 1) & msb) || (data[1] & (data[1] << 1) & msb);
|
||||
}
|
||||
|
||||
bool is_all_empty_or_tombstone() const
|
||||
{
|
||||
return (data[0] & data[1] & msb) == msb;
|
||||
}
|
||||
|
||||
meta_byte get(size_t index) const
|
||||
{
|
||||
return mcl::bit_cast<std::array<meta_byte, max_group_size>>(data)[index];
|
||||
}
|
||||
|
||||
void set(size_t index, meta_byte value)
|
||||
{
|
||||
auto array = mcl::bit_cast<std::array<meta_byte, max_group_size>>(data);
|
||||
array[index] = value;
|
||||
data = mcl::bit_cast<std::array<u64, 2>>(array);
|
||||
}
|
||||
|
||||
std::array<u64, 2> data;
|
||||
};
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP(MATCH, ...) \
|
||||
{ \
|
||||
const std::array<u64, 2> match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
# define MCL_HMAP_MATCH_META_BYTE_GROUP_EXCEPT_LAST(MATCH, ...) \
|
||||
{ \
|
||||
const std::array<u64, 2> match_result{MATCH}; \
|
||||
\
|
||||
for (u64 match_result_v{match_result[0]}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
\
|
||||
for (u64 match_result_v{match_result[1] & 0x00ffffffffffffff}; match_result_v != 0; match_result_v &= match_result_v - 1) { \
|
||||
const size_t match_index{static_cast<size_t>(8 + std::countr_zero(match_result_v) / 8)}; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mcl::detail
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "mcl/assert.hpp"
|
||||
#include "mcl/container/detail/meta_byte.hpp"
|
||||
#include "mcl/container/detail/meta_byte_group.hpp"
|
||||
#include "mcl/container/detail/slot_union.hpp"
|
||||
#include "mcl/hash/xmrx.hpp"
|
||||
#include "mcl/hint/assume.hpp"
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "mcl/assert.hpp"
|
||||
#include "mcl/container/detail/meta_byte.hpp"
|
||||
#include "mcl/container/detail/meta_byte_group.hpp"
|
||||
#include "mcl/container/detail/slot_union.hpp"
|
||||
#include "mcl/hash/xmrx.hpp"
|
||||
#include "mcl/hint/assume.hpp"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user