@@ -15,6 +15,8 @@ use core::iter::repeat;
1515use core:: num:: Wrapping as w;
1616use core:: fmt;
1717
18+ use rand_core:: impls;
19+
1820use { Rng , SeedFromRng , SeedableRng , Error } ;
1921
2022#[ allow( non_camel_case_types) ]
@@ -71,12 +73,12 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
7173/// [1]: Bob Jenkins, [*ISAAC and RC4*]
7274/// (http://burtleburtle.net/bob/rand/isaac.html)
7375pub struct Isaac64Rng {
74- rsl : [ w64 ; RAND_SIZE ] ,
76+ rsl : [ u64 ; RAND_SIZE ] ,
7577 mem : [ w64 ; RAND_SIZE ] ,
7678 a : w64 ,
7779 b : w64 ,
7880 c : w64 ,
79- cnt : u32 ,
81+ index : u32 ,
8082}
8183
8284// Cannot be derived because [u64; 256] does not implement Clone
@@ -89,7 +91,7 @@ impl Clone for Isaac64Rng {
8991 a : self . a ,
9092 b : self . b ,
9193 c : self . c ,
92- cnt : self . cnt ,
94+ index : self . index ,
9395 }
9496 }
9597}
@@ -132,20 +134,23 @@ impl Isaac64Rng {
132134 /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
133135 /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
134136 /// arithmetic.
137+ /// - We fill `rsl` backwards. The reference implementation reads values
138+ /// from `rsl` in reverse. We read them in the normal direction, to make
139+ /// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
135140 fn isaac64 ( & mut self ) {
136141 self . c += w ( 1 ) ;
137142 // abbreviations
138143 let mut a = self . a ;
139144 let mut b = self . b + self . c ;
140145 const MIDPOINT : usize = RAND_SIZE / 2 ;
141146
142- #[ inline( always ) ]
147+ #[ inline]
143148 fn ind ( mem : & [ w64 ; RAND_SIZE ] , v : w64 , amount : usize ) -> w64 {
144149 let index = ( v >> amount) . 0 as usize % RAND_SIZE ;
145150 mem[ index]
146151 }
147152
148- #[ inline( always ) ]
153+ #[ inline]
149154 fn rngstep ( ctx : & mut Isaac64Rng ,
150155 mix : w64 ,
151156 a : & mut w64 ,
@@ -158,7 +163,7 @@ impl Isaac64Rng {
158163 let y = * a + * b + ind ( & ctx. mem , x, 3 ) ;
159164 ctx. mem [ base + m] = y;
160165 * b = x + ind ( & ctx. mem , y, 3 + RAND_SIZE_LEN ) ;
161- ctx. rsl [ base + m] = * b ;
166+ ctx. rsl [ RAND_SIZE - 1 - base - m] = ( * b ) . 0 ;
162167 }
163168
164169 let mut m = 0 ;
@@ -181,7 +186,7 @@ impl Isaac64Rng {
181186
182187 self . a = a;
183188 self . b = b;
184- self . cnt = RAND_SIZE as u32 ;
189+ self . index = 0 ;
185190 }
186191}
187192
@@ -193,33 +198,36 @@ impl Rng for Isaac64Rng {
193198
194199 #[ inline]
195200 fn next_u64 ( & mut self ) -> u64 {
196- if self . cnt == 0 {
197- // make some more numbers
201+ let mut index = self . index as usize ;
202+ if index >= RAND_SIZE {
198203 self . isaac64 ( ) ;
204+ index = 0 ;
199205 }
200- self . cnt -= 1 ;
201-
202- // self.cnt is at most RAND_SIZE, but that is before the
203- // subtraction above. We want to index without bounds
204- // checking, but this could lead to incorrect code if someone
205- // misrefactors, so we check, sometimes.
206- //
207- // (Changes here should be reflected in IsaacRng.next_u32.)
208- debug_assert ! ( ( self . cnt as usize ) < RAND_SIZE ) ;
209-
210- // (the % is cheaply telling the optimiser that we're always
211- // in bounds, without unsafe. NB. this is a power of two, so
212- // it optimises to a bitwise mask).
213- self . rsl [ self . cnt as usize % RAND_SIZE ] . 0
206+
207+ let value = self . rsl [ index] ;
208+ self . index += 1 ;
209+ value
214210 }
215211
216212 #[ cfg( feature = "i128_support" ) ]
217213 fn next_u128 ( & mut self ) -> u128 {
218- :: rand_core :: impls:: next_u128_via_u64 ( self )
214+ impls:: next_u128_via_u64 ( self )
219215 }
220216
221217 fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
222- :: rand_core:: impls:: fill_bytes_via_u64 ( self , dest) ;
218+ let mut read_len = 0 ;
219+ while read_len < dest. len ( ) {
220+ if self . index as usize >= RAND_SIZE {
221+ self . isaac64 ( ) ;
222+ }
223+
224+ let ( consumed_u64, filled_u8) =
225+ impls:: fill_via_u64_chunks ( & mut self . rsl [ ( self . index as usize ) ..] ,
226+ & mut dest[ read_len..] ) ;
227+
228+ self . index += consumed_u64 as u32 ;
229+ read_len += filled_u8;
230+ }
223231 }
224232
225233 fn try_fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
@@ -259,12 +267,12 @@ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Isaac64Rng {
259267 }
260268
261269 let mut rng = Isaac64Rng {
262- rsl : [ w ( 0 ) ; RAND_SIZE ] ,
270+ rsl : [ 0 ; RAND_SIZE ] ,
263271 mem : mem,
264272 a : w ( 0 ) ,
265273 b : w ( 0 ) ,
266274 c : w ( 0 ) ,
267- cnt : 0 ,
275+ index : 0 ,
268276 } ;
269277
270278 // Prepare the first set of results
0 commit comments