Skip to content

Commit 98dd041

Browse files
brodeuralexisandrewrk
authored andcommitted
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 parent 2737dce commit 98dd041

File tree

1 file changed

+44
-10
lines changed

1 file changed

+44
-10
lines changed

lib/std/sort.zig

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ const math = std.math;
66

77
pub 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

0 commit comments

Comments
 (0)