]> git.proxmox.com Git - rustc.git/blame - vendor/rand-0.5.5/src/distributions/other.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / vendor / rand-0.5.5 / src / distributions / other.rs
CommitLineData
0731742a
XL
1// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// https://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! The implementations of the `Standard` distribution for other built-in types.
12
13use core::char;
14use core::num::Wrapping;
15
16use {Rng};
17use distributions::{Distribution, Standard, Uniform};
18
19// ----- Sampling distributions -----
20
21/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
22/// a-z, A-Z and 0-9.
23///
24/// # Example
25///
26/// ```
27/// use std::iter;
28/// use rand::{Rng, thread_rng};
29/// use rand::distributions::Alphanumeric;
30///
31/// let mut rng = thread_rng();
32/// let chars: String = iter::repeat(())
33/// .map(|()| rng.sample(Alphanumeric))
34/// .take(7)
35/// .collect();
36/// println!("Random chars: {}", chars);
37/// ```
38#[derive(Debug)]
39pub struct Alphanumeric;
40
41
42// ----- Implementations of distributions -----
43
44impl Distribution<char> for Standard {
45 #[inline]
46 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
47 let range = Uniform::new(0u32, 0x11_0000);
48 loop {
49 match char::from_u32(range.sample(rng)) {
50 Some(c) => return c,
51 // About 0.2% of numbers in the range 0..0x110000 are invalid
52 // codepoints (surrogates).
53 None => {}
54 }
55 }
56 }
57}
58
59impl Distribution<char> for Alphanumeric {
60 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
61 const RANGE: u32 = 26 + 26 + 10;
62 const GEN_ASCII_STR_CHARSET: &[u8] =
63 b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
64 abcdefghijklmnopqrstuvwxyz\
65 0123456789";
66 // We can pick from 62 characters. This is so close to a power of 2, 64,
67 // that we can do better than `Uniform`. Use a simple bitshift and
68 // rejection sampling. We do not use a bitmask, because for small RNGs
69 // the most significant bits are usually of higher quality.
70 loop {
71 let var = rng.next_u32() >> (32 - 6);
72 if var < RANGE {
73 return GEN_ASCII_STR_CHARSET[var as usize] as char
74 }
75 }
76 }
77}
78
79impl Distribution<bool> for Standard {
80 #[inline]
81 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
82 // We can compare against an arbitrary bit of an u32 to get a bool.
83 // Because the least significant bits of a lower quality RNG can have
84 // simple patterns, we compare against the most significant bit. This is
85 // easiest done using a sign test.
86 (rng.next_u32() as i32) < 0
87 }
88}
89
90macro_rules! tuple_impl {
91 // use variables to indicate the arity of the tuple
92 ($($tyvar:ident),* ) => {
93 // the trailing commas are for the 1 tuple
94 impl< $( $tyvar ),* >
95 Distribution<( $( $tyvar ),* , )>
96 for Standard
97 where $( Standard: Distribution<$tyvar> ),*
98 {
99 #[inline]
100 fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
101 (
102 // use the $tyvar's to get the appropriate number of
103 // repeats (they're not actually needed)
104 $(
105 _rng.gen::<$tyvar>()
106 ),*
107 ,
108 )
109 }
110 }
111 }
112}
113
114impl Distribution<()> for Standard {
115 #[inline]
116 fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
117}
118tuple_impl!{A}
119tuple_impl!{A, B}
120tuple_impl!{A, B, C}
121tuple_impl!{A, B, C, D}
122tuple_impl!{A, B, C, D, E}
123tuple_impl!{A, B, C, D, E, F}
124tuple_impl!{A, B, C, D, E, F, G}
125tuple_impl!{A, B, C, D, E, F, G, H}
126tuple_impl!{A, B, C, D, E, F, G, H, I}
127tuple_impl!{A, B, C, D, E, F, G, H, I, J}
128tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
129tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
130
131macro_rules! array_impl {
132 // recursive, given at least one type parameter:
133 {$n:expr, $t:ident, $($ts:ident,)*} => {
134 array_impl!{($n - 1), $($ts,)*}
135
136 impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
137 #[inline]
138 fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
139 [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
140 }
141 }
142 };
143 // empty case:
144 {$n:expr,} => {
145 impl<T> Distribution<[T; $n]> for Standard {
146 fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
147 }
148 };
149}
150
151array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
152
153impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
154 #[inline]
155 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
156 // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
157 if rng.gen::<bool>() {
158 Some(rng.gen())
159 } else {
160 None
161 }
162 }
163}
164
165impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
166 #[inline]
167 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
168 Wrapping(rng.gen())
169 }
170}
171
172
173#[cfg(test)]
174mod tests {
175 use {Rng, RngCore, Standard};
176 use distributions::Alphanumeric;
177 #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String;
178
179 #[test]
180 fn test_misc() {
181 let rng: &mut RngCore = &mut ::test::rng(820);
182
183 rng.sample::<char, _>(Standard);
184 rng.sample::<bool, _>(Standard);
185 }
186
187 #[cfg(feature="alloc")]
188 #[test]
189 fn test_chars() {
190 use core::iter;
191 let mut rng = ::test::rng(805);
192
193 // Test by generating a relatively large number of chars, so we also
194 // take the rejection sampling path.
195 let word: String = iter::repeat(())
196 .map(|()| rng.gen::<char>()).take(1000).collect();
197 assert!(word.len() != 0);
198 }
199
200 #[test]
201 fn test_alphanumeric() {
202 let mut rng = ::test::rng(806);
203
204 // Test by generating a relatively large number of chars, so we also
205 // take the rejection sampling path.
206 let mut incorrect = false;
207 for _ in 0..100 {
208 let c = rng.sample(Alphanumeric);
209 incorrect |= !((c >= '0' && c <= '9') ||
210 (c >= 'A' && c <= 'Z') ||
211 (c >= 'a' && c <= 'z') );
212 }
213 assert!(incorrect == false);
214 }
215}