Skip to content

Commit

Permalink
Merge pull request #242 from pitdicker/fill_via_chunks_immutable
Browse files Browse the repository at this point in the history
Make `Fill_via_u*_chunks` not modify `src`
  • Loading branch information
dhardy authored Jan 21, 2018
2 parents c1d7dbf + 47964fd commit 97d0a46
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 32 deletions.
50 changes: 25 additions & 25 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#![allow(unused)]

use core::intrinsics::transmute;
use core::ptr::copy_nonoverlapping;
use core::slice;
use core::cmp::min;
use core::mem::size_of;
Expand Down Expand Up @@ -82,21 +83,28 @@ macro_rules! impl_uint_from_fill {
}

macro_rules! fill_via_chunks {
($src:expr, $dest:expr, $N:expr) => ({
let chunk_size_u8 = min($src.len() * $N, $dest.len());
let chunk_size = (chunk_size_u8 + $N - 1) / $N;

// Convert to little-endian:
for ref mut x in $src[0..chunk_size].iter_mut() {
**x = (*x).to_le();
($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
let chunk_size_u8 = min($src.len() * $size, $dst.len());
let chunk_size = (chunk_size_u8 + $size - 1) / $size;
if cfg!(target_endian="little") {
unsafe {
copy_nonoverlapping(
$src.as_ptr() as *const u8,
$dst.as_mut_ptr(),
chunk_size_u8);
}
} else {
for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
let tmp = n.to_le();
let src_ptr = &tmp as *const $ty as *const u8;
unsafe {
copy_nonoverlapping(src_ptr,
chunk.as_mut_ptr(),
chunk.len());
}
}
}

let bytes = unsafe { slice::from_raw_parts($src.as_ptr() as *const u8,
$src.len() * $N) };

let dest_chunk = &mut $dest[0..chunk_size_u8];
dest_chunk.copy_from_slice(&bytes[0..chunk_size_u8]);

(chunk_size, chunk_size_u8)
});
}
Expand All @@ -111,10 +119,6 @@ macro_rules! fill_via_chunks {
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// Note that on big-endian systems values in the output buffer `src` are
/// mutated. `src[0..consumed_u32]` get converted to little-endian before
/// copying.
///
/// # Example
/// (from `IsaacRng`)
///
Expand All @@ -135,8 +139,8 @@ macro_rules! fill_via_chunks {
/// }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, 4)
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, u32, 4)
}

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

/// Implement `next_u32` via `fill_bytes`, little-endian order.
Expand Down
16 changes: 14 additions & 2 deletions src/prng/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,20 @@ impl Rng for ChaChaRng {
}


fn fill_bytes(&mut self, bytes: &mut [u8]) {
impls::fill_bytes_via_u32(self, bytes)
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
while read_len < dest.len() {
if self.index >= self.buffer.len() {
self.update();
}

let (consumed_u32, filled_u8) =
impls::fill_via_u32_chunks(&self.buffer[self.index..],
&mut dest[read_len..]);

self.index += consumed_u32;
read_len += filled_u8;
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/prng/hc128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl Rng for Hc128Rng {
// Continue filling from the current set of results
if self.index < 16 {
let (consumed_u32, filled_u8) =
impls::fill_via_u32_chunks(&mut self.results[self.index..],
impls::fill_via_u32_chunks(&self.results[self.index..],
dest);

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

let (consumed_u32, _) =
impls::fill_via_u32_chunks(&mut self.results,
impls::fill_via_u32_chunks(&self.results,
&mut dest[filled..]);

self.index = consumed_u32;
Expand All @@ -384,7 +384,7 @@ impl Rng for Hc128Rng {
}

let (consumed_u32, filled_u8) =
impls::fill_via_u32_chunks(&mut self.results[self.index..],
impls::fill_via_u32_chunks(&self.results[self.index..],
&mut dest[read_len..]);

self.index += consumed_u32;
Expand Down
2 changes: 1 addition & 1 deletion src/prng/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl Rng for IsaacRng {
}

let (consumed_u32, filled_u8) =
impls::fill_via_u32_chunks(&mut self.rsl[(self.index as usize)..],
impls::fill_via_u32_chunks(&self.rsl[(self.index as usize)..],
&mut dest[read_len..]);

self.index += consumed_u32 as u32;
Expand Down
2 changes: 1 addition & 1 deletion src/prng/isaac64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl Rng for Isaac64Rng {
}

let (consumed_u64, filled_u8) =
impls::fill_via_u64_chunks(&mut self.rsl[self.index as usize..],
impls::fill_via_u64_chunks(&self.rsl[self.index as usize..],
&mut dest[read_len..]);

self.index += consumed_u64 as u32;
Expand Down

0 comments on commit 97d0a46

Please sign in to comment.