From 4e380b89b889912865f4de3cb0ee6b50f35d9605 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 22 Nov 2024 15:30:07 -0800 Subject: [PATCH] std.mem: adjust semantics * some kinds of types require comptime calls to eql * don't rely on compare equal for undefined --- lib/std/mem.zig | 64 +++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 53b7d29567..1f1e925f54 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -654,21 +654,14 @@ const eqlBytes_allowed = switch (builtin.zig_backend) { else => !builtin.fuzz, }; -/// Compares two slices and returns whether they are equal. +/// Returns true if and only if the slices have the same length and all elements +/// compare true using equality operator. pub fn eql(comptime T: type, a: []const T, b: []const T) bool { - switch (@typeInfo(T)) { - .Type, .ComptimeInt, .ComptimeFloat => { - if (a.len != b.len) return false; - inline for (a, b) |a_elem, b_elem| { - if (a_elem != b_elem) return false; - } - return true; - }, - .Null, .Undefined => return a.len == b.len, - else => {}, + if (!@inComptime() and @sizeOf(T) != 0 and std.meta.hasUniqueRepresentation(T) and + eqlBytes_allowed) + { + return eqlBytes(sliceAsBytes(a), sliceAsBytes(b)); } - if (@sizeOf(T) == 0) return a.len == b.len; - if (!@inComptime() and std.meta.hasUniqueRepresentation(T) and eqlBytes_allowed) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b)); if (a.len != b.len) return false; if (a.len == 0 or a.ptr == b.ptr) return true; @@ -679,6 +672,25 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { return true; } +test eql { + try testing.expect(eql(u8, "abcd", "abcd")); + try testing.expect(!eql(u8, "abcdef", "abZdef")); + try testing.expect(!eql(u8, "abcdefg", "abcdef")); + + comptime { + try testing.expect(eql(type, &.{ bool, f32 }, &.{ bool, f32 })); + try testing.expect(!eql(type, &.{ bool, f32 }, &.{ f32, bool })); + try testing.expect(!eql(type, &.{ bool, f32 }, &.{bool})); + + try testing.expect(eql(comptime_int, &.{ 1, 2, 3 }, &.{ 1, 2, 3 })); + try testing.expect(!eql(comptime_int, &.{ 1, 2, 3 }, &.{ 3, 2, 1 })); + try testing.expect(!eql(comptime_int, &.{1}, &.{ 1, 2 })); + } + + try testing.expect(eql(void, &.{ {}, {} }, &.{ {}, {} })); + try testing.expect(!eql(void, &.{{}}, &.{ {}, {} })); +} + /// std.mem.eql heavily optimized for slices of bytes. fn eqlBytes(a: []const u8, b: []const u8) bool { comptime assert(eqlBytes_allowed); @@ -3303,32 +3315,6 @@ test concat { } } -test eql { - try testing.expect(eql(u8, "abcd", "abcd")); - try testing.expect(!eql(u8, "abcdef", "abZdef")); - try testing.expect(!eql(u8, "abcdefg", "abcdef")); - - try testing.expect(eql(type, &.{ bool, f32 }, &.{ bool, f32 })); - try testing.expect(!eql(type, &.{ bool, f32 }, &.{ f32, bool })); - try testing.expect(!eql(type, &.{ bool, f32 }, &.{bool})); - - try testing.expect(eql(comptime_int, &.{ 1, 2, 3 }, &.{ 1, 2, 3 })); - try testing.expect(!eql(comptime_int, &.{ 1, 2, 3 }, &.{ 3, 2, 1 })); - try testing.expect(!eql(comptime_int, &.{1}, &.{ 1, 2 })); - - try testing.expect(eql(@TypeOf(undefined), &.{ undefined, undefined }, &.{ undefined, undefined })); - try testing.expect(!eql(@TypeOf(undefined), &.{undefined}, &.{ undefined, undefined })); - - try testing.expect(eql(enum {}, &.{ undefined, undefined }, &.{ undefined, undefined })); - try testing.expect(!eql(enum {}, &.{undefined}, &.{ undefined, undefined })); - - try testing.expect(eql(void, &.{ {}, {} }, &.{ {}, {} })); - try testing.expect(!eql(void, &.{{}}, &.{ {}, {} })); - - try testing.expect(eql(@TypeOf(null), &.{ null, null }, &.{ null, null })); - try testing.expect(!eql(@TypeOf(null), &.{null}, &.{ null, null })); -} - fn moreReadIntTests() !void { { const bytes = [_]u8{