#![deny(clippy::correctness, clippy::complexity, clippy::perf)]
#![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)]
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#[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;
#[cfg(feature = "std")]
mod hash_map;
#[cfg(feature = "std")]
mod hash_set;
#[cfg(feature = "compile-time-rng")]
use const_random::const_random;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
#[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;
#[cfg(feature = "std")]
pub use crate::hash_map::AHashMap;
#[cfg(feature = "std")]
pub use crate::hash_set::AHashSet;
const MULTIPLE: u64 = 6364136223846793005;
#[cfg(feature = "compile-time-rng")]
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64));
#[cfg(not(feature = "compile-time-rng"))]
static SEED: AtomicUsize = AtomicUsize::new(MULTIPLE as usize);
#[cfg(feature = "compile-time-rng")]
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);
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);
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));
(result2, result1)
}
#[cfg(test)]
mod test {
use crate::convert::Convert;
use crate::*;
use core::hash::BuildHasherDefault;
use std::collections::HashMap;
#[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] = b"dddddddd";
let bytes: u64 = as_array!(input, 8).convert();
assert_eq!(bytes, 0x6464646464646464);
}
#[test]
fn test_ahasher_construction() {
let _ = AHasher::new_with_keys(1245, 5678);
}
}