| ... | @@ -467,8 +467,8 @@ pub fn MultiArrayList(comptime T: type) type { | ... | @@ -467,8 +467,8 @@ pub fn MultiArrayList(comptime T: type) type { |
| 467 | | 467 | |
| 468 | /// `ctx` has the following method: | 468 | /// `ctx` has the following method: |
| 469 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` | 469 | /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` |
| 470 | pub fn sort(self: Self, ctx: anytype) void { | 470 | fn sortInternal(self: Self, a: usize, b: usize, ctx: anytype, comptime mode: enum { stable, unstable }) void { |
| 471 | const SortContext = struct { | 471 | const sort_context: struct { |
| 472 | sub_ctx: @TypeOf(ctx), | 472 | sub_ctx: @TypeOf(ctx), |
| 473 | slice: Slice, | 473 | slice: Slice, |
| 474 | | 474 | |
| ... | @@ -485,9 +485,53 @@ pub fn MultiArrayList(comptime T: type) type { | ... | @@ -485,9 +485,53 @@ pub fn MultiArrayList(comptime T: type) type { |
| 485 | pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool { | 485 | pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool { |
| 486 | return sc.sub_ctx.lessThan(a_index, b_index); | 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 | fn capacityInBytes(capacity: usize) usize { | 537 | fn capacityInBytes(capacity: usize) usize { |
| ... | @@ -817,3 +861,43 @@ test "union" { | ... | @@ -817,3 +861,43 @@ test "union" { |
| 817 | try testing.expectEqual(list.get(1), .{ .b = "zigzag" }); | 861 | try testing.expectEqual(list.get(1), .{ .b = "zigzag" }); |
| 818 | try testing.expectEqual(list.get(2), .{ .b = "foobar" }); | 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 | } |