#![forbid(unsafe_op_in_unsafe_fn)]
#![deny(missing_docs)]
pub mod filter;
pub mod format;
pub(crate) mod banding;
pub(crate) mod banding128;
pub(crate) mod hash;
pub(crate) mod hash128;
use core::hash::Hash;
use xxhash_rust::xxh3::Xxh3;
pub fn hash_key<K: Hash + ?Sized>(key: &K) -> u64 {
let mut h = Xxh3::with_seed(0);
key.hash(&mut h);
core::hash::Hasher::finish(&h)
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct PleatPlan {
pub num_starts: u64,
pub shift: u32,
}
impl PleatPlan {
pub fn new(num_starts: u64, shift: u32) -> Self {
assert!(
shift < usize::BITS,
"pleating window shift must be smaller than the target pointer width"
);
Self { num_starts, shift }
}
pub fn num_windows(&self) -> usize {
((self.num_starts >> self.shift) + 2) as usize
}
pub fn pleat<F: Fn(u64) -> u64>(&self, keys: &[u64], start_of: F) -> (Vec<u64>, Vec<usize>) {
let mut out = vec![0u64; keys.len()];
let counts = self.pleat_into(keys, start_of, &mut out);
(out, counts)
}
pub fn pleat_into<F: Fn(u64) -> u64>(
&self,
keys: &[u64],
start_of: F,
out: &mut [u64],
) -> Vec<usize> {
assert_eq!(keys.len(), out.len(), "pleat output length must match keys");
let nw = self.num_windows();
let mut counts = vec![0usize; nw + 1];
for &k in keys {
counts[(start_of(k) >> self.shift) as usize + 1] += 1;
}
for w in 1..=nw {
counts[w] += counts[w - 1];
}
let mut cursor = counts[..nw].to_vec();
for &k in keys {
let w = (start_of(k) >> self.shift) as usize;
out[cursor[w]] = k;
cursor[w] += 1;
}
counts
}
}
#[cfg(test)]
mod tests {
use super::*;
fn mix64(mut z: u64) -> u64 {
z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
z ^ (z >> 31)
}
#[test]
fn pleat_is_a_permutation_in_window_order() {
let n_starts = 1u64 << 22;
let plan = PleatPlan::new(n_starts, 16);
let keys: Vec<u64> = (0..100_000u64).map(mix64).collect();
let start = |k: u64| mix64(k) % n_starts;
let (out, counts) = plan.pleat(&keys, start);
let mut a = keys.clone();
let mut b = out.clone();
a.sort_unstable();
b.sort_unstable();
assert_eq!(a, b);
for w in 0..plan.num_windows() {
for &k in &out[counts[w]..counts[w + 1]] {
assert_eq!((start(k) >> plan.shift) as usize, w);
}
}
let w0: Vec<u64> = keys
.iter()
.copied()
.filter(|&k| (start(k) >> plan.shift) == 3)
.collect();
assert_eq!(&out[counts[3]..counts[4]], &w0[..]);
}
}