osom_lib_prng/prngs/
splitmix.rs1#![allow(
2 clippy::cast_possible_truncation,
3 clippy::cast_possible_wrap,
4)]
5
6use core::ops::RangeBounds;
7
8use osom_lib_reprc::macros::reprc;
9
10use crate::{
11 prngs::helpers::{
12 fill_raw_from_array_generator, generate_f32_in_range, generate_f64_in_range, generate_i32_in_range,
13 generate_i64_in_range, generate_u32_in_range, generate_u64_in_range
14 },
15 traits::{PRNConcreteBoundedGenerator, PRNConcreteGenerator, PRNGenerator, Seedable},
16};
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21#[reprc]
22#[repr(transparent)]
23#[must_use]
24pub struct SplitMix64 {
25 state: u64
26}
27
28impl SplitMix64 {
29 #[inline(always)]
31 pub const fn with_seed(seed: u64) -> Self {
32 let state = if seed != 0 { seed } else { 1 };
33 Self { state }
34 }
35
36 pub const fn next(&mut self) -> u64 {
38 self.state = self.state.wrapping_add(0x9e3779b97f4a7c15);
39 let mut result = self.state;
40 result = (result ^ (result >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
41 result = (result ^ (result >> 27)).wrapping_mul(0x94d049bb133111eb);
42 result ^ (result >> 31)
43 }
44}
45
46impl Seedable<u64> for SplitMix64 {
47 fn with_seed(seed: u64) -> Self {
48 Self::with_seed(seed)
49 }
50}
51
52impl PRNGenerator for SplitMix64 {
53 unsafe fn fill_raw(&mut self, dst_ptr: *mut u8, dst_len: usize) {
54 fill_raw_from_array_generator(|| self.next().to_be_bytes(), dst_ptr, dst_len);
55 }
56}
57
58impl PRNConcreteGenerator<SplitMix64> for bool {
59 fn generate(generator: &mut SplitMix64) -> Self {
60 (generator.next() & 1) == 1
61 }
62}
63
64impl<const N: usize> PRNConcreteGenerator<SplitMix64> for [u8; N] {
65 fn generate(generator: &mut SplitMix64) -> Self {
66 let mut item = core::mem::MaybeUninit::<Self>::uninit();
67 unsafe {
68 generator.fill_raw(item.as_mut_ptr().cast(), size_of::<Self>());
69 item.assume_init()
70 }
71 }
72}
73
74impl PRNConcreteGenerator<SplitMix64> for u8 {
75 fn generate(generator: &mut SplitMix64) -> Self {
76 u8::from_le_bytes(generator.generate::<[u8; 1]>())
77 }
78}
79
80impl PRNConcreteGenerator<SplitMix64> for i8 {
81 fn generate(generator: &mut SplitMix64) -> Self {
82 i8::from_le_bytes(generator.generate::<[u8; 1]>())
83 }
84}
85
86
87impl PRNConcreteGenerator<SplitMix64> for u32 {
88 fn generate(generator: &mut SplitMix64) -> Self {
89 u32::from_le_bytes(generator.generate::<[u8; 4]>())
90 }
91}
92
93impl PRNConcreteGenerator<SplitMix64> for i32 {
94 fn generate(generator: &mut SplitMix64) -> Self {
95 i32::from_le_bytes(generator.generate::<[u8; 4]>())
96 }
97}
98
99impl PRNConcreteGenerator<SplitMix64> for u64 {
100 fn generate(generator: &mut SplitMix64) -> Self {
101 u64::from_le_bytes(generator.generate::<[u8; 8]>())
102 }
103}
104
105impl PRNConcreteGenerator<SplitMix64> for i64 {
106 fn generate(generator: &mut SplitMix64) -> Self {
107 i64::from_le_bytes(generator.generate::<[u8; 8]>())
108 }
109}
110
111impl PRNConcreteBoundedGenerator<SplitMix64> for u32 {
112 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
113 generate_u32_in_range(generator, range)
114 }
115}
116
117impl PRNConcreteBoundedGenerator<SplitMix64> for u64 {
118 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
119 generate_u64_in_range(generator, range)
120 }
121}
122
123impl PRNConcreteBoundedGenerator<SplitMix64> for i32 {
124 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
125 generate_i32_in_range(generator, range)
126 }
127}
128
129impl PRNConcreteBoundedGenerator<SplitMix64> for i64 {
130 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
131 generate_i64_in_range(generator, range)
132 }
133}
134
135impl PRNConcreteBoundedGenerator<SplitMix64> for f32 {
136 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
137 generate_f32_in_range(generator, range)
138 }
139}
140
141impl PRNConcreteBoundedGenerator<SplitMix64> for f64 {
142 fn generate<TBounds: RangeBounds<Self>>(generator: &mut SplitMix64, range: TBounds) -> Self {
143 generate_f64_in_range(generator, range)
144 }
145}