Skip to content

Commit 940e401

Browse files
authored
Merge pull request #242 from pitdicker/fill_via_chunks_immutable
Make `Fill_via_u*_chunks` not modify `src`
2 parents a2f99f8 + 027e030 commit 940e401

File tree

5 files changed

+44
-32
lines changed

5 files changed

+44
-32
lines changed

src/impls.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![allow(unused)]
2424

2525
use core::intrinsics::transmute;
26+
use core::ptr::copy_nonoverlapping;
2627
use core::slice;
2728
use core::cmp::min;
2829
use core::mem::size_of;
@@ -82,21 +83,28 @@ macro_rules! impl_uint_from_fill {
8283
}
8384

8485
macro_rules! fill_via_chunks {
85-
($src:expr, $dest:expr, $N:expr) => ({
86-
let chunk_size_u8 = min($src.len() * $N, $dest.len());
87-
let chunk_size = (chunk_size_u8 + $N - 1) / $N;
88-
89-
// Convert to little-endian:
90-
for ref mut x in $src[0..chunk_size].iter_mut() {
91-
**x = (*x).to_le();
86+
($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
87+
let chunk_size_u8 = min($src.len() * $size, $dst.len());
88+
let chunk_size = (chunk_size_u8 + $size - 1) / $size;
89+
if cfg!(target_endian="little") {
90+
unsafe {
91+
copy_nonoverlapping(
92+
$src.as_ptr() as *const u8,
93+
$dst.as_mut_ptr(),
94+
chunk_size_u8);
95+
}
96+
} else {
97+
for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
98+
let tmp = n.to_le();
99+
let src_ptr = &tmp as *const $ty as *const u8;
100+
unsafe {
101+
copy_nonoverlapping(src_ptr,
102+
chunk.as_mut_ptr(),
103+
chunk.len());
104+
}
105+
}
92106
}
93107

94-
let bytes = unsafe { slice::from_raw_parts($src.as_ptr() as *const u8,
95-
$src.len() * $N) };
96-
97-
let dest_chunk = &mut $dest[0..chunk_size_u8];
98-
dest_chunk.copy_from_slice(&bytes[0..chunk_size_u8]);
99-
100108
(chunk_size, chunk_size_u8)
101109
});
102110
}
@@ -111,10 +119,6 @@ macro_rules! fill_via_chunks {
111119
/// `consumed_u32` is the number of words consumed from `src`, which is the same
112120
/// as `filled_u8 / 4` rounded up.
113121
///
114-
/// Note that on big-endian systems values in the output buffer `src` are
115-
/// mutated. `src[0..consumed_u32]` get converted to little-endian before
116-
/// copying.
117-
///
118122
/// # Example
119123
/// (from `IsaacRng`)
120124
///
@@ -135,8 +139,8 @@ macro_rules! fill_via_chunks {
135139
/// }
136140
/// }
137141
/// ```
138-
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
139-
fill_via_chunks!(src, dest, 4)
142+
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
143+
fill_via_chunks!(src, dest, u32, 4)
140144
}
141145

142146
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
@@ -148,13 +152,9 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
148152
/// `consumed_u64` is the number of words consumed from `src`, which is the same
149153
/// as `filled_u8 / 8` rounded up.
150154
///
151-
/// Note that on big-endian systems values in the output buffer `src` are
152-
/// mutated. `src[0..consumed_u64]` get converted to little-endian before
153-
/// copying.
154-
///
155155
/// See `fill_via_u32_chunks` for an example.
156-
pub fn fill_via_u64_chunks(src: &mut [u64], dest: &mut [u8]) -> (usize, usize) {
157-
fill_via_chunks!(src, dest, 8)
156+
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
157+
fill_via_chunks!(src, dest, u64, 8)
158158
}
159159

160160
/// Implement `next_u32` via `fill_bytes`, little-endian order.

src/prng/chacha.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,20 @@ impl Rng for ChaChaRng {
208208
}
209209

210210

211-
fn fill_bytes(&mut self, bytes: &mut [u8]) {
212-
impls::fill_bytes_via_u32(self, bytes)
211+
fn fill_bytes(&mut self, dest: &mut [u8]) {
212+
let mut read_len = 0;
213+
while read_len < dest.len() {
214+
if self.index >= self.buffer.len() {
215+
self.update();
216+
}
217+
218+
let (consumed_u32, filled_u8) =
219+
impls::fill_via_u32_chunks(&self.buffer[self.index..],
220+
&mut dest[read_len..]);
221+
222+
self.index += consumed_u32;
223+
read_len += filled_u8;
224+
}
213225
}
214226
}
215227

src/prng/hc128.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ impl Rng for Hc128Rng {
342342
// Continue filling from the current set of results
343343
if self.index < 16 {
344344
let (consumed_u32, filled_u8) =
345-
impls::fill_via_u32_chunks(&mut self.results[self.index..],
345+
impls::fill_via_u32_chunks(&self.results[self.index..],
346346
dest);
347347

348348
self.index += consumed_u32;
@@ -367,7 +367,7 @@ impl Rng for Hc128Rng {
367367
self.state.update(&mut self.results);
368368

369369
let (consumed_u32, _) =
370-
impls::fill_via_u32_chunks(&mut self.results,
370+
impls::fill_via_u32_chunks(&self.results,
371371
&mut dest[filled..]);
372372

373373
self.index = consumed_u32;
@@ -384,7 +384,7 @@ impl Rng for Hc128Rng {
384384
}
385385

386386
let (consumed_u32, filled_u8) =
387-
impls::fill_via_u32_chunks(&mut self.results[self.index..],
387+
impls::fill_via_u32_chunks(&self.results[self.index..],
388388
&mut dest[read_len..]);
389389

390390
self.index += consumed_u32;

src/prng/isaac.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ impl Rng for IsaacRng {
242242
}
243243

244244
let (consumed_u32, filled_u8) =
245-
impls::fill_via_u32_chunks(&mut self.rsl[(self.index as usize)..],
245+
impls::fill_via_u32_chunks(&self.rsl[(self.index as usize)..],
246246
&mut dest[read_len..]);
247247

248248
self.index += consumed_u32 as u32;

src/prng/isaac64.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ impl Rng for Isaac64Rng {
245245
}
246246

247247
let (consumed_u64, filled_u8) =
248-
impls::fill_via_u64_chunks(&mut self.rsl[self.index as usize..],
248+
impls::fill_via_u64_chunks(&self.rsl[self.index as usize..],
249249
&mut dest[read_len..]);
250250

251251
self.index += consumed_u64 as u32;

0 commit comments

Comments
 (0)