Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Fill_via_u*_chunks not modify src #242

Merged
merged 2 commits into from
Jan 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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