Skip to content

Commit 8dc7b56

Browse files
pitdickerdhardy
authored andcommitted
Fill isaac64 backwards, and use fill_via_u32_chunks
[Cherry-picked from 707c3e1]
1 parent 4c9a032 commit 8dc7b56

File tree

1 file changed

+32
-26
lines changed

1 file changed

+32
-26
lines changed

src/prng/isaac64.rs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
7272
/// [1]: Bob Jenkins, [*ISAAC and RC4*]
7373
/// (http://burtleburtle.net/bob/rand/isaac.html)
7474
pub struct Isaac64Rng {
75-
rsl: [w64; RAND_SIZE],
75+
rsl: [u64; RAND_SIZE],
7676
mem: [w64; RAND_SIZE],
7777
a: w64,
7878
b: w64,
7979
c: w64,
80-
cnt: u32,
80+
index: u32,
8181
}
8282

8383
// Cannot be derived because [u64; 256] does not implement Clone
@@ -90,7 +90,7 @@ impl Clone for Isaac64Rng {
9090
a: self.a,
9191
b: self.b,
9292
c: self.c,
93-
cnt: self.cnt,
93+
index: self.index,
9494
}
9595
}
9696
}
@@ -133,20 +133,23 @@ impl Isaac64Rng {
133133
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
134134
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
135135
/// arithmetic.
136+
/// - We fill `rsl` backwards. The reference implementation reads values
137+
/// from `rsl` in reverse. We read them in the normal direction, to make
138+
/// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
136139
fn isaac64(&mut self) {
137140
self.c += w(1);
138141
// abbreviations
139142
let mut a = self.a;
140143
let mut b = self.b + self.c;
141144
const MIDPOINT: usize = RAND_SIZE / 2;
142145

143-
#[inline(always)]
146+
#[inline]
144147
fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 {
145148
let index = (v >> amount).0 as usize % RAND_SIZE;
146149
mem[index]
147150
}
148151

149-
#[inline(always)]
152+
#[inline]
150153
fn rngstep(ctx: &mut Isaac64Rng,
151154
mix: w64,
152155
a: &mut w64,
@@ -159,7 +162,7 @@ impl Isaac64Rng {
159162
let y = *a + *b + ind(&ctx.mem, x, 3);
160163
ctx.mem[base + m] = y;
161164
*b = x + ind(&ctx.mem, y, 3 + RAND_SIZE_LEN);
162-
ctx.rsl[base + m] = *b;
165+
ctx.rsl[RAND_SIZE - 1 - base - m] = (*b).0;
163166
}
164167

165168
let mut m = 0;
@@ -182,7 +185,7 @@ impl Isaac64Rng {
182185

183186
self.a = a;
184187
self.b = b;
185-
self.cnt = RAND_SIZE as u32;
188+
self.index = 0;
186189
}
187190
}
188191

@@ -194,28 +197,31 @@ impl Rng for Isaac64Rng {
194197

195198
#[inline]
196199
fn next_u64(&mut self) -> u64 {
197-
if self.cnt == 0 {
198-
// make some more numbers
200+
let mut index = self.index as usize;
201+
if index >= RAND_SIZE {
199202
self.isaac64();
203+
index = 0;
200204
}
201-
self.cnt -= 1;
202-
203-
// self.cnt is at most RAND_SIZE, but that is before the
204-
// subtraction above. We want to index without bounds
205-
// checking, but this could lead to incorrect code if someone
206-
// misrefactors, so we check, sometimes.
207-
//
208-
// (Changes here should be reflected in IsaacRng.next_u32.)
209-
debug_assert!((self.cnt as usize) < RAND_SIZE);
210-
211-
// (the % is cheaply telling the optimiser that we're always
212-
// in bounds, without unsafe. NB. this is a power of two, so
213-
// it optimises to a bitwise mask).
214-
self.rsl[self.cnt as usize % RAND_SIZE].0
205+
206+
let value = self.rsl[index];
207+
self.index += 1;
208+
value
215209
}
216210

217211
fn fill_bytes(&mut self, dest: &mut [u8]) {
218-
impls::fill_bytes_via_u64(self, dest)
212+
let mut read_len = 0;
213+
while read_len < dest.len() {
214+
if self.index as usize >= RAND_SIZE {
215+
self.isaac64();
216+
}
217+
218+
let (consumed_u64, filled_u8) =
219+
impls::fill_via_u64_chunks(&mut self.rsl[(self.index as usize)..],
220+
&mut dest[read_len..]);
221+
222+
self.index += consumed_u64 as u32;
223+
read_len += filled_u8;
224+
}
219225
}
220226
}
221227

@@ -251,12 +257,12 @@ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Isaac64Rng {
251257
}
252258

253259
let mut rng = Isaac64Rng {
254-
rsl: [w(0); RAND_SIZE],
260+
rsl: [0; RAND_SIZE],
255261
mem: mem,
256262
a: w(0),
257263
b: w(0),
258264
c: w(0),
259-
cnt: 0,
265+
index: 0,
260266
};
261267

262268
// Prepare the first set of results

0 commit comments

Comments
 (0)