devela/num/rand/xorshift/
u128p.rs
1#[cfg(any(feature = "join", feature = "split"))]
7use crate::Cast;
8use crate::{ConstDefault, Own};
9
10#[must_use]
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub struct XorShift128p([u64; 2]);
19
20impl Default for XorShift128p {
22 fn default() -> Self {
23 Self::DEFAULT
24 }
25}
26impl ConstDefault for XorShift128p {
28 const DEFAULT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
29}
30
31impl XorShift128p {
33 const DEFAULT_SEED: [u64; 2] = [0xDEFA_0017_DEFA_0017; 2];
34
35 #[cold] #[allow(dead_code)] #[rustfmt::skip]
36 const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
37}
38
39impl XorShift128p {
40 pub const fn new(seeds: [u64; 2]) -> Self {
44 if (seeds[0] | seeds[1]) == 0 {
45 Self::cold_path_default()
46 } else {
47 Self(seeds)
48 }
49 }
50
51 pub const fn new_unchecked(seeds: [u64; 2]) -> Self {
59 debug_assert![(seeds[0] | seeds[1]) != 0, "Seeds must be non-zero"];
60 Self(seeds)
61 }
62
63 #[must_use]
64 pub const fn inner_state(self) -> [u64; 2] {
66 self.0
67 }
68 pub const fn from_state(state: [u64; 2]) -> Self {
70 Self(state)
71 }
72
73 #[must_use]
75 pub const fn current_u64(&self) -> u64 {
76 self.0[0].wrapping_add(self.0[1])
77 }
78
79 #[must_use]
81 pub fn next_u64(&mut self) -> u64 {
82 let [s0, mut s1] = [self.0[0], self.0[1]];
83 let result = s0.wrapping_add(s1);
84
85 s1 ^= s0;
86 self.0[0] = s0.rotate_left(55) ^ s1 ^ (s1 << 14); self.0[1] = s1.rotate_left(36); result
90 }
91
92 pub const fn peek_next_state(&self) -> Self {
94 let mut x = self.0;
95 let [s0, mut s1] = [x[0], x[1]];
96
97 s1 ^= s0;
98 x[0] = s0.rotate_left(55) ^ s1 ^ (s1 << 14); x[1] = s1.rotate_left(36); Self(x)
102 }
103
104 pub const fn own_next_u64(self) -> Own<Self, u64> {
106 let s = self.peek_next_state();
107 let v = s.current_u64();
108 Own::new(s, v)
109 }
110}
111
112impl XorShift128p {
114 #[cfg(feature = "split")]
118 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
119 pub const fn new1_u128(seed: u128) -> Self {
120 Self::new(Cast(seed).into_u64_le())
121 }
122
123 pub const fn new2_u64(seeds: [u64; 2]) -> Self {
127 Self::new(seeds)
128 }
129
130 #[cfg(feature = "join")]
134 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
135 pub const fn new4_u32(seeds: [u32; 4]) -> Self {
136 Self::new([
137 Cast::<u64>::from_u32_le([seeds[0], seeds[1]]),
138 Cast::<u64>::from_u32_le([seeds[2], seeds[3]]),
139 ])
140 }
141
142 #[cfg(feature = "join")]
146 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
147 pub const fn new8_u16(seeds: [u16; 8]) -> Self {
148 Self::new([
149 Cast::<u64>::from_u16_le([seeds[0], seeds[1], seeds[2], seeds[3]]),
150 Cast::<u64>::from_u16_le([seeds[4], seeds[5], seeds[6], seeds[7]]),
151 ])
152 }
153
154 pub const fn new16_u8(seeds: [u8; 16]) -> Self {
158 let s = seeds;
159 Self::new([
160 u64::from_le_bytes([s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]]),
161 u64::from_le_bytes([s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]]),
162 ])
163 }
164}
165
166#[cfg(feature = "dep_rand_core")]
167#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "dep_rand_core")))]
168mod impl_rand {
169 use super::XorShift128p;
170 use crate::_dep::rand_core::{RngCore, SeedableRng};
171
172 impl RngCore for XorShift128p {
173 fn next_u32(&mut self) -> u32 {
176 self.next_u64() as u32
177 }
178
179 fn next_u64(&mut self) -> u64 {
181 self.next_u64()
182 }
183
184 fn fill_bytes(&mut self, dest: &mut [u8]) {
185 let mut i = 0;
186 while i < dest.len() {
187 let random_u64 = self.next_u64();
188 let bytes = random_u64.to_le_bytes();
189 let remaining = dest.len() - i;
190
191 if remaining >= 8 {
192 dest[i..i + 8].copy_from_slice(&bytes);
193 i += 8;
194 } else {
195 dest[i..].copy_from_slice(&bytes[..remaining]);
196 break;
197 }
198 }
199 }
200 }
201
202 impl SeedableRng for XorShift128p {
203 type Seed = [u8; 16];
204
205 fn from_seed(seed: Self::Seed) -> Self {
208 let mut seed_u64s = [0u64; 2];
209 if seed == [0; 16] {
210 Self::cold_path_default()
211 } else {
212 for i in 0..2 {
213 seed_u64s[i] = u64::from_le_bytes([
214 seed[i * 8],
215 seed[i * 8 + 1],
216 seed[i * 8 + 2],
217 seed[i * 8 + 3],
218 seed[i * 8 + 4],
219 seed[i * 8 + 5],
220 seed[i * 8 + 6],
221 seed[i * 8 + 7],
222 ]);
223 }
224 Self::new_unchecked(seed_u64s)
225 }
226 }
227 }
228}