authorgravatar for jay@jayschwa.netJay Petacat <jay@jayschwa.net> 2024-09-09 22:23:18-06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-09-16 14:04:18-07:00
log812557bfde3c577b5f00cb556201c71ad5ed6fa4
tree78dc955c7aa665ea95f32a3820903f63c025aed7
parent7caa3d9da71c38665340247a1c2bf9bedb8db925

std: Restore conventional `compareFn` behavior for `binarySearch`

PR #20927 made some improvements to the `binarySearch` API, but one change I found surprising was the relationship between the left-hand and right-hand parameters of `compareFn` was inverted. This is different from how comparison functions typically behave, both in other parts of Zig (e.g. `std.math.order`) and in other languages (e.g. C's `bsearch`). Unless a strong reason can be identified and documented for doing otherwise, I think it'll be better to stick with convention. While writing this patch and changing things back to the way they were, the predicates of `lowerBound` and `upperBound` seemed to be the only areas that benefited from the inversion. I don't think that benefit is worth the cost, personally. Calling `Order.invert()` in the predicates accomplishes the same goal.

5 files changed, 30 insertions(+), 32 deletions(-)

lib/compiler/aro/aro/Preprocessor.zig+1-1
...@@ -271,7 +271,7 @@ fn clearBuffers(pp: *Preprocessor) void {...@@ -271,7 +271,7 @@ fn clearBuffers(pp: *Preprocessor) void {
271pub fn expansionSlice(pp: *Preprocessor, tok: Tree.TokenIndex) []Source.Location {271pub fn expansionSlice(pp: *Preprocessor, tok: Tree.TokenIndex) []Source.Location {
272 const S = struct {272 const S = struct {
273 fn orderTokenIndex(context: Tree.TokenIndex, item: Tree.TokenIndex) std.math.Order {273 fn orderTokenIndex(context: Tree.TokenIndex, item: Tree.TokenIndex) std.math.Order {
274 return std.math.order(item, context);274 return std.math.order(context, item);
275 }275 }
276 };276 };
277277
lib/std/debug/Coverage.zig+1-1
...@@ -196,7 +196,7 @@ pub fn resolveAddressesDwarf(...@@ -196,7 +196,7 @@ pub fn resolveAddressesDwarf(
196 const table_addrs = slc.line_table.keys();196 const table_addrs = slc.line_table.keys();
197 line_table_i = std.sort.upperBound(u64, table_addrs, pc, struct {197 line_table_i = std.sort.upperBound(u64, table_addrs, pc, struct {
198 fn order(context: u64, item: u64) std.math.Order {198 fn order(context: u64, item: u64) std.math.Order {
199 return std.math.order(item, context);199 return std.math.order(context, item);
200 }200 }
201 }.order);201 }.order);
202 }202 }
lib/std/debug/Dwarf.zig+1-1
...@@ -182,7 +182,7 @@ pub const CompileUnit = struct {...@@ -182,7 +182,7 @@ pub const CompileUnit = struct {
182 pub fn findSource(slc: *const SrcLocCache, address: u64) !LineEntry {182 pub fn findSource(slc: *const SrcLocCache, address: u64) !LineEntry {
183 const index = std.sort.upperBound(u64, slc.line_table.keys(), address, struct {183 const index = std.sort.upperBound(u64, slc.line_table.keys(), address, struct {
184 fn order(context: u64, item: u64) std.math.Order {184 fn order(context: u64, item: u64) std.math.Order {
185 return std.math.order(item, context);185 return std.math.order(context, item);
186 }186 }
187 }.order);187 }.order);
188 if (index == 0) return missing();188 if (index == 0) return missing();
lib/std/debug/SelfInfo.zig+2-2
...@@ -1624,12 +1624,12 @@ pub fn unwindFrameDwarf(...@@ -1624,12 +1624,12 @@ pub fn unwindFrameDwarf(
1624 } else {1624 } else {
1625 const index = std.sort.binarySearch(Dwarf.FrameDescriptionEntry, di.fde_list.items, context.pc, struct {1625 const index = std.sort.binarySearch(Dwarf.FrameDescriptionEntry, di.fde_list.items, context.pc, struct {
1626 pub fn compareFn(pc: usize, item: Dwarf.FrameDescriptionEntry) std.math.Order {1626 pub fn compareFn(pc: usize, item: Dwarf.FrameDescriptionEntry) std.math.Order {
1627 if (pc < item.pc_begin) return .gt;1627 if (pc < item.pc_begin) return .lt;
16281628
1629 const range_end = item.pc_begin + item.pc_range;1629 const range_end = item.pc_begin + item.pc_range;
1630 if (pc < range_end) return .eq;1630 if (pc < range_end) return .eq;
16311631
1632 return .lt;1632 return .gt;
1633 }1633 }
1634 }.compareFn);1634 }.compareFn);
16351635
lib/std/sort.zig+25-27
...@@ -461,8 +461,8 @@ pub fn binarySearch(...@@ -461,8 +461,8 @@ pub fn binarySearch(
461 const mid = low + (high - low) / 2;461 const mid = low + (high - low) / 2;
462 switch (compareFn(context, items[mid])) {462 switch (compareFn(context, items[mid])) {
463 .eq => return mid,463 .eq => return mid,
464 .lt => low = mid + 1, // item too small464 .gt => low = mid + 1,
465 .gt => high = mid, // item too big465 .lt => high = mid,
466 }466 }
467 }467 }
468 return null;468 return null;
...@@ -471,13 +471,13 @@ pub fn binarySearch(...@@ -471,13 +471,13 @@ pub fn binarySearch(
471test binarySearch {471test binarySearch {
472 const S = struct {472 const S = struct {
473 fn orderU32(context: u32, item: u32) std.math.Order {473 fn orderU32(context: u32, item: u32) std.math.Order {
474 return std.math.order(item, context);474 return std.math.order(context, item);
475 }475 }
476 fn orderI32(context: i32, item: i32) std.math.Order {476 fn orderI32(context: i32, item: i32) std.math.Order {
477 return std.math.order(item, context);477 return std.math.order(context, item);
478 }478 }
479 fn orderLength(context: usize, item: []const u8) std.math.Order {479 fn orderLength(context: usize, item: []const u8) std.math.Order {
480 return std.math.order(item.len, context);480 return std.math.order(context, item.len);
481 }481 }
482 };482 };
483 const R = struct {483 const R = struct {
...@@ -489,9 +489,9 @@ test binarySearch {...@@ -489,9 +489,9 @@ test binarySearch {
489 }489 }
490490
491 fn order(context: i32, item: @This()) std.math.Order {491 fn order(context: i32, item: @This()) std.math.Order {
492 if (item.e < context) {492 if (context < item.b) {
493 return .lt;493 return .lt;
494 } else if (item.b > context) {494 } else if (context > item.e) {
495 return .gt;495 return .gt;
496 } else {496 } else {
497 return .eq;497 return .eq;
...@@ -513,9 +513,8 @@ test binarySearch {...@@ -513,9 +513,8 @@ test binarySearch {
513 try std.testing.expectEqual(2, binarySearch([]const u8, &[_][]const u8{ "", "abc", "1234", "vwxyz" }, @as(usize, 4), S.orderLength));513 try std.testing.expectEqual(2, binarySearch([]const u8, &[_][]const u8{ "", "abc", "1234", "vwxyz" }, @as(usize, 4), S.orderLength));
514}514}
515515
516/// Returns the index of the first element in `items` returning `.eq` or `.gt`516/// Returns the index of the first element in `items` that is greater than or equal to `context`,
517/// when given to `compareFn`.517/// as determined by `compareFn`. If no such element exists, returns `items.len`.
518/// - Returns `items.len` if all elements return `.lt`.
519///518///
520/// `items` must be sorted in ascending order with respect to `compareFn`:519/// `items` must be sorted in ascending order with respect to `compareFn`:
521/// ```520/// ```
...@@ -540,7 +539,7 @@ pub fn lowerBound(...@@ -540,7 +539,7 @@ pub fn lowerBound(
540) usize {539) usize {
541 const S = struct {540 const S = struct {
542 fn predicate(ctx: @TypeOf(context), item: T) bool {541 fn predicate(ctx: @TypeOf(context), item: T) bool {
543 return compareFn(ctx, item) == .lt;542 return compareFn(ctx, item).invert() == .lt;
544 }543 }
545 };544 };
546 return partitionPoint(T, items, context, S.predicate);545 return partitionPoint(T, items, context, S.predicate);
...@@ -549,13 +548,13 @@ pub fn lowerBound(...@@ -549,13 +548,13 @@ pub fn lowerBound(
549test lowerBound {548test lowerBound {
550 const S = struct {549 const S = struct {
551 fn compareU32(context: u32, item: u32) std.math.Order {550 fn compareU32(context: u32, item: u32) std.math.Order {
552 return std.math.order(item, context);551 return std.math.order(context, item);
553 }552 }
554 fn compareI32(context: i32, item: i32) std.math.Order {553 fn compareI32(context: i32, item: i32) std.math.Order {
555 return std.math.order(item, context);554 return std.math.order(context, item);
556 }555 }
557 fn compareF32(context: f32, item: f32) std.math.Order {556 fn compareF32(context: f32, item: f32) std.math.Order {
558 return std.math.order(item, context);557 return std.math.order(context, item);
559 }558 }
560 };559 };
561 const R = struct {560 const R = struct {
...@@ -566,7 +565,7 @@ test lowerBound {...@@ -566,7 +565,7 @@ test lowerBound {
566 }565 }
567566
568 fn compareFn(context: i32, item: @This()) std.math.Order {567 fn compareFn(context: i32, item: @This()) std.math.Order {
569 return std.math.order(item.val, context);568 return std.math.order(context, item.val);
570 }569 }
571 };570 };
572571
...@@ -584,9 +583,8 @@ test lowerBound {...@@ -584,9 +583,8 @@ test lowerBound {
584 try std.testing.expectEqual(2, lowerBound(R, &[_]R{ R.r(-100), R.r(-40), R.r(-10), R.r(30) }, @as(i32, -20), R.compareFn));583 try std.testing.expectEqual(2, lowerBound(R, &[_]R{ R.r(-100), R.r(-40), R.r(-10), R.r(30) }, @as(i32, -20), R.compareFn));
585}584}
586585
587/// Returns the index of the first element in `items` returning `.gt`586/// Returns the index of the first element in `items` that is greater than `context`, as determined
588/// when given to `compareFn`.587/// by `compareFn`. If no such element exists, returns `items.len`.
589/// - Returns `items.len` if none of the elements return `.gt`.
590///588///
591/// `items` must be sorted in ascending order with respect to `compareFn`:589/// `items` must be sorted in ascending order with respect to `compareFn`:
592/// ```590/// ```
...@@ -611,7 +609,7 @@ pub fn upperBound(...@@ -611,7 +609,7 @@ pub fn upperBound(
611) usize {609) usize {
612 const S = struct {610 const S = struct {
613 fn predicate(ctx: @TypeOf(context), item: T) bool {611 fn predicate(ctx: @TypeOf(context), item: T) bool {
614 return compareFn(ctx, item) != .gt;612 return compareFn(ctx, item).invert() != .gt;
615 }613 }
616 };614 };
617 return partitionPoint(T, items, context, S.predicate);615 return partitionPoint(T, items, context, S.predicate);
...@@ -620,13 +618,13 @@ pub fn upperBound(...@@ -620,13 +618,13 @@ pub fn upperBound(
620test upperBound {618test upperBound {
621 const S = struct {619 const S = struct {
622 fn compareU32(context: u32, item: u32) std.math.Order {620 fn compareU32(context: u32, item: u32) std.math.Order {
623 return std.math.order(item, context);621 return std.math.order(context, item);
624 }622 }
625 fn compareI32(context: i32, item: i32) std.math.Order {623 fn compareI32(context: i32, item: i32) std.math.Order {
626 return std.math.order(item, context);624 return std.math.order(context, item);
627 }625 }
628 fn compareF32(context: f32, item: f32) std.math.Order {626 fn compareF32(context: f32, item: f32) std.math.Order {
629 return std.math.order(item, context);627 return std.math.order(context, item);
630 }628 }
631 };629 };
632 const R = struct {630 const R = struct {
...@@ -637,7 +635,7 @@ test upperBound {...@@ -637,7 +635,7 @@ test upperBound {
637 }635 }
638636
639 fn compareFn(context: i32, item: @This()) std.math.Order {637 fn compareFn(context: i32, item: @This()) std.math.Order {
640 return std.math.order(item.val, context);638 return std.math.order(context, item.val);
641 }639 }
642 };640 };
643641
...@@ -780,16 +778,16 @@ pub fn equalRange(...@@ -780,16 +778,16 @@ pub fn equalRange(
780test equalRange {778test equalRange {
781 const S = struct {779 const S = struct {
782 fn orderU32(context: u32, item: u32) std.math.Order {780 fn orderU32(context: u32, item: u32) std.math.Order {
783 return std.math.order(item, context);781 return std.math.order(context, item);
784 }782 }
785 fn orderI32(context: i32, item: i32) std.math.Order {783 fn orderI32(context: i32, item: i32) std.math.Order {
786 return std.math.order(item, context);784 return std.math.order(context, item);
787 }785 }
788 fn orderF32(context: f32, item: f32) std.math.Order {786 fn orderF32(context: f32, item: f32) std.math.Order {
789 return std.math.order(item, context);787 return std.math.order(context, item);
790 }788 }
791 fn orderLength(context: usize, item: []const u8) std.math.Order {789 fn orderLength(context: usize, item: []const u8) std.math.Order {
792 return std.math.order(item.len, context);790 return std.math.order(context, item.len);
793 }791 }
794 };792 };
795793