authorgravatar for 37453713+Ominitay@users.noreply.github.comOminitay <37453713+Ominitay@users.noreply.github.com> 2021-10-27 15:53:29+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-27 16:07:48-04:00
logc1a5ff34f3f68a2a0bc32828ab483328cd436fea
treebad85387a89da38890f72696ccfc0ae3c416ab0f
parent9024f27d8f5cb651e2260348ce0ee6fd67fc2c32

std.rand: Refactor `Random` interface

These changes have been made to resolve issue #10037. The `Random` interface was implemented in such a way that causes significant slowdown when calling the `fill` function of the rng used. The `Random` interface is no longer stored in a field of the rng, and is instead returned by the child function `random()` of the rng. This avoids the performance issues caused by the interface.

18 files changed, 291 insertions(+), 244 deletions(-)

lib/std/atomic/queue.zig+3-2
......@@ -242,10 +242,11 @@ test "std.atomic.Queue" {
242242
243243fn startPuts(ctx: *Context) u8 {
244244 var put_count: usize = puts_per_thread;
245 var r = std.rand.DefaultPrng.init(0xdeadbeef);
245 var prng = std.rand.DefaultPrng.init(0xdeadbeef);
246 const random = prng.random();
246247 while (put_count != 0) : (put_count -= 1) {
247248 std.time.sleep(1); // let the os scheduler be our fuzz
248 const x = @bitCast(i32, r.random.int(u32));
249 const x = @bitCast(i32, random.int(u32));
249250 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
250251 node.* = .{
251252 .prev = undefined,
lib/std/atomic/stack.zig+3-2
......@@ -147,10 +147,11 @@ test "std.atomic.stack" {
147147
148148fn startPuts(ctx: *Context) u8 {
149149 var put_count: usize = puts_per_thread;
150 var r = std.rand.DefaultPrng.init(0xdeadbeef);
150 var prng = std.rand.DefaultPrng.init(0xdeadbeef);
151 const random = prng.random();
151152 while (put_count != 0) : (put_count -= 1) {
152153 std.time.sleep(1); // let the os scheduler be our fuzz
153 const x = @bitCast(i32, r.random.int(u32));
154 const x = @bitCast(i32, random.int(u32));
154155 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
155156 node.* = Stack(i32).Node{
156157 .next = undefined,
lib/std/crypto/benchmark.zig+11-10
......@@ -11,6 +11,7 @@ const KiB = 1024;
1111const MiB = 1024 * KiB;
1212
1313var prng = std.rand.DefaultPrng.init(0);
14const random = prng.random();
1415
1516const Crypto = struct {
1617 ty: type,
......@@ -34,7 +35,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
3435 var h = Hash.init(.{});
3536
3637 var block: [Hash.digest_length]u8 = undefined;
37 prng.random.bytes(block[0..]);
38 random.bytes(block[0..]);
3839
3940 var offset: usize = 0;
4041 var timer = try Timer.start();
......@@ -66,11 +67,11 @@ const macs = [_]Crypto{
6667
6768pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
6869 var in: [512 * KiB]u8 = undefined;
69 prng.random.bytes(in[0..]);
70 random.bytes(in[0..]);
7071
7172 const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;
7273 var key: [key_length]u8 = undefined;
73 prng.random.bytes(key[0..]);
74 random.bytes(key[0..]);
7475
7576 var mac: [Mac.mac_length]u8 = undefined;
7677 var offset: usize = 0;
......@@ -94,10 +95,10 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
9495 std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);
9596
9697 var secret: [DhKeyExchange.shared_length]u8 = undefined;
97 prng.random.bytes(secret[0..]);
98 random.bytes(secret[0..]);
9899
99100 var public: [DhKeyExchange.shared_length]u8 = undefined;
100 prng.random.bytes(public[0..]);
101 random.bytes(public[0..]);
101102
102103 var timer = try Timer.start();
103104 const start = timer.lap();
......@@ -211,15 +212,15 @@ const aeads = [_]Crypto{
211212
212213pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
213214 var in: [512 * KiB]u8 = undefined;
214 prng.random.bytes(in[0..]);
215 random.bytes(in[0..]);
215216
216217 var tag: [Aead.tag_length]u8 = undefined;
217218
218219 var key: [Aead.key_length]u8 = undefined;
219 prng.random.bytes(key[0..]);
220 random.bytes(key[0..]);
220221
221222 var nonce: [Aead.nonce_length]u8 = undefined;
222 prng.random.bytes(nonce[0..]);
223 random.bytes(nonce[0..]);
223224
224225 var offset: usize = 0;
225226 var timer = try Timer.start();
......@@ -244,7 +245,7 @@ const aes = [_]Crypto{
244245
245246pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
246247 var key: [Aes.key_bits / 8]u8 = undefined;
247 prng.random.bytes(key[0..]);
248 random.bytes(key[0..]);
248249 const ctx = Aes.initEnc(key);
249250
250251 var in = [_]u8{0} ** 16;
......@@ -273,7 +274,7 @@ const aes8 = [_]Crypto{
273274
274275pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
275276 var key: [Aes.key_bits / 8]u8 = undefined;
276 prng.random.bytes(key[0..]);
277 random.bytes(key[0..]);
277278 const ctx = Aes.initEnc(key);
278279
279280 var in = [_]u8{0} ** (8 * 16);
lib/std/crypto/tlcsprng.zig+5-2
......@@ -11,7 +11,10 @@ const os = std.os;
1111
1212/// We use this as a layer of indirection because global const pointers cannot
1313/// point to thread-local variables.
14pub var interface = std.rand.Random{ .fillFn = tlsCsprngFill };
14pub const interface = std.rand.Random{
15 .ptr = undefined,
16 .fillFn = tlsCsprngFill,
17};
1518
1619const os_has_fork = switch (builtin.os.tag) {
1720 .dragonfly,
......@@ -55,7 +58,7 @@ var install_atfork_handler = std.once(struct {
5558
5659threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};
5760
58fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {
61fn tlsCsprngFill(_: *c_void, buffer: []u8) void {
5962 if (builtin.link_libc and @hasDecl(std.c, "arc4random_buf")) {
6063 // arc4random is already a thread-local CSPRNG.
6164 return std.c.arc4random_buf(buffer.ptr, buffer.len);
lib/std/hash/benchmark.zig+3-2
......@@ -11,6 +11,7 @@ const MiB = 1024 * KiB;
1111const GiB = 1024 * MiB;
1212
1313var prng = std.rand.DefaultPrng.init(0);
14const random = prng.random();
1415
1516const Hash = struct {
1617 ty: type,
......@@ -88,7 +89,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {
8889 };
8990
9091 var block: [block_size]u8 = undefined;
91 prng.random.bytes(block[0..]);
92 random.bytes(block[0..]);
9293
9394 var offset: usize = 0;
9495 var timer = try Timer.start();
......@@ -110,7 +111,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {
110111pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize) !Result {
111112 const key_count = bytes / key_size;
112113 var block: [block_size]u8 = undefined;
113 prng.random.bytes(block[0..]);
114 random.bytes(block[0..]);
114115
115116 var i: usize = 0;
116117 var timer = try Timer.start();
lib/std/hash_map.zig+7-5
......@@ -1795,10 +1795,11 @@ test "std.hash_map put and remove loop in random order" {
17951795 while (i < size) : (i += 1) {
17961796 try keys.append(i);
17971797 }
1798 var rng = std.rand.DefaultPrng.init(0);
1798 var prng = std.rand.DefaultPrng.init(0);
1799 const random = prng.random();
17991800
18001801 while (i < iterations) : (i += 1) {
1801 std.rand.Random.shuffle(&rng.random, u32, keys.items);
1802 random.shuffle(u32, keys.items);
18021803
18031804 for (keys.items) |key| {
18041805 try map.put(key, key);
......@@ -1826,14 +1827,15 @@ test "std.hash_map remove one million elements in random order" {
18261827 keys.append(i) catch unreachable;
18271828 }
18281829
1829 var rng = std.rand.DefaultPrng.init(0);
1830 std.rand.Random.shuffle(&rng.random, u32, keys.items);
1830 var prng = std.rand.DefaultPrng.init(0);
1831 const random = prng.random();
1832 random.shuffle(u32, keys.items);
18311833
18321834 for (keys.items) |key| {
18331835 map.put(key, key) catch unreachable;
18341836 }
18351837
1836 std.rand.Random.shuffle(&rng.random, u32, keys.items);
1838 random.shuffle(u32, keys.items);
18371839 i = 0;
18381840 while (i < n) : (i += 1) {
18391841 const key = keys.items[i];
lib/std/io/test.zig+2-1
......@@ -20,7 +20,8 @@ test "write a file, read it, then delete it" {
2020
2121 var data: [1024]u8 = undefined;
2222 var prng = DefaultPrng.init(1234);
23 prng.random.bytes(data[0..]);
23 const random = prng.random();
24 random.bytes(data[0..]);
2425 const tmp_file_name = "temp_test_file.txt";
2526 {
2627 var file = try tmp.dir.createFile(tmp_file_name, .{});
lib/std/math/big/rational.zig+2-1
......@@ -589,9 +589,10 @@ test "big.rational set/to Float round-trip" {
589589 var a = try Rational.init(testing.allocator);
590590 defer a.deinit();
591591 var prng = std.rand.DefaultPrng.init(0x5EED);
592 const random = prng.random();
592593 var i: usize = 0;
593594 while (i < 512) : (i += 1) {
594 const r = prng.random.float(f64);
595 const r = random.float(f64);
595596 try a.setFloat(f64, r);
596597 try testing.expect((try a.toFloat(f64)) == r);
597598 }
lib/std/priority_dequeue.zig+10-7
......@@ -850,17 +850,18 @@ test "std.PriorityDequeue: shrinkAndFree" {
850850
851851test "std.PriorityDequeue: fuzz testing min" {
852852 var prng = std.rand.DefaultPrng.init(0x12345678);
853 const random = prng.random();
853854
854855 const test_case_count = 100;
855856 const queue_size = 1_000;
856857
857858 var i: usize = 0;
858859 while (i < test_case_count) : (i += 1) {
859 try fuzzTestMin(&prng.random, queue_size);
860 try fuzzTestMin(random, queue_size);
860861 }
861862}
862863
863fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void {
864fn fuzzTestMin(rng: std.rand.Random, comptime queue_size: usize) !void {
864865 const allocator = testing.allocator;
865866 const items = try generateRandomSlice(allocator, rng, queue_size);
866867
......@@ -878,17 +879,18 @@ fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void {
878879
879880test "std.PriorityDequeue: fuzz testing max" {
880881 var prng = std.rand.DefaultPrng.init(0x87654321);
882 const random = prng.random();
881883
882884 const test_case_count = 100;
883885 const queue_size = 1_000;
884886
885887 var i: usize = 0;
886888 while (i < test_case_count) : (i += 1) {
887 try fuzzTestMax(&prng.random, queue_size);
889 try fuzzTestMax(random, queue_size);
888890 }
889891}
890892
891fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void {
893fn fuzzTestMax(rng: std.rand.Random, queue_size: usize) !void {
892894 const allocator = testing.allocator;
893895 const items = try generateRandomSlice(allocator, rng, queue_size);
894896
......@@ -906,17 +908,18 @@ fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void {
906908
907909test "std.PriorityDequeue: fuzz testing min and max" {
908910 var prng = std.rand.DefaultPrng.init(0x87654321);
911 const random = prng.random();
909912
910913 const test_case_count = 100;
911914 const queue_size = 1_000;
912915
913916 var i: usize = 0;
914917 while (i < test_case_count) : (i += 1) {
915 try fuzzTestMinMax(&prng.random, queue_size);
918 try fuzzTestMinMax(random, queue_size);
916919 }
917920}
918921
919fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void {
922fn fuzzTestMinMax(rng: std.rand.Random, queue_size: usize) !void {
920923 const allocator = testing.allocator;
921924 const items = try generateRandomSlice(allocator, rng, queue_size);
922925
......@@ -943,7 +946,7 @@ fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void {
943946 }
944947}
945948
946fn generateRandomSlice(allocator: *std.mem.Allocator, rng: *std.rand.Random, size: usize) ![]u32 {
949fn generateRandomSlice(allocator: *std.mem.Allocator, rng: std.rand.Random, size: usize) ![]u32 {
947950 var array = std.ArrayList(u32).init(allocator);
948951 try array.ensureTotalCapacity(size);
949952
lib/std/rand.zig+195-159
......@@ -29,19 +29,40 @@ pub const Xoshiro256 = @import("rand/Xoshiro256.zig");
2929pub const Sfc64 = @import("rand/Sfc64.zig");
3030
3131pub const Random = struct {
32 fillFn: fn (r: *Random, buf: []u8) void,
32 ptr: *c_void,
33 fillFn: fn (ptr: *c_void, buf: []u8) void,
34
35 pub fn init(pointer: anytype) Random {
36 const Ptr = @TypeOf(pointer);
37 assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer
38 assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer
39 assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct
40 assert(std.meta.trait.hasFn("fill")(@typeInfo(Ptr).Pointer.child)); // Struct must provide the `fill` function
41 const gen = struct {
42 fn fill(ptr: *c_void, buf: []u8) void {
43 const alignment = @typeInfo(Ptr).Pointer.alignment;
44 const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
45 self.fill(buf);
46 }
47 };
48
49 return .{
50 .ptr = pointer,
51 .fillFn = gen.fill,
52 };
53 }
3354
3455 /// Read random bytes into the specified buffer until full.
35 pub fn bytes(r: *Random, buf: []u8) void {
36 r.fillFn(r, buf);
56 pub fn bytes(r: Random, buf: []u8) void {
57 r.fillFn(r.ptr, buf);
3758 }
3859
39 pub fn boolean(r: *Random) bool {
60 pub fn boolean(r: Random) bool {
4061 return r.int(u1) != 0;
4162 }
4263
4364 /// Returns a random value from an enum, evenly distributed.
44 pub fn enumValue(r: *Random, comptime EnumType: type) EnumType {
65 pub fn enumValue(r: Random, comptime EnumType: type) EnumType {
4566 if (comptime !std.meta.trait.is(.Enum)(EnumType)) {
4667 @compileError("Random.enumValue requires an enum type, not a " ++ @typeName(EnumType));
4768 }
......@@ -55,7 +76,7 @@ pub const Random = struct {
5576
5677 /// Returns a random int `i` such that `minInt(T) <= i <= maxInt(T)`.
5778 /// `i` is evenly distributed.
58 pub fn int(r: *Random, comptime T: type) T {
79 pub fn int(r: Random, comptime T: type) T {
5980 const bits = @typeInfo(T).Int.bits;
6081 const UnsignedT = std.meta.Int(.unsigned, bits);
6182 const ByteAlignedT = std.meta.Int(.unsigned, @divTrunc(bits + 7, 8) * 8);
......@@ -73,7 +94,7 @@ pub const Random = struct {
7394
7495 /// Constant-time implementation off `uintLessThan`.
7596 /// The results of this function may be biased.
76 pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
97 pub fn uintLessThanBiased(r: Random, comptime T: type, less_than: T) T {
7798 comptime assert(@typeInfo(T).Int.signedness == .unsigned);
7899 const bits = @typeInfo(T).Int.bits;
79100 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
......@@ -93,7 +114,7 @@ pub const Random = struct {
93114 /// However, if `fillFn` is backed by any evenly distributed pseudo random number generator,
94115 /// this function is guaranteed to return.
95116 /// If you need deterministic runtime bounds, use `uintLessThanBiased`.
96 pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
117 pub fn uintLessThan(r: Random, comptime T: type, less_than: T) T {
97118 comptime assert(@typeInfo(T).Int.signedness == .unsigned);
98119 const bits = @typeInfo(T).Int.bits;
99120 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
......@@ -130,7 +151,7 @@ pub const Random = struct {
130151
131152 /// Constant-time implementation off `uintAtMost`.
132153 /// The results of this function may be biased.
133 pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
154 pub fn uintAtMostBiased(r: Random, comptime T: type, at_most: T) T {
134155 assert(@typeInfo(T).Int.signedness == .unsigned);
135156 if (at_most == maxInt(T)) {
136157 // have the full range
......@@ -142,7 +163,7 @@ pub const Random = struct {
142163 /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
143164 /// See `uintLessThan`, which this function uses in most cases,
144165 /// for commentary on the runtime of this function.
145 pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {
166 pub fn uintAtMost(r: Random, comptime T: type, at_most: T) T {
146167 assert(@typeInfo(T).Int.signedness == .unsigned);
147168 if (at_most == maxInt(T)) {
148169 // have the full range
......@@ -153,7 +174,7 @@ pub const Random = struct {
153174
154175 /// Constant-time implementation off `intRangeLessThan`.
155176 /// The results of this function may be biased.
156 pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
177 pub fn intRangeLessThanBiased(r: Random, comptime T: type, at_least: T, less_than: T) T {
157178 assert(at_least < less_than);
158179 const info = @typeInfo(T).Int;
159180 if (info.signedness == .signed) {
......@@ -172,7 +193,7 @@ pub const Random = struct {
172193 /// Returns an evenly distributed random integer `at_least <= i < less_than`.
173194 /// See `uintLessThan`, which this function uses in most cases,
174195 /// for commentary on the runtime of this function.
175 pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {
196 pub fn intRangeLessThan(r: Random, comptime T: type, at_least: T, less_than: T) T {
176197 assert(at_least < less_than);
177198 const info = @typeInfo(T).Int;
178199 if (info.signedness == .signed) {
......@@ -190,7 +211,7 @@ pub const Random = struct {
190211
191212 /// Constant-time implementation off `intRangeAtMostBiased`.
192213 /// The results of this function may be biased.
193 pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
214 pub fn intRangeAtMostBiased(r: Random, comptime T: type, at_least: T, at_most: T) T {
194215 assert(at_least <= at_most);
195216 const info = @typeInfo(T).Int;
196217 if (info.signedness == .signed) {
......@@ -209,7 +230,7 @@ pub const Random = struct {
209230 /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
210231 /// See `uintLessThan`, which this function uses in most cases,
211232 /// for commentary on the runtime of this function.
212 pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {
233 pub fn intRangeAtMost(r: Random, comptime T: type, at_least: T, at_most: T) T {
213234 assert(at_least <= at_most);
214235 const info = @typeInfo(T).Int;
215236 if (info.signedness == .signed) {
......@@ -230,7 +251,7 @@ pub const Random = struct {
230251 pub const range = @compileError("deprecated; use intRangeLessThan()");
231252
232253 /// Return a floating point value evenly distributed in the range [0, 1).
233 pub fn float(r: *Random, comptime T: type) T {
254 pub fn float(r: Random, comptime T: type) T {
234255 // Generate a uniform value between [1, 2) and scale down to [0, 1).
235256 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
236257 switch (T) {
......@@ -251,7 +272,7 @@ pub const Random = struct {
251272 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
252273 ///
253274 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
254 pub fn floatNorm(r: *Random, comptime T: type) T {
275 pub fn floatNorm(r: Random, comptime T: type) T {
255276 const value = ziggurat.next_f64(r, ziggurat.NormDist);
256277 switch (T) {
257278 f32 => return @floatCast(f32, value),
......@@ -263,7 +284,7 @@ pub const Random = struct {
263284 /// Return an exponentially distributed float with a rate parameter of 1.
264285 ///
265286 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
266 pub fn floatExp(r: *Random, comptime T: type) T {
287 pub fn floatExp(r: Random, comptime T: type) T {
267288 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
268289 switch (T) {
269290 f32 => return @floatCast(f32, value),
......@@ -273,7 +294,7 @@ pub const Random = struct {
273294 }
274295
275296 /// Shuffle a slice into a random order.
276 pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
297 pub fn shuffle(r: Random, comptime T: type, buf: []T) void {
277298 if (buf.len < 2) {
278299 return;
279300 }
......@@ -303,18 +324,19 @@ pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
303324
304325const SequentialPrng = struct {
305326 const Self = @This();
306 random: Random,
307327 next_value: u8,
308328
309329 pub fn init() Self {
310330 return Self{
311 .random = Random{ .fillFn = fill },
312331 .next_value = 0,
313332 };
314333 }
315334
316 fn fill(r: *Random, buf: []u8) void {
317 const self = @fieldParentPtr(Self, "random", r);
335 pub fn random(self: *Self) Random {
336 return Random.init(self);
337 }
338
339 pub fn fill(self: *Self, buf: []u8) void {
318340 for (buf) |*b| {
319341 b.* = self.next_value;
320342 }
......@@ -327,45 +349,46 @@ test "Random int" {
327349 comptime try testRandomInt();
328350}
329351fn testRandomInt() !void {
330 var r = SequentialPrng.init();
331
332 try expect(r.random.int(u0) == 0);
333
334 r.next_value = 0;
335 try expect(r.random.int(u1) == 0);
336 try expect(r.random.int(u1) == 1);
337 try expect(r.random.int(u2) == 2);
338 try expect(r.random.int(u2) == 3);
339 try expect(r.random.int(u2) == 0);
340
341 r.next_value = 0xff;
342 try expect(r.random.int(u8) == 0xff);
343 r.next_value = 0x11;
344 try expect(r.random.int(u8) == 0x11);
345
346 r.next_value = 0xff;
347 try expect(r.random.int(u32) == 0xffffffff);
348 r.next_value = 0x11;
349 try expect(r.random.int(u32) == 0x11111111);
350
351 r.next_value = 0xff;
352 try expect(r.random.int(i32) == -1);
353 r.next_value = 0x11;
354 try expect(r.random.int(i32) == 0x11111111);
355
356 r.next_value = 0xff;
357 try expect(r.random.int(i8) == -1);
358 r.next_value = 0x11;
359 try expect(r.random.int(i8) == 0x11);
360
361 r.next_value = 0xff;
362 try expect(r.random.int(u33) == 0x1ffffffff);
363 r.next_value = 0xff;
364 try expect(r.random.int(i1) == -1);
365 r.next_value = 0xff;
366 try expect(r.random.int(i2) == -1);
367 r.next_value = 0xff;
368 try expect(r.random.int(i33) == -1);
352 var rng = SequentialPrng.init();
353 const random = rng.random();
354
355 try expect(random.int(u0) == 0);
356
357 rng.next_value = 0;
358 try expect(random.int(u1) == 0);
359 try expect(random.int(u1) == 1);
360 try expect(random.int(u2) == 2);
361 try expect(random.int(u2) == 3);
362 try expect(random.int(u2) == 0);
363
364 rng.next_value = 0xff;
365 try expect(random.int(u8) == 0xff);
366 rng.next_value = 0x11;
367 try expect(random.int(u8) == 0x11);
368
369 rng.next_value = 0xff;
370 try expect(random.int(u32) == 0xffffffff);
371 rng.next_value = 0x11;
372 try expect(random.int(u32) == 0x11111111);
373
374 rng.next_value = 0xff;
375 try expect(random.int(i32) == -1);
376 rng.next_value = 0x11;
377 try expect(random.int(i32) == 0x11111111);
378
379 rng.next_value = 0xff;
380 try expect(random.int(i8) == -1);
381 rng.next_value = 0x11;
382 try expect(random.int(i8) == 0x11);
383
384 rng.next_value = 0xff;
385 try expect(random.int(u33) == 0x1ffffffff);
386 rng.next_value = 0xff;
387 try expect(random.int(i1) == -1);
388 rng.next_value = 0xff;
389 try expect(random.int(i2) == -1);
390 rng.next_value = 0xff;
391 try expect(random.int(i33) == -1);
369392}
370393
371394test "Random boolean" {
......@@ -373,11 +396,13 @@ test "Random boolean" {
373396 comptime try testRandomBoolean();
374397}
375398fn testRandomBoolean() !void {
376 var r = SequentialPrng.init();
377 try expect(r.random.boolean() == false);
378 try expect(r.random.boolean() == true);
379 try expect(r.random.boolean() == false);
380 try expect(r.random.boolean() == true);
399 var rng = SequentialPrng.init();
400 const random = rng.random();
401
402 try expect(random.boolean() == false);
403 try expect(random.boolean() == true);
404 try expect(random.boolean() == false);
405 try expect(random.boolean() == true);
381406}
382407
383408test "Random enum" {
......@@ -390,11 +415,12 @@ fn testRandomEnumValue() !void {
390415 Second,
391416 Third,
392417 };
393 var r = SequentialPrng.init();
394 r.next_value = 0;
395 try expect(r.random.enumValue(TestEnum) == TestEnum.First);
396 try expect(r.random.enumValue(TestEnum) == TestEnum.First);
397 try expect(r.random.enumValue(TestEnum) == TestEnum.First);
418 var rng = SequentialPrng.init();
419 const random = rng.random();
420 rng.next_value = 0;
421 try expect(random.enumValue(TestEnum) == TestEnum.First);
422 try expect(random.enumValue(TestEnum) == TestEnum.First);
423 try expect(random.enumValue(TestEnum) == TestEnum.First);
398424}
399425
400426test "Random intLessThan" {
......@@ -403,38 +429,40 @@ test "Random intLessThan" {
403429 comptime try testRandomIntLessThan();
404430}
405431fn testRandomIntLessThan() !void {
406 var r = SequentialPrng.init();
407 r.next_value = 0xff;
408 try expect(r.random.uintLessThan(u8, 4) == 3);
409 try expect(r.next_value == 0);
410 try expect(r.random.uintLessThan(u8, 4) == 0);
411 try expect(r.next_value == 1);
432 var rng = SequentialPrng.init();
433 const random = rng.random();
434
435 rng.next_value = 0xff;
436 try expect(random.uintLessThan(u8, 4) == 3);
437 try expect(rng.next_value == 0);
438 try expect(random.uintLessThan(u8, 4) == 0);
439 try expect(rng.next_value == 1);
412440
413 r.next_value = 0;
414 try expect(r.random.uintLessThan(u64, 32) == 0);
441 rng.next_value = 0;
442 try expect(random.uintLessThan(u64, 32) == 0);
415443
416444 // trigger the bias rejection code path
417 r.next_value = 0;
418 try expect(r.random.uintLessThan(u8, 3) == 0);
445 rng.next_value = 0;
446 try expect(random.uintLessThan(u8, 3) == 0);
419447 // verify we incremented twice
420 try expect(r.next_value == 2);
421
422 r.next_value = 0xff;
423 try expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
424 r.next_value = 0xff;
425 try expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
426
427 r.next_value = 0xff;
428 try expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
429 r.next_value = 0xff;
430 try expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
431 r.next_value = 0xff;
432 try expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
433
434 r.next_value = 0xff;
435 try expect(r.random.intRangeLessThan(i3, -4, 0) == -1);
436 r.next_value = 0xff;
437 try expect(r.random.intRangeLessThan(i3, -2, 2) == 1);
448 try expect(rng.next_value == 2);
449
450 rng.next_value = 0xff;
451 try expect(random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
452 rng.next_value = 0xff;
453 try expect(random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
454
455 rng.next_value = 0xff;
456 try expect(random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
457 rng.next_value = 0xff;
458 try expect(random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
459 rng.next_value = 0xff;
460 try expect(random.intRangeLessThan(i8, -0x80, 0) == -1);
461
462 rng.next_value = 0xff;
463 try expect(random.intRangeLessThan(i3, -4, 0) == -1);
464 rng.next_value = 0xff;
465 try expect(random.intRangeLessThan(i3, -2, 2) == 1);
438466}
439467
440468test "Random intAtMost" {
......@@ -443,67 +471,70 @@ test "Random intAtMost" {
443471 comptime try testRandomIntAtMost();
444472}
445473fn testRandomIntAtMost() !void {
446 var r = SequentialPrng.init();
447 r.next_value = 0xff;
448 try expect(r.random.uintAtMost(u8, 3) == 3);
449 try expect(r.next_value == 0);
450 try expect(r.random.uintAtMost(u8, 3) == 0);
474 var rng = SequentialPrng.init();
475 const random = rng.random();
476
477 rng.next_value = 0xff;
478 try expect(random.uintAtMost(u8, 3) == 3);
479 try expect(rng.next_value == 0);
480 try expect(random.uintAtMost(u8, 3) == 0);
451481
452482 // trigger the bias rejection code path
453 r.next_value = 0;
454 try expect(r.random.uintAtMost(u8, 2) == 0);
483 rng.next_value = 0;
484 try expect(random.uintAtMost(u8, 2) == 0);
455485 // verify we incremented twice
456 try expect(r.next_value == 2);
457
458 r.next_value = 0xff;
459 try expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
460 r.next_value = 0xff;
461 try expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
462
463 r.next_value = 0xff;
464 try expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
465 r.next_value = 0xff;
466 try expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
467 r.next_value = 0xff;
468 try expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
469
470 r.next_value = 0xff;
471 try expect(r.random.intRangeAtMost(i3, -4, -1) == -1);
472 r.next_value = 0xff;
473 try expect(r.random.intRangeAtMost(i3, -2, 1) == 1);
474
475 try expect(r.random.uintAtMost(u0, 0) == 0);
486 try expect(rng.next_value == 2);
487
488 rng.next_value = 0xff;
489 try expect(random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
490 rng.next_value = 0xff;
491 try expect(random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
492
493 rng.next_value = 0xff;
494 try expect(random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
495 rng.next_value = 0xff;
496 try expect(random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
497 rng.next_value = 0xff;
498 try expect(random.intRangeAtMost(i8, -0x80, -1) == -1);
499
500 rng.next_value = 0xff;
501 try expect(random.intRangeAtMost(i3, -4, -1) == -1);
502 rng.next_value = 0xff;
503 try expect(random.intRangeAtMost(i3, -2, 1) == 1);
504
505 try expect(random.uintAtMost(u0, 0) == 0);
476506}
477507
478508test "Random Biased" {
479 var r = DefaultPrng.init(0);
509 var prng = DefaultPrng.init(0);
510 const random = prng.random();
480511 // Not thoroughly checking the logic here.
481512 // Just want to execute all the paths with different types.
482513
483 try expect(r.random.uintLessThanBiased(u1, 1) == 0);
484 try expect(r.random.uintLessThanBiased(u32, 10) < 10);
485 try expect(r.random.uintLessThanBiased(u64, 20) < 20);
514 try expect(random.uintLessThanBiased(u1, 1) == 0);
515 try expect(random.uintLessThanBiased(u32, 10) < 10);
516 try expect(random.uintLessThanBiased(u64, 20) < 20);
486517
487 try expect(r.random.uintAtMostBiased(u0, 0) == 0);
488 try expect(r.random.uintAtMostBiased(u1, 0) <= 0);
489 try expect(r.random.uintAtMostBiased(u32, 10) <= 10);
490 try expect(r.random.uintAtMostBiased(u64, 20) <= 20);
518 try expect(random.uintAtMostBiased(u0, 0) == 0);
519 try expect(random.uintAtMostBiased(u1, 0) <= 0);
520 try expect(random.uintAtMostBiased(u32, 10) <= 10);
521 try expect(random.uintAtMostBiased(u64, 20) <= 20);
491522
492 try expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
493 try expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
494 try expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
495 try expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
496 try expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
497 try expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
523 try expect(random.intRangeLessThanBiased(u1, 0, 1) == 0);
524 try expect(random.intRangeLessThanBiased(i1, -1, 0) == -1);
525 try expect(random.intRangeLessThanBiased(u32, 10, 20) >= 10);
526 try expect(random.intRangeLessThanBiased(i32, 10, 20) >= 10);
527 try expect(random.intRangeLessThanBiased(u64, 20, 40) >= 20);
528 try expect(random.intRangeLessThanBiased(i64, 20, 40) >= 20);
498529
499530 // uncomment for broken module error:
500 //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
501 try expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
502 try expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
503 try expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
504 try expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
505 try expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
506 try expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
531 //expect(random.intRangeAtMostBiased(u0, 0, 0) == 0);
532 try expect(random.intRangeAtMostBiased(u1, 0, 1) >= 0);
533 try expect(random.intRangeAtMostBiased(i1, -1, 0) >= -1);
534 try expect(random.intRangeAtMostBiased(u32, 10, 20) >= 10);
535 try expect(random.intRangeAtMostBiased(i32, 10, 20) >= 10);
536 try expect(random.intRangeAtMostBiased(u64, 20, 40) >= 20);
537 try expect(random.intRangeAtMostBiased(i64, 20, 40) >= 20);
507538}
508539
509540// Generator to extend 64-bit seed values into longer sequences.
......@@ -547,14 +578,15 @@ test "splitmix64 sequence" {
547578// Actual Random helper function tests, pcg engine is assumed correct.
548579test "Random float" {
549580 var prng = DefaultPrng.init(0);
581 const random = prng.random();
550582
551583 var i: usize = 0;
552584 while (i < 1000) : (i += 1) {
553 const val1 = prng.random.float(f32);
585 const val1 = random.float(f32);
554586 try expect(val1 >= 0.0);
555587 try expect(val1 < 1.0);
556588
557 const val2 = prng.random.float(f64);
589 const val2 = random.float(f64);
558590 try expect(val2 >= 0.0);
559591 try expect(val2 < 1.0);
560592 }
......@@ -562,13 +594,14 @@ test "Random float" {
562594
563595test "Random shuffle" {
564596 var prng = DefaultPrng.init(0);
597 const random = prng.random();
565598
566599 var seq = [_]u8{ 0, 1, 2, 3, 4 };
567600 var seen = [_]bool{false} ** 5;
568601
569602 var i: usize = 0;
570603 while (i < 1000) : (i += 1) {
571 prng.random.shuffle(u8, seq[0..]);
604 random.shuffle(u8, seq[0..]);
572605 seen[seq[0]] = true;
573606 try expect(sumArray(seq[0..]) == 10);
574607 }
......@@ -588,17 +621,19 @@ fn sumArray(s: []const u8) u32 {
588621
589622test "Random range" {
590623 var prng = DefaultPrng.init(0);
591 try testRange(&prng.random, -4, 3);
592 try testRange(&prng.random, -4, -1);
593 try testRange(&prng.random, 10, 14);
594 try testRange(&prng.random, -0x80, 0x7f);
624 const random = prng.random();
625
626 try testRange(random, -4, 3);
627 try testRange(random, -4, -1);
628 try testRange(random, 10, 14);
629 try testRange(random, -0x80, 0x7f);
595630}
596631
597fn testRange(r: *Random, start: i8, end: i8) !void {
632fn testRange(r: Random, start: i8, end: i8) !void {
598633 try testRangeBias(r, start, end, true);
599634 try testRangeBias(r, start, end, false);
600635}
601fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) !void {
636fn testRangeBias(r: Random, start: i8, end: i8, biased: bool) !void {
602637 const count = @intCast(usize, @as(i32, end) - @as(i32, start));
603638 var values_buffer = [_]bool{false} ** 0x100;
604639 const values = values_buffer[0..count];
......@@ -617,9 +652,10 @@ test "CSPRNG" {
617652 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;
618653 std.crypto.random.bytes(&secret_seed);
619654 var csprng = DefaultCsprng.init(secret_seed);
620 const a = csprng.random.int(u64);
621 const b = csprng.random.int(u64);
622 const c = csprng.random.int(u64);
655 const random = csprng.random();
656 const a = random.int(u64);
657 const b = random.int(u64);
658 const c = random.int(u64);
623659 try expect(a ^ b ^ c != 0);
624660}
625661
lib/std/rand/Gimli.zig+4-4
......@@ -5,7 +5,6 @@ const Random = std.rand.Random;
55const mem = std.mem;
66const Gimli = @This();
77
8random: Random,
98state: std.crypto.core.Gimli,
109
1110pub const secret_seed_length = 32;
......@@ -16,15 +15,16 @@ pub fn init(secret_seed: [secret_seed_length]u8) Gimli {
1615 mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
1716 mem.set(u8, initial_state[secret_seed_length..], 0);
1817 var self = Gimli{
19 .random = Random{ .fillFn = fill },
2018 .state = std.crypto.core.Gimli.init(initial_state),
2119 };
2220 return self;
2321}
2422
25fn fill(r: *Random, buf: []u8) void {
26 const self = @fieldParentPtr(Gimli, "random", r);
23pub fn random(self: *Gimli) Random {
24 return Random.init(self);
25}
2726
27pub fn fill(self: *Gimli, buf: []u8) void {
2828 if (buf.len != 0) {
2929 self.state.squeeze(buf);
3030 } else {
lib/std/rand/Isaac64.zig+6-7
......@@ -8,8 +8,6 @@ const Random = std.rand.Random;
88const mem = std.mem;
99const Isaac64 = @This();
1010
11random: Random,
12
1311r: [256]u64,
1412m: [256]u64,
1513a: u64,
......@@ -19,7 +17,6 @@ i: usize,
1917
2018pub fn init(init_s: u64) Isaac64 {
2119 var isaac = Isaac64{
22 .random = Random{ .fillFn = fill },
2320 .r = undefined,
2421 .m = undefined,
2522 .a = undefined,
......@@ -33,6 +30,10 @@ pub fn init(init_s: u64) Isaac64 {
3330 return isaac;
3431}
3532
33pub fn random(self: *Isaac64) Random {
34 return Random.init(self);
35}
36
3637fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
3738 const x = self.m[base + m1];
3839 self.a = mix +% self.m[base + m2];
......@@ -149,9 +150,7 @@ fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
149150 self.i = self.r.len; // trigger refill on first value
150151}
151152
152fn fill(r: *Random, buf: []u8) void {
153 const self = @fieldParentPtr(Isaac64, "random", r);
154
153pub fn fill(self: *Isaac64, buf: []u8) void {
155154 var i: usize = 0;
156155 const aligned_len = buf.len - (buf.len & 7);
157156
......@@ -230,7 +229,7 @@ test "isaac64 fill" {
230229 var buf0: [8]u8 = undefined;
231230 var buf1: [7]u8 = undefined;
232231 std.mem.writeIntLittle(u64, &buf0, s);
233 Isaac64.fill(&r.random, &buf1);
232 r.fill(&buf1);
234233 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
235234 }
236235}
lib/std/rand/Pcg.zig+6-7
......@@ -8,14 +8,11 @@ const Pcg = @This();
88
99const default_multiplier = 6364136223846793005;
1010
11random: Random,
12
1311s: u64,
1412i: u64,
1513
1614pub fn init(init_s: u64) Pcg {
1715 var pcg = Pcg{
18 .random = Random{ .fillFn = fill },
1916 .s = undefined,
2017 .i = undefined,
2118 };
......@@ -24,6 +21,10 @@ pub fn init(init_s: u64) Pcg {
2421 return pcg;
2522}
2623
24pub fn random(self: *Pcg) Random {
25 return Random.init(self);
26}
27
2728fn next(self: *Pcg) u32 {
2829 const l = self.s;
2930 self.s = l *% default_multiplier +% (self.i | 1);
......@@ -48,9 +49,7 @@ fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
4849 self.s = self.s *% default_multiplier +% self.i;
4950}
5051
51fn fill(r: *Random, buf: []u8) void {
52 const self = @fieldParentPtr(Pcg, "random", r);
53
52pub fn fill(self: *Pcg, buf: []u8) void {
5453 var i: usize = 0;
5554 const aligned_len = buf.len - (buf.len & 7);
5655
......@@ -113,7 +112,7 @@ test "pcg fill" {
113112 var buf0: [4]u8 = undefined;
114113 var buf1: [3]u8 = undefined;
115114 std.mem.writeIntLittle(u32, &buf0, s);
116 Pcg.fill(&r.random, &buf1);
115 r.fill(&buf1);
117116 try std.testing.expect(std.mem.eql(u8, buf0[0..3], buf1[0..]));
118117 }
119118}
lib/std/rand/Sfc64.zig+7-9
......@@ -7,8 +7,6 @@ const Random = std.rand.Random;
77const math = std.math;
88const Sfc64 = @This();
99
10random: Random,
11
1210a: u64 = undefined,
1311b: u64 = undefined,
1412c: u64 = undefined,
......@@ -19,14 +17,16 @@ const RightShift = 11;
1917const LeftShift = 3;
2018
2119pub fn init(init_s: u64) Sfc64 {
22 var x = Sfc64{
23 .random = Random{ .fillFn = fill },
24 };
20 var x = Sfc64{};
2521
2622 x.seed(init_s);
2723 return x;
2824}
2925
26pub fn random(self: *Sfc64) Random {
27 return Random.init(self);
28}
29
3030fn next(self: *Sfc64) u64 {
3131 const tmp = self.a +% self.b +% self.counter;
3232 self.counter += 1;
......@@ -47,9 +47,7 @@ fn seed(self: *Sfc64, init_s: u64) void {
4747 }
4848}
4949
50fn fill(r: *Random, buf: []u8) void {
51 const self = @fieldParentPtr(Sfc64, "random", r);
52
50pub fn fill(self: *Sfc64, buf: []u8) void {
5351 var i: usize = 0;
5452 const aligned_len = buf.len - (buf.len & 7);
5553
......@@ -128,7 +126,7 @@ test "Sfc64 fill" {
128126 var buf0: [8]u8 = undefined;
129127 var buf1: [7]u8 = undefined;
130128 std.mem.writeIntLittle(u64, &buf0, s);
131 Sfc64.fill(&r.random, &buf1);
129 r.fill(&buf1);
132130 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
133131 }
134132}
lib/std/rand/Xoroshiro128.zig+7-10
......@@ -7,20 +7,19 @@ const Random = std.rand.Random;
77const math = std.math;
88const Xoroshiro128 = @This();
99
10random: Random,
11
1210s: [2]u64,
1311
1412pub fn init(init_s: u64) Xoroshiro128 {
15 var x = Xoroshiro128{
16 .random = Random{ .fillFn = fill },
17 .s = undefined,
18 };
13 var x = Xoroshiro128{ .s = undefined };
1914
2015 x.seed(init_s);
2116 return x;
2217}
2318
19pub fn random(self: *Xoroshiro128) Random {
20 return Random.init(self);
21}
22
2423fn next(self: *Xoroshiro128) u64 {
2524 const s0 = self.s[0];
2625 var s1 = self.s[1];
......@@ -66,9 +65,7 @@ pub fn seed(self: *Xoroshiro128, init_s: u64) void {
6665 self.s[1] = gen.next();
6766}
6867
69fn fill(r: *Random, buf: []u8) void {
70 const self = @fieldParentPtr(Xoroshiro128, "random", r);
71
68pub fn fill(self: *Xoroshiro128, buf: []u8) void {
7269 var i: usize = 0;
7370 const aligned_len = buf.len - (buf.len & 7);
7471
......@@ -144,7 +141,7 @@ test "xoroshiro fill" {
144141 var buf0: [8]u8 = undefined;
145142 var buf1: [7]u8 = undefined;
146143 std.mem.writeIntLittle(u64, &buf0, s);
147 Xoroshiro128.fill(&r.random, &buf1);
144 r.fill(&buf1);
148145 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
149146 }
150147}
lib/std/rand/Xoshiro256.zig+6-7
......@@ -7,13 +7,10 @@ const Random = std.rand.Random;
77const math = std.math;
88const Xoshiro256 = @This();
99
10random: Random,
11
1210s: [4]u64,
1311
1412pub fn init(init_s: u64) Xoshiro256 {
1513 var x = Xoshiro256{
16 .random = Random{ .fillFn = fill },
1714 .s = undefined,
1815 };
1916
......@@ -21,6 +18,10 @@ pub fn init(init_s: u64) Xoshiro256 {
2118 return x;
2219}
2320
21pub fn random(self: *Xoshiro256) Random {
22 return Random.init(self);
23}
24
2425fn next(self: *Xoshiro256) u64 {
2526 const r = math.rotl(u64, self.s[0] +% self.s[3], 23) +% self.s[0];
2627
......@@ -64,9 +65,7 @@ pub fn seed(self: *Xoshiro256, init_s: u64) void {
6465 self.s[3] = gen.next();
6566}
6667
67fn fill(r: *Random, buf: []u8) void {
68 const self = @fieldParentPtr(Xoshiro256, "random", r);
69
68pub fn fill(self: *Xoshiro256, buf: []u8) void {
7069 var i: usize = 0;
7170 const aligned_len = buf.len - (buf.len & 7);
7271
......@@ -138,7 +137,7 @@ test "xoroshiro fill" {
138137 var buf0: [8]u8 = undefined;
139138 var buf1: [7]u8 = undefined;
140139 std.mem.writeIntLittle(u64, &buf0, s);
141 Xoshiro256.fill(&r.random, &buf1);
140 r.fill(&buf1);
142141 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
143142 }
144143}
lib/std/rand/ziggurat.zig+11-7
......@@ -13,7 +13,7 @@ const builtin = @import("builtin");
1313const math = std.math;
1414const Random = std.rand.Random;
1515
16pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 {
16pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
1717 while (true) {
1818 // We manually construct a float from parts as we can avoid an extra random lookup here by
1919 // using the unused exponent for the lookup table entry.
......@@ -61,7 +61,7 @@ pub const ZigTable = struct {
6161 // whether the distribution is symmetric
6262 is_symmetric: bool,
6363 // fallback calculation in the case we are in the 0 block
64 zero_case: fn (*Random, f64) f64,
64 zero_case: fn (Random, f64) f64,
6565};
6666
6767// zigNorInit
......@@ -71,7 +71,7 @@ fn ZigTableGen(
7171 comptime v: f64,
7272 comptime f: fn (f64) f64,
7373 comptime f_inv: fn (f64) f64,
74 comptime zero_case: fn (*Random, f64) f64,
74 comptime zero_case: fn (Random, f64) f64,
7575) ZigTable {
7676 var tables: ZigTable = undefined;
7777
......@@ -111,7 +111,7 @@ fn norm_f(x: f64) f64 {
111111fn norm_f_inv(y: f64) f64 {
112112 return math.sqrt(-2.0 * math.ln(y));
113113}
114fn norm_zero_case(random: *Random, u: f64) f64 {
114fn norm_zero_case(random: Random, u: f64) f64 {
115115 var x: f64 = 1;
116116 var y: f64 = 0;
117117
......@@ -133,9 +133,11 @@ test "normal dist sanity" {
133133 if (please_windows_dont_oom) return error.SkipZigTest;
134134
135135 var prng = std.rand.DefaultPrng.init(0);
136 const random = prng.random();
137
136138 var i: usize = 0;
137139 while (i < 1000) : (i += 1) {
138 _ = prng.random.floatNorm(f64);
140 _ = random.floatNorm(f64);
139141 }
140142}
141143
......@@ -154,7 +156,7 @@ fn exp_f(x: f64) f64 {
154156fn exp_f_inv(y: f64) f64 {
155157 return -math.ln(y);
156158}
157fn exp_zero_case(random: *Random, _: f64) f64 {
159fn exp_zero_case(random: Random, _: f64) f64 {
158160 return exp_r - math.ln(random.float(f64));
159161}
160162
......@@ -162,9 +164,11 @@ test "exp dist sanity" {
162164 if (please_windows_dont_oom) return error.SkipZigTest;
163165
164166 var prng = std.rand.DefaultPrng.init(0);
167 const random = prng.random();
168
165169 var i: usize = 0;
166170 while (i < 1000) : (i += 1) {
167 _ = prng.random.floatExp(f64);
171 _ = random.floatExp(f64);
168172 }
169173}
170174
lib/std/sort.zig+3-2
......@@ -1328,16 +1328,17 @@ test "another sort case" {
13281328
13291329test "sort fuzz testing" {
13301330 var prng = std.rand.DefaultPrng.init(0x12345678);
1331 const random = prng.random();
13311332 const test_case_count = 10;
13321333 var i: usize = 0;
13331334 while (i < test_case_count) : (i += 1) {
1334 try fuzzTest(&prng.random);
1335 try fuzzTest(random);
13351336 }
13361337}
13371338
13381339var fixed_buffer_mem: [100 * 1024]u8 = undefined;
13391340
1340fn fuzzTest(rng: *std.rand.Random) !void {
1341fn fuzzTest(rng: std.rand.Random) !void {
13411342 const array_size = rng.intRangeLessThan(usize, 0, 1000);
13421343 var array = try testing.allocator.alloc(IdAndValue, array_size);
13431344 defer testing.allocator.free(array);