Make Fill_via_u*_chunks not modify src
This commit is contained in:
parent
a2f99f88d0
commit
cdc09e530a
52
src/impls.rs
52
src/impls.rs
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user