authorgravatar for brodeuralexis@gmail.comAlexis Brodeur <brodeuralexis@gmail.com> 2022-09-02 20:56:36-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-21 12:28:43-05:00
log98dd041d536aad1d4936353b4f5e4a2e0aab0fe1
tree62e966ccc6156110737c9552b33648993c339d97
parent2737dce84f99a05af51b66fc12794b43dc10fa41

Relax `std.sort.binarySearch` requirements

Forcing the key to be of the same type as the sorted items used during the search is a valid use case. There, however, exists some cases where the key and the items are of heterogeneous types, like searching for a code point in ordered ranges of code points: ```zig const CodePoint = u21; const CodePointRange = [2]CodePoint; const valid_ranges = &[_]CodePointRange{ // an ordered array of ranges }; fn orderCodePointAndRange( context: void, code_point: CodePoint, range: CodePointRange ) std.math.Order { _ = context; if (code_point < range[0]) { return .lt; } if (code_point > range[1]) { return .gt; } return .eq; } fn isValidCodePoint(code_point: CodePoint) bool { return std.sort.binarySearch( CodePointRange, code_point, valid_ranges, void, orderCodePointAndRange ) != null; } ``` It is so expected that `std.sort.binarySearch` should therefore support both homogeneous and heterogeneous keys.

1 files changed, 44 insertions(+), 10 deletions(-)

lib/std/sort.zig+44-10
......@@ -6,10 +6,10 @@ const math = std.math;
66
77pub fn binarySearch(
88 comptime T: type,
9 key: T,
9 key: anytype,
1010 items: []const T,
1111 context: anytype,
12 comptime compareFn: fn (context: @TypeOf(context), lhs: T, rhs: T) math.Order,
12 comptime compareFn: fn (context: @TypeOf(context), key: @TypeOf(key), mid: T) math.Order,
1313) ?usize {
1414 var left: usize = 0;
1515 var right: usize = items.len;
......@@ -41,35 +41,69 @@ test "binarySearch" {
4141 };
4242 try testing.expectEqual(
4343 @as(?usize, null),
44 binarySearch(u32, 1, &[_]u32{}, {}, S.order_u32),
44 binarySearch(u32, @as(u32, 1), &[_]u32{}, {}, S.order_u32),
4545 );
4646 try testing.expectEqual(
4747 @as(?usize, 0),
48 binarySearch(u32, 1, &[_]u32{1}, {}, S.order_u32),
48 binarySearch(u32, @as(u32, 1), &[_]u32{1}, {}, S.order_u32),
4949 );
5050 try testing.expectEqual(
5151 @as(?usize, null),
52 binarySearch(u32, 1, &[_]u32{0}, {}, S.order_u32),
52 binarySearch(u32, @as(u32, 1), &[_]u32{0}, {}, S.order_u32),
5353 );
5454 try testing.expectEqual(
5555 @as(?usize, null),
56 binarySearch(u32, 0, &[_]u32{1}, {}, S.order_u32),
56 binarySearch(u32, @as(u32, 0), &[_]u32{1}, {}, S.order_u32),
5757 );
5858 try testing.expectEqual(
5959 @as(?usize, 4),
60 binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32),
60 binarySearch(u32, @as(u32, 5), &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32),
6161 );
6262 try testing.expectEqual(
6363 @as(?usize, 0),
64 binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32),
64 binarySearch(u32, @as(u32, 2), &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32),
6565 );
6666 try testing.expectEqual(
6767 @as(?usize, 1),
68 binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32),
68 binarySearch(i32, @as(i32, -4), &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32),
6969 );
7070 try testing.expectEqual(
7171 @as(?usize, 3),
72 binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32),
72 binarySearch(i32, @as(i32, 98), &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32),
73 );
74 const R = struct {
75 b: i32,
76 e: i32,
77
78 fn r(b: i32, e: i32) @This() {
79 return @This(){ .b = b, .e = e };
80 }
81
82 fn order(context: void, key: i32, mid: @This()) math.Order {
83 _ = context;
84
85 if (key < mid.b) {
86 return .lt;
87 }
88
89 if (key > mid.e) {
90 return .gt;
91 }
92
93 return .eq;
94 }
95 };
96 try testing.expectEqual(
97 @as(?usize, null),
98 binarySearch(R, @as(i32, -45), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
99 );
100 try testing.expectEqual(
101 @as(?usize, 2),
102 binarySearch(R, @as(i32, 10), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
103 );
104 try testing.expectEqual(
105 @as(?usize, 1),
106 binarySearch(R, @as(i32, -20), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
73107 );
74108}
75109