1#![warn(missing_docs)]
4#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
5#![no_std]
6
7mod utils;
8
9use utils::*;
10
11use core::sync::atomic::{AtomicU64, Ordering};
12
13const DEFAULT_SECRET: [u64; 5] = [0xa0761d6478bd642f, 0xe7037ed1a0b428db, 0x8ebc6af09c88c6e3, 0x589965cc75374cc3, 0x1d8e4e27c47d124f];
14const SEED_MOD: u64 = DEFAULT_SECRET[0];
15
16pub fn random(seed: u64) -> u64 {
24 const SEED_EXTRA: u64 = DEFAULT_SECRET[1];
25 let mut seed_extra = seed ^ SEED_EXTRA;
26
27 #[cfg(target_pointer_width = "32")]
28 {
29 seed_extra *= (seed_extra >> 32) | (seed_extra << 32);
30
31 (seed * ((seed >> 32) | (seed << 32 ))) ^ ((seed_extra >> 32) | (seed_extra << 32))
32 }
33
34 #[cfg(target_pointer_width = "64")]
35 {
36 let mut seed = seed;
37
38 let seeds = u128::from(seed) * u128::from(seed_extra);
39 seed = seeds as u64;
40 seed_extra = (seeds >> 64) as u64;
41 seed ^ seed_extra
42 }
43}
44
45pub struct Random {
47 seed: u64,
48}
49
50impl Random {
51 #[inline(always)]
52 pub const fn new(seed: u64) -> Self {
54 Self {
55 seed
56 }
57 }
58
59 #[inline(always)]
60 pub const fn into_seed(self) -> u64 {
62 self.seed
63 }
64
65 #[inline(always)]
66 pub fn gen(&mut self) -> u64 {
68 self.seed = self.seed.wrapping_add(SEED_MOD);
69 random(self.seed)
70 }
71}
72
73pub struct AtomicRandom {
78 seed: AtomicU64,
79}
80
81impl AtomicRandom {
82 #[inline(always)]
83 pub const fn new(seed: u64) -> Self {
85 Self {
86 seed: AtomicU64::new(seed.wrapping_add(SEED_MOD))
87 }
88 }
89
90 #[inline(always)]
91 pub fn into_seed(self) -> u64 {
93 self.seed.into_inner()
94 }
95
96 #[inline(always)]
97 pub fn set_seed(&self, seed: u64) {
99 self.seed.swap(seed.wrapping_add(SEED_MOD), Ordering::SeqCst);
100 }
101
102 #[inline(always)]
103 pub fn gen(&self) -> u64 {
105 let seed = self.seed.fetch_add(SEED_MOD, Ordering::SeqCst);
109 random(seed)
110 }
111}
112
113pub fn hash32(mut data: &[u8], mut seed: u32) -> u32 {
115 const HASH_MOD: u64 = 0x53c5ca59;
116 const HASH_MOD2: u64 = 0x74743c1b;
117
118 let mut seed_extra = data.len() as u32;
119 seed ^= (data.len() >> 32) as u32;
120
121 let mut mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
122 seed = mix as u32;
123 seed_extra = (mix >> 32) as u32;
124
125 while data.len() > 8 {
126 seed ^= read_u32(data);
127 data = &data[4..];
128
129 seed_extra ^= read_u32(data);
130 data = &data[4..];
131
132 mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
133 seed = mix as u32;
134 seed_extra = (mix >> 32) as u32;
135 }
136
137 if data.len() >= 4 {
138 seed ^= read_u32(data);
139 data = &data[data.len() - 4..];
140
141 seed_extra ^= read_u32(data);
142 } else if data.len() > 0 {
143 seed ^= read_part_u32(data);
144 }
145
146 mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
147 seed = mix as u32;
148 seed_extra = (mix >> 32) as u32;
149
150 mix = (seed as u64 ^ HASH_MOD) * (seed_extra as u64 ^ HASH_MOD2);
151 seed = mix as u32;
152 seed_extra = (mix >> 32) as u32;
153
154 seed ^ seed_extra
155}
156
157#[inline(always)]
158pub fn def_hash(data: &[u8], seed: u64) -> u64 {
160 hash(data, seed, &DEFAULT_SECRET)
161}
162
163pub fn hash(mut data: &[u8], mut seed: u64, secret: &[u64; 5]) -> u64 {
165 let len = data.len() as u64;
166 #[cold]
167 fn unlikely_branch<'a>(mut data: &'a [u8], seed: &mut u64, secret: &[u64; 5]) -> &'a [u8] {
168 let mut seed_extra = *seed;
169
170 loop {
171 *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);
172 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);
173
174 data = &data[64..];
175 if data.len() <= 64 {
176 break;
177 }
178 }
179
180 data
181 }
182
183 if data.len() > 64 {
184 data = unlikely_branch(data, &mut seed, secret);
185 }
186
187 while data.len() > 16 {
188 seed = mix(read_u64(data, 0) ^ secret[1], read_u64(data, 8) ^ seed);
189
190 data = &data[16..]
191 }
192
193 if data.len() > 8 {
194 mix(secret[1] ^ len, mix(read_u64(data, 0) ^ secret[0], read_u64(data, data.len() as isize - 8) ^ seed))
195 } else if data.len() >= 4 {
196 mix(secret[1] ^ len, mix(read_u32(data) as u64 ^ secret[0], read_u32(&data[data.len() - 4..]) as u64 ^ seed))
197 } else if data.len() > 0 {
198 mix(secret[1] ^ len, mix(read_part_u32(data) as u64 ^ secret[0], seed))
199 } else {
200 mix(secret[1] ^ len, mix(secret[0], seed))
201 }
202}