authorgravatar for jay@jayschwa.netJay Petacat <jay@jayschwa.net> 2025-10-31 12:31:57-06:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-10-31 18:34:33-07:00
log5a38dd28dc6eb7fe1acb7bb94710ab1a99a13565
tree8112bc5794cb642c91e91cc95db3234eb679af1f
parent84685497268c0e7dcf11ad8c7aae067ef37a0ab7

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`.

2 files changed, 25 insertions(+), 13 deletions(-)

lib/std/ascii.zig+9-7
...@@ -420,13 +420,15 @@ test indexOfIgnoreCase {...@@ -420,13 +420,15 @@ test indexOfIgnoreCase {
420420
421/// Returns the lexicographical order of two slices. O(n).421/// Returns the lexicographical order of two slices. O(n).
422pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {422pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {
423 const n = @min(lhs.len, rhs.len);423 if (lhs.ptr != rhs.ptr) {
424 var i: usize = 0;424 const n = @min(lhs.len, rhs.len);
425 while (i < n) : (i += 1) {425 var i: usize = 0;
426 switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) {426 while (i < n) : (i += 1) {
427 .eq => continue,427 switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) {
428 .lt => return .lt,428 .eq => continue,
429 .gt => return .gt,429 .lt => return .lt,
430 .gt => return .gt,
431 }
430 }432 }
431 }433 }
432 return std.math.order(lhs.len, rhs.len);434 return std.math.order(lhs.len, rhs.len);
lib/std/mem.zig+16-6
...@@ -647,12 +647,14 @@ pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {...@@ -647,12 +647,14 @@ pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {
647647
648/// Compares two slices of numbers lexicographically. O(n).648/// Compares two slices of numbers lexicographically. O(n).
649pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {649pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
650 const n = @min(lhs.len, rhs.len);650 if (lhs.ptr != rhs.ptr) {
651 for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| {651 const n = @min(lhs.len, rhs.len);
652 switch (math.order(lhs_elem, rhs_elem)) {652 for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| {
653 .eq => continue,653 switch (math.order(lhs_elem, rhs_elem)) {
654 .lt => return .lt,654 .eq => continue,
655 .gt => return .gt,655 .lt => return .lt,
656 .gt => return .gt,
657 }
656 }658 }
657 }659 }
658 return math.order(lhs.len, rhs.len);660 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 {...@@ -660,6 +662,7 @@ pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
660662
661/// Compares two many-item pointers with NUL-termination lexicographically.663/// Compares two many-item pointers with NUL-termination lexicographically.
662pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {664pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {
665 if (lhs == rhs) return .eq;
663 var i: usize = 0;666 var i: usize = 0;
664 while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {}667 while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {}
665 return math.order(lhs[i], rhs[i]);668 return math.order(lhs[i], rhs[i]);
...@@ -671,6 +674,10 @@ test order {...@@ -671,6 +674,10 @@ test order {
671 try testing.expect(order(u8, "abc", "abc0") == .lt);674 try testing.expect(order(u8, "abc", "abc0") == .lt);
672 try testing.expect(order(u8, "", "") == .eq);675 try testing.expect(order(u8, "", "") == .eq);
673 try testing.expect(order(u8, "", "a") == .lt);676 try testing.expect(order(u8, "", "a") == .lt);
677
678 const s: []const u8 = "abc";
679 try testing.expect(order(u8, s, s) == .eq);
680 try testing.expect(order(u8, s[0..2], s) == .lt);
674}681}
675682
676test orderZ {683test orderZ {
...@@ -679,6 +686,9 @@ test orderZ {...@@ -679,6 +686,9 @@ test orderZ {
679 try testing.expect(orderZ(u8, "abc", "abc0") == .lt);686 try testing.expect(orderZ(u8, "abc", "abc0") == .lt);
680 try testing.expect(orderZ(u8, "", "") == .eq);687 try testing.expect(orderZ(u8, "", "") == .eq);
681 try testing.expect(orderZ(u8, "", "a") == .lt);688 try testing.expect(orderZ(u8, "", "a") == .lt);
689
690 const s: [*:0]const u8 = "abc";
691 try testing.expect(orderZ(u8, s, s) == .eq);
682}692}
683693
684/// Returns true if lhs < rhs, false otherwise694/// Returns true if lhs < rhs, false otherwise