Make Fill_via_u*_chunks not modify src

This commit is contained in:
Paul Dicker 2018-01-20 19:55:18 +01:00
parent a2f99f88d0
commit cdc09e530a
5 changed files with 48 additions and 30 deletions

View File

@ -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;
@ -82,21 +83,34 @@ 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, $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 code copied from `byteorder::write_slice_native`.
unsafe {
copy_nonoverlapping(
$src.as_ptr() as *const u8,
$dst.as_mut_ptr(),
chunk_size_u8);
}
} else {
// Unsafe code copied from `byteorder::write_slice` and
// `byteorder::write_num_bytes`, with the addition to copy only
// `chunk.len()`.
// Byteorder assumes we want to copy only complete integers, while
// for us the destination may need only a part of the last integer.
for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
unsafe {
// N.B. https://github.com/rust-lang/rust/issues/22776
let bytes = transmute::<_, [u8; $size]>(n.to_le());
copy_nonoverlapping((&bytes).as_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)
});
}
@ -111,10 +125,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`)
///
@ -135,7 +145,7 @@ macro_rules! fill_via_chunks {
/// }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, 4)
}
@ -148,12 +158,8 @@ 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) {
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, 8)
}

View File

@ -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;
}
}
}

View File

@ -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;
@ -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;
@ -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;

View File

@ -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;

View File

@ -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;