Skip to content

Optimize fill_bytes_via_* and prepare rand_core 0.1 #397

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

Merged
merged 2 commits into from
Apr 15, 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ You may also find the [Update Guide](UPDATING.md) useful.
- Add `Error` and `ErrorKind`. (#225)
- Add `CryptoRng` marker trait. (#273)
- Add `BlockRngCore` trait. (#281)
- Add `BlockRng` wrapper to help implementations. (#281)
- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
- Revise the `SeedableRng` trait. (#233)
- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
- Add `RngCore::try_fill_bytes`. (#225)
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ serde1 = ["serde", "serde_derive", "rand_core/serde1"] # enables serialization f
members = ["rand_core"]

[dependencies]
rand_core = { path="rand_core", default-features = false }
rand_core = { path = "rand_core", version = "0.1.0-pre.0", default-features = false }
log = { version = "0.4", optional = true }
serde = { version = "1", optional = true }
serde_derive = { version = "1", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion rand_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `Error` and `ErrorKind`. (#225)
- Add `CryptoRng` marker trait. (#273)
- Add `BlockRngCore` trait. (#281)
- Add `BlockRng` wrapper to help implemtations. (#281)
- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
- Revise the `SeedableRng` trait. (#233)
- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
- Add `RngCore::try_fill_bytes`. (#225)
Expand Down
3 changes: 3 additions & 0 deletions rand_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596),
unioned across the whole dependency tree, any crate using `rand` with its
default features will also enable `std` support in `rand_core`.

The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG
implementations that use the `BlockRng` or `BlockRng64` wrappers.


# License

Expand Down
57 changes: 28 additions & 29 deletions rand_core/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,35 +37,34 @@ pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
(y << 32) | x
}

macro_rules! fill_bytes_via {
($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
let mut left = $dest;
while left.len() >= $BYTES {
let (l, r) = {left}.split_at_mut($BYTES);
left = r;
let chunk: [u8; $BYTES] = unsafe {
transmute($rng.$next_u().to_le())
};
l.copy_from_slice(&chunk);
}
let n = left.len();
if n > 0 {
let chunk: [u8; $BYTES] = unsafe {
transmute($rng.$next_u().to_le())
};
left.copy_from_slice(&chunk[..n]);
}
}}
}

/// Implement `fill_bytes` via `next_u32`, little-endian order.
pub fn fill_bytes_via_u32<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
fill_bytes_via!(rng, next_u32, 4, dest)
}

/// Implement `fill_bytes` via `next_u64`, little-endian order.
pub fn fill_bytes_via_u64<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
fill_bytes_via!(rng, next_u64, 8, dest)
/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
///
/// The fastest way to fill a slice is usually to work as long as possible with
/// integers. That is why this method mostly uses `next_u64`, and only when
/// there are 4 or less bytes remaining at the end of the slice it uses
/// `next_u32` once.
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
let mut left = dest;
while left.len() >= 8 {
let (l, r) = {left}.split_at_mut(8);
left = r;
let chunk: [u8; 8] = unsafe {
transmute(rng.next_u64().to_le())
};
l.copy_from_slice(&chunk);
}
let n = left.len();
if n > 4 {
let chunk: [u8; 8] = unsafe {
transmute(rng.next_u64().to_le())
};
left.copy_from_slice(&chunk[..n]);
} else if n > 0 {
let chunk: [u8; 4] = unsafe {
transmute(rng.next_u32().to_le())
};
left.copy_from_slice(&chunk[..n]);
}
}

macro_rules! impl_uint_from_fill {
Expand Down
7 changes: 3 additions & 4 deletions rand_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://docs.rs/rand_core/0.1")]
html_root_url = "https://docs.rs/rand_core/0.1.0-pre.0")]

#![deny(missing_debug_implementations)]

Expand Down Expand Up @@ -121,7 +121,7 @@ pub mod le;
/// }
///
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
/// impls::fill_bytes_via_u64(self, dest)
/// impls::fill_bytes_via_next(self, dest)
/// }
///
/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Expand Down Expand Up @@ -160,8 +160,7 @@ pub trait RngCore {
///
/// RNGs must implement at least one method from this trait directly. In
/// the case this method is not implemented directly, it can be implemented
/// [via `next_u32`](../rand_core/impls/fn.fill_bytes_via_u32.html) or
/// [via `next_u64`](../rand_core/impls/fn.fill_bytes_via_u64.html) or
/// [via `next_u*`](../rand_core/impls/fn.fill_bytes_via_next.html) or
/// via `try_fill_bytes`; if this generator can fail the implementation
/// must choose how best to handle errors here (e.g. panic with a
/// descriptive message or log a warning and retry a few times).
Expand Down
2 changes: 1 addition & 1 deletion src/jitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ impl RngCore for JitterRng {
//
// This is done especially for wrappers that implement `next_u32`
// themselves via `fill_bytes`.
impls::fill_bytes_via_u32(self, dest)
impls::fill_bytes_via_next(self, dest)
}

fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Expand Down
2 changes: 1 addition & 1 deletion src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl RngCore for StepRng {
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest);
impls::fill_bytes_via_next(self, dest);
}

fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Expand Down
4 changes: 3 additions & 1 deletion src/prng/xorshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ impl RngCore for XorShiftRng {
self.w.0
}

#[inline]
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}

#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u32(self, dest)
impls::fill_bytes_via_next(self, dest)
}

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