authorgravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2022-11-02 23:38:46+01:00
committergravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2022-11-07 02:46:19+01:00
log1f0e9e4e1104dc1140de0f68778536d4f49a5cfa
treef13b5fe7ce8ccb32aa59c15d8d0b9fa2438db236
parent8828fe3a7d5db66ad3caae0c275b4917c6247b5e
signaturelock-open Commit is signed but in an unrecognized format.

rand: add enumValueWithIndex

and reimplement enumValue in terms of it. Same rationale as shuffleWithIndex. Share small piece of code through MinArrayIndex.

1 files changed, 39 insertions(+), 6 deletions(-)

lib/std/rand.zig+39-6
...@@ -61,14 +61,41 @@ pub const Random = struct {...@@ -61,14 +61,41 @@ pub const Random = struct {
61 }61 }
6262
63 /// Returns a random value from an enum, evenly distributed.63 /// Returns a random value from an enum, evenly distributed.
64 pub fn enumValue(r: Random, comptime EnumType: type) EnumType {64 ///
65 /// Note that this will not yield consistent results across all targets
66 /// due to dependence on the representation of `usize` as an index.
67 /// See `enumValueWithIndex` for further commentary.
68 pub inline fn enumValue(r: Random, comptime EnumType: type) EnumType {
69 return r.enumValueWithIndex(EnumType, usize);
70 }
71
72 /// Returns a random value from an enum, evenly distributed.
73 ///
74 /// An index into an array of all named values is generated using the
75 /// specified `Index` type to determine the return value.
76 /// This allows for results to be independent of `usize` representation.
77 ///
78 /// Prefer `enumValue` if this isn't important.
79 ///
80 /// See `uintLessThan`, which this function uses in most cases,
81 /// for commentary on the runtime of this function.
82 pub fn enumValueWithIndex(r: Random, comptime EnumType: type, comptime Index: type) EnumType {
65 comptime assert(@typeInfo(EnumType) == .Enum);83 comptime assert(@typeInfo(EnumType) == .Enum);
6684
67 // We won't use int -> enum casting because enum elements can have85 // We won't use int -> enum casting because enum elements can have
68 // arbitrary values. Instead we'll randomly pick one of the type's values.86 // arbitrary values. Instead we'll randomly pick one of the type's values.
69 const values = std.enums.values(EnumType);87 const values = comptime std.enums.values(EnumType);
70 const index = r.uintLessThan(usize, values.len);88 comptime assert(values.len > 0); // can't return anything
71 return values[index];89 comptime assert(maxInt(Index) >= values.len - 1); // can't access all values
90 comptime if (values.len == 1) return values[0];
91
92 const index = if (comptime values.len - 1 == maxInt(Index))
93 r.int(Index)
94 else
95 r.uintLessThan(Index, values.len);
96
97 const MinInt = MinArrayIndex(Index);
98 return values[@intCast(MinInt, index)];
72 }99 }
73100
74 /// Returns a random int `i` such that `minInt(T) <= i <= maxInt(T)`.101 /// Returns a random int `i` such that `minInt(T) <= i <= maxInt(T)`.
...@@ -344,8 +371,7 @@ pub const Random = struct {...@@ -344,8 +371,7 @@ pub const Random = struct {
344 /// See `intRangeLessThan`, which this function uses,371 /// See `intRangeLessThan`, which this function uses,
345 /// for commentary on the runtime of this function.372 /// for commentary on the runtime of this function.
346 pub fn shuffleWithIndex(r: Random, comptime T: type, buf: []T, comptime Index: type) void {373 pub fn shuffleWithIndex(r: Random, comptime T: type, buf: []T, comptime Index: type) void {
347 comptime std.debug.assert(@typeInfo(Index).Int.signedness == .unsigned);374 const MinInt = MinArrayIndex(Index);
348 const MinInt = std.meta.Int(.unsigned, @min(@typeInfo(Index).Int.bits, @typeInfo(usize).Int.bits));
349 if (buf.len < 2) {375 if (buf.len < 2) {
350 return;376 return;
351 }377 }
...@@ -394,6 +420,13 @@ pub const Random = struct {...@@ -394,6 +420,13 @@ pub const Random = struct {
394420
395 unreachable;421 unreachable;
396 }422 }
423
424 /// Returns the smallest of `Index` and `usize`.
425 fn MinArrayIndex(comptime Index: type) type {
426 const index_info = @typeInfo(Index).Int;
427 assert(index_info.signedness == .unsigned);
428 return if (index_info.bits >= @typeInfo(usize).Int.bits) usize else Index;
429 }
397};430};
398431
399/// Convert a random integer 0 <= random_int <= maxValue(T),432/// Convert a random integer 0 <= random_int <= maxValue(T),