@@ -62,8 +62,12 @@ impl Distribution<char> for Alphanumeric {
62
62
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
63
63
abcdefghijklmnopqrstuvwxyz\
64
64
0123456789";
65
+ // We can pick from 62 characters. This is so close to a power of 2, 64,
66
+ // that we can do better than `Range`. Use a simple bitshift and
67
+ // rejection sampling. We do not use a bitmask, because for small RNGs
68
+ // the most significant bits are usually of higher quality.
65
69
loop {
66
- let var = rng. next_u32 ( ) >> 26 ;
70
+ let var = rng. next_u32 ( ) >> ( 32 - 6 ) ;
67
71
if var < RANGE {
68
72
return GEN_ASCII_STR_CHARSET [ var as usize ] as char
69
73
}
@@ -161,8 +165,9 @@ impl<T> Distribution<Option<T>> for Uniform where Uniform: Distribution<T> {
161
165
#[ cfg( test) ]
162
166
mod tests {
163
167
use { Rng , RngCore , Uniform } ;
168
+ use distributions:: Alphanumeric ;
164
169
#[ cfg( all( not( feature="std" ) , feature="alloc" ) ) ] use alloc:: String ;
165
-
170
+
166
171
#[ test]
167
172
fn test_misc ( ) {
168
173
let rng: & mut RngCore = & mut :: test:: rng ( 820 ) ;
@@ -175,14 +180,28 @@ mod tests {
175
180
#[ test]
176
181
fn test_chars ( ) {
177
182
use core:: iter;
178
- use distributions:: Alphanumeric ;
179
183
let mut rng = :: test:: rng ( 805 ) ;
180
-
181
- let c = rng. sample ( Alphanumeric ) ;
182
- assert ! ( ( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) ;
183
-
184
+
185
+ // Test by generating a relatively large number of chars, so we also
186
+ // take the rejection sampling path.
184
187
let word: String = iter:: repeat ( ( ) )
185
- . map ( |( ) | rng. sample ( Alphanumeric ) ) . take ( 5 ) . collect ( ) ;
186
- assert_eq ! ( word. len( ) , 5 ) ;
188
+ . map ( |( ) | rng. gen :: < char > ( ) ) . take ( 1000 ) . collect ( ) ;
189
+ assert ! ( word. len( ) != 0 ) ;
190
+ }
191
+
192
+ #[ test]
193
+ fn test_alphanumeric ( ) {
194
+ let mut rng = :: test:: rng ( 806 ) ;
195
+
196
+ // Test by generating a relatively large number of chars, so we also
197
+ // take the rejection sampling path.
198
+ let mut incorrect = false ;
199
+ for _ in 0 ..100 {
200
+ let c = rng. sample ( Alphanumeric ) ;
201
+ incorrect |= !( ( c >= '0' && c <= '9' ) ||
202
+ ( c >= 'A' && c <= 'Z' ) ||
203
+ ( c >= 'a' && c <= 'z' ) ) ;
204
+ }
205
+ assert ! ( incorrect == false ) ;
187
206
}
188
207
}
0 commit comments