small_map/raw/mod.rs
1use core::mem;
2
3cfg_if! {
4 // Use the SSE2 implementation if possible: it allows us to scan 16 buckets
5 // at once instead of 8. We don't bother with AVX since it would require
6 // runtime dispatch and wouldn't gain us much anyways: the probability of
7 // finding a match drops off drastically after the first few buckets.
8 //
9 // I attempted an implementation on ARM using NEON instructions, but it
10 // turns out that most NEON instructions have multi-cycle latency, which in
11 // the end outweighs any gains over the generic implementation.
12 if #[cfg(all(
13 target_feature = "sse2",
14 any(target_arch = "x86", target_arch = "x86_64"),
15 ))] {
16 mod sse2;
17 use sse2 as imp;
18 } else if #[cfg(all(
19 target_arch = "aarch64",
20 target_feature = "neon",
21 // NEON intrinsics are currently broken on big-endian targets.
22 // See https://github.com/rust-lang/stdarch/issues/1484.
23 target_endian = "little",
24 ))] {
25 mod neon;
26 use neon as imp;
27 } else {
28 mod generic;
29 use generic as imp;
30 }
31}
32
33mod bitmask;
34pub mod util;
35
36pub(crate) use imp::Group;
37
38// Constant for h2 function that grabs the top 8 bits of the hash.
39const MIN_HASH_LEN: usize = if mem::size_of::<usize>() < mem::size_of::<u64>() {
40 mem::size_of::<usize>()
41} else {
42 mem::size_of::<u64>()
43};
44
45/// Secondary hash function, saved in the control byte.
46/// Uses full 8 bits since we don't need empty/deleted markers (we use len for validity).
47#[inline]
48#[allow(clippy::cast_possible_truncation)]
49pub(crate) fn h2(hash: u64) -> u8 {
50 // Grab the top 8 bits of the hash. While the hash is normally a full 64-bit
51 // value, some hash functions (such as FxHash) produce a usize result
52 // instead, which means that the top 32 bits are 0 on 32-bit platforms.
53 // So we use MIN_HASH_LEN constant to handle this.
54 (hash >> (MIN_HASH_LEN * 8 - 8)) as u8
55}