authorgravatar for Validark@pm.meNiles Salter <Validark@pm.me> 2023-07-11 00:37:51-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-11 06:37:51+00:00
loge395a08e608ec37f83a5a4ca1a1f78eb59787479
tree33360f130225a2150e6919968d7bf4356fbf04a2
parent3d5751b57922a2ccadde70b63fac91665a74cae7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Add more sorting functions to MultiArrayList (#16377)


1 files changed, 87 insertions(+), 3 deletions(-)

lib/std/multi_array_list.zig+87-3
...@@ -467,8 +467,8 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -467,8 +467,8 @@ pub fn MultiArrayList(comptime T: type) type {
467467
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,
474474
...@@ -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 };
489492
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 }
492536
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
865test "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}