authorgravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2022-11-02 18:23:14+01:00
committergravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2022-11-07 02:45:52+01:00
log8828fe3a7d5db66ad3caae0c275b4917c6247b5e
tree9eeea24d04d9244919f8deb54659ddfcb03959d7
parentb40fc70188fd097e9e05b5c18b635b67b718380e
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 28 insertions(+), 4 deletions(-)

lib/std/rand.zig+28-4
......@@ -323,14 +323,38 @@ pub const Random = struct {
323323 }
324324
325325 /// Shuffle a slice into a random order.
326 pub fn shuffle(r: Random, comptime T: type, buf: []T) void {
326 ///
327 /// Note that this will not yield consistent results across all targets
328 /// due to dependence on the representation of `usize` as an index.
329 /// See `shuffleWithIndex` for further commentary.
330 pub inline fn shuffle(r: Random, comptime T: type, buf: []T) void {
331 r.shuffleWithIndex(T, buf, usize);
332 }
333
334 /// Shuffle a slice into a random order, using an index of a
335 /// specified type to maintain distribution across targets.
336 /// Asserts the index type can represent `buf.len`.
337 ///
338 /// Indexes into the slice are generated using the specified `Index`
339 /// type, which determines distribution properties. This allows for
340 /// results to be independent of `usize` representation.
341 ///
342 /// Prefer `shuffle` if this isn't important.
343 ///
344 /// See `intRangeLessThan`, which this function uses,
345 /// for commentary on the runtime of this function.
346 pub fn shuffleWithIndex(r: Random, comptime T: type, buf: []T, comptime Index: type) void {
347 comptime std.debug.assert(@typeInfo(Index).Int.signedness == .unsigned);
348 const MinInt = std.meta.Int(.unsigned, @min(@typeInfo(Index).Int.bits, @typeInfo(usize).Int.bits));
327349 if (buf.len < 2) {
328350 return;
329351 }
330352
331 var i: usize = 0;
332 while (i < buf.len - 1) : (i += 1) {
333 const j = r.intRangeLessThan(usize, i, buf.len);
353 // `i <= j < max <= maxInt(MinInt)`
354 const max = @intCast(MinInt, buf.len);
355 var i: MinInt = 0;
356 while (i < max - 1) : (i += 1) {
357 const j = @intCast(MinInt, r.intRangeLessThan(Index, i, max));
334358 mem.swap(T, &buf[i], &buf[j]);
335359 }
336360 }