std: Skip element comparisons if mem.order args point to same memory

This optimization is used in `mem.eql`, but was missing from `order`,
`orderZ`, and `ascii.orderIgnoreCase`.
This commit is contained in:
Jay Petacat 2025-10-31 12:31:57 -06:00 committed by Ryan Liptak
parent 8468549726
commit 5a38dd28dc
2 changed files with 25 additions and 13 deletions

View File

@ -420,6 +420,7 @@ test indexOfIgnoreCase {
/// Returns the lexicographical order of two slices. O(n). /// Returns the lexicographical order of two slices. O(n).
pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order { pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {
if (lhs.ptr != rhs.ptr) {
const n = @min(lhs.len, rhs.len); const n = @min(lhs.len, rhs.len);
var i: usize = 0; var i: usize = 0;
while (i < n) : (i += 1) { while (i < n) : (i += 1) {
@ -429,6 +430,7 @@ pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {
.gt => return .gt, .gt => return .gt,
} }
} }
}
return std.math.order(lhs.len, rhs.len); return std.math.order(lhs.len, rhs.len);
} }

View File

@ -647,6 +647,7 @@ pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {
/// Compares two slices of numbers lexicographically. O(n). /// Compares two slices of numbers lexicographically. O(n).
pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order { pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
if (lhs.ptr != rhs.ptr) {
const n = @min(lhs.len, rhs.len); const n = @min(lhs.len, rhs.len);
for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| { for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| {
switch (math.order(lhs_elem, rhs_elem)) { switch (math.order(lhs_elem, rhs_elem)) {
@ -655,11 +656,13 @@ pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
.gt => return .gt, .gt => return .gt,
} }
} }
}
return math.order(lhs.len, rhs.len); return math.order(lhs.len, rhs.len);
} }
/// Compares two many-item pointers with NUL-termination lexicographically. /// Compares two many-item pointers with NUL-termination lexicographically.
pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order { pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {
if (lhs == rhs) return .eq;
var i: usize = 0; var i: usize = 0;
while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {} while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {}
return math.order(lhs[i], rhs[i]); return math.order(lhs[i], rhs[i]);
@ -671,6 +674,10 @@ test order {
try testing.expect(order(u8, "abc", "abc0") == .lt); try testing.expect(order(u8, "abc", "abc0") == .lt);
try testing.expect(order(u8, "", "") == .eq); try testing.expect(order(u8, "", "") == .eq);
try testing.expect(order(u8, "", "a") == .lt); try testing.expect(order(u8, "", "a") == .lt);
const s: []const u8 = "abc";
try testing.expect(order(u8, s, s) == .eq);
try testing.expect(order(u8, s[0..2], s) == .lt);
} }
test orderZ { test orderZ {
@ -679,6 +686,9 @@ test orderZ {
try testing.expect(orderZ(u8, "abc", "abc0") == .lt); try testing.expect(orderZ(u8, "abc", "abc0") == .lt);
try testing.expect(orderZ(u8, "", "") == .eq); try testing.expect(orderZ(u8, "", "") == .eq);
try testing.expect(orderZ(u8, "", "a") == .lt); try testing.expect(orderZ(u8, "", "a") == .lt);
const s: [*:0]const u8 = "abc";
try testing.expect(orderZ(u8, s, s) == .eq);
} }
/// Returns true if lhs < rhs, false otherwise /// Returns true if lhs < rhs, false otherwise