From 7c82d408a0d256ac471f5d7c09cf8d6cb3ef51a7 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Fri, 19 Jun 2020 10:43:59 -0700 Subject: [PATCH] add (default) rand feature, so users can build without rand (closes #10) --- Cargo.toml | 6 +++- proptest-regressions/setusize.txt | 7 +++++ src/lib.rs | 2 ++ src/rand.rs | 50 +++++++++++++++++++++++++++++++ src/setu32.rs | 10 +++---- src/setu64.rs | 10 +++---- 6 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 proptest-regressions/setusize.txt create mode 100644 src/rand.rs diff --git a/Cargo.toml b/Cargo.toml index 3630f12..de053f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,9 +26,13 @@ travis-ci = { repository = "droundy/tinyset" } appveyor = { repository = "droundy/tinyset" } [dependencies] -rand = "0.7.2" +rand = { version = "0.7.2", optional = true } itertools = "0.8.1" +[features] + +default = ["rand"] + [[bench]] name = "bench" harness = false diff --git a/proptest-regressions/setusize.txt b/proptest-regressions/setusize.txt new file mode 100644 index 0000000..d116ac4 --- /dev/null +++ b/proptest-regressions/setusize.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc ba58eac8bcfa93ea30ebf22f46fad0b05ee2fd1543b593b1e0ad3a5cb340b1dd # shrinks to slice = [4611686018427387904] diff --git a/src/lib.rs b/src/lib.rs index 89a0170..fd594c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,8 @@ #![deny(missing_docs)] +mod rand; + #[doc(hidden)] pub mod setu32b; diff --git a/src/rand.rs b/src/rand.rs new file mode 100644 index 0000000..814fb48 --- /dev/null +++ b/src/rand.rs @@ -0,0 +1,50 @@ +#[cfg(not(feature = "rand"))] +use std::sync::atomic::{AtomicU64, Ordering}; + +#[cfg(not(feature = "rand"))] +static SEED: AtomicU64 = AtomicU64::new(0); + +#[cfg(not(feature = "rand"))] +pub fn rand32() -> u32 { + rand64() as u32 +} + +#[cfg(feature = "rand")] +pub fn rand32() -> u32 { + rand::random::() +} + +#[cfg(not(feature = "rand"))] +pub fn rand64() -> u64 { + use std::num::Wrapping; + // This is the SplitMix64 algorithm. It's pretty crude, + // but should actually be good enough in most cases. + let z = Wrapping(SEED.fetch_add(0x9e3779b97f4a7c15, Ordering::Relaxed)); + if z == Wrapping(0) { + let seed = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().subsec_nanos(); + SEED.store(seed as u64, Ordering::Relaxed); + return rand64(); + } + let z = (z ^ (z >> 30)) * Wrapping(0xbf58476d1ce4e5b9); + let z = (z ^ (z >> 27)) * Wrapping(0x94d049bb133111eb); + (z ^ (z >> 31)).0 + // uint64_t z = (x += 0x9e3779b97f4a7c15); + // z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + // z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + // return z ^ (z >> 31); +} + +#[cfg(feature = "rand")] +pub fn rand64() -> u64 { + rand::random::() +} + +#[cfg(not(feature = "rand"))] +pub fn rand_usize() -> usize { + rand64() as usize +} + +#[cfg(feature = "rand")] +pub fn rand_usize() -> usize { + rand::random::() +} \ No newline at end of file diff --git a/src/setu32.rs b/src/setu32.rs index be35a1e..0d50133 100644 --- a/src/setu32.rs +++ b/src/setu32.rs @@ -832,7 +832,7 @@ impl SetU32 { (*x.0).bits = if bits == 0 { let mut b = 0; while b <= 32 { - b = rand::random(); + b = crate::rand::rand32(); } b } else { @@ -914,7 +914,7 @@ impl SetU32 { } InternalMut::Heap { s, a } => { if compute_array_bits(e) < s.bits { - let newcap = s.cap+1+(rand::random::() % s.cap); + let newcap = s.cap+1+(crate::rand::rand32() % s.cap); let mut new = Self::with_capacity_and_bits(newcap as usize, compute_array_bits(e)); // new.debug_me("\n\nnew set"); @@ -974,7 +974,7 @@ impl SetU32 { } else { // Let's keep things sparse // A dense set will cost us memory - let newcap: u32 = s.cap + 1 + (rand::random::() % s.cap); + let newcap: u32 = s.cap + 1 + (crate::rand::rand32() % s.cap); let mut new = Self::with_capacity_and_bits(newcap as usize, s.bits); // new.debug_me("initial new"); for v in self.iter() { @@ -995,7 +995,7 @@ impl SetU32 { // a high O(1) cost to reduce collisions. let had_zero = p_remove(s.bits, a, 0); loop { - let i: u32 = rand::random(); + let i: u32 = crate::rand::rand32(); if i > 32 && !a.iter().any(|&v| v == i) { s.bits = i; break; @@ -1030,7 +1030,7 @@ impl SetU32 { return true; } // println!("no room in the set... {:?}", a); - let newcap: u32 = s.cap + 1 + (rand::random::() % s.cap); + let newcap: u32 = s.cap + 1 + (crate::rand::rand32() % s.cap); let mut new = Self::with_capacity_and_bits(newcap as usize, s.bits); // new.debug_me("initial new"); match new.internal_mut() { diff --git a/src/setu64.rs b/src/setu64.rs index 0282606..22041f8 100644 --- a/src/setu64.rs +++ b/src/setu64.rs @@ -585,7 +585,7 @@ impl SetU64 { (*x.0).bits = if bits == 0 { let mut b = 0; while b <= 64 { - b = rand::random(); + b = crate::rand::rand64(); } b } else { @@ -678,7 +678,7 @@ impl SetU64 { } InternalMut::Heap { s, a } => { if compute_array_bits(e) < s.bits { - let mut new = Self::with_capacity_and_bits(s.cap+1+2*(rand::random::() % s.cap), + let mut new = Self::with_capacity_and_bits(s.cap+1+2*(crate::rand::rand_usize() % s.cap), compute_array_bits(e)); // new.debug_me("\n\nnew set"); for d in self.iter() { @@ -733,7 +733,7 @@ impl SetU64 { } else { // Let's keep things sparse // A dense set will cost us memory - let newcap: usize = s.cap + 1 + (rand::random::() % s.cap); + let newcap: usize = s.cap + 1 + (crate::rand::rand_usize() % s.cap); let mut new = Self::with_capacity_and_bits(newcap, s.bits); // new.debug_me("initial new"); for v in self.iter() { @@ -754,7 +754,7 @@ impl SetU64 { // a high O(1) cost to reduce collisions. let had_zero = p_remove(s.bits, a, 0); loop { - let i: u64 = rand::random(); + let i: u64 = crate::rand::rand64(); if i > 64 && !a.iter().any(|&v| v == i) { s.bits = i; break; @@ -784,7 +784,7 @@ impl SetU64 { return true; } // println!("no room in the set... {:?}", a); - let newcap: usize = s.cap + 1 + (rand::random::() % (2*s.cap)); + let newcap: usize = s.cap + 1 + (crate::rand::rand_usize() % (2*s.cap)); let mut new = Self::with_capacity_and_bits(newcap, s.bits); // new.debug_me("initial new"); match new.internal_mut() {