#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LengthError;
impl core::fmt::Display for LengthError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("the hash table exceeds its maximum size")
}
}
impl std::error::Error for LengthError {}
pub trait GrowthPolicy: Clone {
fn new(min_bucket_count: usize) -> Result<(Self, usize), LengthError>;
fn bucket_for_hash(&self, hash: usize) -> usize;
fn next_bucket_count(&self) -> Result<usize, LengthError>;
fn max_bucket_count(&self) -> usize;
fn clear(&mut self);
fn is_power_of_two() -> bool {
false
}
}
use crate::util::{is_power_of_two, round_up_to_power_of_two};
#[derive(Clone)]
pub struct PowerOfTwo<const FACTOR: usize = 2> {
mask: usize,
}
impl<const FACTOR: usize> GrowthPolicy for PowerOfTwo<FACTOR> {
fn new(min_bucket_count: usize) -> Result<(Self, usize), LengthError> {
assert!(
is_power_of_two(FACTOR) && FACTOR >= 2,
"growth factor must be a power of two >= 2"
);
let max = Self::max_bucket_count_static();
if min_bucket_count > max {
return Err(LengthError);
}
if min_bucket_count > 0 {
let rounded = round_up_to_power_of_two(min_bucket_count);
Ok((Self { mask: rounded - 1 }, rounded))
} else {
Ok((Self { mask: 0 }, 0))
}
}
#[inline]
fn bucket_for_hash(&self, hash: usize) -> usize {
hash & self.mask
}
fn next_bucket_count(&self) -> Result<usize, LengthError> {
if (self.mask + 1) > Self::max_bucket_count_static() / FACTOR {
return Err(LengthError);
}
Ok((self.mask + 1) * FACTOR)
}
fn max_bucket_count(&self) -> usize {
Self::max_bucket_count_static()
}
fn clear(&mut self) {
self.mask = 0;
}
fn is_power_of_two() -> bool {
true
}
}
impl<const FACTOR: usize> PowerOfTwo<FACTOR> {
#[inline]
fn max_bucket_count_static() -> usize {
(usize::MAX / 2) + 1
}
}
#[derive(Clone)]
pub struct Mod<const NUM: usize = 3, const DEN: usize = 2> {
modulo: usize,
}
impl<const NUM: usize, const DEN: usize> Mod<NUM, DEN> {
#[inline]
fn factor() -> f64 {
NUM as f64 / DEN as f64
}
#[inline]
fn max_bucket_count_static() -> usize {
(usize::MAX as f64 / Self::factor()) as usize
}
}
impl<const NUM: usize, const DEN: usize> GrowthPolicy for Mod<NUM, DEN> {
fn new(min_bucket_count: usize) -> Result<(Self, usize), LengthError> {
assert!(DEN != 0, "growth factor denominator must be nonzero");
assert!(Self::factor() >= 1.1, "growth factor should be >= 1.1");
if min_bucket_count > Self::max_bucket_count_static() {
return Err(LengthError);
}
let modulo = if min_bucket_count > 0 {
min_bucket_count
} else {
1
};
Ok((Self { modulo }, min_bucket_count))
}
#[inline]
fn bucket_for_hash(&self, hash: usize) -> usize {
hash % self.modulo
}
fn next_bucket_count(&self) -> Result<usize, LengthError> {
let max = Self::max_bucket_count_static();
if self.modulo == max {
return Err(LengthError);
}
let next = (self.modulo as f64 * Self::factor()).ceil();
if !next.is_normal() {
return Err(LengthError);
}
if next > max as f64 {
Ok(max)
} else {
Ok(next as usize)
}
}
fn max_bucket_count(&self) -> usize {
Self::max_bucket_count_static()
}
fn clear(&mut self) {
self.modulo = 1;
}
}
#[cfg(test)]
mod tests {
use super::{GrowthPolicy, Mod};
#[test]
#[should_panic(expected = "growth factor denominator must be nonzero")]
fn mod_policy_rejects_zero_denominator() {
let _ = Mod::<2, 0>::new(0);
}
}
pub const PRIMES_TABLE: [usize; 40] = [
1, 5, 17, 29, 37, 53, 67, 79, 97, 131, 193, 257, 389, 521, 769, 1031, 1543, 2053, 3079, 6151,
12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917,
25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 3221225473,
4294967291,
];
#[derive(Clone)]
pub struct Prime {
iprime: usize,
}
impl GrowthPolicy for Prime {
fn new(min_bucket_count: usize) -> Result<(Self, usize), LengthError> {
let iprime = PRIMES_TABLE.partition_point(|&p| p < min_bucket_count);
if iprime == PRIMES_TABLE.len() {
return Err(LengthError);
}
let settled = if min_bucket_count > 0 {
PRIMES_TABLE[iprime]
} else {
0
};
Ok((Self { iprime }, settled))
}
#[inline]
fn bucket_for_hash(&self, hash: usize) -> usize {
hash % PRIMES_TABLE[self.iprime]
}
fn next_bucket_count(&self) -> Result<usize, LengthError> {
if self.iprime + 1 >= PRIMES_TABLE.len() {
return Err(LengthError);
}
Ok(PRIMES_TABLE[self.iprime + 1])
}
fn max_bucket_count(&self) -> usize {
PRIMES_TABLE[PRIMES_TABLE.len() - 1]
}
fn clear(&mut self) {
self.iprime = 0;
}
}