| ... | @@ -74,29 +74,29 @@ pub fn heap( | ... | @@ -74,29 +74,29 @@ pub fn heap( |
| 74 | /// Sorts in ascending order with respect to the given `lessThan` function. | 74 | /// Sorts in ascending order with respect to the given `lessThan` function. |
| 75 | pub fn heapContext(a: usize, b: usize, context: anytype) void { | 75 | pub fn heapContext(a: usize, b: usize, context: anytype) void { |
| 76 | // build the heap in linear time. | 76 | // build the heap in linear time. |
| 77 | var i = b / 2; | 77 | var i = a + (b - a) / 2; |
| 78 | while (i > a) : (i -= 1) { | 78 | while (i > a) { |
| 79 | siftDown(i - 1, b, context); | 79 | i -= 1; |
| | 80 | siftDown(a, i, b, context); |
| 80 | } | 81 | } |
| 81 | | 82 | |
| 82 | // pop maximal elements from the heap. | 83 | // pop maximal elements from the heap. |
| 83 | i = b; | 84 | i = b; |
| 84 | while (i > a) : (i -= 1) { | 85 | while (i > a) { |
| 85 | context.swap(a, i - 1); | 86 | i -= 1; |
| 86 | siftDown(a, i - 1, context); | 87 | context.swap(a, i); |
| | 88 | siftDown(a, a, i, context); |
| 87 | } | 89 | } |
| 88 | } | 90 | } |
| 89 | | 91 | |
| 90 | fn siftDown(root: usize, n: usize, context: anytype) void { | 92 | fn siftDown(a: usize, root: usize, n: usize, context: anytype) void { |
| 91 | var node = root; | 93 | var node = root; |
| 92 | while (true) { | 94 | while (true) { |
| 93 | var child = 2 * node + 1; | 95 | var child = a + 2 * (node - a) + 1; |
| 94 | if (child >= n) break; | 96 | if (child >= n) break; |
| 95 | | 97 | |
| 96 | // choose the greater child. | 98 | // choose the greater child. |
| 97 | if (child + 1 < n and context.lessThan(child, child + 1)) { | 99 | child += @boolToInt(child + 1 < n and context.lessThan(child, child + 1)); |
| 98 | child += 1; | | |
| 99 | } | | |
| 100 | | 100 | |
| 101 | // stop if the invariant holds at `node`. | 101 | // stop if the invariant holds at `node`. |
| 102 | if (!context.lessThan(node, child)) break; | 102 | if (!context.lessThan(node, child)) break; |
| ... | @@ -138,6 +138,13 @@ const sort_funcs = &[_]fn (comptime type, anytype, anytype, comptime anytype) vo | ... | @@ -138,6 +138,13 @@ const sort_funcs = &[_]fn (comptime type, anytype, anytype, comptime anytype) vo |
| 138 | heap, | 138 | heap, |
| 139 | }; | 139 | }; |
| 140 | | 140 | |
| | 141 | const context_sort_funcs = &[_]fn (usize, usize, anytype) void{ |
| | 142 | // blockContext, |
| | 143 | pdqContext, |
| | 144 | insertionContext, |
| | 145 | heapContext, |
| | 146 | }; |
| | 147 | |
| 141 | const IdAndValue = struct { | 148 | const IdAndValue = struct { |
| 142 | id: usize, | 149 | id: usize, |
| 143 | value: i32, | 150 | value: i32, |
| ... | @@ -248,11 +255,15 @@ test "sort" { | ... | @@ -248,11 +255,15 @@ test "sort" { |
| 248 | &[_]i32{ 2, 1, 3 }, | 255 | &[_]i32{ 2, 1, 3 }, |
| 249 | &[_]i32{ 1, 2, 3 }, | 256 | &[_]i32{ 1, 2, 3 }, |
| 250 | }, | 257 | }, |
| | 258 | &[_][]const i32{ |
| | 259 | &[_]i32{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 55, 32, 39, 58, 21, 88, 43, 22, 59 }, |
| | 260 | &[_]i32{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 21, 22, 32, 39, 43, 55, 58, 59, 88 }, |
| | 261 | }, |
| 251 | }; | 262 | }; |
| 252 | | 263 | |
| 253 | inline for (sort_funcs) |sortFn| { | 264 | inline for (sort_funcs) |sortFn| { |
| 254 | for (u8cases) |case| { | 265 | for (u8cases) |case| { |
| 255 | var buf: [8]u8 = undefined; | 266 | var buf: [20]u8 = undefined; |
| 256 | const slice = buf[0..case[0].len]; | 267 | const slice = buf[0..case[0].len]; |
| 257 | @memcpy(slice, case[0]); | 268 | @memcpy(slice, case[0]); |
| 258 | sortFn(u8, slice, {}, asc_u8); | 269 | sortFn(u8, slice, {}, asc_u8); |
| ... | @@ -260,7 +271,7 @@ test "sort" { | ... | @@ -260,7 +271,7 @@ test "sort" { |
| 260 | } | 271 | } |
| 261 | | 272 | |
| 262 | for (i32cases) |case| { | 273 | for (i32cases) |case| { |
| 263 | var buf: [8]i32 = undefined; | 274 | var buf: [20]i32 = undefined; |
| 264 | const slice = buf[0..case[0].len]; | 275 | const slice = buf[0..case[0].len]; |
| 265 | @memcpy(slice, case[0]); | 276 | @memcpy(slice, case[0]); |
| 266 | sortFn(i32, slice, {}, asc_i32); | 277 | sortFn(i32, slice, {}, asc_i32); |
| ... | @@ -308,6 +319,45 @@ test "sort descending" { | ... | @@ -308,6 +319,45 @@ test "sort descending" { |
| 308 | } | 319 | } |
| 309 | } | 320 | } |
| 310 | | 321 | |
| | 322 | test "sort with context in the middle of a slice" { |
| | 323 | const Context = struct { |
| | 324 | items: []i32, |
| | 325 | |
| | 326 | pub fn lessThan(ctx: @This(), a: usize, b: usize) bool { |
| | 327 | return ctx.items[a] < ctx.items[b]; |
| | 328 | } |
| | 329 | |
| | 330 | pub fn swap(ctx: @This(), a: usize, b: usize) void { |
| | 331 | return mem.swap(i32, &ctx.items[a], &ctx.items[b]); |
| | 332 | } |
| | 333 | }; |
| | 334 | |
| | 335 | const i32cases = [_][]const []const i32{ |
| | 336 | &[_][]const i32{ |
| | 337 | &[_]i32{ 0, 1, 8, 3, 6, 5, 4, 2, 9, 7, 10, 55, 32, 39, 58, 21, 88, 43, 22, 59 }, |
| | 338 | &[_]i32{ 50, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 22, 32, 39, 43, 55, 58, 59, 88 }, |
| | 339 | }, |
| | 340 | }; |
| | 341 | |
| | 342 | const ranges = [_]struct { start: usize, end: usize }{ |
| | 343 | .{ .start = 10, .end = 20 }, |
| | 344 | .{ .start = 1, .end = 11 }, |
| | 345 | .{ .start = 3, .end = 7 }, |
| | 346 | }; |
| | 347 | |
| | 348 | inline for (context_sort_funcs) |sortFn| { |
| | 349 | for (i32cases) |case| { |
| | 350 | for (ranges) |range| { |
| | 351 | var buf: [20]i32 = undefined; |
| | 352 | const slice = buf[0..case[0].len]; |
| | 353 | @memcpy(slice, case[0]); |
| | 354 | sortFn(range.start, range.end, Context{ .items = slice }); |
| | 355 | try testing.expectEqualSlices(i32, slice[range.start..range.end], case[1][range.start..range.end]); |
| | 356 | } |
| | 357 | } |
| | 358 | } |
| | 359 | } |
| | 360 | |
| 311 | test "sort fuzz testing" { | 361 | test "sort fuzz testing" { |
| 312 | var prng = std.rand.DefaultPrng.init(0x12345678); | 362 | var prng = std.rand.DefaultPrng.init(0x12345678); |
| 313 | const random = prng.random(); | 363 | const random = prng.random(); |