#![cfg_attr(test, allow(dead_code))]
#[cfg(any(test, feature = "diag"))]
use super::kernels::hash64_fn;
use super::{
dispatch_tables::DispatchTable,
kernels::{Xxh3KernelId, hash64_long_fn, hash128_long_fn, required_caps},
};
use crate::{backend::cache::OnceCache, platform::Caps};
type Hash64Fn = fn(&[u8], u64) -> u64;
type Hash128Fn = fn(&[u8], u64) -> u128;
#[derive(Clone, Copy)]
struct ActiveDispatch {
long64: Hash64Fn,
long128: Hash128Fn,
#[cfg(any(test, feature = "diag"))]
boundaries: [usize; 3],
#[cfg(any(test, feature = "diag"))]
xs64: Hash64Fn,
#[cfg(any(test, feature = "diag"))]
s64: Hash64Fn,
#[cfg(any(test, feature = "diag"))]
m64: Hash64Fn,
#[cfg(any(test, feature = "diag"))]
l64: Hash64Fn,
#[cfg(any(test, feature = "diag"))]
xs_name: &'static str,
#[cfg(any(test, feature = "diag"))]
s_name: &'static str,
#[cfg(any(test, feature = "diag"))]
m_name: &'static str,
#[cfg(any(test, feature = "diag"))]
l_name: &'static str,
}
static ACTIVE: OnceCache<ActiveDispatch> = OnceCache::new();
#[cfg(target_arch = "x86_64")]
const ZEN5_XXH3_64_AVX2_LONG_MAX: usize = 1024;
#[cfg(target_arch = "x86_64")]
#[inline(always)]
fn use_zen5_xxh3_64_avx2_short_long(len: usize) -> bool {
len <= ZEN5_XXH3_64_AVX2_LONG_MAX
&& crate::platform::caps().has(crate::platform::caps::x86::AMD_ZEN5 | crate::platform::caps::x86::AVX2)
}
#[inline]
#[must_use]
fn resolve(id: Xxh3KernelId, caps: Caps) -> Xxh3KernelId {
if caps.has(required_caps(id)) {
id
} else {
Xxh3KernelId::Portable
}
}
#[inline]
#[must_use]
fn active() -> ActiveDispatch {
ACTIVE.get_or_init(|| {
let caps = crate::platform::caps();
let table: &'static DispatchTable = super::dispatch_tables::select_runtime_table(caps);
#[cfg(any(test, feature = "diag"))]
let xs_id = resolve(table.xs, caps);
#[cfg(any(test, feature = "diag"))]
let s_id = resolve(table.s, caps);
#[cfg(any(test, feature = "diag"))]
let m_id = resolve(table.m, caps);
let l_id = resolve(table.l, caps);
ActiveDispatch {
long64: hash64_long_fn(l_id),
long128: hash128_long_fn(l_id),
#[cfg(any(test, feature = "diag"))]
boundaries: table.boundaries,
#[cfg(any(test, feature = "diag"))]
xs64: hash64_fn(xs_id),
#[cfg(any(test, feature = "diag"))]
s64: hash64_fn(s_id),
#[cfg(any(test, feature = "diag"))]
m64: hash64_fn(m_id),
#[cfg(any(test, feature = "diag"))]
l64: hash64_fn(l_id),
#[cfg(any(test, feature = "diag"))]
xs_name: xs_id.as_str(),
#[cfg(any(test, feature = "diag"))]
s_name: s_id.as_str(),
#[cfg(any(test, feature = "diag"))]
m_name: m_id.as_str(),
#[cfg(any(test, feature = "diag"))]
l_name: l_id.as_str(),
}
})
}
#[cfg(any(test, feature = "diag"))]
#[inline]
#[must_use]
fn select64(d: &ActiveDispatch, len: usize) -> (Hash64Fn, &'static str) {
let [xs_max, s_max, m_max] = d.boundaries;
if len <= xs_max {
(d.xs64, d.xs_name)
} else if len <= s_max {
(d.s64, d.s_name)
} else if len <= m_max {
(d.m64, d.m_name)
} else {
(d.l64, d.l_name)
}
}
#[cfg(any(test, feature = "diag"))]
#[inline]
#[must_use]
pub fn kernel_name_for_len(len: usize) -> &'static str {
let d = active();
select64(&d, len).1
}
#[inline(always)]
#[must_use]
pub fn hash64(data: &[u8]) -> u64 {
let len = data.len();
if len == 0 {
return super::XXH3_64_EMPTY_DEFAULT;
}
if len <= 16 {
return super::xxh3_64_0to16(data, 0, &super::DEFAULT_SECRET);
}
if len == 64 {
return super::xxh3_64_64(data, 0, &super::DEFAULT_SECRET);
}
if len == 32 {
return super::xxh3_64_32(data, 0, &super::DEFAULT_SECRET);
}
if len <= 128 {
return super::xxh3_64_7to128(data, 0, &super::DEFAULT_SECRET);
}
if len <= super::MID_SIZE_MAX {
return super::xxh3_64_129to240(data, 0, &super::DEFAULT_SECRET);
}
hash64_long_default(data)
}
#[inline(always)]
#[must_use]
pub fn hash128(data: &[u8]) -> u128 {
let len = data.len();
if len == 0 {
return super::XXH3_128_EMPTY_DEFAULT;
}
if len <= 16 {
return super::xxh3_128_0to16(data, 0, &super::DEFAULT_SECRET);
}
if len == 64 {
return super::xxh3_128_64(data, 0, &super::DEFAULT_SECRET);
}
if len == 32 {
return super::xxh3_128_32(data, 0, &super::DEFAULT_SECRET);
}
if len <= 128 {
return super::xxh3_128_7to128(data, 0, &super::DEFAULT_SECRET);
}
if len <= super::MID_SIZE_MAX {
return super::xxh3_128_129to240(data, 0, &super::DEFAULT_SECRET);
}
hash128_long_default(data)
}
#[inline(always)]
#[must_use]
pub fn hash64_with_seed(seed: u64, data: &[u8]) -> u64 {
let len = data.len();
if len == 0 && seed == 0 {
return super::XXH3_64_EMPTY_DEFAULT;
}
if len <= 16 {
return super::xxh3_64_0to16(data, seed, &super::DEFAULT_SECRET);
}
if len == 64 {
return super::xxh3_64_64(data, seed, &super::DEFAULT_SECRET);
}
if len == 32 {
return super::xxh3_64_32(data, seed, &super::DEFAULT_SECRET);
}
if len <= 128 {
return super::xxh3_64_7to128(data, seed, &super::DEFAULT_SECRET);
}
if len <= super::MID_SIZE_MAX {
return super::xxh3_64_129to240(data, seed, &super::DEFAULT_SECRET);
}
hash64_long(seed, data)
}
#[inline(always)]
fn hash64_long_default(data: &[u8]) -> u64 {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f", target_feature = "avx2"))]
{
if use_zen5_xxh3_64_avx2_short_long(data.len()) {
return super::x86_64_avx2::xxh3_64_long_default(data);
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
{
return super::x86_64_avx512::xxh3_64_long_default(data);
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")))]
{
return super::x86_64_avx2::xxh3_64_long_default(data);
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
{
return super::aarch64_neon::xxh3_64_long_default(data);
}
#[cfg(target_arch = "riscv64")]
{
return super::xxh3_64_long_default(data);
}
#[allow(unreachable_code)]
{
let d = active();
(d.long64)(data, 0)
}
}
#[inline(always)]
fn hash64_long(seed: u64, data: &[u8]) -> u64 {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f", target_feature = "avx2"))]
{
if use_zen5_xxh3_64_avx2_short_long(data.len()) {
return super::x86_64_avx2::xxh3_64_long(data, seed);
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
{
return super::x86_64_avx512::xxh3_64_long(data, seed);
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")))]
{
return super::x86_64_avx2::xxh3_64_long(data, seed);
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
{
return super::aarch64_neon::xxh3_64_long(data, seed);
}
#[cfg(target_arch = "riscv64")]
{
return super::xxh3_64_long(data, seed);
}
#[allow(unreachable_code)]
hash64_long_runtime(seed, data)
}
#[inline(never)]
fn hash64_long_runtime(seed: u64, data: &[u8]) -> u64 {
#[cfg(target_arch = "x86_64")]
{
if use_zen5_xxh3_64_avx2_short_long(data.len()) {
return super::x86_64_avx2::xxh3_64_long(data, seed);
}
}
let d = active();
(d.long64)(data, seed)
}
#[inline(always)]
#[must_use]
pub fn hash128_with_seed(seed: u64, data: &[u8]) -> u128 {
let len = data.len();
if len == 0 && seed == 0 {
return super::XXH3_128_EMPTY_DEFAULT;
}
if len <= 16 {
return super::xxh3_128_0to16(data, seed, &super::DEFAULT_SECRET);
}
if len == 64 {
return super::xxh3_128_64(data, seed, &super::DEFAULT_SECRET);
}
if len == 32 {
return super::xxh3_128_32(data, seed, &super::DEFAULT_SECRET);
}
if len <= 128 {
return super::xxh3_128_7to128(data, seed, &super::DEFAULT_SECRET);
}
if len <= super::MID_SIZE_MAX {
return super::xxh3_128_129to240(data, seed, &super::DEFAULT_SECRET);
}
hash128_long(seed, data)
}
#[inline(always)]
fn hash128_long_default(data: &[u8]) -> u128 {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
{
return super::x86_64_avx512::xxh3_128_long_default(data);
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")))]
{
return super::x86_64_avx2::xxh3_128_long_default(data);
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
{
return super::aarch64_neon::xxh3_128_long_default(data);
}
#[cfg(target_arch = "riscv64")]
{
return super::xxh3_128_long_default(data);
}
#[allow(unreachable_code)]
{
let d = active();
(d.long128)(data, 0)
}
}
#[inline(always)]
fn hash128_long(seed: u64, data: &[u8]) -> u128 {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
{
return super::x86_64_avx512::xxh3_128_long(data, seed);
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")))]
{
return super::x86_64_avx2::xxh3_128_long(data, seed);
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
{
return super::aarch64_neon::xxh3_128_long(data, seed);
}
#[cfg(target_arch = "riscv64")]
{
return super::xxh3_128_long(data, seed);
}
#[allow(unreachable_code)]
hash128_long_runtime(seed, data)
}
#[inline(never)]
fn hash128_long_runtime(seed: u64, data: &[u8]) -> u128 {
let d = active();
(d.long128)(data, seed)
}