authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-03-30 01:36:04+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-03-30 01:50:58+13:00
log0fd0f6fd1f4b9e02cc33eac304b9f6db242cbb67
treedc06675959dce091f7fa58c138d4b567cf2ba87f
parent032fccf6151ff201ce4b8c7ab28ca460fed794c0

Rewrite Rand functions

We now use a generic Rand structure which abstracts the core functions from the backing engine. The old Mersenne Twister engine is removed and replaced instead with three alternatives: - Pcg32 - Xoroshiro128+ - Isaac64 These should provide sufficient coverage for most purposes, including a CSPRNG using Isaac64. Consumers of the library that do not care about the actual engine implementation should use DefaultPrng and DefaultCsprng.

7 files changed, 735 insertions(+), 830 deletions(-)

CMakeLists.txt+1-1
...@@ -509,7 +509,7 @@ set(ZIG_STD_FILES...@@ -509,7 +509,7 @@ set(ZIG_STD_FILES
509 "os/windows/index.zig"509 "os/windows/index.zig"
510 "os/windows/util.zig"510 "os/windows/util.zig"
511 "os/zen.zig"511 "os/zen.zig"
512 "rand.zig"512 "rand/index.zig"
513 "sort.zig"513 "sort.zig"
514 "special/bootstrap.zig"514 "special/bootstrap.zig"
515 "special/bootstrap_lib.zig"515 "special/bootstrap_lib.zig"
std/index.zig+2-2
...@@ -26,7 +26,7 @@ pub const math = @import("math/index.zig");...@@ -26,7 +26,7 @@ pub const math = @import("math/index.zig");
26pub const mem = @import("mem.zig");26pub const mem = @import("mem.zig");
27pub const net = @import("net.zig");27pub const net = @import("net.zig");
28pub const os = @import("os/index.zig");28pub const os = @import("os/index.zig");
29pub const rand = @import("rand.zig");29pub const rand = @import("rand/index.zig");
30pub const sort = @import("sort.zig");30pub const sort = @import("sort.zig");
31pub const unicode = @import("unicode.zig");31pub const unicode = @import("unicode.zig");
32pub const zig = @import("zig/index.zig");32pub const zig = @import("zig/index.zig");
...@@ -58,7 +58,7 @@ test "std" {...@@ -58,7 +58,7 @@ test "std" {
58 _ = @import("heap.zig");58 _ = @import("heap.zig");
59 _ = @import("net.zig");59 _ = @import("net.zig");
60 _ = @import("os/index.zig");60 _ = @import("os/index.zig");
61 _ = @import("rand.zig");61 _ = @import("rand/index.zig");
62 _ = @import("sort.zig");62 _ = @import("sort.zig");
63 _ = @import("unicode.zig");63 _ = @import("unicode.zig");
64 _ = @import("zig/index.zig");64 _ = @import("zig/index.zig");
std/io_test.zig+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const io = std.io;2const io = std.io;
3const allocator = std.debug.global_allocator;3const allocator = std.debug.global_allocator;
4const Rand = std.rand.Rand;4const DefaultPrng = std.rand.DefaultPrng;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const mem = std.mem;6const mem = std.mem;
7const os = std.os;7const os = std.os;
...@@ -9,8 +9,8 @@ const builtin = @import("builtin");...@@ -9,8 +9,8 @@ const builtin = @import("builtin");
99
10test "write a file, read it, then delete it" {10test "write a file, read it, then delete it" {
11 var data: [1024]u8 = undefined;11 var data: [1024]u8 = undefined;
12 var rng = Rand.init(1234);12 var prng = DefaultPrng.init(1234);
13 rng.fillBytes(data[0..]);13 prng.random.bytes(data[0..]);
14 const tmp_file_name = "temp_test_file.txt";14 const tmp_file_name = "temp_test_file.txt";
15 {15 {
16 var file = try os.File.openWrite(allocator, tmp_file_name);16 var file = try os.File.openWrite(allocator, tmp_file_name);
std/rand.zig deleted-240
...@@ -1,240 +0,0 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const rand_test = @import("rand_test.zig");
5const mem = std.mem;
6const math = std.math;
7
8pub const MT19937_32 = MersenneTwister(
9 u32, 624, 397, 31,
10 0x9908B0DF,
11 11, 0xFFFFFFFF,
12 7, 0x9D2C5680,
13 15, 0xEFC60000,
14 18, 1812433253);
15
16pub const MT19937_64 = MersenneTwister(
17 u64, 312, 156, 31,
18 0xB5026F5AA96619E9,
19 29, 0x5555555555555555,
20 17, 0x71D67FFFEDA60000,
21 37, 0xFFF7EEE000000000,
22 43, 6364136223846793005);
23
24/// Use `init` to initialize this state.
25pub const Rand = struct {
26 const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;
27
28 rng: Rng,
29
30 /// Initialize random state with the given seed.
31 pub fn init(seed: usize) Rand {
32 return Rand {
33 .rng = Rng.init(seed),
34 };
35 }
36
37 /// Get an integer or boolean with random bits.
38 pub fn scalar(r: &Rand, comptime T: type) T {
39 if (T == usize) {
40 return r.rng.get();
41 } else if (T == bool) {
42 return (r.rng.get() & 0b1) == 0;
43 } else {
44 var result: [@sizeOf(T)]u8 = undefined;
45 r.fillBytes(result[0..]);
46 return mem.readInt(result, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Fill `buf` with randomness.
51 pub fn fillBytes(r: &Rand, buf: []u8) void {
52 var bytes_left = buf.len;
53 while (bytes_left >= @sizeOf(usize)) {
54 mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little);
55 bytes_left -= @sizeOf(usize);
56 }
57 if (bytes_left > 0) {
58 var rand_val_array: [@sizeOf(usize)]u8 = undefined;
59 mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little);
60 while (bytes_left > 0) {
61 buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
62 bytes_left -= 1;
63 }
64 }
65 }
66
67 /// Get a random unsigned integer with even distribution between `start`
68 /// inclusive and `end` exclusive.
69 pub fn range(r: &Rand, comptime T: type, start: T, end: T) T {
70 assert(start <= end);
71 if (T.is_signed) {
72 const uint = @IntType(false, T.bit_count);
73 if (start >= 0 and end >= 0) {
74 return T(r.range(uint, uint(start), uint(end)));
75 } else if (start < 0 and end < 0) {
76 // Can't overflow because the range is over signed ints
77 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
78 } else if (start < 0 and end >= 0) {
79 const end_uint = uint(end);
80 const total_range = math.absCast(start) + end_uint;
81 const value = r.range(uint, 0, total_range);
82 const result = if (value < end_uint) x: {
83 break :x T(value);
84 } else if (value == end_uint) x: {
85 break :x start;
86 } else x: {
87 // Can't overflow because the range is over signed ints
88 break :x math.negateCast(value - end_uint) catch unreachable;
89 };
90 return result;
91 } else {
92 unreachable;
93 }
94 } else {
95 const total_range = end - start;
96 const leftover = @maxValue(T) % total_range;
97 const upper_bound = @maxValue(T) - leftover;
98 var rand_val_array: [@sizeOf(T)]u8 = undefined;
99
100 while (true) {
101 r.fillBytes(rand_val_array[0..]);
102 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
103 if (rand_val < upper_bound) {
104 return start + (rand_val % total_range);
105 }
106 }
107 }
108 }
109
110 /// Get a floating point value in the range 0.0..1.0.
111 pub fn float(r: &Rand, comptime T: type) T {
112 // TODO Implement this way instead:
113 // const int = @int_type(false, @sizeOf(T) * 8);
114 // const mask = ((1 << @float_mantissa_bit_count(T)) - 1);
115 // const rand_bits = r.rng.scalar(int) & mask;
116 // return @float_compose(T, false, 0, rand_bits) - 1.0
117 const int_type = @IntType(false, @sizeOf(T) * 8);
118 const precision = if (T == f32)
119 16777216
120 else if (T == f64)
121 9007199254740992
122 else
123 @compileError("unknown floating point type")
124 ;
125 return T(r.range(int_type, 0, precision)) / T(precision);
126 }
127};
128
129fn MersenneTwister(
130 comptime int: type, comptime n: usize, comptime m: usize, comptime r: int,
131 comptime a: int,
132 comptime u: math.Log2Int(int), comptime d: int,
133 comptime s: math.Log2Int(int), comptime b: int,
134 comptime t: math.Log2Int(int), comptime c: int,
135 comptime l: math.Log2Int(int), comptime f: int) type
136{
137 return struct {
138 const Self = this;
139
140 array: [n]int,
141 index: usize,
142
143 pub fn init(seed: int) Self {
144 var mt = Self {
145 .array = undefined,
146 .index = n,
147 };
148
149 var prev_value = seed;
150 mt.array[0] = prev_value;
151 var i: usize = 1;
152 while (i < n) : (i += 1) {
153 prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
154 mt.array[i] = prev_value;
155 }
156 return mt;
157 }
158
159 pub fn get(mt: &Self) int {
160 const mag01 = []int{0, a};
161 const LM: int = (1 << r) - 1;
162 const UM = ~LM;
163
164 if (mt.index >= n) {
165 var i: usize = 0;
166
167 while (i < n - m) : (i += 1) {
168 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
169 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
170 }
171
172 while (i < n - 1) : (i += 1) {
173 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
174 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
175
176 }
177 const x = (mt.array[i] & UM) | (mt.array[0] & LM);
178 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
179
180 mt.index = 0;
181 }
182
183 var x = mt.array[mt.index];
184 mt.index += 1;
185
186 x ^= ((x >> u) & d);
187 x ^= ((x << s) & b);
188 x ^= ((x << t) & c);
189 x ^= (x >> l);
190
191 return x;
192 }
193 };
194}
195
196test "rand float 32" {
197 var r = Rand.init(42);
198 var i: usize = 0;
199 while (i < 1000) : (i += 1) {
200 const val = r.float(f32);
201 assert(val >= 0.0);
202 assert(val < 1.0);
203 }
204}
205
206test "rand.MT19937_64" {
207 var rng = MT19937_64.init(rand_test.mt64_seed);
208 for (rand_test.mt64_data) |value| {
209 assert(value == rng.get());
210 }
211}
212
213test "rand.MT19937_32" {
214 var rng = MT19937_32.init(rand_test.mt32_seed);
215 for (rand_test.mt32_data) |value| {
216 assert(value == rng.get());
217 }
218}
219
220test "rand.Rand.range" {
221 var r = Rand.init(42);
222 testRange(&r, -4, 3);
223 testRange(&r, -4, -1);
224 testRange(&r, 10, 14);
225}
226
227fn testRange(r: &Rand, start: i32, end: i32) void {
228 const count = usize(end - start);
229 var values_buffer = []bool{false} ** 20;
230 const values = values_buffer[0..count];
231 var i: usize = 0;
232 while (i < count) {
233 const value = r.range(i32, start, end);
234 const index = usize(value - start);
235 if (!values[index]) {
236 i += 1;
237 values[index] = true;
238 }
239 }
240}
std/rand/index.zig created+652
...@@ -0,0 +1,652 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.
4//
5// ```
6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);
8// const seed = mem.readInt(buf[0..8], u64, builtin.Endian.Little);
9//
10// var r = DefaultPrng.init(seed);
11//
12// const s = r.random.scalar(u64);
13// ```
14//
15// TODO(tiehuis): Benchmark these against other reference implementations.
16
17const std = @import("../index.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const mem = std.mem;
21const math = std.math;
22
23// When you need fast unbiased random numbers
24pub const DefaultPrng = Xoroshiro128;
25
26// When you need cryptographically secure random numbers
27pub const DefaultCsprng = Isaac64;
28
29pub const Rand = struct {
30 fillFn: fn(r: &Rand, buf: []u8) void,
31
32 /// Read random bytes into the specified buffer until fill.
33 pub fn bytes(r: &Rand, buf: []u8) void {
34 r.fillFn(r, buf);
35 }
36
37 /// Return a random integer/boolean type.
38 pub fn scalar(r: &Rand, comptime T: type) T {
39 var rand_bytes: [@sizeOf(T)]u8 = undefined;
40 r.bytes(rand_bytes[0..]);
41
42 if (T == bool) {
43 return rand_bytes[0] & 0b1 == 0;
44 } else {
45 // NOTE: Cannot @bitCast array to integer type.
46 return mem.readInt(rand_bytes, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Get a random unsigned integer with even distribution between `start`
51 /// inclusive and `end` exclusive.
52 pub fn range(r: &Rand, comptime T: type, start: T, end: T) T {
53 assert(start <= end);
54 if (T.is_signed) {
55 const uint = @IntType(false, T.bit_count);
56 if (start >= 0 and end >= 0) {
57 return T(r.range(uint, uint(start), uint(end)));
58 } else if (start < 0 and end < 0) {
59 // Can't overflow because the range is over signed ints
60 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
61 } else if (start < 0 and end >= 0) {
62 const end_uint = uint(end);
63 const total_range = math.absCast(start) + end_uint;
64 const value = r.range(uint, 0, total_range);
65 const result = if (value < end_uint) x: {
66 break :x T(value);
67 } else if (value == end_uint) x: {
68 break :x start;
69 } else x: {
70 // Can't overflow because the range is over signed ints
71 break :x math.negateCast(value - end_uint) catch unreachable;
72 };
73 return result;
74 } else {
75 unreachable;
76 }
77 } else {
78 const total_range = end - start;
79 const leftover = @maxValue(T) % total_range;
80 const upper_bound = @maxValue(T) - leftover;
81 var rand_val_array: [@sizeOf(T)]u8 = undefined;
82
83 while (true) {
84 r.bytes(rand_val_array[0..]);
85 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
86 if (rand_val < upper_bound) {
87 return start + (rand_val % total_range);
88 }
89 }
90 }
91 }
92
93 /// Return a floating point value evenly distributed in the range [0, 1).
94 pub fn float(r: &Rand, comptime T: type) T {
95 // Generate a uniform value between [1, 2) and scale down to [0, 1).
96 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
97 switch (T) {
98 f32 => {
99 const s = r.scalar(u32);
100 const repr = (0x7f << 23) | (s >> 9);
101 return @bitCast(f32, repr) - 1.0;
102 },
103 f64 => {
104 const s = r.scalar(u64);
105 const repr = (0x3ff << 52) | (s >> 12);
106 return @bitCast(f64, repr) - 1.0;
107 },
108 else => @compileError("unknown floating point type"),
109 }
110 }
111
112 /// Return a floating point value normally distributed in the range [0, 1].
113 pub fn floatNorm(r: &Rand, comptime T: type) T {
114 // TODO(tiehuis): See https://www.doornik.com/research/ziggurat.pdf
115 @compileError("floatNorm is unimplemented");
116 }
117
118 /// Return a exponentially distributed float between (0, @maxValue(f64))
119 pub fn floatExp(r: &Rand, comptime T: type) T {
120 @compileError("floatExp is unimplemented");
121 }
122
123 /// Shuffle a slice into a random order.
124 pub fn shuffle(r: &Rand, comptime T: type, buf: []T) void {
125 if (buf.len < 2) {
126 return;
127 }
128
129 var i: usize = 0;
130 while (i < buf.len - 1) : (i += 1) {
131 const j = r.range(usize, i, buf.len);
132 mem.swap(T, &buf[i], &buf[j]);
133 }
134 }
135};
136
137// Generator to extend 64-bit seed values into longer sequences.
138//
139// The number of cycles is thus limited to 64-bits regardless of the engine, but this
140// is still plenty for practical purposes.
141const SplitMix64 = struct {
142 s: u64,
143
144 pub fn init(seed: u64) SplitMix64 {
145 return SplitMix64 { .s = seed };
146 }
147
148 pub fn next(self: &SplitMix64) u64 {
149 self.s +%= 0x9e3779b97f4a7c15;
150
151 var z = self.s;
152 z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
153 z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
154 return z ^ (z >> 31);
155 }
156};
157
158test "splitmix64 sequence" {
159 var r = SplitMix64.init(0xaeecf86f7878dd75);
160
161 const seq = []const u64 {
162 0x5dbd39db0178eb44,
163 0xa9900fb66b397da3,
164 0x5c1a28b1aeebcf5c,
165 0x64a963238f776912,
166 0xc6d4177b21d1c0ab,
167 0xb2cbdbdb5ea35394,
168 };
169
170 for (seq) |s| {
171 std.debug.assert(s == r.next());
172 }
173}
174
175// PCG32 - http://www.pcg-random.org/
176//
177// PRNG
178pub const Pcg = struct {
179 const default_multiplier = 6364136223846793005;
180
181 random: Rand,
182
183 s: u64,
184 i: u64,
185
186 pub fn init(init_s: u64) Pcg {
187 var pcg = Pcg {
188 .random = Rand { .fillFn = fill },
189 .s = undefined,
190 .i = undefined,
191 };
192
193 pcg.seed(init_s);
194 return pcg;
195 }
196
197 fn next(self: &Pcg) u32 {
198 const l = self.s;
199 self.s = l *% default_multiplier +% (self.i | 1);
200
201 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
202 const rot = u32(l >> 59);
203
204 return (xor_s >> u5(rot)) | (xor_s << u5((0 -% rot) & 31));
205 }
206
207 fn seed(self: &Pcg, init_s: u64) void {
208 // Pcg requires 128-bits of seed.
209 var gen = SplitMix64.init(init_s);
210 self.seedTwo(gen.next(), gen.next());
211 }
212
213 fn seedTwo(self: &Pcg, init_s: u64, init_i: u64) void {
214 self.s = 0;
215 self.i = (init_s << 1) | 1;
216 self.s = self.s *% default_multiplier +% self.i;
217 self.s +%= init_i;
218 self.s = self.s *% default_multiplier +% self.i;
219 }
220
221 fn fill(r: &Rand, buf: []u8) void {
222 const self = @fieldParentPtr(Pcg, "random", r);
223
224 var i: usize = 0;
225 const aligned_len = buf.len - (buf.len & 7);
226
227 // Complete 4 byte segments.
228 while (i < aligned_len) : (i += 4) {
229 var n = self.next();
230 comptime var j: usize = 0;
231 inline while (j < 4) : (j += 1) {
232 buf[i + j] = @truncate(u8, n);
233 n >>= 8;
234 }
235 }
236
237 // Remaining. (cuts the stream)
238 if (i != buf.len) {
239 var n = self.next();
240 while (i < buf.len) : (i += 1) {
241 buf[i] = @truncate(u8, n);
242 n >>= 4;
243 }
244 }
245 }
246};
247
248test "pcg sequence" {
249 var r = Pcg.init(0);
250 const s0: u64 = 0x9394bf54ce5d79de;
251 const s1: u64 = 0x84e9c579ef59bbf7;
252 r.seedTwo(s0, s1);
253
254 const seq = []const u32 {
255 2881561918,
256 3063928540,
257 1199791034,
258 2487695858,
259 1479648952,
260 3247963454,
261 };
262
263 for (seq) |s| {
264 std.debug.assert(s == r.next());
265 }
266}
267
268// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
269//
270// PRNG
271pub const Xoroshiro128 = struct {
272 random: Rand,
273
274 s: [2]u64,
275
276 pub fn init(init_s: u64) Xoroshiro128 {
277 var x = Xoroshiro128 {
278 .random = Rand { .fillFn = fill },
279 .s = undefined,
280 };
281
282 x.seed(init_s);
283 return x;
284 }
285
286 fn next(self: &Xoroshiro128) u64 {
287 const s0 = self.s[0];
288 var s1 = self.s[1];
289 const r = s0 +% s1;
290
291 s1 ^= s0;
292 self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
293 self.s[1] = math.rotl(u64, s1, u8(36));
294
295 return r;
296 }
297
298 // Skip 2^64 places ahead in the sequence
299 fn jump(self: &Xoroshiro128) void {
300 var s0: u64 = 0;
301 var s1: u64 = 0;
302
303 const table = []const u64 {
304 0xbeac0467eba5facb,
305 0xd86b048b86aa9922
306 };
307
308 inline for (table) |entry| {
309 var b: usize = 0;
310 while (b < 64) : (b += 1) {
311 if ((entry & (u64(1) << u6(b))) != 0) {
312 s0 ^= self.s[0];
313 s1 ^= self.s[1];
314 }
315 _ = self.next();
316 }
317 }
318
319 self.s[0] = s0;
320 self.s[1] = s1;
321 }
322
323 fn seed(self: &Xoroshiro128, init_s: u64) void {
324 // Xoroshiro requires 128-bits of seed.
325 var gen = SplitMix64.init(init_s);
326
327 self.s[0] = gen.next();
328 self.s[1] = gen.next();
329 }
330
331 fn fill(r: &Rand, buf: []u8) void {
332 const self = @fieldParentPtr(Xoroshiro128, "random", r);
333
334 var i: usize = 0;
335 const aligned_len = buf.len - (buf.len & 7);
336
337 // Complete 8 byte segments.
338 while (i < aligned_len) : (i += 8) {
339 var n = self.next();
340 comptime var j: usize = 0;
341 inline while (j < 8) : (j += 1) {
342 buf[i + j] = @truncate(u8, n);
343 n >>= 8;
344 }
345 }
346
347 // Remaining. (cuts the stream)
348 if (i != buf.len) {
349 var n = self.next();
350 while (i < buf.len) : (i += 1) {
351 buf[i] = @truncate(u8, n);
352 n >>= 8;
353 }
354 }
355 }
356};
357
358test "xoroshiro sequence" {
359 var r = Xoroshiro128.init(0);
360 r.s[0] = 0xaeecf86f7878dd75;
361 r.s[1] = 0x01cd153642e72622;
362
363 const seq1 = []const u64 {
364 0xb0ba0da5bb600397,
365 0x18a08afde614dccc,
366 0xa2635b956a31b929,
367 0xabe633c971efa045,
368 0x9ac19f9706ca3cac,
369 0xf62b426578c1e3fb,
370 };
371
372 for (seq1) |s| {
373 std.debug.assert(s == r.next());
374 }
375
376
377 r.jump();
378
379 const seq2 = []const u64 {
380 0x95344a13556d3e22,
381 0xb4fb32dafa4d00df,
382 0xb2011d9ccdcfe2dd,
383 0x05679a9b2119b908,
384 0xa860a1da7c9cd8a0,
385 0x658a96efe3f86550,
386 };
387
388 for (seq2) |s| {
389 std.debug.assert(s == r.next());
390 }
391}
392
393// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
394//
395// CSPRNG
396//
397// Follows the general idea of the implementation from here with a few shortcuts.
398// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
399pub const Isaac64 = struct {
400 random: Rand,
401
402 r: [256]u64,
403 m: [256]u64,
404 a: u64,
405 b: u64,
406 c: u64,
407 i: usize,
408
409 pub fn init(init_s: u64) Isaac64 {
410 var isaac = Isaac64 {
411 .random = Rand { .fillFn = fill },
412 .r = undefined,
413 .m = undefined,
414 .a = undefined,
415 .b = undefined,
416 .c = undefined,
417 .i = undefined,
418 };
419
420 // seed == 0 => same result as the unseeded reference implementation
421 isaac.seed(init_s, 1);
422 return isaac;
423 }
424
425 fn step(self: &Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
426 const x = self.m[base + m1];
427 self.a = mix +% self.m[base + m2];
428
429 const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
430 self.m[base + m1] = y;
431
432 self.b = x +% self.m[(y >> 11) % self.m.len];
433 self.r[self.r.len - 1 - base - m1] = self.b;
434 }
435
436 fn refill(self: &Isaac64) void {
437 const midpoint = self.r.len / 2;
438
439 self.c +%= 1;
440 self.b +%= self.c;
441
442 {
443 var i: usize = 0;
444 while (i < midpoint) : (i += 4) {
445 self.step( ~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
446 self.step( self.a ^ (self.a >> 5) , i + 1, 0, midpoint);
447 self.step( self.a ^ (self.a << 12) , i + 2, 0, midpoint);
448 self.step( self.a ^ (self.a >> 33) , i + 3, 0, midpoint);
449 }
450 }
451
452 {
453 var i: usize = 0;
454 while (i < midpoint) : (i += 4) {
455 self.step( ~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
456 self.step( self.a ^ (self.a >> 5) , i + 1, midpoint, 0);
457 self.step( self.a ^ (self.a << 12) , i + 2, midpoint, 0);
458 self.step( self.a ^ (self.a >> 33) , i + 3, midpoint, 0);
459 }
460 }
461
462 self.i = 0;
463 }
464
465 fn next(self: &Isaac64) u64 {
466 if (self.i >= self.r.len) {
467 self.refill();
468 }
469
470 const value = self.r[self.i];
471 self.i += 1;
472 return value;
473 }
474
475 fn seed(self: &Isaac64, init_s: u64, comptime rounds: usize) void {
476 // We ignore the multi-pass requirement since we don't currently expose full access to
477 // seeding the self.m array completely.
478 mem.set(u64, self.m[0..], 0);
479 self.m[0] = init_s;
480
481 // prescrambled golden ratio constants
482 var a = []const u64 {
483 0x647c4677a2884b7c,
484 0xb9f8b322c73ac862,
485 0x8c0ea5053d4712a0,
486 0xb29b2e824a595524,
487 0x82f053db8355e0ce,
488 0x48fe4a0fa5a09315,
489 0xae985bf2cbfc89ed,
490 0x98f5704f6c44c0ab,
491 };
492
493 comptime var i: usize = 0;
494 inline while (i < rounds) : (i += 1) {
495 var j: usize = 0;
496 while (j < self.m.len) : (j += 8) {
497 comptime var x1: usize = 0;
498 inline while (x1 < 8) : (x1 += 1) {
499 a[x1] +%= self.m[j + x1];
500 }
501
502 a[0] -%= a[4]; a[5] ^= a[7] >> 9; a[7] +%= a[0];
503 a[1] -%= a[5]; a[6] ^= a[0] << 9; a[0] +%= a[1];
504 a[2] -%= a[6]; a[7] ^= a[1] >> 23; a[1] +%= a[2];
505 a[3] -%= a[7]; a[0] ^= a[2] << 15; a[2] +%= a[3];
506 a[4] -%= a[0]; a[1] ^= a[3] >> 14; a[3] +%= a[4];
507 a[5] -%= a[1]; a[2] ^= a[4] << 20; a[4] +%= a[5];
508 a[6] -%= a[2]; a[3] ^= a[5] >> 17; a[5] +%= a[6];
509 a[7] -%= a[3]; a[4] ^= a[6] << 14; a[6] +%= a[7];
510
511 comptime var x2: usize = 0;
512 inline while (x2 < 8) : (x2 += 1) {
513 self.m[j + x2] = a[x2];
514 }
515 }
516 }
517
518 mem.set(u64, self.r[0..], 0);
519 self.a = 0;
520 self.b = 0;
521 self.c = 0;
522 self.i = self.r.len; // trigger refill on first value
523 }
524
525 fn fill(r: &Rand, buf: []u8) void {
526 const self = @fieldParentPtr(Isaac64, "random", r);
527
528 var i: usize = 0;
529 const aligned_len = buf.len - (buf.len & 7);
530
531 // Fill complete 64-byte segments
532 while (i < aligned_len) : (i += 8) {
533 var n = self.next();
534 comptime var j: usize = 0;
535 inline while (j < 8) : (j += 1) {
536 buf[i + j] = @truncate(u8, n);
537 n >>= 8;
538 }
539 }
540
541 // Fill trailing, ignoring excess (cut the stream).
542 if (i != buf.len) {
543 var n = self.next();
544 while (i < buf.len) : (i += 1) {
545 buf[i] = @truncate(u8, n);
546 n >>= 8;
547 }
548 }
549 }
550};
551
552test "isaac64 sequence" {
553 var r = Isaac64.init(0);
554
555 // from reference implementation
556 const seq = []const u64 {
557 0xf67dfba498e4937c,
558 0x84a5066a9204f380,
559 0xfee34bd5f5514dbb,
560 0x4d1664739b8f80d6,
561 0x8607459ab52a14aa,
562 0x0e78bc5a98529e49,
563 0xfe5332822ad13777,
564 0x556c27525e33d01a,
565 0x08643ca615f3149f,
566 0xd0771faf3cb04714,
567 0x30e86f68a37b008d,
568 0x3074ebc0488a3adf,
569 0x270645ea7a2790bc,
570 0x5601a0a8d3763c6a,
571 0x2f83071f53f325dd,
572 0xb9090f3d42d2d2ea,
573 };
574
575 for (seq) |s| {
576 std.debug.assert(s == r.next());
577 }
578}
579
580// Actual Rand helper function tests, pcg engine is assumed correct.
581test "Rand float" {
582 var prng = DefaultPrng.init(0);
583
584 var i: usize = 0;
585 while (i < 1000) : (i += 1) {
586 const val1 = prng.random.float(f32);
587 std.debug.assert(val1 >= 0.0);
588 std.debug.assert(val1 < 1.0);
589
590 const val2 = prng.random.float(f64);
591 std.debug.assert(val2 >= 0.0);
592 std.debug.assert(val2 < 1.0);
593 }
594}
595
596test "Rand scalar" {
597 var prng = DefaultPrng.init(0);
598 const s = prng .random.scalar(u64);
599}
600
601test "Rand bytes" {
602 var prng = DefaultPrng.init(0);
603 var buf: [2048]u8 = undefined;
604 prng.random.bytes(buf[0..]);
605}
606
607test "Rand shuffle" {
608 var prng = DefaultPrng.init(0);
609
610 var seq = []const u8 { 0, 1, 2, 3, 4 };
611 var seen = []bool {false} ** 5;
612
613 var i: usize = 0;
614 while (i < 1000) : (i += 1) {
615 prng.random.shuffle(u8, seq[0..]);
616 seen[seq[0]] = true;
617 std.debug.assert(sumArray(seq[0..]) == 10);
618 }
619
620 // we should see every entry at the head at least once
621 for (seen) |e| {
622 std.debug.assert(e == true);
623 }
624}
625
626fn sumArray(s: []const u8) u32 {
627 var r: u32 = 0;
628 for (s) |e| r += e;
629 return r;
630}
631
632test "Rand range" {
633 var prng = DefaultPrng.init(0);
634 testRange(&prng.random, -4, 3);
635 testRange(&prng.random, -4, -1);
636 testRange(&prng.random, 10, 14);
637}
638
639fn testRange(r: &Rand, start: i32, end: i32) void {
640 const count = usize(end - start);
641 var values_buffer = []bool{false} ** 20;
642 const values = values_buffer[0..count];
643 var i: usize = 0;
644 while (i < count) {
645 const value = r.range(i32, start, end);
646 const index = usize(value - start);
647 if (!values[index]) {
648 i += 1;
649 values[index] = true;
650 }
651 }
652}
std/rand_test.zig deleted-507
...@@ -1,507 +0,0 @@
1pub const mt64_seed = 0xb334e49d0977c37e;
2pub const mt64_data = []u64 {
3 0x2ad1a63fab6d25a9, 0xb7143aba12569814, 0xc1b60d8d49e53e8, 0x5652adfc8da656dc,
4 0x43e3beb6d9e484a9, 0x17b09b71e9418ff7, 0x541646292686cfa4, 0x260457071268ecfc,
5 0x1627af31774e1dc1, 0x362a49b34ed75bb3, 0x7acf72002fe0f733, 0x3aaaf2e7b9409452,
6 0x9cfc2d9908115c2, 0x6e81a7f16ae613e9, 0xfc4da89c04acf3c7, 0x6984b6adb4feb9ae,
7 0x6a128b334e27b03d, 0xcc45a2b02937871a, 0xe585b229e00b2283, 0x7a92c0664a6f678a,
8 0x972735011bdc0744, 0xb494e743d658a084, 0x1eda3c4e7b1b2d0c, 0x4c7adb3831d87332,
9 0x12f8c7355f5ec631, 0xfc2bcb6be7d60eba, 0x74b95b47895f8687, 0x171de6fe92b97f5a,
10 0x86383730f52719ac, 0xe4e43ce0f61274f6, 0x514f7e072d96f19c, 0xabef324fbc6cb7fe,
11 0x7534b945b742f14f, 0x47f9efe33265adbe, 0x7bcab027a0abf16b, 0x3312a2b34225bff7,
12 0xb61455ce8c2e3e0b, 0x2b81008deeee4d94, 0x743b0b2b4974c7b6, 0xfc219101fd665f7d,
13 0x863d78891cbfe5e5, 0x7531bb1839181778, 0xf614359a65356e72, 0xfcdd1f6e3f250bdd,
14 0x528e10bd536eed5b, 0x9f69386ac60cd618, 0xbf5f242706817f01, 0x8e7da8070072cf64,
15 0xaa318b622da0667f, 0xc9580540fb7efd66, 0xb5d996deccd02e0e, 0x81c6a799ea3f5a41,
16 0xe6b896f4e21a8550, 0xde5206f177a24ceb, 0x53343e81639ec0b6, 0x5a6edb63d08be9f6,
17 0x3602c2892f7da1b9, 0xda84f4259841bdea, 0x5880e169a7746e45, 0x57cddb5ffd3c2423,
18 0x28fe1166fe7b8595, 0x92136c9decb42243, 0xa8c4199818ca7d62, 0x5042cd96f62854dd,
19 0x22b2d38c3f21f8d0, 0x73a2bfccf1b5f7bb, 0xaba3718f40b6984e, 0x9c1f5dc3e399f5f0,
20 0x9cf463f95369c149, 0xa7546d69e4232e18, 0x9ea57317d19ab7fc, 0xfb13c83d830731fb,
21 0x635a123eaa099259, 0x9a2fe7d0ba6e3c5c, 0x40b903cd0d0d3b4e, 0xc8210eb2d2e941cb,
22 0xd2582d4b1e016484, 0x1d048030875af39c, 0xb51c31a6c193d76f, 0x5ce9b801b8d61626,
23 0x2bae30455cbb0022, 0xba54df5998b2443f, 0x927abb9342c9a90a, 0xc431eb7df3e06727,
24 0x726f885d3da88d5, 0x7d85ff1ca4260280, 0xaf3fecf8f019817, 0x31d39105d6fc4fe8,
25 0x262d9842dbafd4bd, 0x54c28a2876e62e39, 0x95a986e24e214dde, 0xbf677a1abd2e553,
26 0x48ac890ff787b2b6, 0x2890ec1c67c539f4, 0x7ce88bf3975882c3, 0x88ef340414a29c88,
27 0xe30de9c88a00805b, 0xe772225e3ee6c68a, 0xa3a7d0921c5d5816, 0x8354957227b1663f,
28 0xb5b65ded7c747cbc, 0x93b4a12ff2e8fcea, 0x6359579c3c438b3c, 0x45b2c12e9722f2bd,
29 0x659a604414f19e1, 0x4ec9a149d4219ca5, 0xd830290dd6aebe2b, 0xabc7874a6b4827f8,
30 0xc91be5dd875847e7, 0x5b761d39f3f96aee, 0x5749dffad692b6c8, 0x86c94840cbd249d2,
31 0x411a466e886ad7, 0x27dca1f51aebb9a0, 0x1cceb093fbab7a42, 0x7140c2d6706e927c,
32 0x6881fdb87299a92f, 0xa81a28de171f3c47, 0x8fa9a1b3bb5dfb2a, 0xae076853e3e0abde,
33 0xe76572308ecd6b54, 0x6cd926c2e2760d8a, 0xdf080266cfbe3dc3, 0xb99b961999765d7b,
34 0xadb5d4e2b896ddf1, 0x8d3aaf4c83c83c56, 0x9b66e4f6eb65bef7, 0x7a81c3bf785eb1df,
35 0xc53f02b3e8c38647, 0xcdfeb25ee787759d, 0xead5e734d64ab5f6, 0x7930d87af1072499,
36 0xf30690a71d88ad6e, 0x73c347923c84728a, 0x3f2b588221003fe4, 0xe747052d0b453af2,
37 0xabe6fa70539b5edf, 0x4db6d1530d628c2, 0x4ec929af434eb1b0, 0x15afbe39886181ff,
38 0xa9141b9c89a07b80, 0x7d33f966c6232057, 0x8ddcb412f34a491d, 0xa74472b8ecc1e2f2,
39 0x34d745de1cb7de2e, 0x6cf67091309e5e93, 0xfb25004efa59450a, 0x3355947066522286,
40 0x5a8cffdf079dac21, 0x419445d6e6825887, 0x6e9c064f84381dcf, 0xbbcaf462a3a8ad76,
41 0x75836c68d6c1a13e, 0xf38141565d5c3759, 0x8c65989142ffa802, 0x106067ec26e6463,
42 0xadfac5e3a80de9c2, 0xc48b16e2df25b9f2, 0xa3257889c33669e6, 0x5bc760d4d65a1745,
43 0x303cd31fead81139, 0xfb97f78cade31e1d, 0xb888b8e05820a469, 0x7ebb8e44d47f54d9,
44 0xce76cdbb5ecdc529, 0xb1eb29949a099d52, 0xb6affc1b240a7eb3, 0x22977eac542906f1,
45 0x9b105b391ff729df, 0x83371186b2834968, 0xd5b893f382ea9e90, 0x5d17aa80a1fd4854,
46 0xe8ed8525eb29210c, 0xc789f3cd36c4dae3, 0x556e50a5f46b73fb, 0xef1d129b523dff77,
47 0x851de0f53f6707f9, 0x8deeeadfb1fa8bfc, 0x3d8c89c0e08c4f2e, 0xecfaaea537123333,
48 0x5bc9053d2dfd7669, 0x408c5bb2e880a9a2, 0x495726b3f3248219, 0x2b23cca4a6ea1ccc,
49 0x1df3663045092d61, 0xaf977a46e965e45b, 0x43a2facfff7f97e, 0x9b7714344c7b51e,
50 0x35643b24efb0559a, 0x502820785dc1af13, 0xbf82d2775b46433d, 0x1db626f2e16ca66,
51 0x744b031447c1e27d, 0x99e79898612f4606, 0xda02a728d234821f, 0xcf00c6fbb637a6e9,
52 0x242f2963196fd8b, 0x7aed8efc2dd562bb, 0x6204fb5d3dc6208a, 0x3e84861182fc7f6,
53 0xd14c4ee5aeef5c7a, 0x3749fbef94378dc1, 0x8fe710ec5cfc8566, 0xf43d7e495d5384d7,
54 0x8ff6396f1f1ce7c4, 0xf1252a6b6f86b42c, 0xddbbd098d6dca83f, 0x4e228724a227232a,
55 0x92a5a52ba2b24fa8, 0xdfc172b03fde669c, 0x34ee55adf7f0711c, 0x21d181e79b8000bc,
56 0xc788b1f48b37b693, 0x544fc4cfed0e0f92, 0xafca0c6de41789cc, 0xbb37bb5107ef97f8,
57 0xb9d62bf1dc0f6c95, 0xc78b5a36110dfb1, 0x1d615b658f39657e, 0x2bb2cd04cabcc360,
58 0xe563488ece6362f0, 0x213b56ce006fecc6, 0xc38207089fed0270, 0xa33199ff4a51d095,
59 0x1802ad28fb1896b1, 0xbead8f18c164a332, 0xceb5149101aa450f, 0x39ad89851ee8b62a,
60 0x317229aafabf37c4, 0xee68b8b9bf3520b3, 0xe4db499288350f04, 0xf8ea27feddb0ae7a,
61 0xa17235067b489c42, 0xbf4a570245f95d78, 0x8065c67e1d1537ab, 0xbd9357fb1b30aee5,
62 0xc224166ebeb24c42, 0xf9baf8ccd01b53bf, 0x5c13775c3fea8038, 0x4ea66f6d650ce62d,
63 0x470592ed81c140f2, 0xc2d0eb6f7999321f, 0x85d762f20290dc0c, 0x9f7d0d13936f6e78,
64 0x41f1fd2d20f2d62d, 0x891cb19ce1af2c2f, 0xe7ff34c3b29c3719, 0x246743f43126c69c,
65 0xea4b2da3195ebab9, 0x4831e4de995187dc, 0x7fb8969bbee45ce5, 0xe35b483da73c44ed,
66 0xf89158ca9af36227, 0x9fc7f34a35469a7a, 0xd02483ebca6564e7, 0xca00da156aaeda03,
67 0x303d1514646822f1, 0x226832ae582b8eac, 0xf772d719e413504e, 0x87603b928c068ab1,
68 0x4dc1552230e9b883, 0xef8c5e9db946fc87, 0x935581290bf7a4ee, 0xca632d2c7674bf2,
69 0xd8a3933b80d39efd, 0xf026574d0ffee6fb, 0xe4412d0dcd2fe94f, 0x668916490a2983ec,
70 0x73b1fe84a995718, 0x729bedefe21cc0e7, 0xd3a770f1c683b98f, 0x5d597a96323a10c2,
71 0xfbb7834bbf5fed23, 0xf3546c805a42ccdd, 0x9ef3e2164bb31a0c, 0x388363ce6c6c2253,
72 0x8120f4a949f017cb, 0x925a61942bbd3d10, 0xa03182d8599c0521, 0x2412e23004b40ebb,
73 0x35010a126bf2aecc, 0x21147869a1a84ca7, 0x53cba503b6127b98, 0x10c89dd62ab3591c,
74 0xf4c7f84faaf9f5f1, 0x8b4a37a2e844b97b, 0x23ddeb236a0bd9af, 0x4fd51d7207f49e62,
75 0x6cdab447c27706b2, 0x9e8f54b9a2d1a790, 0x191aed85d4d77087, 0xf74ecf5015265af6,
76 0x45925e25404922a1, 0xcf5467a0f5b42b98, 0x73590809c85c728c, 0xc16beeda74a1a1b8,
77 0xc3bbe7999803dd6a, 0x1a368bb32eec184, 0xafad2d86b7bb574f, 0xdc7c7b8960dc921a,
78 0xd9b68d854f5e0ae1, 0xe9e1a6a16efe0bea, 0x304a15bd6ca1cb14, 0x713ce3144e0af4b9,
79 0xc50eb410981be1d2, 0xb0fba6119bf7a300, 0x7a107296731fd314, 0xdd764898a90042b3,
80 0x8a69973262da3bc8, 0x29c6b9d048596c44, 0x62581bd20da76f1b, 0x4d1a3941d6d3e4bb,
81 0x19c447306245055, 0xb2978afcd04ba357, 0x7c01cdefcfe24432, 0xc4b268314411deae,
82 0x5ba56d49da714765, 0x33299186ac6dfd09, 0xede087aec096ef0d, 0xf758da2c7bcf9ddb,
83 0x5ea6c40d56824cdd, 0x121ff879d6ba905b, 0xb5fed0c42b616f5c, 0x21029cdc347de152,
84 0xb251d93f4cd7bf4a, 0xaedcb2dc6402cf13, 0x840e5e0d96e89407, 0x6a92fd328efcc6ef,
85 0xc63f5d8f6fcadcbd, 0x405bd64d1621128e, 0xe1318888172f58ed, 0x1009c9764d49da2b,
86 0x4bc0592cbfdf9f91, 0x972f0e080dfecd02, 0xa1cb961958eeb6aa, 0x6ee6467ad8c20aca,
87 0xb3f1c738390d6a83, 0x6504eb7ac498650d, 0xdf7dda67f198f59f, 0x72615652e56a82c3,
88 0x85e0fa2dfb51755a, 0x98b1f92a3d2ad940, 0xce81d51d875c0045, 0x437004d0be0a4d69,
89 0x64065895526f896c, 0xe1e1fea920785d49, 0x7d507ffd56fda19a, 0x17309b625cecb42,
90 0x67b6d83f0fd0f572, 0x5178665a5bcd38f4, 0x3c49fda2d35a8606, 0x7f058d2cb0ad351c,
91 0xfb95691559245416, 0xc991b857662b1b9f, 0x9e6d0f4e19774f96, 0x26cc7502212ca578,
92 0x3466110f03225e49, 0x2ae4958375eab9f3, 0x939a8d94c8871191, 0xa27356548ac6b28d,
93 0xacf86d43ec3aa030, 0xe0d16c7fa0b13a8c, 0x408ec2b2f8da531b, 0xde72494115ee4e83,
94 0xd26d7f79a02c5b1e, 0x2b6f835520c97f6a, 0x1f30f008b109ae7d, 0x698dbf9acaa222f1,
95 0xbd55de40838376d5, 0xebe53822cec7eb80, 0x7ce900793008d2bc, 0x494fc7d10e8331bb,
96 0x53509b90bdb7d588, 0x62aa920e9554b2f2, 0xe103098542011b6f, 0xeb722b9523d68af8,
97 0xb71b1a6ea2c6591b, 0x97cd7da55c940270, 0x8ab70184427e45dc, 0x6cb6907427808465,
98 0xf69232a42dbe7475, 0xbc9816d429fa8909, 0xef1e74244539d41b, 0x5569b6d10440d5c,
99 0x7dda6817985c8ef5, 0xb270ed19cc8161b3, 0x87d80b66c8a15db0, 0x96966684c3ba47fb,
100 0x996669bc87aff3bf, 0x17c015383c793f2, 0xa4b5de41fc69f61a, 0x14a0eb4e3055742f,
101 0x5f0da5a7a2b8bc79, 0x5fe0353728aac023, 0x1554daf4abe92eed, 0x545722dac774b6a4,
102 0x733fc54174f2e0d1, 0x3478ef85dd994316, 0x58ba2ac090ef7575, 0xa66b9b0cbc77b6e2,
103 0xdc78cab5c708a3ee, 0x97a30c27be510f61, 0xb95d0b06fc0910b6, 0xdc80bdc42f79a25f,
104 0x5cadc438e65b3070, 0x6263df49ce691b9c, 0xa7ce160daa64416b, 0xa4f8bfedb57288c1,
105 0xa51714e187bbcfe9, 0xe25df4e9fc44644c, 0xeaf1854b3116ce11, 0xde1b8f810991a604,
106 0xd4fc2e365e99be4b, 0x8d1b0d2799527e06, 0x7cac59eaf46baba, 0x4fa63c74d2dabaf1,
107 0x4f6c5d5e676733a6, 0x7ab7ddb9c1b789b7, 0x5d9beb4877a37034, 0x5e96bc9de3985bcb,
108 0x72bab4dcb75b3228, 0xfa40f33c4d799e1f, 0x73e6f61a69984a6b, 0x7499c9af466cf22f,
109 0x42fab9136bfa64dd, 0xd5e8e39513b6fffd, 0x8eda1fd5ad8cd51d, 0x95338744859dff44,
110 0x4f0c5e5ae768c729, 0x5bc92c60495ae348, 0xcbb48c170ac21168, 0x8374aa2440eeb138,
111 0x70b663d6f6d70ca9, 0x11264ca6dd79e5a0, 0xf058a2c156974514, 0x36820eefc435ba63,
112 0xd7b69f3d0c0c27a1, 0xe1a2eddf3b41d205, 0x80508ec93b038bc8, 0xd7e0429bd511ff37,
113 0x7bf55a4e87e183b8, 0x4cb370ce7edb4bea, 0x26fbd0b31dcef45b, 0xf7acbd6781419fa6,
114 0xf7849659f05c90c, 0xb686271ea57a47c6, 0x16f3f839dbfb4e1b, 0x906872b08b2c61a,
115 0xc30c86d0a0203c15, 0xdaf238a6aa4fc9f7, 0x2399aa09ad2c069a, 0xf133c3aca703f545,
116 0x868a10304a1c98ba, 0x60ef0607f46f7e90, 0xe4e69f26931e11a5, 0x487b8f6bd6d92941,
117 0xd10cb2971798c0c7, 0x7126d81aa4bd0106, 0xcb620311dc84ab82, 0x26f8734a7a356bb2,
118 0xcf9b9eeb02ee978c, 0x8a9ff0285d4d6b30, 0xe30e3b957e2cc7f8, 0x7c15a09e4d275809,
119 0xdf723ae1dda5d167, 0xac212e4f6264bba2, 0xe3d60920ed983308, 0x91b403cbc91e290c,
120 0xcdb905b012aff7c7, 0xb5ee73d45f900897, 0xafacc7cd7f5d52e7, 0xa8653272621165d6,
121 0x90e2efc485ddd0d1, 0x56ef1ca9097b1a96, 0xc7a20f85777eb0a, 0xf4cec0271a50eae9,
122 0x21acd76442024973, 0x19a46be82a4abdbe, 0x1bc12e0b8bf41fbb, 0x3766fe3d8e5119f2,
123 0x7fea355c4c18e8ad, 0xd08b496a24fb8017, 0xe1a7cfaa0877aa2, 0xd37ad9e2a2a3fa96,
124 0xaa362ba0e696f679, 0x7e7de89142c3aca5, 0x2dedb0842a3575b8, 0xb74c1e1d9082fe5b,
125 0xb1ae74323699140f, 0x73623f80c727a6ea, 0x132ed204b0f10441, 0xc3e6ebe8ffc252bf,
126 0x5f15cffb8286dce0, 0x66dab32df780fa8f, 0xeb00da7b25ea99e4, 0x113ad2448fafb671,
127 0xee065c10a8f1924f, 0x2fcb7367cc01fe5, 0x484338f5c2d0aacd, 0xecfacd785e42d7a6,
128 0x11513f845de8af3a, 0xd11be6b29054de0d, 0x2536e5d2856af9b7, 0x60ab519760acd4c4,
129 0x6bfe010250a831ac, 0xb28a93e44b53b21b, 0x281cf9b233858583, 0x4ca6139abc79a710,
130 0x5717d33616d77a95, 0x9ba52d2b7dfe71b5, 0x32e1c543476aa17d, 0xae242cc75806b7fa,
131 0xa1415cb8fde770da, 0x3956c67542dc004d, 0x3a6f51518fdd20ce, 0x448c848f6c936d93,
132 0x8fec38ff51bb5fab, 0x7463816cfc0754ac, 0x83b38e531ba39e73, 0xf9fc84dcf4f8c93e,
133 0xdf20dbe8b91c3d6f, 0xec65939ac9516f9a, 0x888346f6c1aaa94a, 0xe42cabb108f60d95,
134 0x39bb2e46b0599fa9, 0x529335ed75acba9e, 0x6a8767c5d00776c4, 0x8243346104fe61a5,
135 0x7a2bd0339b3e9bac, 0xb68ccdf14473f4ba, 0xa06f389531ab553a, 0xc7c6f074fc2882d3,
136 0x50a5fd6e6d0df962, 0xd7c0000d194139b7, 0x5ae27ef4033f873d, 0x4e7abe8a6d3570f8,
137 0x27011ccd3885e709, 0x3dae53f7b7a8924a, 0xa9086c9b2b86fb71, 0xa3f9e534a399e62c,
138 0x9f2f0379f9a33ec6, 0xceb51af95d4472bd, 0x15aa534182f8465, 0x96373b9cd28a627b,
139 0x9fdce0ad99d41907, 0x2755bb0f52b8c239, 0x2f2e241b6aa7d243, 0xf040afbacb2f6001,
140 0x552267c5f8b4c1b0, 0x22bfb3f0b58f9e48, 0x6bff8de368dbee3a, 0x652025c63d4069ce,
141 0x743eb697b25f9c90, 0x8a3742c9dbf67b1c, 0xaf3bcfc260d7e69, 0x491facaa59b7e1d,
142 0xd07d0761e6535fcd, 0x79ef09d9d3859232, 0xe0e0a013317d9207, 0x4b94baecf6fe4b4e,
143 0x574576ed054cfc38, 0x90e90edd1a26f0aa, 0x616d32a371af78c6, 0x392cea9c34ffb0a8,
144 0x692a6e730c33ac6f, 0x9e4b92ef425b78a6, 0x291d4c962d2f3e7c, 0x5f0f8ebb67f308fc,
145 0xc1a0faf70ec747a3, 0x641da9550cd89392, 0x6adbe38115f09648, 0x3a51980fb324da0d,
146 0xee894f2b5c17a380, 0x58788fa693f767c9, 0xc9f490ff5d88c4c0, 0x2ca6e8b204aa3070,
147 0x7693837d7910c40c, 0x9240e04f16051720, 0xab773072d922faa2, 0xacb6892db8362872,
148 0x5ac8b4d130613c0e, 0x65cd5ac259c653cb, 0x9647e0276864f3f8, 0xe207c57ee9237a53,
149 0xe41f2663482a8fdb, 0xf605931fce8b95bd, 0x5b0247a9009255d2, 0xae949df3ab5a4ab5,
150 0xc0e912dacbb72c42, 0x4226971e6351f33a, 0xd98d41f9f0fdb6c3, 0x64bf6a0af66782d5,
151 0xb4ca689b3959bf46, 0xb4cbf621b4970922, 0xe9f27469c2412fe6, 0xb529d406d27c785e,
152 0xf33be21f2672ec78, 0x34b3c4c4603656cd, 0x4a7efe099a0ae9d1, 0xa6ad5b909667945b,
153 0xe20850e47ab440f7, 0x68739e1b4fa069e5, 0x4c191300a9207cf4, 0x9b613a1a38160c98,
154 0x2cc631eb015081c9, 0x52af80aad7b676f4, 0x904b38943300ca8f, 0x50a515c0d302620f,
155 0x52ae95b8a0c1f36c, 0x6a62ab87786774e2, 0x17ea45367ad58985, 0x92959c57166aa21b,
156 0x2a9d91bd1a9716b4, 0x552c2f8528220174, 0xd665856c96b47d17, 0x14c6cba13b6dca3b,
157 0x865f1c93ec9000d0, 0x23dda8b5e161910e, 0xc191ac4342717953, 0x6783fdb95e098f1d,
158 0x1a4c26a5cad1e8ee, 0xde96e2a1e33e3046, 0xa57e65bedcf9047e, 0xa1cdef163fe7f80c,
159 0xeb0abcc13feeb7b2, 0xaa158c61b0e44470, 0x98dc901679caf85b, 0x954046758f8d2e96,
160 0x56db5e99c5d8c68, 0x7bb8d36962a4ac81, 0x2e301b4ecb03821, 0x121c1b2df70f0e1c,
161 0x3fbdad1e8faa0543, 0x6efb222398a2f88b, 0x65760de4d96338e0, 0x15b2c58a67fb43fa,
162 0x22f1532c89367d77, 0x1f726ffdad411d9e, 0x42572b54dcedf3ba, 0x3f8e0f6e9f0bbb7b,
163 0x4b0e705c86571a1c, 0xf8c9b04f8bd75117, 0x67ed2e9e4545557, 0x57e8853f681bbf8c,
164 0x6f99d1fd5fdbf582, 0xd2aa9bd48ad692e2, 0x2efc88bddecfe616, 0x8e9779a1e119abf4,
165 0x52dfee4722a20b75, 0x79465be3aea146d6, 0x588997dbcbd5f005, 0x79bda8bcc5d4c650,
166 0x2384e131ed3b5330, 0x229cb1d89738aa26, 0x1526d1a020a96507, 0xc7b6ac961a740cb9,
167 0xe78cec14478c4f71, 0xaba61cfd8f1e2a71, 0x24123c8a37ae66f3, 0xbad8b07709aa215d,
168 0x7896fa53fd2418e7, 0x72265842e8c4f955, 0x9f6331fd80527661, 0x7c649eeddb382c9d,
169 0xd3b0708dd6b5ae84, 0xeda51f244551e15, 0xb7822c860b93dd44, 0xdf9afcc3c9cac88f,
170 0x9244b9816573be70, 0xf3d103887cc4ce2d, 0xb3295c2e5bcb0218, 0x85243b7a2e0af441,
171 0xbffd3df508d06098, 0x4908b967f6765c12, 0x8886ac94c0dabb, 0x9c7865af133eb6c0,
172 0x5946fee66e64d7b2, 0x7737bc5af713087f, 0xbec815a80782dd5d, 0xe7672cfe0f7945fb,
173 0xe1f80b6df5beece1, 0x5b749d3a22450fd6, 0xaf34a567bf838668, 0xa72a177d20943ceb,
174 0x257c45c1601c4922, 0x3d7c68f6fe36ce59, 0x1b8ef47186e06c96, 0x8040426656154c17,
175 0xc15f74f980647bda, 0x36389393336a78be, 0x15d174ed5536afe2, 0x51e702e8adb61f63,
176 0xc9c95ca3f1c08f30, 0x6653094c8531c93a, 0xf7be5dfc2eb3b5b, 0xb5e21ec5c63850b0,
177 0x9ab5f082e01021a5, 0x75c4ca38d7678fb1, 0xb20bd13e05e5bd67, 0x3378133e631fbaee,
178 0x17cb3686511aeb6e, 0x4c0dea4c80ec7bc, 0x21fe874bf5509300, 0xece4f84e34d52e54,
179 0x3f2649803ca9918b, 0xdb493adeac5c60f5, 0x7c02a1d153afedd, 0x2d08ceda0fef7967,
180 0x6a32e018e432b0ea, 0x86479f3ea38ad57e, 0x84e3e04f1e5877be, 0x41b898cb02772049,
181 0xd6dded3714d71084, 0x9df5b2f3a0ab275d, 0xd5ab652dfa73ee0a, 0x4633e03fa37d6edb,
182 0x226314b8c4b937ff, 0x45d66a00ab031188, 0xb93ce1cfbcd1eaa0, 0xf88e0756f7e7c1c1,
183 0xf3611966fed51e03, 0x81235048c662d9f7, 0xcc8275f866147b4f, 0xd3b3ca0f5033a863,
184 0x970212eb8c2b3429, 0xec848dd58f3449d6, 0xa1d527af824d09f2, 0x60bd5e91448b9cf4,
185 0x1210ddfac603aa88, 0xcbf4270f3407e25a, 0x212955fec55466a0, 0x3afeaef4c9ccc793,
186 0xdd114286ec304817, 0x849e6ae3c2cf794f, 0x71c08228d6a05310, 0x177e77779d155b11,
187 0xdc59148f219a9c04, 0xb0702a7802d5276d, 0x56085d6761aee015, 0x3f79ce06bcfb4f3,
188 0x459a1f917f8f3e0, 0xe4ea5635e8bcd512, 0xa88e99b63f135a39, 0x95bd628d77d39446,
189 0xe6432158ef4c7d98, 0xb349cd3d1c74369e, 0x25b1a32db58efb0a, 0xc2add3a44cecc0b5,
190 0x5d676629f23010b5, 0x9890b3a62599408e, 0xef68ea8144d97805, 0x429e0fda34046a85,
191 0x7723d9043053bf52, 0xbb78842d9b67ae91, 0x9155ef932192e6a3, 0xdb523ea403d39f6b,
192 0xdb8fa1eee23ea58, 0x7c735492524a3448, 0xc580cb82e81505, 0xb0be6a006414841c,
193 0xdec2e763b5cedaa5, 0x8da58bb23638af5f, 0xb0e6b33f6736e7d0, 0x8146bbcd3dd4df61,
194 0x978080148a8989bb, 0x7f8119caa3308095, 0x4e88c318ea0604f3, 0x6ee5262f16b3cf83,
195 0xc44395c7a578ace9, 0x92016ee635de27e1, 0xb8dc5ceb36e67fd2, 0x95c851d65bd35f8c,
196 0xbe393620503c49fa, 0x42af183b92eac923, 0xfef0e660435135ce, 0x262d67d480451ed1,
197 0x590f92e1ee0502b3, 0x18825c97d49e3700, 0x2cd8c30a848c9acf, 0x1025c7747fda0115,
198 0x54109f23e82590aa, 0x93917bf1f8325981, 0xda674b183fa0e3cf, 0x2a0b2467eb8aefc5,
199 0xb0085eb83468793c, 0x607cabb2c9d3a81b, 0xe7a6b6013804d665, 0x67629a769c1efede,
200 0x2830ab6ef6d10166, 0xffd02b0655332bd4, 0x19bd056c3117568f, 0x385a834785662c6f,
201 0x938b5d56bd5f7248, 0x969afe82dd4829c8, 0xf455d4ace41c797d, 0x23d9cd67eff27512,
202 0x2b0c7037ecb322e2, 0x73df193328258bda, 0x5d7ee05cf2054f93, 0xdabfbd5b46b61cea,
203 0xcea02d82546b96de, 0x2245d5e74d5f60ae, 0x842ca45f8ef2a44, 0x7505cc4e1c3060d8,
204 0x869146ac8e68565e, 0x22ea711fb30e73e3, 0x53cd64736898a0c0, 0xfa88458b920684df,
205 0xc3ae23f451e0616f, 0xe2dd69393141ff32, 0x98863ab129bcd866, 0x8c9756a40dd5b834,
206 0x2eeeef78c36fede5, 0xe84d2eb23e22153b, 0xb0ccc2f7ac541d78, 0x151faba0f513acfa,
207 0x4300e3cea0260717, 0xaba308c6d857d2d0, 0x5eb25dd325256c6a, 0x3342627b68038da4,
208 0x70d7d75526da35, 0x80ff3f5ea2ac3cf1, 0xe7434f2f026394b0, 0xa7c5ff17f7d2cb07,
209 0xdfed0bb33a06ff78, 0x485cc64d38ce2596, 0x88db8580147aa8fc, 0xf52a5111d693b973,
210 0xeeaa031c02b370a8, 0xbb3b1678222d0e81, 0x27b569f2a6630939, 0x2b301fa3e50efeb8,
211 0x4dbc1f85bf3f8972, 0xb37e4f2cb75a825b, 0x3c8848e0f1777cc7, 0x8fae2e6938ba00aa,
212 0xfb4674b50884992c, 0x2b765005b85b7388, 0xaaf0007fb9662ce5, 0x684bd59009a4ad65,
213 0x221ffead3d73ab35, 0xccfe6d02d46856b5, 0x54d3323359e1b114, 0xcb412202ed42f097,
214 0x15d63df422771b9b, 0x71852bca1581d14f, 0xf30dcbb6cf891e63, 0x478fb1eed3cc5a10,
215 0x849a3b52bc5bb196, 0x4c1a98dbc546dd81, 0x846dc8c2258ec4f8, 0xbd4da447c7340bd0,
216 0x8f1ee1d6a85b9db0, 0x123ebfa8aaec07f2, 0xae34948e375d4477, 0xd466a4177842d8e4,
217 0xd5108efeb19cac6, 0x3266f7db8f133bdb, 0xe69af4e5d8d767e4, 0xea0efc0331df64a2,
218 0xb879052746ed72ed, 0x2c8233cc84de4144, 0xdcd5dda825186731, 0xb9e3b679d268f34c,
219 0x7ce12e2fa95bda8b, 0xa34afd12e611a4c1, 0x6043d06ee7619f90, 0xca3a3d4813c0addf,
220 0x6e97a61d1e4b3c4f, 0x8cdeae467a4bb292, 0xf08a6c69e70076b5, 0x97aa5c3180d3edbe,
221 0xc39813e1573904d5, 0x42577549d026e8c8, 0xaf5827ffe259b62a, 0x9e1d48596c4f0b24,
222 0xab9dd230ba8efb64, 0x81769493b85868d4, 0x715b45c5e3952245, 0x84735e138d228f35,
223 0xf4f987da7d19c74d, 0x1bdc77979baf29b, 0x785b3640158e0278, 0x77fc9d00681bcdd,
224 0xb5980cc490dcab93, 0x9062c158196b8244, 0xc16af5418cc97c4a, 0xdd4a4e9e8e00e524,
225 0x870b554b629277f1, 0xf90ff72bb54322c0, 0xd4c273bc2199823, 0xeebc75970d438466,
226 0xe4cad67413074a53, 0x6eccde71bd09dc0c, 0x14278b0ca6b910b4, 0x6e8895f17cdb933c,
227 0xa0b3987821416e11, 0x71b7d24b81fa769f, 0x1d3b1a805b885a58, 0x1bc737b1719736a,
228 0xea4d1dbb8823037, 0xe50ce48c8469adbd, 0x34c2d5e6c41a888e, 0x446a756eb06dc3a4,
229 0xbac5ed8a8f90262, 0x7f1b76e0c707ab9d, 0xb31323309b94a12e, 0xf58269b9852f986e,
230 0x3b74c2b338c244fc, 0x879b46f23a4deae4, 0x3f2591e34cdce1c9, 0x73c6f81eb560ed5c,
231 0xd2aa923c7a5c18a9, 0x7170c1f7621cace9, 0xa18b327b11b951a, 0x2b36315510f56370,
232 0x5cfed2f703dfc0bb, 0x1e43b99175054c07, 0x392dfa3210e8013b, 0x65e0c5c0454ee693,
233 0x2a795f6f493349db, 0x17995ebdfe848db0, 0xf23174b823a52cf7, 0xaac6ef104bfd396e,
234 0xfa0f5b29156eeccd, 0x9ccb3590a6e88c1a, 0x2edae0b1b80aafab, 0x1e1e92baae39aa30,
235 0x24475af89cec7f33, 0xacdbeceaadb9936c, 0x7725948da8586e93, 0xcc05595e17947215,
236 0x1f3cbde17a508faa, 0x2795f58ff5c8919b, 0x309658d1748f30d3, 0xe90c11962e5ed4bb,
237 0xc22b876286d32e27, 0x495c8b667c6ea3dd, 0x84263045f7d6eab5, 0xf8d3a9ab1494a315,
238 0xabc42cf769a21d9d, 0x3fef7fb40bdf3a81, 0xfd35336e188925a3, 0xd472bdaf277ab26d,
239 0x4949e8ff51da2307, 0xbec86dce960ff3b, 0x1aa1ce4f70256b10, 0xd52986ff8cd700ea,
240 0x364d8efc0f5afad6, 0xca3d1958f57a9050, 0x17a0a2ec122dc677, 0x7992695be3363fd6,
241 0x5c66a265e0607da8, 0x7250114e050bb917, 0x30cd3a70bc7b723d, 0x7b77433392b3fbf8,
242 0x295bb7bf46318b38, 0xdb15025af2a71c65, 0x26a82b21ef67f50c, 0x14a5573d4fc798c1,
243 0xd8cad4642ec68e5e, 0x9276d7f60142822c, 0xf7b8efc27522e52f, 0xd0a3f36f6d340bed,
244 0x341260fb11765c02, 0xcd1d394d796702cc, 0x7d483ef031eb3346, 0x74eaab49374576c1,
245 0xa073bea32a71a273, 0xd65ce2552993b5cf, 0x8670afe77caaeb16, 0xb607f1455d072a47,
246 0x30ed96be92809559, 0xa58380a503c23c9c, 0x916aa68fb957a30d, 0x30c5a675bf19738c,
247 0xd4cbad34e4e4b886, 0xd6cb83061f2b0ebf, 0xceddb4040f535fa9, 0x778c586927b1e247,
248 0xe4bb5c4b6e0f3c3d, 0x3e857d671db80667, 0x2b909dd8725f1fa2, 0x558ffd0772db7841,
249 0x710f9638d3edb2c4, 0x21a4ccee53d46556, 0xf76e8e4737b9628b, 0x71cd157f23581c71,
250 0x68d8fded9b66efd6, 0x7d9f5e182c0b9457, 0x2140757748a217ff, 0xdd1e5365520b77a4,
251 0x644d8e4b2f30dcfa, 0xa1de42f4e9791564, 0x70e148ababfe9f86, 0xb97f463e0ac7daec,
252 0x82844f729d9fa554, 0x5c8475e84470c924, 0x3a83de748eac32fd, 0x68725fbc9c202c5b,
253};
254
255pub const mt32_seed = 0x7dc0d160;
256pub const mt32_data = []u32 {
257 0x59327332, 0x200858fa, 0xab53c028, 0x5c442427,
258 0xd8be0287, 0x3b69d304, 0x15fdf62f, 0x59b8ecd,
259 0x6d7ab30c, 0x3a3dd6f1, 0xc1b9773e, 0xa12fb017,
260 0xa805b5c1, 0x4a313ba5, 0xd82c790c, 0x8de311f2,
261 0xe7cb23dd, 0x784b2efb, 0x9743487c, 0x73e2f2fb,
262 0x1a7ac286, 0xaef90d, 0x6c0a4514, 0xae1d83aa,
263 0x412fcca1, 0x3acd2d28, 0xde78292f, 0x13237756,
264 0xdd6cdeba, 0x44ae4df9, 0x3e9902eb, 0x39e1cf20,
265 0x62f561b9, 0x6cbdf531, 0x4a000673, 0xb1c82daa,
266 0x896156ca, 0x75e410f2, 0x9c69e72c, 0x396b42bb,
267 0x25c97ec0, 0xe12173f1, 0x8dcd42e5, 0x82aac3e3,
268 0xcdc1c84d, 0x13509c0c, 0x46a696d2, 0xb89ad987,
269 0x92da5e7f, 0xaa87d8a9, 0xe433ff57, 0x80a7ee49,
270 0xd387cfcc, 0x7dc47d92, 0x21516140, 0x989ca465,
271 0xf2a8e002, 0x73b99ddb, 0x2204108f, 0x27e84890,
272 0x371c81c0, 0x9f581854, 0xc0841c35, 0x770f6804,
273 0x87c55f4e, 0xd29516bb, 0x2b6d6bde, 0x5541f6ee,
274 0x1ec9b182, 0x7d599729, 0x4f4b9a14, 0x6f8c8562,
275 0x2d5151aa, 0xb54f5bc, 0xa252452b, 0x2a4266da,
276 0x25a6b75d, 0x2d11106e, 0xc5d77943, 0xb10b6e0b,
277 0xeb5cae4a, 0x43a0dd53, 0xa40bea1f, 0x63e632c2,
278 0xf420b6ce, 0x8b080233, 0x7f70ae87, 0xf460f0d6,
279 0x147c7e74, 0x710692ea, 0xa0a7d8fb, 0xe7f05808,
280 0xa6173aaf, 0xae608de0, 0x8702036, 0xbf1bfc7b,
281 0xf14cd548, 0xbbc7553d, 0x5358dd1d, 0xcc0c1fe5,
282 0xfab6f78d, 0x9365c118, 0xf64216a3, 0xb4bdcf1b,
283 0xc90b8a7a, 0x8b7b78a, 0x4c7b6854, 0xba7b5628,
284 0xdd728c15, 0xcb1f8905, 0xa63e2342, 0xa78822,
285 0xbda61b18, 0x160a59fa, 0xeccf473b, 0xc5a445b5,
286 0x7aa86430, 0x362e0d7c, 0x8006a0cb, 0x8b11586f,
287 0x6677bba9, 0x6208cf27, 0xeec9b5, 0x3dfedfc9,
288 0x886cc0e8, 0x32ed77ca, 0x43525faf, 0x9786354a,
289 0x1a2eb378, 0xf0e6b168, 0x49064b09, 0x8ab39681,
290 0x7b6655fc, 0x35adb168, 0xc417d430, 0x2784288a,
291 0xea17836, 0xc85006e7, 0x673dfdc3, 0x42765688,
292 0xc2b9251, 0x840a45b, 0xcac98e2f, 0x1a6f9777,
293 0x34959b23, 0xf0dcec81, 0xcaa2c6c8, 0x1cf93061,
294 0x787e598d, 0xd5d9e31e, 0x14e08791, 0xd9d9d782,
295 0xef162f23, 0x238f4113, 0x23f42107, 0x6ed5cc3f,
296 0xa55e5a7c, 0x4650595, 0x5217da8b, 0x6eeaacdc,
297 0xb453d7b1, 0xfa1ff004, 0xb9d17f74, 0x2bd6a53e,
298 0xe4c2d9dd, 0xed66375e, 0xf8215568, 0x9bcadbb3,
299 0x9c4f9d51, 0xff68312, 0x82308422, 0x83e990b0,
300 0x38b6135b, 0x70e2aa13, 0xa30065d2, 0x6396a00,
301 0x77d423bc, 0xa93abf0a, 0xc7bb8c31, 0x5d7bd3d3,
302 0x6a374f2e, 0xe4b5bc88, 0x39f6e512, 0xd6aea995,
303 0x878c1bfa, 0x4636014d, 0x9caa2c09, 0x7ac4758b,
304 0xbd3b957e, 0x518c2fd6, 0xea009a2e, 0x542bf419,
305 0x59090006, 0xb1d94703, 0xe0d9eefc, 0xe7fccb17,
306 0x40111951, 0xf2560485, 0xb50ce9e1, 0xd7a1ee51,
307 0x28dffa99, 0x41d12275, 0xdd89a365, 0xf22eda29,
308 0x104f94ee, 0xe669983b, 0x6346a250, 0x86326fc5,
309 0xb7f347df, 0x3849a39f, 0xf433929a, 0xeea5155,
310 0x4cf9b778, 0x6bd7926a, 0xcda9496, 0xf430d7a2,
311 0x41637670, 0xaf3bbad6, 0xeb66e44e, 0x2499605d,
312 0x9988920d, 0xf9d652ef, 0x67aa80c0, 0x505073c9,
313 0x85cd418f, 0x9f83fb65, 0xf50b3eac, 0x812ba6bd,
314 0x74d61788, 0x86d64f3b, 0xb1f8fc1c, 0x3e2af667,
315 0x4d118a2, 0xd028ffa9, 0x32e88a44, 0x4ed9ba35,
316 0xea3c7030, 0xffe44aaf, 0x5e39c467, 0xeabcfebb,
317 0x53e656ec, 0xced701d0, 0x31020b02, 0x4b4c1dc5,
318 0x8744885c, 0xa8e93656, 0x3ef457e5, 0x272bde23,
319 0xe541477c, 0x3ad3ac04, 0x63eaa692, 0x81055cf9,
320 0x3ff5f782, 0xa8efe6bc, 0x15f37656, 0xaaaebf1d,
321 0xf73d461a, 0xe8b2c0b5, 0x5035ff48, 0x3a95e34b,
322 0x6f21d94f, 0x6f6d1f96, 0xdaf79f37, 0x826f69f3,
323 0x209a00b8, 0x2ad1b2f2, 0x2c64fb45, 0xcf8bf26e,
324 0x9befcff2, 0xc08f6951, 0x96d98205, 0xa267dcb5,
325 0xbc43ec5, 0xee6a7e1c, 0x49224eae, 0x14e820e,
326 0xbb340212, 0x68ed572c, 0x45e9e623, 0x1297f3af,
327 0x49a98ed2, 0xddd34ae8, 0x211838ab, 0x47e7652d,
328 0xb40430c6, 0xc8d3bd7, 0x4352356e, 0xf0e5cac9,
329 0x21880df4, 0xc16b343a, 0xd9ed7350, 0x17fe1f65,
330 0x6637192e, 0xd81c93aa, 0x7d6e17d2, 0xd407b13f,
331 0x425da072, 0x380d423d, 0x6ce57b22, 0x7b17ed17,
332 0x95fbf626, 0x768303d6, 0x76ab6b3e, 0x591491e3,
333 0x259f79ab, 0xd4babeaf, 0x9c7de2f8, 0x4fe6cb58,
334 0xf43680a9, 0x651a1266, 0x730ea3c8, 0x9188d4c5,
335 0x12d01e34, 0x47afb2e9, 0xb4b76d35, 0x5e5164bc,
336 0xc864fc46, 0x5d018aa7, 0x17fac975, 0x5a775fbd,
337 0x40e6fa14, 0x7a00b683, 0x99e4e102, 0x2f933b90,
338 0x474e14ba, 0xde1b0754, 0xe84aba2b, 0xb386cd43,
339 0x17ca77c9, 0x7b4f38ef, 0x803ea1a8, 0x93553947,
340 0x806c8224, 0x2608451e, 0x63157fe3, 0xaf53930e,
341 0x5dfe8c16, 0x65592bda, 0x7086eb3f, 0x838e6a50,
342 0xa27836d9, 0xf2f16d92, 0xdc0a981, 0xfbf8f915,
343 0x2caea00d, 0x86bb3e18, 0x6d94c209, 0x3bbbeb6c,
344 0x114d68f4, 0xc271e48f, 0xa3350dc1, 0xb8d55eb4,
345 0x68be5ee1, 0xbf22ef29, 0xd6e0aa54, 0x48f7219,
346 0x21aca253, 0xfbf07910, 0xfcdd61a8, 0x118a09b,
347 0x3f2bbde6, 0x46eea63f, 0xdb51ed16, 0xf8a9fc36,
348 0x31614dc0, 0xdd84f54d, 0xd2b66065, 0xdae0af99,
349 0x6d071a51, 0xbdbac46c, 0x15deee25, 0xf792e64c,
350 0x910194e8, 0xfc989a8f, 0x919727fd, 0x6f93a56c,
351 0x2df36e9a, 0xd395b948, 0xb026b54a, 0xf0938a5,
352 0xe9c64399, 0xb5cda15b, 0xb7b8dd41, 0x7146f944,
353 0x8d41ce2f, 0x47c74099, 0x2e5a8e5f, 0x28f7a19c,
354 0xef7a8ef9, 0x6a763eb9, 0xf13a3ec4, 0x9f352360,
355 0x42317561, 0x6c6a0ca5, 0x5e40b472, 0x3ddaadd4,
356 0x2f5d14eb, 0x5dd49aeb, 0xc89edb24, 0xa2da269b,
357 0x5cf0a38b, 0x8e2f435c, 0x40970e54, 0xa2cb730e,
358 0xf9d8c301, 0x8ef29fb1, 0xf08b1840, 0x7d45e4a2,
359 0xa0fe4ce1, 0x939a21c4, 0xfdeebfea, 0x4c661550,
360 0xdd304d1c, 0x3cdb078d, 0x94ae8db2, 0x4f6b4287,
361 0xffe64fa8, 0x50384bb0, 0x16cf5ed3, 0xa91a8fec,
362 0xdb8ebb1, 0x59c2898b, 0xd587edc9, 0xdec2e75a,
363 0x496ccdd2, 0x897db91d, 0xf8ea5149, 0x6bed4bad,
364 0xce76e472, 0x43c7f976, 0xb055dc01, 0x7ffd5671,
365 0xe193b86a, 0xe288ce11, 0x514d531e, 0xa42fa47e,
366 0xe7c0e194, 0xffc059ba, 0x26548e36, 0xe1f10d92,
367 0x3ef5d95e, 0xa6e69282, 0xffacb09e, 0xf4a16ff5,
368 0x9b7f03bd, 0x588c54b4, 0xc2b6eaa1, 0x2d83acdc,
369 0x7fdbb606, 0x2b160650, 0x9923e57e, 0x32bd23bd,
370 0x50cd6d4c, 0x205d901f, 0x810a9935, 0x27ce6e7a,
371 0xe0c6c66, 0xac06c99c, 0x4326aa9b, 0xe1af1e90,
372 0xe358c8b1, 0x2f601c2a, 0xefca77e7, 0x1a7ed2f8,
373 0x8ad2e191, 0xe5520809, 0x27084438, 0xe4d8e782,
374 0x5e8a4038, 0x87bba694, 0x65f07eba, 0x616f8f07,
375 0xc5565d9, 0x555955e4, 0xf41c2caa, 0xb085fbf5,
376 0xa5f9d9ff, 0x418fa0df, 0xec5a576d, 0x7fc332ab,
377 0x7683ed33, 0x968ef54b, 0x834d598d, 0x6833f356,
378 0x59dc7e7f, 0x779661dc, 0x58942dd4, 0x80387aab,
379 0xf6dac9e5, 0xe043be04, 0x2ae4f872, 0x881f8d01,
380 0x82cfd69d, 0x931f4648, 0x2a76ab31, 0xa3f1dd7c,
381 0xd7f4826a, 0xe74918da, 0xe4c98636, 0x441164f,
382 0x15a0e9aa, 0xce7480ad, 0xba39076b, 0x233aa8d,
383 0x6c32f0e6, 0x169c62bf, 0xa2cd17f6, 0xb5590084,
384 0xb2036f00, 0x18315935, 0x11e9c9c7, 0x25c77861,
385 0x41596cda, 0x635e5e02, 0x8f396cc, 0x4cd00d8d,
386 0xd665597e, 0x90f891ef, 0x547b93ee, 0x376959c1,
387 0xdc5fa80, 0x9b4797a6, 0x53673041, 0x25ab117a,
388 0x7b8b8292, 0xf4e99584, 0x5139da98, 0x30e2afeb,
389 0xff2664b9, 0x591eb6f0, 0x9e87e602, 0xf5e26193,
390 0x61831f07, 0xabc139f9, 0x984eda0a, 0xaea1b8da,
391 0x65c7410d, 0x2b84800d, 0x1d3cfec3, 0xd05cb8a1,
392 0x4529641b, 0x7d6712e6, 0xc38cbde7, 0xacad7787,
393 0xd8482f3a, 0xa5662eaa, 0x24836ee9, 0xf3b5cc97,
394 0x50a581ae, 0xff6004b6, 0x650fc547, 0x161898b1,
395 0xa7593447, 0x325827dd, 0xf1844a1a, 0x7eb56de2,
396 0x89882452, 0xfebb49a, 0xfe86ae9c, 0x7dba98b1,
397 0x1d65adb5, 0xb71acffa, 0x861215af, 0xc0f1496,
398 0x70967c72, 0x3803d127, 0x6c8fdd84, 0xe40991f1,
399 0x1343e3a, 0xf57b4e73, 0x25f34f76, 0xaebcdee8,
400 0x8752d71f, 0xfc710e54, 0x34f3af44, 0xfa7dea4e,
401 0x477d4d83, 0x42640ff1, 0x2c5c31ce, 0xa82de5e4,
402 0xcc813271, 0x4d40bf86, 0x4e416095, 0xb5ac332c,
403 0xd2d44703, 0xe4c5ef57, 0xde193a29, 0xbf3e7974,
404 0xbb313d75, 0x8dc973d5, 0x301b2657, 0x44dc5064,
405 0x8c58c633, 0x83424c74, 0xb7cbf7ac, 0xa04238c2,
406 0x6ceabd59, 0xd25e6fd0, 0x3409167, 0x42d6ef80,
407 0x1f47c437, 0xdb21e45f, 0x2fd48e29, 0x9498cfb7,
408 0xc9e4cb12, 0xc6dcf0df, 0xa1633c39, 0x1b349670,
409 0xf76d4a64, 0x15ecd8dd, 0x777bb76d, 0xc46008e7,
410 0x23d94e44, 0x78aa07de, 0x2eeac782, 0x3757b114,
411 0x2b22de2a, 0x37726519, 0xf107546d, 0xe9847f74,
412 0x449a4ea6, 0x2e31fa5a, 0xd719ea88, 0xb2115c87,
413 0xfa6b7231, 0xf72fc9ff, 0xcd22bc37, 0x9080778a,
414 0x93430a21, 0x97c24360, 0x6e5b1a76, 0x5e8baa7c,
415 0x300c94f8, 0x2843d9da, 0xdceac0ae, 0xeeed885,
416 0x1898ffd0, 0xa3bbee3c, 0xc16f8fd7, 0x82992b68,
417 0x39c153b6, 0x1b3ba4c8, 0x41e7c3ac, 0xcdf8f06a,
418 0xd40b8ae6, 0x4982b6c2, 0xb32f7437, 0x22ed3691,
419 0x16579a2a, 0xff9de457, 0xc421e8e4, 0x17c8f6cb,
420 0xa5c4a8da, 0x49bd8afa, 0xe2be081c, 0x95170f28,
421 0xd679fbdf, 0xcf39d563, 0x4e2d2ee9, 0x39471096,
422 0x3918bef0, 0x279b7679, 0xa5281a0f, 0x49481d6f,
423 0x11f95ee1, 0xd9df649f, 0x2993eb27, 0x48ad815f,
424 0x99cf306d, 0xca9457e4, 0xc27c51d2, 0xc2a838ec,
425 0x537faf4c, 0x55dccddf, 0x8df5aeb8, 0xabb317ca,
426 0xfc1bcf6b, 0x669c2b1b, 0x719b62d5, 0x6b9325cf,
427 0xc123d0d3, 0x2ddc6ace, 0x27fdc30a, 0xd3f93cd8,
428 0x704f5486, 0xd3f448ec, 0xbbd1e32c, 0x3bcd4c0b,
429 0x86f8166, 0x957db888, 0x899b6a5e, 0x270dc8b7,
430 0xff16222e, 0x51e139a8, 0x3d8b4b9f, 0x68d20818,
431 0xa639ad00, 0x4c2e0fd2, 0xb4949cdc, 0x2ab6eb32,
432 0xdd0c67ad, 0xd2208cbe, 0xcd17a0bc, 0xacc541f7,
433 0xfa9e714f, 0x316d31a7, 0xed79fa91, 0xb5c0e980,
434 0x412ecc9b, 0x9815753, 0xd0df1f43, 0x8e37dbb9,
435 0xe640df75, 0x379c2fb6, 0xc7ed26a4, 0xc5190400,
436 0x1cc81b53, 0xcb0b0cd5, 0x360f061b, 0x6d90284e,
437 0x83c05bd0, 0xbd80bae9, 0xd584ef12, 0x228a46ec,
438 0x657c4fbe, 0x5ca1043c, 0x852aca0f, 0x31ce950,
439 0x33ee2cd8, 0x3cdecbf7, 0x787ef08c, 0xea610ee,
440 0x47c1db89, 0x90eeda11, 0x74f8d429, 0x51d3a4c5,
441 0x3135b401, 0x2e14783c, 0xb9af855c, 0xb66348d9,
442 0xa3a47387, 0x6eb72af1, 0x7bb56088, 0xc664542d,
443 0x7ed96b8, 0x995870a8, 0x385b1fd6, 0xa430680d,
444 0x98a883ec, 0x2497a389, 0x7a880627, 0x8350ba9d,
445 0x4cb35c33, 0x30bf6b14, 0x8695a469, 0x9a81e44b,
446 0x8bb27c9a, 0xbfb6a4dd, 0xbae7cf6e, 0x4ebccc87,
447 0xb712ed3d, 0x31e90365, 0xcc1fa63f, 0x32b93df6,
448 0xbad4c7bc, 0xb2570e17, 0x73fa21be, 0x5c02a8d2,
449 0x94446d75, 0x7265f3ad, 0xd58487a2, 0x919b7a07,
450 0xbe2d0e05, 0xd36ccf4f, 0x6d5c66d7, 0x8448522f,
451 0x8409c294, 0x6f1c7af7, 0x173a13bc, 0x1b3e4a0b,
452 0x705b941b, 0x77eb584f, 0x85b68458, 0x8e3ad1ac,
453 0x4aa99702, 0x7ae1b24c, 0x899ba29c, 0x860a3711,
454 0xabe53a4f, 0x37870133, 0x1ed7cb89, 0xea539762,
455 0x4ba64130, 0x48517a2d, 0xce0a869d, 0x937ba48,
456 0xd0f234c4, 0xf9b2cf26, 0xc3c311f0, 0x153d09a9,
457 0x404d3af9, 0x9f7edbc1, 0xbdcecded, 0x97969ba8,
458 0x3379437, 0xadd3c893, 0x7c024639, 0x459390b,
459 0xcb7c7320, 0xa5c63725, 0x65907e3e, 0xbf70583b,
460 0xcebb601b, 0x4edfb286, 0x9350336f, 0xdfb4be76,
461 0x88b56f39, 0x9937d7f9, 0xa12a286d, 0x34f141c,
462 0xa2e75c15, 0xd69a7060, 0x931340c3, 0x22447f25,
463 0xe8aed82c, 0xd76a9ae7, 0xc967288, 0xe572facd,
464 0xbe82b0ee, 0x10f5dce1, 0x4f03ee35, 0x2340b923,
465 0xf4fb6bd0, 0x64adbf01, 0x3d277a0a, 0x39e76f2c,
466 0xe3c024d9, 0x57869c82, 0x743b7826, 0xf66f1574,
467 0xc93965c, 0xf86a552, 0x13557069, 0x9e0845de,
468 0xaee084f9, 0x5eafaedb, 0xc06f5f3, 0x9051f6ea,
469 0x98fceda2, 0x2af2f8cc, 0x6c41b5a8, 0xc1af74de,
470 0x57302276, 0x253923c9, 0xd79996b3, 0x8ecb3141,
471 0x641387cc, 0xf87a4101, 0x96a50c76, 0xbcf24a11,
472 0x87b6bb6, 0x58ee501b, 0xaa859695, 0xb2eed107,
473 0x554173f0, 0xb12ec0e6, 0x57785c1b, 0x53685c9a,
474 0x114c3163, 0x9383cf19, 0x31fd7cdf, 0xaeb8225c,
475 0x58774fe7, 0x54700ad4, 0xad418726, 0xf055b71c,
476 0x7d31237f, 0xdd97cad5, 0xcdd5325e, 0x42f2acf4,
477 0x4bed262b, 0x7a8faaf2, 0x2b1eafdd, 0xa1b806ac,
478 0x26965c6e, 0xb41b7168, 0x15e2e70b, 0x7daa8e13,
479 0x6198aa5a, 0xc9b8b94c, 0x339b5754, 0xcd3b285c,
480 0xffd1486c, 0xf224979a, 0xafb89ec5, 0x222058c,
481 0xcb4814d0, 0x2b0e7c7d, 0x9eb25b84, 0x271564b0,
482 0xbb72e076, 0x48251020, 0x18008023, 0x48d10005,
483 0x4a452eaa, 0xb2365308, 0x19cdb632, 0x1fd56d04,
484 0xffa5ff2a, 0xaba89e42, 0x388fc17d, 0xea61c00f,
485 0x5156273d, 0x776f1a56, 0x8d539d28, 0x289c01cb,
486 0x857aa71f, 0x348e411f, 0xc9eb3c91, 0x67a61079,
487 0xe4276a0f, 0x45bdc15f, 0x8e0a698e, 0xbdefc310,
488 0x82377ba6, 0x3bfbf404, 0xcbf22c79, 0x35f501bc,
489 0xb16044a7, 0xeffdb8, 0xdbac383d, 0x7816663f,
490 0x18f5a318, 0x3d04f1cb, 0x735da9b4, 0x75e339a1,
491 0x5b6c55f, 0x1c18887e, 0xf698e14f, 0x338a6da1,
492 0xdac85699, 0x1aca7768, 0x8eb0fa7a, 0xc98fa71d,
493 0x3b794408, 0x92913041, 0xf8dc8827, 0x1cf706e9,
494 0x3aeee292, 0x321dbaa8, 0xee1eb8d1, 0x23554be9,
495 0x811c7804, 0xf0f4de6b, 0xd457e382, 0xeda56795,
496 0xeffdfc71, 0xf2a52829, 0xa7460732, 0x2c1321c0,
497 0x2f734db0, 0xf04ecb0b, 0xec7d777e, 0x43c54317,
498 0xccaa74cd, 0xfe49dd9d, 0x4c509829, 0x278f9bd7,
499 0x581dc500, 0x4ad38c2e, 0xcbee1047, 0x13302c1c,
500 0xbc0cb734, 0xc1c8f234, 0x1df52b35, 0xd8815548,
501 0x319edefb, 0x437cebe5, 0x3dcb6026, 0xe9d4f93f,
502 0xb2661154, 0xeb8c15a0, 0xb008505, 0x5f869981,
503 0xf5588ca4, 0xd6929c5b, 0xa3dd13d1, 0xdc863314,
504 0x891a454f, 0x91737e49, 0x5064d4d8, 0x2fd32675,
505 0xadefe9b1, 0xdde32b11, 0x741bbd6, 0x3b4363a9,
506 0xb121d9e8, 0x916ca61d, 0x38c0af15, 0x5e3dfd72,
507};
std/sort.zig+77-77
...@@ -67,7 +67,7 @@ const Iterator = struct {...@@ -67,7 +67,7 @@ const Iterator = struct {
67 self.numerator -= self.denominator;67 self.numerator -= self.denominator;
68 self.decimal += 1;68 self.decimal += 1;
69 }69 }
70 70
71 return Range {.start = start, .end = self.decimal};71 return Range {.start = start, .end = self.decimal};
72 }72 }
7373
...@@ -82,7 +82,7 @@ const Iterator = struct {...@@ -82,7 +82,7 @@ const Iterator = struct {
82 self.numerator_step -= self.denominator;82 self.numerator_step -= self.denominator;
83 self.decimal_step += 1;83 self.decimal_step += 1;
84 }84 }
85 85
86 return (self.decimal_step < self.size);86 return (self.decimal_step < self.size);
87 }87 }
8888
...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
219 var B1 = iterator.nextRange();219 var B1 = iterator.nextRange();
220 var A2 = iterator.nextRange();220 var A2 = iterator.nextRange();
221 var B2 = iterator.nextRange();221 var B2 = iterator.nextRange();
222 222
223 if (lessThan(items[B1.end - 1], items[A1.start])) {223 if (lessThan(items[B1.end - 1], items[A1.start])) {
224 // the two ranges are in reverse order, so copy them in reverse order into the cache224 // the two ranges are in reverse order, so copy them in reverse order into the cache
225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);
...@@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
230 } else {230 } else {
231 // if A1, B1, A2, and B2 are all in order, skip doing anything else231 // if A1, B1, A2, and B2 are all in order, skip doing anything else
232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;
233 233
234 // copy A1 and B1 into the cache in the same order234 // copy A1 and B1 into the cache in the same order
235 mem.copy(T, cache[0..], items[A1.start..A1.end]);235 mem.copy(T, cache[0..], items[A1.start..A1.end]);
236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);
237 }237 }
238 A1 = Range.init(A1.start, B1.end);238 A1 = Range.init(A1.start, B1.end);
239 239
240 // merge A2 and B2 into the cache240 // merge A2 and B2 into the cache
241 if (lessThan(items[B2.end - 1], items[A2.start])) {241 if (lessThan(items[B2.end - 1], items[A2.start])) {
242 // the two ranges are in reverse order, so copy them in reverse order into the cache242 // the two ranges are in reverse order, so copy them in reverse order into the cache
...@@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
252 }252 }
253 A2 = Range.init(A2.start, B2.end);253 A2 = Range.init(A2.start, B2.end);
254 254
255 // merge A1 and A2 from the cache into the items255 // merge A1 and A2 from the cache into the items
256 const A3 = Range.init(0, A1.length());256 const A3 = Range.init(0, A1.length());
257 const B3 = Range.init(A1.length(), A1.length() + A2.length());257 const B3 = Range.init(A1.length(), A1.length() + A2.length());
258 258
259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260 // the two ranges are in reverse order, so copy them in reverse order into the items260 // the two ranges are in reverse order, so copy them in reverse order into the items
261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);
...@@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
270 }270 }
271 }271 }
272 272
273 // we merged two levels at the same time, so we're done with this level already273 // we merged two levels at the same time, so we're done with this level already
274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275 _ = iterator.nextLevel();275 _ = iterator.nextLevel();
276 276
277 } else {277 } else {
278 iterator.begin();278 iterator.begin();
279 while (!iterator.finished()) {279 while (!iterator.finished()) {
280 var A = iterator.nextRange();280 var A = iterator.nextRange();
281 var B = iterator.nextRange();281 var B = iterator.nextRange();
282 282
283 if (lessThan(items[B.end - 1], items[A.start])) {283 if (lessThan(items[B.end - 1], items[A.start])) {
284 // the two ranges are in reverse order, so a simple rotation should fix it284 // the two ranges are in reverse order, so a simple rotation should fix it
285 mem.rotate(T, items[A.start..B.end], A.length());285 mem.rotate(T, items[A.start..B.end], A.length());
...@@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302 // 7. sort the second internal buffer if it exists302 // 7. sort the second internal buffer if it exists
303 // 8. redistribute the two internal buffers back into the items303 // 8. redistribute the two internal buffers back into the items
304 304
305 var block_size: usize = math.sqrt(iterator.length());305 var block_size: usize = math.sqrt(iterator.length());
306 var buffer_size = iterator.length()/block_size + 1;306 var buffer_size = iterator.length()/block_size + 1;
307 307
308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
310 var A: Range = undefined;310 var A: Range = undefined;
...@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
322322
323 var buffer1 = Range.init(0, 0);323 var buffer1 = Range.init(0, 0);
324 var buffer2 = Range.init(0, 0);324 var buffer2 = Range.init(0, 0);
325 325
326 // find two internal buffers of size 'buffer_size' each326 // find two internal buffers of size 'buffer_size' each
327 find = buffer_size + buffer_size;327 find = buffer_size + buffer_size;
328 var find_separately = false;328 var find_separately = false;
329 329
330 if (block_size <= cache.len) {330 if (block_size <= cache.len) {
331 // if every A block fits into the cache then we won't need the second internal buffer,331 // if every A block fits into the cache then we won't need the second internal buffer,
332 // so we really only need to find 'buffer_size' unique values332 // so we really only need to find 'buffer_size' unique values
...@@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
336 find = buffer_size;336 find = buffer_size;
337 find_separately = true;337 find_separately = true;
338 }338 }
339 339
340 // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each),340 // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each),
341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,
342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get
343 343
344 // in the case where it couldn't find a single buffer of at least √A unique values,344 // in the case where it couldn't find a single buffer of at least √A unique values,
345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)
346 iterator.begin();346 iterator.begin();
347 while (!iterator.finished()) {347 while (!iterator.finished()) {
348 A = iterator.nextRange();348 A = iterator.nextRange();
349 B = iterator.nextRange();349 B = iterator.nextRange();
350 350
351 // just store information about where the values will be pulled from and to,351 // just store information about where the values will be pulled from and to,
352 // as well as how many values there are, to create the two internal buffers352 // as well as how many values there are, to create the two internal buffers
353 353
354 // check A for the number of unique values we need to fill an internal buffer354 // check A for the number of unique values we need to fill an internal buffer
355 // these values will be pulled out to the start of A355 // these values will be pulled out to the start of A
356 last = A.start;356 last = A.start;
...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
360 if (index == A.end) break;360 if (index == A.end) break;
361 }361 }
362 index = last;362 index = last;
363 363
364 if (count >= buffer_size) {364 if (count >= buffer_size) {
365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366 pull[pull_index] = Pull {366 pull[pull_index] = Pull {
...@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
370 .to = A.start,370 .to = A.start,
371 };371 };
372 pull_index = 1;372 pull_index = 1;
373 373
374 if (count == buffer_size + buffer_size) {374 if (count == buffer_size + buffer_size) {
375 // we were able to find a single contiguous section containing 2√A unique values,375 // we were able to find a single contiguous section containing 2√A unique values,
376 // so this section can be used to contain both of the internal buffers we'll need376 // so this section can be used to contain both of the internal buffers we'll need
...@@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
405 .to = A.start,405 .to = A.start,
406 };406 };
407 }407 }
408 408
409 // check B for the number of unique values we need to fill an internal buffer409 // check B for the number of unique values we need to fill an internal buffer
410 // these values will be pulled out to the end of B410 // these values will be pulled out to the end of B
411 last = B.end - 1;411 last = B.end - 1;
...@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
415 if (index == B.start) break;415 if (index == B.start) break;
416 }416 }
417 index = last;417 index = last;
418 418
419 if (count >= buffer_size) {419 if (count >= buffer_size) {
420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421 pull[pull_index] = Pull {421 pull[pull_index] = Pull {
...@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
425 .to = B.end,425 .to = B.end,
426 };426 };
427 pull_index = 1;427 pull_index = 1;
428 428
429 if (count == buffer_size + buffer_size) {429 if (count == buffer_size + buffer_size) {
430 // we were able to find a single contiguous section containing 2√A unique values,430 // we were able to find a single contiguous section containing 2√A unique values,
431 // so this section can be used to contain both of the internal buffers we'll need431 // so this section can be used to contain both of the internal buffers we'll need
...@@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,
450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2
451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;
452 452
453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!
454 buffer2 = Range.init(B.end - count, B.end);454 buffer2 = Range.init(B.end - count, B.end);
455 break;455 break;
...@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
465 };465 };
466 }466 }
467 }467 }
468 468
469 // pull out the two ranges so we can use them as internal buffers469 // pull out the two ranges so we can use them as internal buffers
470 pull_index = 0;470 pull_index = 0;
471 while (pull_index < 2) : (pull_index += 1) {471 while (pull_index < 2) : (pull_index += 1) {
472 const length = pull[pull_index].count;472 const length = pull[pull_index].count;
473 473
474 if (pull[pull_index].to < pull[pull_index].from) {474 if (pull[pull_index].to < pull[pull_index].from) {
475 // we're pulling the values out to the left, which means the start of an A subarray475 // we're pulling the values out to the left, which means the start of an A subarray
476 index = pull[pull_index].from;476 index = pull[pull_index].from;
...@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
493 }493 }
494 }494 }
495 }495 }
496 496
497 // adjust block_size and buffer_size based on the values we were able to pull out497 // adjust block_size and buffer_size based on the values we were able to pull out
498 buffer_size = buffer1.length();498 buffer_size = buffer1.length();
499 block_size = iterator.length()/buffer_size + 1;499 block_size = iterator.length()/buffer_size + 1;
500 500
501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502 // so this was originally here to test the math for adjusting block_size above502 // so this was originally here to test the math for adjusting block_size above
503 // assert((iterator.length() + 1)/block_size <= buffer_size);503 // assert((iterator.length() + 1)/block_size <= buffer_size);
504 504
505 // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort!505 // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort!
506 iterator.begin();506 iterator.begin();
507 while (!iterator.finished()) {507 while (!iterator.finished()) {
508 A = iterator.nextRange();508 A = iterator.nextRange();
509 B = iterator.nextRange();509 B = iterator.nextRange();
510 510
511 // remove any parts of A or B that are being used by the internal buffers511 // remove any parts of A or B that are being used by the internal buffers
512 start = A.start;512 start = A.start;
513 if (start == pull[0].range.start) {513 if (start == pull[0].range.start) {
514 if (pull[0].from > pull[0].to) {514 if (pull[0].from > pull[0].to) {
515 A.start += pull[0].count;515 A.start += pull[0].count;
516 516
517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge
518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,
519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal
...@@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
532 if (B.length() == 0) continue;532 if (B.length() == 0) continue;
533 }533 }
534 }534 }
535 535
536 if (lessThan(items[B.end - 1], items[A.start])) {536 if (lessThan(items[B.end - 1], items[A.start])) {
537 // the two ranges are in reverse order, so a simple rotation should fix it537 // the two ranges are in reverse order, so a simple rotation should fix it
538 mem.rotate(T, items[A.start..B.end], A.length());538 mem.rotate(T, items[A.start..B.end], A.length());
539 } else if (lessThan(items[A.end], items[A.end - 1])) {539 } else if (lessThan(items[A.end], items[A.end - 1])) {
540 // these two ranges weren't already in order, so we'll need to merge them!540 // these two ranges weren't already in order, so we'll need to merge them!
541 var findA: usize = undefined;541 var findA: usize = undefined;
542 542
543 // break the remainder of A into blocks. firstA is the uneven-sized first A block543 // break the remainder of A into blocks. firstA is the uneven-sized first A block
544 var blockA = Range.init(A.start, A.end);544 var blockA = Range.init(A.start, A.end);
545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);
546 546
547 // swap the first value of each A block with the value in buffer1547 // swap the first value of each A block with the value in buffer1
548 var indexA = buffer1.start;548 var indexA = buffer1.start;
549 index = firstA.end;549 index = firstA.end;
550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
551 mem.swap(T, &items[indexA], &items[index]);551 mem.swap(T, &items[indexA], &items[index]);
552 }552 }
553 553
554 // start rolling the A blocks through the B blocks!554 // start rolling the A blocks through the B blocks!
555 // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well555 // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well
556 var lastA = firstA;556 var lastA = firstA;
...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));
559 blockA.start += firstA.length();559 blockA.start += firstA.length();
560 indexA = buffer1.start;560 indexA = buffer1.start;
561 561
562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it
563 // otherwise, if the second buffer is available, block swap the contents into that563 // otherwise, if the second buffer is available, block swap the contents into that
564 if (lastA.length() <= cache.len) {564 if (lastA.length() <= cache.len) {
...@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
566 } else if (buffer2.length() > 0) {566 } else if (buffer2.length() > 0) {
567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());
568 }568 }
569 569
570 if (blockA.length() > 0) {570 if (blockA.length() > 0) {
571 while (true) {571 while (true) {
572 // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block,572 // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block,
...@@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
575 // figure out where to split the previous B block, and rotate it at the split575 // figure out where to split the previous B block, and rotate it at the split
576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);
577 const B_remaining = lastB.end - B_split;577 const B_remaining = lastB.end - B_split;
578 578
579 // swap the minimum A block to the beginning of the rolling A blocks579 // swap the minimum A block to the beginning of the rolling A blocks
580 var minA = blockA.start;580 var minA = blockA.start;
581 findA = minA + block_size;581 findA = minA + block_size;
...@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
585 }585 }
586 }586 }
587 blockSwap(T, items, blockA.start, minA, block_size);587 blockSwap(T, items, blockA.start, minA, block_size);
588 588
589 // swap the first item of the previous A block back with its original value, which is stored in buffer1589 // swap the first item of the previous A block back with its original value, which is stored in buffer1
590 mem.swap(T, &items[blockA.start], &items[indexA]);590 mem.swap(T, &items[blockA.start], &items[indexA]);
591 indexA += 1;591 indexA += 1;
592 592
593 // locally merge the previous A block with the B values that follow it593 // locally merge the previous A block with the B values that follow it
594 // if lastA fits into the external cache we'll use that (with MergeExternal),594 // if lastA fits into the external cache we'll use that (with MergeExternal),
595 // or if the second internal buffer exists we'll use that (with MergeInternal),595 // or if the second internal buffer exists we'll use that (with MergeInternal),
596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)
597 597
598 if (lastA.length() <= cache.len) {598 if (lastA.length() <= cache.len) {
599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);
600 } else if (buffer2.length() > 0) {600 } else if (buffer2.length() > 0) {
...@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
602 } else {602 } else {
603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);
604 }604 }
605 605
606 if (buffer2.length() > 0 or block_size <= cache.len) {606 if (buffer2.length() > 0 or block_size <= cache.len) {
607 // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway607 // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway
608 if (block_size <= cache.len) {608 if (block_size <= cache.len) {
...@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
610 } else {610 } else {
611 blockSwap(T, items, blockA.start, buffer2.start, block_size);611 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612 }612 }
613 613
614 // this is equivalent to rotating, but faster614 // this is equivalent to rotating, but faster
615 // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it615 // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it
616 // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs616 // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs
...@@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation
620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);
621 }621 }
622 622
623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);
625 lastB = Range.init(lastA.end, lastA.end + B_remaining);625 lastB = Range.init(lastA.end, lastA.end + B_remaining);
626 626
627 // if there are no more A blocks remaining, this step is finished!627 // if there are no more A blocks remaining, this step is finished!
628 blockA.start += block_size;628 blockA.start += block_size;
629 if (blockA.length() == 0)629 if (blockA.length() == 0)
630 break;630 break;
631 631
632 } else if (blockB.length() < block_size) {632 } else if (blockB.length() < block_size) {
633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634 // the cache is disabled here since it might contain the contents of the previous A block634 // the cache is disabled here since it might contain the contents of the previous A block
635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);
636 636
637 lastB = Range.init(blockA.start, blockA.start + blockB.length());637 lastB = Range.init(blockA.start, blockA.start + blockB.length());
638 blockA.start += blockB.length();638 blockA.start += blockB.length();
639 blockA.end += blockB.length();639 blockA.end += blockB.length();
...@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
642 // roll the leftmost A block to the end by swapping it with the next B block642 // roll the leftmost A block to the end by swapping it with the next B block
643 blockSwap(T, items, blockA.start, blockB.start, block_size);643 blockSwap(T, items, blockA.start, blockB.start, block_size);
644 lastB = Range.init(blockA.start, blockA.start + block_size);644 lastB = Range.init(blockA.start, blockA.start + block_size);
645 645
646 blockA.start += block_size;646 blockA.start += block_size;
647 blockA.end += block_size;647 blockA.end += block_size;
648 blockB.start += block_size;648 blockB.start += block_size;
649 649
650 if (blockB.end > B.end - block_size) {650 if (blockB.end > B.end - block_size) {
651 blockB.end = B.end;651 blockB.end = B.end;
652 } else {652 } else {
...@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
655 }655 }
656 }656 }
657 }657 }
658 658
659 // merge the last A block with the remaining B values659 // merge the last A block with the remaining B values
660 if (lastA.length() <= cache.len) {660 if (lastA.length() <= cache.len) {
661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);
...@@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
666 }666 }
667 }667 }
668 }668 }
669 669
670 // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up670 // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up
671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer
672 672
673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,
674 // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here674 // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here
675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);
676 676
677 pull_index = 0;677 pull_index = 0;
678 while (pull_index < 2) : (pull_index += 1) {678 while (pull_index < 2) : (pull_index += 1) {
679 var unique = pull[pull_index].count * 2;679 var unique = pull[pull_index].count * 2;
...@@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
702 }702 }
703 }703 }
704 }704 }
705 705
706 // double the size of each A and B subarray that will be merged in the next level706 // double the size of each A and B subarray that will be merged in the next level
707 if (!iterator.nextLevel()) break;707 if (!iterator.nextLevel()) break;
708 }708 }
...@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
711// merge operation without a buffer711// merge operation without a buffer
712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
713 if (A_arg.length() == 0 or B_arg.length() == 0) return;713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714 714
715 // this just repeatedly binary searches into B and rotates A into position.715 // this just repeatedly binary searches into B and rotates A into position.
716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
717 // but I decided to stick with this because it had better situational performance717 // but I decided to stick with this because it had better situational performance
718 // 718 //
719 // (Hwang and Lin is designed for merging subarrays of very different sizes,719 // (Hwang and Lin is designed for merging subarrays of very different sizes,
720 // but WikiSort almost always uses subarrays that are roughly the same size)720 // but WikiSort almost always uses subarrays that are roughly the same size)
721 // 721 //
722 // normally this is incredibly suboptimal, but this function is only called722 // normally this is incredibly suboptimal, but this function is only called
723 // when none of the A or B blocks in any subarray contained 2√A unique values,723 // when none of the A or B blocks in any subarray contained 2√A unique values,
724 // which places a hard limit on the number of times this will ACTUALLY need724 // which places a hard limit on the number of times this will ACTUALLY need
725 // to binary search and rotate.725 // to binary search and rotate.
726 // 726 //
727 // according to my analysis the worst case is √A rotations performed on √A items727 // according to my analysis the worst case is √A rotations performed on √A items
728 // once the constant factors are removed, which ends up being O(n)728 // once the constant factors are removed, which ends up being O(n)
729 // 729 //
730 // again, this is NOT a general-purpose solution – it only works well in this case!730 // again, this is NOT a general-purpose solution – it only works well in this case!
731 // kind of like how the O(n^2) insertion sort is used in some places731 // kind of like how the O(n^2) insertion sort is used in some places
732732
733 var A = *A_arg;733 var A = *A_arg;
734 var B = *B_arg;734 var B = *B_arg;
735 735
736 while (true) {736 while (true) {
737 // find the first place in B where the first item in A needs to be inserted737 // find the first place in B where the first item in A needs to be inserted
738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);
739 739
740 // rotate A into place740 // rotate A into place
741 const amount = mid - A.end;741 const amount = mid - A.end;
742 mem.rotate(T, items[A.start..mid], A.length());742 mem.rotate(T, items[A.start..mid], A.length());
743 if (B.end == mid) break;743 if (B.end == mid) break;
744 744
745 // calculate the new A and B ranges745 // calculate the new A and B ranges
746 B.start = mid;746 B.start = mid;
747 A = Range.init(A.start + amount, B.start);747 A = Range.init(A.start + amount, B.start);
...@@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
757 var A_count: usize = 0;757 var A_count: usize = 0;
758 var B_count: usize = 0;758 var B_count: usize = 0;
759 var insert: usize = 0;759 var insert: usize = 0;
760 760
761 if (B.length() > 0 and A.length() > 0) {761 if (B.length() > 0 and A.length() > 0) {
762 while (true) {762 while (true) {
763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {
...@@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
773 }773 }
774 }774 }
775 }775 }
776 776
777 // swap the remainder of A into the final array777 // swap the remainder of A into the final array
778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);
779}779}
...@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s...@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
791 if (range.length() == 0) return range.start;791 if (range.length() == 0) return range.start;
792 const skip = math.max(range.length()/unique, usize(1));792 const skip = math.max(range.length()/unique, usize(1));
793 793
794 var index = range.start + skip;794 var index = range.start + skip;
795 while (lessThan(items[index - 1], value)) : (index += skip) {795 while (lessThan(items[index - 1], value)) : (index += skip) {
796 if (index >= range.end - skip) {796 if (index >= range.end - skip) {
797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);
798 }798 }
799 }799 }
800 800
801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802}802}
803803
804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
805 if (range.length() == 0) return range.start;805 if (range.length() == 0) return range.start;
806 const skip = math.max(range.length()/unique, usize(1));806 const skip = math.max(range.length()/unique, usize(1));
807 807
808 var index = range.end - skip;808 var index = range.end - skip;
809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
810 if (index < range.start + skip) {810 if (index < range.start + skip) {
811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);
812 }812 }
813 }813 }
814 814
815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816}816}
817817
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
819 if (range.length() == 0) return range.start;819 if (range.length() == 0) return range.start;
820 const skip = math.max(range.length()/unique, usize(1));820 const skip = math.max(range.length()/unique, usize(1));
821 821
822 var index = range.start + skip;822 var index = range.start + skip;
823 while (!lessThan(value, items[index - 1])) : (index += skip) {823 while (!lessThan(value, items[index - 1])) : (index += skip) {
824 if (index >= range.end - skip) {824 if (index >= range.end - skip) {
825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);
826 }826 }
827 }827 }
828 828
829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830}830}
831831
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
833 if (range.length() == 0) return range.start;833 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));834 const skip = math.max(range.length()/unique, usize(1));
835 835
836 var index = range.end - skip;836 var index = range.end - skip;
837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838 if (index < range.start + skip) {838 if (index < range.start + skip) {
839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840 }840 }
841 }841 }
842 842
843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844}844}
845845
...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
885 const A_last = A.end;885 const A_last = A.end;
886 const B_last = B.end;886 const B_last = B.end;
887 var insert_index: usize = 0;887 var insert_index: usize = 0;
888 888
889 while (true) {889 while (true) {
890 if (!lessThan(from[B_index], from[A_index])) {890 if (!lessThan(from[B_index], from[A_index])) {
891 into[insert_index] = from[A_index];891 into[insert_index] = from[A_index];
...@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
916 var insert_index: usize = A.start;916 var insert_index: usize = A.start;
917 const A_last = A.length();917 const A_last = A.length();
918 const B_last = B.end;918 const B_last = B.end;
919 919
920 if (B.length() > 0 and A.length() > 0) {920 if (B.length() > 0 and A.length() > 0) {
921 while (true) {921 while (true) {
922 if (!lessThan(items[B_index], cache[A_index])) {922 if (!lessThan(items[B_index], cache[A_index])) {
...@@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
932 }932 }
933 }933 }
934 }934 }
935 935
936 // copy the remainder of A into the final array936 // copy the remainder of A into the final array
937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938}938}
...@@ -1081,11 +1081,11 @@ test "another sort case" {...@@ -1081,11 +1081,11 @@ test "another sort case" {
1081}1081}
10821082
1083test "sort fuzz testing" {1083test "sort fuzz testing" {
1084 var rng = std.rand.Rand.init(0x12345678);1084 var prng = std.rand.DefaultPrng.init(0x12345678);
1085 const test_case_count = 10;1085 const test_case_count = 10;
1086 var i: usize = 0;1086 var i: usize = 0;
1087 while (i < test_case_count) : (i += 1) {1087 while (i < test_case_count) : (i += 1) {
1088 fuzzTest(&rng);1088 fuzzTest(&prng.random);
1089 }1089 }
1090}1090}
10911091