Skip to content

Commit

Permalink
fill_via_chunks: make a generic function
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Sep 13, 2021
1 parent 45f33d1 commit 1327048
Showing 1 changed file with 34 additions and 22 deletions.
56 changes: 34 additions & 22 deletions rand_core/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,29 +52,41 @@ pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
}
}

macro_rules! fill_via_chunks {
($src:expr, $dst:expr, $ty:ty) => {{
const SIZE: usize = core::mem::size_of::<$ty>();
let chunk_size_u8 = min($src.len() * SIZE, $dst.len());
let chunk_size = (chunk_size_u8 + SIZE - 1) / SIZE;

// Byte-swap for portability of results:
if cfg!(target_endian = "big") {
for x in &mut $src[..chunk_size] {
*x = x.to_le();
}
}
trait ToLe: Copy {
fn to_le(self) -> Self;
}
impl ToLe for u32 {
fn to_le(self) -> Self {
self.to_le()
}
}
impl ToLe for u64 {
fn to_le(self) -> Self {
self.to_le()
}
}

fn fill_via_chunks<T: ToLe>(src: &mut [T], dest: &mut [u8]) -> (usize, usize) {
let size = core::mem::size_of::<T>();
let chunk_size_u8 = min(src.len() * size, dest.len());
let chunk_size = (chunk_size_u8 + size - 1) / size;

// We do a simple copy, which is 25-50% faster:
unsafe {
core::ptr::copy_nonoverlapping(
$src.as_ptr() as *const u8,
$dst.as_mut_ptr(),
chunk_size_u8);
// Byte-swap for portability of results:
if cfg!(target_endian = "big") {
for x in &mut src[..chunk_size] {
*x = x.to_le();
}
}

unsafe {
core::ptr::copy_nonoverlapping(
src.as_ptr() as *const u8,
dest.as_mut_ptr(),
chunk_size_u8,
);
}

(chunk_size, chunk_size_u8)
}};
(chunk_size, chunk_size_u8)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
Expand Down Expand Up @@ -111,7 +123,7 @@ macro_rules! fill_via_chunks {
/// }
/// ```
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, u32)
fill_via_chunks(src, dest)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
Expand All @@ -129,7 +141,7 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
///
/// 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, u64)
fill_via_chunks(src, dest)
}

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

0 comments on commit 1327048

Please sign in to comment.