From 5a38dd28dc6eb7fe1acb7bb94710ab1a99a13565 Mon Sep 17 00:00:00 2001 From: Jay Petacat Date: Fri, 31 Oct 2025 12:31:57 -0600 Subject: [PATCH] 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`. --- lib/std/ascii.zig | 16 +++++++++------- lib/std/mem.zig | 22 ++++++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/std/ascii.zig b/lib/std/ascii.zig index 48116a7230..f9b3ca9878 100644 --- a/lib/std/ascii.zig +++ b/lib/std/ascii.zig @@ -420,13 +420,15 @@ test indexOfIgnoreCase { /// Returns the lexicographical order of two slices. O(n). pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order { - const n = @min(lhs.len, rhs.len); - var i: usize = 0; - while (i < n) : (i += 1) { - switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) { - .eq => continue, - .lt => return .lt, - .gt => return .gt, + if (lhs.ptr != rhs.ptr) { + const n = @min(lhs.len, rhs.len); + var i: usize = 0; + while (i < n) : (i += 1) { + switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) { + .eq => continue, + .lt => return .lt, + .gt => return .gt, + } } } return std.math.order(lhs.len, rhs.len); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index ade7d1e777..01dbac73a0 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -647,12 +647,14 @@ pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void { /// Compares two slices of numbers lexicographically. O(n). pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order { - const n = @min(lhs.len, rhs.len); - for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| { - switch (math.order(lhs_elem, rhs_elem)) { - .eq => continue, - .lt => return .lt, - .gt => return .gt, + if (lhs.ptr != rhs.ptr) { + const n = @min(lhs.len, rhs.len); + for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| { + switch (math.order(lhs_elem, rhs_elem)) { + .eq => continue, + .lt => return .lt, + .gt => return .gt, + } } } return math.order(lhs.len, rhs.len); @@ -660,6 +662,7 @@ pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order { /// 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 { + if (lhs == rhs) return .eq; var i: usize = 0; while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {} 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, "", "") == .eq); 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 { @@ -679,6 +686,9 @@ test orderZ { try testing.expect(orderZ(u8, "abc", "abc0") == .lt); try testing.expect(orderZ(u8, "", "") == .eq); 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