@@ -78,6 +78,7 @@ pub struct Isaac64Rng {
78
78
b : w64 ,
79
79
c : w64 ,
80
80
index : u32 ,
81
+ half_used : bool , // true if only half of the previous result is used
81
82
}
82
83
83
84
// Cannot be derived because [u64; 256] does not implement Clone
@@ -91,6 +92,7 @@ impl Clone for Isaac64Rng {
91
92
b : self . b ,
92
93
c : self . c ,
93
94
index : self . index ,
95
+ half_used : self . half_used ,
94
96
}
95
97
}
96
98
}
@@ -136,13 +138,6 @@ impl Isaac64Rng {
136
138
/// - We fill `rsl` backwards. The reference implementation reads values
137
139
/// from `rsl` in reverse. We read them in the normal direction, to make
138
140
/// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
139
- /// - We store `index` as if `rsl` contains `u32`'s instead of `u64`'s, plus
140
- /// one. This way we can make more efficient use of the generated results
141
- /// in `next_u32`.
142
- /// For `next_u32` the correct index is `index - 1`.
143
- /// For `next_u64` the correct index is `index >> 1`, which also takes
144
- /// care of any alignment issues that could arise if `next_u64` was called
145
- /// after `next_u32`.
146
141
fn isaac64 ( & mut self ) {
147
142
self . c += w ( 1 ) ;
148
143
// abbreviations
@@ -192,7 +187,8 @@ impl Isaac64Rng {
192
187
193
188
self . a = a;
194
189
self . b = b;
195
- self . index = 1 ;
190
+ self . index = 0 ;
191
+ self . half_used = false ;
196
192
}
197
193
}
198
194
@@ -201,54 +197,52 @@ impl Rng for Isaac64Rng {
201
197
fn next_u32 ( & mut self ) -> u32 {
202
198
// Using a local variable for `index`, and checking the size avoids a
203
199
// bounds check later on.
204
- let mut index = self . index as usize - 1 ;
200
+ let mut index = self . index as usize * 2 - self . half_used as usize ;
205
201
if index >= RAND_SIZE * 2 {
206
202
self . isaac64 ( ) ;
207
203
index = 0 ;
208
204
}
209
205
210
- let value;
206
+ self . half_used = !self . half_used ;
207
+ self . index += self . half_used as u32 ;
208
+
209
+ // Index as if this is a u32 slice.
210
+ let rsl = unsafe { & * ( & mut self . rsl as * mut [ u64 ; RAND_SIZE ]
211
+ as * mut [ u32 ; RAND_SIZE * 2 ] ) } ;
212
+
211
213
if cfg ! ( target_endian = "little" ) {
212
- // Index as if this is a u32 slice.
213
- let rsl = unsafe { & * ( & mut self . rsl as * mut [ u64 ; RAND_SIZE ]
214
- as * mut [ u32 ; RAND_SIZE * 2 ] ) } ;
215
- value = rsl[ index] ;
214
+ rsl[ index]
216
215
} else {
217
- // Index into the u64 slice, rotate and truncate the result.
218
- // Works always, also on big-endian systems, but is slower.
219
- let tmp = self . rsl [ index >> 1 ] ;
220
- value = tmp as u32 ;
221
- self . rsl [ index >> 1 ] = tmp. rotate_right ( 32 ) ;
216
+ rsl[ index ^ 1 ]
222
217
}
223
- self . index += 1 ;
224
- value
225
218
}
226
219
227
220
#[ inline]
228
221
fn next_u64 ( & mut self ) -> u64 {
229
- let mut index = self . index as usize >> 1 ;
222
+ let mut index = self . index as usize ;
230
223
if index >= RAND_SIZE {
231
224
self . isaac64 ( ) ;
232
225
index = 0 ;
233
226
}
234
227
235
228
let value = self . rsl [ index] ;
236
- self . index += 2 ;
229
+ self . index += 1 ;
230
+ self . half_used = false ;
237
231
value
238
232
}
239
233
240
234
fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
241
235
let mut read_len = 0 ;
242
236
while read_len < dest. len ( ) {
243
- if ( self . index as usize >> 1 ) >= RAND_SIZE {
237
+ if self . index as usize >= RAND_SIZE {
244
238
self . isaac64 ( ) ;
245
239
}
246
240
247
241
let ( consumed_u64, filled_u8) =
248
- impls:: fill_via_u64_chunks ( & mut self . rsl [ ( self . index as usize >> 1 ) ..] ,
242
+ impls:: fill_via_u64_chunks ( & mut self . rsl [ self . index as usize ..] ,
249
243
& mut dest[ read_len..] ) ;
250
244
251
- self . index += consumed_u64 as u32 * 2 ;
245
+ self . index += consumed_u64 as u32 ;
252
246
read_len += filled_u8;
253
247
}
254
248
}
@@ -292,6 +286,7 @@ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Isaac64Rng {
292
286
b : w ( 0 ) ,
293
287
c : w ( 0 ) ,
294
288
index : 0 ,
289
+ half_used : false ,
295
290
} ;
296
291
297
292
// Prepare the first set of results
0 commit comments