| ... | ... | @@ -467,8 +467,8 @@ pub fn MultiArrayList(comptime T: type) type { |
| 467 | 467 | |
| 468 | 468 | /// `ctx` has the following method: |
| 469 | 469 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 470 | | pub fn sort(self: Self, ctx: anytype) void { |
| 471 | | const SortContext = struct { |
| 470 | fn sortInternal(self: Self, a: usize, b: usize, ctx: anytype, comptime mode: enum { stable, unstable }) void { |
| 471 | const sort_context: struct { |
| 472 | 472 | sub_ctx: @TypeOf(ctx), |
| 473 | 473 | slice: Slice, |
| 474 | 474 | |
| ... | ... | @@ -485,9 +485,53 @@ pub fn MultiArrayList(comptime T: type) type { |
| 485 | 485 | pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool { |
| 486 | 486 | return sc.sub_ctx.lessThan(a_index, b_index); |
| 487 | 487 | } |
| 488 | } = .{ |
| 489 | .sub_ctx = ctx, |
| 490 | .slice = self.slice(), |
| 488 | 491 | }; |
| 489 | 492 | |
| 490 | | mem.sortContext(0, self.len, SortContext{ .sub_ctx = ctx, .slice = self.slice() }); |
| 493 | switch (mode) { |
| 494 | .stable => mem.sortContext(a, b, sort_context), |
| 495 | .unstable => mem.sortUnstableContext(a, b, sort_context), |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | /// This function guarantees a stable sort, i.e the relative order of equal elements is preserved during sorting. |
| 500 | /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability |
| 501 | /// If this guarantee does not matter, `sortUnstable` might be a faster alternative. |
| 502 | /// `ctx` has the following method: |
| 503 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 504 | pub fn sort(self: Self, ctx: anytype) void { |
| 505 | self.sortInternal(0, self.len, ctx, .stable); |
| 506 | } |
| 507 | |
| 508 | /// Sorts only the subsection of items between indices `a` and `b` (excluding `b`) |
| 509 | /// This function guarantees a stable sort, i.e the relative order of equal elements is preserved during sorting. |
| 510 | /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability |
| 511 | /// If this guarantee does not matter, `sortSpanUnstable` might be a faster alternative. |
| 512 | /// `ctx` has the following method: |
| 513 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 514 | pub fn sortSpan(self: Self, a: usize, b: usize, ctx: anytype) void { |
| 515 | self.sortInternal(a, b, ctx, .stable); |
| 516 | } |
| 517 | |
| 518 | /// This function does NOT guarantee a stable sort, i.e the relative order of equal elements may change during sorting. |
| 519 | /// Due to the weaker guarantees of this function, this may be faster than the stable `sort` method. |
| 520 | /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability |
| 521 | /// `ctx` has the following method: |
| 522 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 523 | pub fn sortUnstable(self: Self, ctx: anytype) void { |
| 524 | self.sortInternal(0, self.len, ctx, .unstable); |
| 525 | } |
| 526 | |
| 527 | /// Sorts only the subsection of items between indices `a` and `b` (excluding `b`) |
| 528 | /// This function does NOT guarantee a stable sort, i.e the relative order of equal elements may change during sorting. |
| 529 | /// Due to the weaker guarantees of this function, this may be faster than the stable `sortSpan` method. |
| 530 | /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability |
| 531 | /// `ctx` has the following method: |
| 532 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 533 | pub fn sortSpanUnstable(self: Self, a: usize, b: usize, ctx: anytype) void { |
| 534 | self.sortInternal(a, b, ctx, .unstable); |
| 491 | 535 | } |
| 492 | 536 | |
| 493 | 537 | fn capacityInBytes(capacity: usize) usize { |
| ... | ... | @@ -817,3 +861,43 @@ test "union" { |
| 817 | 861 | try testing.expectEqual(list.get(1), .{ .b = "zigzag" }); |
| 818 | 862 | try testing.expectEqual(list.get(2), .{ .b = "foobar" }); |
| 819 | 863 | } |
| 864 | |
| 865 | test "sorting a span" { |
| 866 | var list: MultiArrayList(struct { score: u32, chr: u8 }) = .{}; |
| 867 | defer list.deinit(testing.allocator); |
| 868 | |
| 869 | try list.ensureTotalCapacity(testing.allocator, 42); |
| 870 | for ( |
| 871 | // zig fmt: off |
| 872 | [42]u8{ 'b', 'a', 'c', 'a', 'b', 'c', 'b', 'c', 'b', 'a', 'b', 'a', 'b', 'c', 'b', 'a', 'a', 'c', 'c', 'a', 'c', 'b', 'a', 'c', 'a', 'b', 'b', 'c', 'c', 'b', 'a', 'b', 'a', 'b', 'c', 'b', 'a', 'a', 'c', 'c', 'a', 'c' }, |
| 873 | [42]u32{ 1, 1, 1, 2, 2, 2, 3, 3, 4, 3, 5, 4, 6, 4, 7, 5, 6, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 9, 10, 11, 10, 12, 11, 13, 11, 14, 12, 13, 12, 13, 14, 14 }, |
| 874 | // zig fmt: on |
| 875 | ) |chr, score| { |
| 876 | list.appendAssumeCapacity(.{ .chr = chr, .score = score }); |
| 877 | } |
| 878 | |
| 879 | const sliced = list.slice(); |
| 880 | list.sortSpan(6, 21, struct { |
| 881 | chars: []const u8, |
| 882 | |
| 883 | fn lessThan(ctx: @This(), a: usize, b: usize) bool { |
| 884 | return ctx.chars[a] < ctx.chars[b]; |
| 885 | } |
| 886 | }{ .chars = sliced.items(.chr) }); |
| 887 | |
| 888 | var i: u32 = undefined; |
| 889 | var j: u32 = 6; |
| 890 | var c: u8 = 'a'; |
| 891 | |
| 892 | while (j < 21) { |
| 893 | i = j; |
| 894 | j += 5; |
| 895 | var n: u32 = 3; |
| 896 | for (sliced.items(.chr)[i..j], sliced.items(.score)[i..j]) |chr, score| { |
| 897 | try testing.expectEqual(score, n); |
| 898 | try testing.expectEqual(chr, c); |
| 899 | n += 1; |
| 900 | } |
| 901 | c += 1; |
| 902 | } |
| 903 | } |