1 //! Miscellaneous utilities.
2 
3 use std::cell::Cell;
4 use std::num::Wrapping;
5 use std::thread;
6 use std::time::{Duration, Instant};
7 
8 /// Randomly shuffles a slice.
shuffle<T>(v: &mut [T])9 pub(crate) fn shuffle<T>(v: &mut [T]) {
10     let len = v.len();
11     if len <= 1 {
12         return;
13     }
14 
15     std::thread_local! {
16         static RNG: Cell<Wrapping<u32>> = const { Cell::new(Wrapping(1_406_868_647)) };
17     }
18 
19     let _ = RNG.try_with(|rng| {
20         for i in 1..len {
21             // This is the 32-bit variant of Xorshift.
22             //
23             // Source: https://en.wikipedia.org/wiki/Xorshift
24             let mut x = rng.get();
25             x ^= x << 13;
26             x ^= x >> 17;
27             x ^= x << 5;
28             rng.set(x);
29 
30             let x = x.0;
31             let n = i + 1;
32 
33             // This is a fast alternative to `let j = x % n`.
34             //
35             // Author: Daniel Lemire
36             // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
37             let j = ((x as u64).wrapping_mul(n as u64) >> 32) as u32 as usize;
38 
39             v.swap(i, j);
40         }
41     });
42 }
43 
44 /// Sleeps until the deadline, or forever if the deadline isn't specified.
sleep_until(deadline: Option<Instant>)45 pub(crate) fn sleep_until(deadline: Option<Instant>) {
46     loop {
47         match deadline {
48             None => thread::sleep(Duration::from_secs(1000)),
49             Some(d) => {
50                 let now = Instant::now();
51                 if now >= d {
52                     break;
53                 }
54                 thread::sleep(d - now);
55             }
56         }
57     }
58 }
59