mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 18:38:45 +00:00
rand: add shuffleWithIndex
and reimplement shuffle in terms of it. This allows the caller to specify an index type of a fixed bit width, allowing results to be independent usize.
This commit is contained in:
parent
b40fc70188
commit
8828fe3a7d
@ -323,14 +323,38 @@ pub const Random = struct {
|
||||
}
|
||||
|
||||
/// Shuffle a slice into a random order.
|
||||
pub fn shuffle(r: Random, comptime T: type, buf: []T) void {
|
||||
///
|
||||
/// Note that this will not yield consistent results across all targets
|
||||
/// due to dependence on the representation of `usize` as an index.
|
||||
/// See `shuffleWithIndex` for further commentary.
|
||||
pub inline fn shuffle(r: Random, comptime T: type, buf: []T) void {
|
||||
r.shuffleWithIndex(T, buf, usize);
|
||||
}
|
||||
|
||||
/// Shuffle a slice into a random order, using an index of a
|
||||
/// specified type to maintain distribution across targets.
|
||||
/// Asserts the index type can represent `buf.len`.
|
||||
///
|
||||
/// Indexes into the slice are generated using the specified `Index`
|
||||
/// type, which determines distribution properties. This allows for
|
||||
/// results to be independent of `usize` representation.
|
||||
///
|
||||
/// Prefer `shuffle` if this isn't important.
|
||||
///
|
||||
/// See `intRangeLessThan`, which this function uses,
|
||||
/// for commentary on the runtime of this function.
|
||||
pub fn shuffleWithIndex(r: Random, comptime T: type, buf: []T, comptime Index: type) void {
|
||||
comptime std.debug.assert(@typeInfo(Index).Int.signedness == .unsigned);
|
||||
const MinInt = std.meta.Int(.unsigned, @min(@typeInfo(Index).Int.bits, @typeInfo(usize).Int.bits));
|
||||
if (buf.len < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < buf.len - 1) : (i += 1) {
|
||||
const j = r.intRangeLessThan(usize, i, buf.len);
|
||||
// `i <= j < max <= maxInt(MinInt)`
|
||||
const max = @intCast(MinInt, buf.len);
|
||||
var i: MinInt = 0;
|
||||
while (i < max - 1) : (i += 1) {
|
||||
const j = @intCast(MinInt, r.intRangeLessThan(Index, i, max));
|
||||
mem.swap(T, &buf[i], &buf[j]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user