Skip to content

Commit 8273840

Browse files
committed
Optimize fill_bytes_via
1 parent 74b5f62 commit 8273840

File tree

5 files changed

+35
-35
lines changed

5 files changed

+35
-35
lines changed

rand_core/src/impls.rs

+28-29
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,34 @@ pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
3737
(y << 32) | x
3838
}
3939

40-
macro_rules! fill_bytes_via {
41-
($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
42-
let mut left = $dest;
43-
while left.len() >= $BYTES {
44-
let (l, r) = {left}.split_at_mut($BYTES);
45-
left = r;
46-
let chunk: [u8; $BYTES] = unsafe {
47-
transmute($rng.$next_u().to_le())
48-
};
49-
l.copy_from_slice(&chunk);
50-
}
51-
let n = left.len();
52-
if n > 0 {
53-
let chunk: [u8; $BYTES] = unsafe {
54-
transmute($rng.$next_u().to_le())
55-
};
56-
left.copy_from_slice(&chunk[..n]);
57-
}
58-
}}
59-
}
60-
61-
/// Implement `fill_bytes` via `next_u32`, little-endian order.
62-
pub fn fill_bytes_via_u32<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
63-
fill_bytes_via!(rng, next_u32, 4, dest)
64-
}
65-
66-
/// Implement `fill_bytes` via `next_u64`, little-endian order.
67-
pub fn fill_bytes_via_u64<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
68-
fill_bytes_via!(rng, next_u64, 8, dest)
40+
/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
41+
///
42+
/// The fastest way to fill a slice is usually to work as long as possible with
43+
/// integers. That is why this method mostly uses `next_u64`, and only when
44+
/// there are 4 or less bytes remaining at the end of the slice it uses
45+
/// `next_u32` once.
46+
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
47+
let mut left = dest;
48+
while left.len() >= 8 {
49+
let (l, r) = {left}.split_at_mut(8);
50+
left = r;
51+
let chunk: [u8; 8] = unsafe {
52+
transmute(rng.next_u64().to_le())
53+
};
54+
l.copy_from_slice(&chunk);
55+
}
56+
let n = left.len();
57+
if n >= 4 {
58+
let chunk: [u8; 8] = unsafe {
59+
transmute(rng.next_u64().to_le())
60+
};
61+
left.copy_from_slice(&chunk[..n]);
62+
} else if n > 0 {
63+
let chunk: [u8; 4] = unsafe {
64+
transmute(rng.next_u32().to_le())
65+
};
66+
left.copy_from_slice(&chunk[..n]);
67+
}
6968
}
7069

7170
macro_rules! impl_uint_from_fill {

rand_core/src/lib.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub mod le;
121121
/// }
122122
///
123123
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
124-
/// impls::fill_bytes_via_u64(self, dest)
124+
/// impls::fill_bytes_via_next(self, dest)
125125
/// }
126126
///
127127
/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
@@ -160,8 +160,7 @@ pub trait RngCore {
160160
///
161161
/// RNGs must implement at least one method from this trait directly. In
162162
/// the case this method is not implemented directly, it can be implemented
163-
/// [via `next_u32`](../rand_core/impls/fn.fill_bytes_via_u32.html) or
164-
/// [via `next_u64`](../rand_core/impls/fn.fill_bytes_via_u64.html) or
163+
/// [via `next_u*`](../rand_core/impls/fn.fill_bytes_via_next.html) or
165164
/// via `try_fill_bytes`; if this generator can fail the implementation
166165
/// must choose how best to handle errors here (e.g. panic with a
167166
/// descriptive message or log a warning and retry a few times).

src/jitter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ impl RngCore for JitterRng {
804804
//
805805
// This is done especially for wrappers that implement `next_u32`
806806
// themselves via `fill_bytes`.
807-
impls::fill_bytes_via_u32(self, dest)
807+
impls::fill_bytes_via_next(self, dest)
808808
}
809809

810810
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

src/mock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl RngCore for StepRng {
5252
}
5353

5454
fn fill_bytes(&mut self, dest: &mut [u8]) {
55-
impls::fill_bytes_via_u64(self, dest);
55+
impls::fill_bytes_via_next(self, dest);
5656
}
5757

5858
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

src/prng/xorshift.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ impl RngCore for XorShiftRng {
7171
self.w.0
7272
}
7373

74+
#[inline]
7475
fn next_u64(&mut self) -> u64 {
7576
impls::next_u64_via_u32(self)
7677
}
7778

79+
#[inline]
7880
fn fill_bytes(&mut self, dest: &mut [u8]) {
79-
impls::fill_bytes_via_u32(self, dest)
81+
impls::fill_bytes_via_next(self, dest)
8082
}
8183

8284
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

0 commit comments

Comments
 (0)