1
+ use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
2
+ #[ cfg( feature = "std" ) ]
1
3
use std:: {
2
4
cell:: Cell ,
3
5
collections:: hash_map:: DefaultHasher ,
4
6
hash:: Hasher ,
5
- num:: Wrapping ,
6
- sync:: atomic:: { AtomicUsize , Ordering } ,
7
7
} ;
8
8
9
9
// Based on [Fisher–Yates shuffle].
@@ -18,18 +18,15 @@ pub fn shuffle<T>(slice: &mut [T]) {
18
18
19
19
/// Return a value from `0..n`.
20
20
fn gen_index ( n : usize ) -> usize {
21
- ( random ( ) % n as u64 ) as usize
21
+ random ( ) % n
22
22
}
23
23
24
- /// Pseudorandom number generator based on [xorshift* ].
24
+ /// Pseudorandom number generator based on [xorshift].
25
25
///
26
- /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
27
- fn random ( ) -> u64 {
28
- thread_local ! {
29
- static RNG : Cell <Wrapping <u64 >> = Cell :: new( Wrapping ( prng_seed( ) ) ) ;
30
- }
31
-
32
- fn prng_seed ( ) -> u64 {
26
+ /// [xorshift]: https://en.wikipedia.org/wiki/Xorshift
27
+ fn random ( ) -> usize {
28
+ #[ cfg( feature = "std" ) ]
29
+ fn prng_seed ( ) -> usize {
33
30
static COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
34
31
35
32
// Any non-zero seed will do
@@ -39,16 +36,75 @@ fn random() -> u64 {
39
36
hasher. write_usize ( COUNTER . fetch_add ( 1 , Ordering :: Relaxed ) ) ;
40
37
seed = hasher. finish ( ) ;
41
38
}
42
- seed
39
+ seed as usize
43
40
}
44
41
45
- RNG . with ( |rng| {
46
- let mut x = rng. get ( ) ;
47
- debug_assert_ne ! ( x. 0 , 0 ) ;
42
+ #[ cfg( not( feature = "std" ) ) ]
43
+ const fn prng_seed ( ) -> usize {
44
+ // A deterministic seed is used in absense of TLS
45
+ 42
46
+ }
47
+
48
+ /// [xorshift*] is used on 64bit platforms.
49
+ ///
50
+ /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
51
+ #[ cfg( target_pointer_width = "64" ) ]
52
+ fn xorshift ( mut x : usize ) -> ( usize , usize ) {
53
+ debug_assert_ne ! ( x, 0 ) ;
48
54
x ^= x >> 12 ;
49
55
x ^= x << 25 ;
50
56
x ^= x >> 27 ;
51
- rng. set ( x) ;
52
- x. 0 . wrapping_mul ( 0x2545_f491_4f6c_dd1d )
53
- } )
57
+ (
58
+ x,
59
+ x. wrapping_mul ( 0x2545_f491_4f6c_dd1d ) ,
60
+ )
61
+ }
62
+
63
+ /// [xorshift32] is used on 32bit platforms.
64
+ ///
65
+ /// [xorshift32]: https://en.wikipedia.org/wiki/Xorshift
66
+ #[ cfg( target_pointer_width = "32" ) ]
67
+ fn xorshift ( mut x : usize ) -> ( usize , usize ) {
68
+ debug_assert_ne ! ( x, 0 ) ;
69
+ x ^= x << 13 ;
70
+ x ^= x >> 17 ;
71
+ x ^= x << 5 ;
72
+ ( x, x)
73
+ }
74
+
75
+ /// A non-standard xorshift variant is used on 16bit platforms.
76
+ #[ cfg( target_pointer_width = "16" ) ]
77
+ fn xorshift ( mut x : usize ) -> ( usize , usize ) {
78
+ // Constants chosen from: http://b2d-f9r.blogspot.com/2010/08/16-bit-xorshift-rng.html
79
+ debug_assert_ne ! ( x, 0 ) ;
80
+ x ^= x << 4 ;
81
+ x ^= x >> 3 ;
82
+ x ^= x << 7 ;
83
+ ( x, x)
84
+ }
85
+
86
+ #[ cfg( feature = "std" ) ]
87
+ fn rng ( ) -> usize {
88
+ thread_local ! {
89
+ static RNG : Cell <usize > = Cell :: new( prng_seed( ) ) ;
90
+ }
91
+
92
+ RNG . with ( |rng| {
93
+ let ( x, res) = xorshift ( rng. get ( ) ) ;
94
+ rng. set ( x) ;
95
+ res
96
+ } )
97
+ }
98
+
99
+ #[ cfg( not( feature = "std" ) ) ]
100
+ fn rng ( ) -> usize {
101
+ static RNG : AtomicUsize = AtomicUsize :: new ( prng_seed ( ) ) ;
102
+
103
+ // Preemption here can cause multiple threads to observe repeated state
104
+ let ( x, res) = xorshift ( RNG . load ( Ordering :: Relaxed ) ) ;
105
+ RNG . store ( x, Ordering :: Relaxed ) ;
106
+ res
107
+ }
108
+
109
+ rng ( )
54
110
}
0 commit comments