bring back random
@@ -20,6 +20,40 @@ pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
t
}
+/// Generates a random number in `0..n`.
+#[cfg(feature = "unstable")]
+pub fn random(n: u32) -> u32 {
+ use std::cell::Cell;
+ use std::num::Wrapping;
+
+ thread_local! {
+ static RNG: Cell<Wrapping<u32>> = {
+ // Take the address of a local value as seed.
+ let mut x = 0i32;
+ let r = &mut x;
+ let addr = r as *mut i32 as usize;
+ Cell::new(Wrapping(addr as u32))
+ }
+ }
+
+ RNG.with(|rng| {
+ // This is the 32-bit variant of Xorshift.
+ //
+ // Source: https://en.wikipedia.org/wiki/Xorshift
+ let mut x = rng.get();
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ rng.set(x);
+
+ // This is a fast alternative to `x % n`.
+ //
+ // Author: Daniel Lemire
+ // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+ ((u64::from(x.0)).wrapping_mul(u64::from(n)) >> 32) as u32
+ })
+}
+
/// Add additional context to errors
pub(crate) trait Context {
fn context(self, message: impl Fn() -> String) -> Self;
