#![cfg_attr(not(test), no_std)]
extern crate const_random;
#[cfg(test)]
extern crate no_panic;
#[macro_use]
mod convert;
mod fallback_hash;
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
mod aes_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(test)]
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 {
return AHasher::new_with_keys(const_random!(u64), const_random!(u64));
}
}
#[derive(Clone)]
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
pub struct ABuildHasher {
k0: u64,
k1: u64,
}
#[derive(Clone)]
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
pub struct ABuildHasher {
key: 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 ^ stack_mem_loc).wrapping_mul(MULTIPLE).rotate_left(31);
SEED.store(current_seed as usize, Ordering::Relaxed);
let mut k0 = &SEED as *const _ as u64;
let mut k1 = current_seed ^ k0;
k0 = k0.rotate_left(24) ^ k1 ^ (k1 << 16);
k1 = k1.rotate_left(37);
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
return ABuildHasher { k0: k0, k1: k1 };
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
return ABuildHasher { key: k0.wrapping_add(k1) };
}
}
impl Default for ABuildHasher {
#[inline]
fn default() -> ABuildHasher {
ABuildHasher::new()
}
}
impl BuildHasher for ABuildHasher {
type Hasher = AHasher;
#[inline]
fn build_hasher(&self) -> AHasher {
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
return AHasher::new_with_keys(self.k0, self.k1);
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
return AHasher::new_with_key(self.key);
}
}
#[cfg(test)]
#[inline(never)]
#[no_panic]
#[no_mangle]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
use core::hash::{Hasher};
let builder = ABuildHasher::default();
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 core::hash::BuildHasherDefault;
use std::collections::HashMap;
use crate::convert::Convert;
use crate::*;
#[test]
fn test_no_panic() {
hash_test_final(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);
}
}