1use std::cell::Cell;
10use std::time::SystemTime;
11
12thread_local! {
13 static SEED: Cell<u64> = Cell::new(0);
14 static THREAD_ID: Cell<u64> = Cell::new(0);
15}
16
17pub struct Random;
27
28impl Random {
29 pub fn set_seed(s: u64) {
31 SEED.with(|seed| seed.set(s));
32 return;
33 }
34
35 pub fn next() -> u64 {
37 let mut seed: u64 = SEED.with(|seed| {
38 if seed.get() == 0 {
39 let id: u64 = get_thread_id();
40 let time: u64 = SystemTime::now()
41 .duration_since(std::time::UNIX_EPOCH)
42 .unwrap()
43 .as_millis() as u64;
44 seed.set(id ^ time);
45 }
46 seed.get()
47 });
48 let thread_id: u64 = THREAD_ID.with(|id| {
49 if id.get() == 0 {
50 id.set(get_thread_id() & 0xFFFFFFFF)
51 }
52 id.get()
53 });
54 const TABLE: [u64; 32] = [
55 0x59763CEA1457DFC5,
56 0x0E701C6631DCCC01,
57 0x67793534A8C778D7,
58 0x64770DE4EB0B80CE,
59 0x747A9AF32BB93809,
60 0xC71D4F13A1E22A09,
61 0xE74813B3E6C1ECAB,
62 0x3B88A9B5A97C3862,
63 0x24057CC3128D9579,
64 0xD41D3C71A9426A59,
65 0xE5E61B92D1F676F4,
66 0xA01EC8F62398DE1C,
67 0x3025BB78C7E3DD78,
68 0xD869150399B67D2A,
69 0xD4F8F70CEEFBB738,
70 0xF910F138AFE1C1C9,
71 0xE63F12FA3125DB84,
72 0x84DC6ADA95196F95,
73 0x6C47E3124371EF67,
74 0x3339D137640D3929,
75 0x6604916E4DF3C5AF,
76 0x8D86EBD5FD2374CD,
77 0xAD13E8135162601F,
78 0xDA5C5215F3867431,
79 0x1540D632794D96C6,
80 0x012533A3629D7DE8,
81 0x238F9B1046DDCA4C,
82 0xB61FAC20EBE58CEA,
83 0xF6982B86164D089B,
84 0xEAA86C9587A038B3,
85 0xF4B1F470ABDA3652,
86 0x10A7C3C4A75EF01E,
87 ];
88 const N: usize = 2;
89 for x in 0..N {
90 seed = (seed << 63) | (seed >> 1);
91 seed ^= TABLE[x];
92 seed = ((seed as u128) + (TABLE[x + N] as u128)) as u64;
93 }
94 seed += thread_id;
95 SEED.with(|s| s.set(seed));
96 return seed;
97 }
98
99 pub fn next_less_than(max: u64) -> u64 {
101 return Self::next() % max;
102 }
103}
104
105fn get_thread_id() -> u64 {
109 #[cfg(target_os = "linux")]
110 {
111 use std::ffi::c_ulong;
114 unsafe extern "C" {
115 fn pthread_self() -> c_ulong;
116 }
117 return unsafe { pthread_self() } as u64;
118 }
119 #[cfg(target_os = "windows")]
120 {
121 unsafe extern "C" {
123 fn GetCurrentThreadId() -> u32;
124 }
125 return unsafe { GetCurrentThreadId() } as u64;
126 }
127}