Skip to content

Commit

Permalink
Merge pull request #75 from pitdicker/char_distrs
Browse files Browse the repository at this point in the history
Rename `AsciiWordChar` and optimize `Codepoint`
  • Loading branch information
dhardy authored Dec 18, 2017
2 parents de17011 + a0deb78 commit e3c8ca1
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 21 deletions.
3 changes: 2 additions & 1 deletion benches/distributions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ distr!(distr_uniform_i64, i64, Uniform);
distr!(distr_uniform_i128, i128, Uniform);

distr!(distr_uniform_bool, bool, Uniform);
distr!(distr_uniform_ascii_char, char, AsciiWordChar);
distr!(distr_uniform_alphanumeric, char, Alphanumeric);
distr!(distr_uniform_codepoint, char, Codepoint);

distr!(distr_uniform01_float32, f32, Uniform01);
distr!(distr_closed01_float32, f32, Closed01);
Expand Down
2 changes: 1 addition & 1 deletion src/distributions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use Rng;

pub use self::default::Default;
pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, Codepoint, AsciiWordChar};
pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, Codepoint, Alphanumeric};
pub use self::range::Range;

#[cfg(feature="std")]
Expand Down
4 changes: 4 additions & 0 deletions src/distributions/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,14 @@ macro_rules! range_int_impl {

type X = $ty;

#[inline] // if the range is constant, this helps LLVM to do the
// calculations at compile-time.
fn new(low: Self::X, high: Self::X) -> Self {
RangeImpl::new_inclusive(low, high - 1)
}

#[inline] // if the range is constant, this helps LLVM to do the
// calculations at compile-time.
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
// For a closed range the number of possible numbers we should
// generate is `range = (high - low + 1)`. It is not possible to
Expand Down
24 changes: 11 additions & 13 deletions src/distributions/uniform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use core::char;
use core::mem;

use Rng;
use distributions::Distribution;
use distributions::{Distribution, Range};
use utils::FloatConversions;

// ----- Sampling distributions -----
Expand Down Expand Up @@ -45,7 +45,7 @@ pub struct Codepoint;
/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
#[derive(Debug)]
pub struct AsciiWordChar;
pub struct Alphanumeric;


// ----- actual implementations -----
Expand Down Expand Up @@ -206,29 +206,27 @@ float_impls! { f64, Rng::next_u64 }

impl Distribution<char> for Codepoint {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> char {
// a char is 21 bits
const CHAR_MASK: u32 = 0x001f_ffff;
let range = Range::new(0u32, 0x11_0000);
loop {
// Rejection sampling. About 0.2% of numbers with at most
// 21-bits are invalid codepoints (surrogates), so this
// will succeed first go almost every time.
match char::from_u32(rng.next_u32() & CHAR_MASK) {
match char::from_u32(range.sample(rng)) {
Some(c) => return c,
// About 0.2% of numbers in the range 0..0x110000 are invalid
// codepoints (surrogates).
None => {}
}
}
}
}

impl Distribution<char> for AsciiWordChar {
impl Distribution<char> for Alphanumeric {
fn sample<R: Rng+?Sized>(&self, rng: &mut R) -> char {
const RANGE: u32 = 26 + 26 + 10;
const GEN_ASCII_STR_CHARSET: &'static [u8] =
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
loop {
let var = rng.next_u32() & 0x3F;
let var = rng.next_u32() >> 26;
if var < RANGE {
return GEN_ASCII_STR_CHARSET[var as usize] as char
}
Expand All @@ -241,7 +239,7 @@ impl Distribution<char> for AsciiWordChar {
mod tests {
use {Sample, thread_rng, iter};
use distributions::{Uniform, Uniform01, Open01, Closed01,
Codepoint, AsciiWordChar};
Codepoint, Alphanumeric};

#[test]
fn test_integers() {
Expand Down Expand Up @@ -269,10 +267,10 @@ mod tests {
let mut rng = ::test::rng();

let _ = rng.sample(Codepoint);
let c = rng.sample(AsciiWordChar);
let c = rng.sample(Alphanumeric);
assert!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));

let word: String = iter(&mut rng).take(5).map(|rng| rng.sample(AsciiWordChar)).collect();
let word: String = iter(&mut rng).take(5).map(|rng| rng.sample(Alphanumeric)).collect();
assert_eq!(word.len(), 5);
}

Expand Down
8 changes: 4 additions & 4 deletions src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ pub struct Iter<'a, R: Rng+?Sized+'a> {
///
/// ```
/// use rand::{thread_rng, Rng, Sample, iter};
/// use rand::distributions::{Uniform, AsciiWordChar};
/// use rand::distributions::{Uniform, Alphanumeric};
///
/// let mut rng = thread_rng();
/// let x: Vec<u32> = iter(&mut rng).take(10).map(|rng| rng.sample(Uniform)).collect();
/// println!("{:?}", x);
///
/// let w: String = iter(&mut rng).take(6).map(|rng| rng.sample(AsciiWordChar)).collect();
/// let w: String = iter(&mut rng).take(6).map(|rng| rng.sample(Alphanumeric)).collect();
/// println!("{}", w);
/// ```
pub fn iter<'a, R: Rng+?Sized+'a>(rng: &'a mut R) -> Iter<'a, R> {
Expand Down Expand Up @@ -160,7 +160,7 @@ impl<'a, R:?Sized+'a, U, F> Iterator for FlatMap<'a, R, U, F>
#[cfg(test)]
mod tests {
use {Rng, Sample, thread_rng, iter};
use distributions::{Uniform, AsciiWordChar};
use distributions::{Uniform, Alphanumeric};

#[test]
fn test_iter() {
Expand All @@ -181,7 +181,7 @@ mod tests {
fn test_dyn_dispatch() {
let r: &mut Rng = &mut thread_rng();

let x: String = iter(r).take(10).map(|rng| rng.sample(AsciiWordChar)).collect();
let x: String = iter(r).take(10).map(|rng| rng.sample(Alphanumeric)).collect();
assert_eq!(x.len(), 10);
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,10 @@ pub trait Sample: Rng {
///
/// ```rust
/// use rand::{thread_rng, Sample};
/// use rand::distributions::AsciiWordChar;
/// use rand::distributions::Alphanumeric;
///
/// let mut rng = thread_rng();
/// let x: String = rng.iter().map(|rng| rng.sample(AsciiWordChar)).take(6).collect();
/// let x: String = rng.iter().map(|rng| rng.sample(Alphanumeric)).take(6).collect();
/// ```
fn iter<'a>(&'a mut self) -> iter::Iter<'a, Self> {
iter(self)
Expand Down

0 comments on commit e3c8ca1

Please sign in to comment.