use core::hash::{BuildHasher, Hash};
#[inline]
pub(super) fn h2(hash: u64) -> u8 {
(hash >> 57) as u8
}
pub(super) const H2_EMPTY: u8 = 0xFF;
#[inline]
pub(super) fn make_hash<Q: Hash + ?Sized, S: BuildHasher>(
hash_builder: &S,
val: &Q,
) -> u64 {
hash_builder.hash_one(val)
}
#[derive(Clone, Copy)]
pub(super) struct BitMask(u32);
impl Iterator for BitMask {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
if self.0 == 0 {
None
} else {
let pos = self.0.trailing_zeros() as usize;
self.0 &= self.0 - 1;
Some(pos)
}
}
}
#[inline]
pub(super) unsafe fn match_h2<const N: usize>(
h2_bytes: *const u8,
len: usize,
needle: u8,
) -> BitMask {
unsafe {
debug_assert!(len <= N);
debug_assert!(len <= 32);
#[cfg(target_arch = "x86_64")]
if N >= 16 {
return match_h2_sse2(h2_bytes, len, needle);
}
match_h2_scalar(h2_bytes, len, needle)
}
}
#[inline]
unsafe fn match_h2_scalar(h2_bytes: *const u8, len: usize, needle: u8) -> BitMask {
unsafe {
let mut mask = 0u32;
for i in 0..len {
if *h2_bytes.add(i) == needle {
mask |= 1 << i;
}
}
BitMask(mask)
}
}
#[cfg(target_arch = "x86_64")]
#[inline]
unsafe fn match_h2_sse2(h2_bytes: *const u8, len: usize, needle: u8) -> BitMask {
unsafe {
use core::arch::x86_64::*;
let needle_v = _mm_set1_epi8(needle as i8);
let g1 = _mm_loadu_si128(h2_bytes as *const __m128i);
let mut mask = _mm_movemask_epi8(_mm_cmpeq_epi8(g1, needle_v)) as u32;
if len > 16 {
let g2 = _mm_loadu_si128(h2_bytes.add(16) as *const __m128i);
mask |= (_mm_movemask_epi8(_mm_cmpeq_epi8(g2, needle_v)) as u32) << 16;
}
BitMask(mask & len_mask(len))
}
}
#[inline]
const fn len_mask(len: usize) -> u32 {
if len >= 32 { u32::MAX } else { (1u32 << len) - 1 }
}