use std::collections::{HashMap, HashSet};
use std::hash::{BuildHasher, Hasher};
use crate::gxhash::platform::*;
use crate::gxhash::*;
#[derive(Clone, Debug)]
pub struct GxHasher {
state: State,
}
impl GxHasher {
#[inline]
fn with_state(state: State) -> GxHasher {
GxHasher { state }
}
}
impl Default for GxHasher {
#[inline]
fn default() -> GxHasher {
GxHasher::with_state(unsafe { create_empty() })
}
}
impl GxHasher {
#[inline]
pub fn with_seed(seed: i64) -> GxHasher {
GxHasher::with_state(unsafe { create_seed(seed) })
}
#[inline]
pub fn finish_u128(&self) -> u128 {
debug_assert!(std::mem::size_of::<State>() >= std::mem::size_of::<u128>());
unsafe {
let p = &finalize(self.state) as *const State as *const u128;
*p
}
}
}
macro_rules! write {
($name:ident, $type:ty, $load:expr) => {
#[inline]
fn $name(&mut self, value: $type) {
self.state = unsafe {
aes_encrypt_last($load(value), aes_encrypt(self.state, ld(KEYS.as_ptr())))
};
}
}
}
impl Hasher for GxHasher {
#[inline]
fn finish(&self) -> u64 {
unsafe {
let p = &finalize(self.state) as *const State as *const u64;
*p
}
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state = unsafe { aes_encrypt_last(compress_all(bytes), aes_encrypt(self.state, ld(KEYS.as_ptr()))) };
}
write!(write_u8, u8, load_u8);
write!(write_u16, u16, load_u16);
write!(write_u32, u32, load_u32);
write!(write_u64, u64, load_u64);
write!(write_u128, u128, load_u128);
write!(write_i8, i8, load_i8);
write!(write_i16, i16, load_i16);
write!(write_i32, i32, load_i32);
write!(write_i64, i64, load_i64);
write!(write_i128, i128, load_i128);
}
#[derive(Clone, Debug)]
pub struct GxBuildHasher(State);
#[rustversion::before(1.76)]
use std::collections::hash_map::RandomState;
#[rustversion::since(1.76)]
use std::hash::RandomState;
impl Default for GxBuildHasher {
#[inline]
fn default() -> GxBuildHasher {
let random_state = RandomState::new();
unsafe {
let state: State = std::mem::transmute(random_state);
GxBuildHasher(state)
}
}
}
impl BuildHasher for GxBuildHasher {
type Hasher = GxHasher;
#[inline]
fn build_hasher(&self) -> GxHasher {
GxHasher::with_state(self.0)
}
}
pub type GxHashMap<K, V> = HashMap<K, V, GxBuildHasher>;
pub type GxHashSet<T> = HashSet<T, GxBuildHasher>;
#[cfg(test)]
mod tests {
use std::hash::Hash;
use super::*;
#[test]
fn hasher_produces_stable_hashes() {
let mut hashset = GxHashSet::default();
assert!(hashset.insert(1234));
assert!(!hashset.insert(1234));
assert!(hashset.insert(42));
let mut hashset = GxHashSet::default();
assert!(hashset.insert("hello"));
assert!(hashset.insert("world"));
assert!(!hashset.insert("hello"));
assert!(hashset.insert("bye"));
}
#[test]
fn hasher_resists_permutations() {
let build_hasher = GxBuildHasher::default();
let mut hasher1 = build_hasher.build_hasher();
(1, 2).hash(&mut hasher1);
let mut hasher2 = build_hasher.build_hasher();
(2, 1).hash(&mut hasher2);
assert_ne!(hasher1.finish(), hasher2.finish());
}
#[test]
fn gxhashset_uses_default_gxhasherbuilder() {
let hashset_1 = GxHashSet::<u32>::default();
let hashset_2 = GxHashSet::<u32>::default();
let mut hasher_1 = hashset_1.hasher().build_hasher();
let mut hasher_2 = hashset_2.hasher().build_hasher();
hasher_1.write_i32(42);
let hash_1 = hasher_1.finish();
hasher_2.write_i32(42);
let hash_2 = hasher_2.finish();
assert_ne!(hash_1, hash_2);
}
#[test]
fn default_gxhasherbuilder_is_randomly_seeded() {
let buildhasher_1 = GxBuildHasher::default();
let buildhasher_2 = GxBuildHasher::default();
let mut hasher_1 = buildhasher_1.build_hasher();
let mut hasher_2 = buildhasher_2.build_hasher();
hasher_1.write_i32(42);
let hash_1 = hasher_1.finish();
hasher_2.write_i32(42);
let hash_2 = hasher_2.finish();
assert_ne!(hash_1, hash_2);
}
#[test]
fn gxhasherbuilder_builds_same_hashers() {
let buildhasher = GxBuildHasher::default();
let mut hasher = buildhasher.build_hasher();
hasher.write_i32(42);
let hash = hasher.finish();
let mut hasher = buildhasher.build_hasher();
hasher.write_i32(42);
assert_eq!(hash, hasher.finish());
}
}