#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
#![no_std]
mod utils;
use utils::*;
use core::sync::atomic::{AtomicU64, Ordering};
const DEFAULT_SECRET: [u64; 5] = [0xa0761d6478bd642f, 0xe7037ed1a0b428db, 0x8ebc6af09c88c6e3, 0x589965cc75374cc3, 0x1d8e4e27c47d124f];
const SEED_MOD: u64 = DEFAULT_SECRET[0];
pub fn random(seed: u64) -> u64 {
const SEED_EXTRA: u64 = DEFAULT_SECRET[1];
let mut seed_extra = seed ^ SEED_EXTRA;
#[cfg(target_pointer_width = "32")]
{
seed_extra *= (seed_extra >> 32) | (seed_extra << 32);
(seed * ((seed >> 32) | (seed << 32 ))) ^ ((seed_extra >> 32) | (seed_extra << 32))
}
#[cfg(target_pointer_width = "64")]
{
let mut seed = seed;
let seeds = u128::from(seed) * u128::from(seed_extra);
seed = seeds as u64;
seed_extra = (seeds >> 64) as u64;
seed ^ seed_extra
}
}
pub struct Random {
seed: u64,
}
impl Random {
#[inline(always)]
pub const fn new(seed: u64) -> Self {
Self {
seed
}
}
#[inline(always)]
pub const fn into_seed(self) -> u64 {
self.seed
}
#[inline(always)]
pub fn gen(&mut self) -> u64 {
self.seed = self.seed.wrapping_add(SEED_MOD);
random(self.seed)
}
}
pub struct AtomicRandom {
seed: AtomicU64,
}
impl AtomicRandom {
#[inline(always)]
pub const fn new(seed: u64) -> Self {
Self {
seed: AtomicU64::new(seed.wrapping_add(SEED_MOD))
}
}
#[inline(always)]
pub fn into_seed(self) -> u64 {
self.seed.into_inner()
}
#[inline(always)]
pub fn set_seed(&self, seed: u64) {
self.seed.swap(seed.wrapping_add(SEED_MOD), Ordering::SeqCst);
}
#[inline(always)]
pub fn gen(&self) -> u64 {
let seed = self.seed.fetch_add(SEED_MOD, Ordering::SeqCst);
random(seed)
}
}
pub fn hash32(mut data: &[u8], mut seed: u32) -> u32 {
const HASH_MOD: u64 = 0x53c5ca59;
const HASH_MOD2: u64 = 0x74743c1b;
let mut seed_extra = data.len() as u32;
seed ^= (data.len() >> 32) as u32;
let mut mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
seed = mix as u32;
seed_extra = (mix >> 32) as u32;
while data.len() > 8 {
seed ^= read_u32(data);
data = &data[4..];
seed_extra ^= read_u32(data);
data = &data[4..];
mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
seed = mix as u32;
seed_extra = (mix >> 32) as u32;
}
if data.len() >= 4 {
seed ^= read_u32(data);
data = &data[data.len() - 4..];
seed_extra ^= read_u32(data);
} else if data.len() > 0 {
seed ^= read_part_u32(data);
}
mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
seed = mix as u32;
seed_extra = (mix >> 32) as u32;
mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
seed = mix as u32;
seed_extra = (mix >> 32) as u32;
seed ^ seed_extra
}
#[inline(always)]
pub fn def_hash(data: &[u8], seed: u64) -> u64 {
hash(data, seed, &DEFAULT_SECRET)
}
pub fn hash(mut data: &[u8], mut seed: u64, secret: &[u64; 5]) -> u64 {
let len = data.len() as u64;
#[cold]
fn unlikely_branch<'a>(mut data: &'a [u8], seed: &mut u64, secret: &[u64; 5]) -> &'a [u8] {
let mut seed_extra = *seed;
loop {
*seed = mix(read_u64(data, 0) ^ secret[1], read_u64(data, 8) ^ *seed) ^ mix(read_u64(data, 16) ^ secret[2], read_u64(data, 24) ^ *seed);
seed_extra = mix(read_u64(data, 32) ^ secret[3], read_u64(data, 40) ^ seed_extra) ^ mix(read_u64(data, 48) ^ secret[4], read_u64(data, 56) ^ seed_extra);
data = &data[64..];
if data.len() <= 64 {
break;
}
}
data
}
if data.len() > 64 {
data = unlikely_branch(data, &mut seed, secret);
}
while data.len() > 16 {
seed = mix(read_u64(data, 0) ^ secret[1], read_u64(data, 8) ^ seed);
data = &data[16..]
}
if data.len() > 8 {
mix(secret[1] ^ len, mix(read_u64(data, 0) ^ secret[0], read_u64(data, data.len() as isize - 8) ^ seed))
} else if data.len() >= 4 {
mix(secret[1] ^ len, mix(read_u32(data) as u64 ^ secret[0], read_u32(&data[data.len() - 4..]) as u64 ^ seed))
} else if data.len() > 0 {
mix(secret[1] ^ len, mix(read_part_u32(data) as u64 ^ secret[0], seed))
} else {
mix(secret[1] ^ len, mix(secret[0], seed))
}
}