#![cfg_attr(not(test), no_std)]
extern crate const_random;
#[cfg(all(test, feature = "no_panic"))]
extern crate no_panic;
#[macro_use]
mod convert;
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
mod aes_hash;
mod fallback_hash;
#[cfg(test)]
mod hash_quality_test;
use const_random::const_random;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
#[cfg(all(test, feature = "no_panic"))]
use no_panic::no_panic;
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
pub use crate::aes_hash::AHasher;
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
pub use crate::fallback_hash::AHasher;
const MULTIPLE: u64 = 6364136223846793005;
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64));
impl Default for AHasher {
#[inline]
fn default() -> AHasher {
AHasher::new_with_keys(const_random!(u64), const_random!(u64))
}
}
#[derive(Clone)]
pub struct ABuildHasher {
k0: u64,
k1: u64,
}
impl ABuildHasher {
#[inline]
pub fn new() -> ABuildHasher {
let previous = SEED.load(Ordering::Relaxed) as u64;
let stack_mem_loc = &previous as *const _ as u64;
let current_seed = previous.wrapping_mul(MULTIPLE).wrapping_add(stack_mem_loc).rotate_left(31);
SEED.store(current_seed as usize, Ordering::Relaxed);
return ABuildHasher {
k0: &SEED as *const _ as u64,
k1: current_seed
};
}
}
impl Default for ABuildHasher {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl BuildHasher for ABuildHasher {
type Hasher = AHasher;
#[inline]
fn build_hasher(&self) -> AHasher {
let (k0, k1) = scramble_keys(self.k0, self.k1);
return AHasher::new_with_keys(k0, k1);
}
}
pub(crate) fn scramble_keys(k0: u64, k1: u64) -> (u64, u64) {
let result1 = k0.wrapping_add(k1);
let k1 = k1 ^ k0;
let k0 = k0.rotate_left(24) ^ k1 ^ (k1.wrapping_shl(16));
let result2 = k0.wrapping_add(k1.rotate_left(37));
return (result2, result1);
}
#[cfg(all(test, feature = "no_panic"))]
#[inline(never)]
#[no_panic]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
use core::hash::Hasher;
let builder = ABuildHasher::new();
let mut hasher1 = builder.build_hasher();
let mut hasher2 = builder.build_hasher();
hasher1.write_i32(num);
hasher2.write(string.as_bytes());
(hasher1.finish(), hasher2.finish())
}
#[cfg(test)]
mod test {
use crate::convert::Convert;
use crate::*;
use core::hash::BuildHasherDefault;
use std::collections::HashMap;
#[cfg(feature = "no_panic")]
#[inline(never)]
fn hash_test_final_wrapper(num: i32, string: &str) {
hash_test_final(num, string);
}
#[cfg(feature = "no_panic")]
#[test]
fn test_no_panic() {
hash_test_final_wrapper(2, "");
}
#[test]
fn test_default_builder() {
let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
map.insert(1, 3);
}
#[test]
fn test_builder() {
let mut map = HashMap::<u32, u64, ABuildHasher>::default();
map.insert(1, 3);
}
#[test]
fn test_conversion() {
let input: &[u8] = "dddddddd".as_bytes();
let bytes: u64 = as_array!(input, 8).convert();
assert_eq!(bytes, 0x6464646464646464);
}
}