authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-22 15:10:34-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-22 15:10:51-08:00
loga3342cea188e1c006b20dd2e4712398f9e8c7fdd
tree49450a37ecbe9df4bbe0da4ba471425358e31dc2
parent73dcd1914071984c5a2e7c195212404824dbfb9e

std.mem.eql: make comparisons for zero-sized and non-sized types work

The `if (@sizeOf(T) == 0) return true;` check simply doesn't work for a number of cases so that is removed and changed into `@sizeOf(T) != 0` and then used in the `eqlBytes` check chain to make comparing `enum{}`s possible. The rest special-cases for comptime-only types and undefined to make those comparisons possible as well. Fixes #19929

1 files changed, 32 insertions(+), 1 deletions(-)

lib/std/mem.zig+32-1
...@@ -656,7 +656,18 @@ const eqlBytes_allowed = switch (builtin.zig_backend) {...@@ -656,7 +656,18 @@ const eqlBytes_allowed = switch (builtin.zig_backend) {
656656
657/// Compares two slices and returns whether they are equal.657/// Compares two slices and returns whether they are equal.
658pub fn eql(comptime T: type, a: []const T, b: []const T) bool {658pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
659 if (@sizeOf(T) == 0) return true;659 switch (@typeInfo(T)) {
660 .Type, .ComptimeInt, .ComptimeFloat => {
661 if (a.len != b.len) return false;
662 inline for (a, b) |a_elem, b_elem| {
663 if (a_elem != b_elem) return false;
664 }
665 return true;
666 },
667 .Null, .Undefined => return a.len == b.len,
668 else => {},
669 }
670 if (@sizeOf(T) == 0) return a.len == b.len;
660 if (!@inComptime() and std.meta.hasUniqueRepresentation(T) and eqlBytes_allowed) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));671 if (!@inComptime() and std.meta.hasUniqueRepresentation(T) and eqlBytes_allowed) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));
661672
662 if (a.len != b.len) return false;673 if (a.len != b.len) return false;
...@@ -3296,6 +3307,26 @@ test eql {...@@ -3296,6 +3307,26 @@ test eql {
3296 try testing.expect(eql(u8, "abcd", "abcd"));3307 try testing.expect(eql(u8, "abcd", "abcd"));
3297 try testing.expect(!eql(u8, "abcdef", "abZdef"));3308 try testing.expect(!eql(u8, "abcdef", "abZdef"));
3298 try testing.expect(!eql(u8, "abcdefg", "abcdef"));3309 try testing.expect(!eql(u8, "abcdefg", "abcdef"));
3310
3311 try testing.expect(eql(type, &.{ bool, f32 }, &.{ bool, f32 }));
3312 try testing.expect(!eql(type, &.{ bool, f32 }, &.{ f32, bool }));
3313 try testing.expect(!eql(type, &.{ bool, f32 }, &.{bool}));
3314
3315 try testing.expect(eql(comptime_int, &.{ 1, 2, 3 }, &.{ 1, 2, 3 }));
3316 try testing.expect(!eql(comptime_int, &.{ 1, 2, 3 }, &.{ 3, 2, 1 }));
3317 try testing.expect(!eql(comptime_int, &.{1}, &.{ 1, 2 }));
3318
3319 try testing.expect(eql(@TypeOf(undefined), &.{ undefined, undefined }, &.{ undefined, undefined }));
3320 try testing.expect(!eql(@TypeOf(undefined), &.{undefined}, &.{ undefined, undefined }));
3321
3322 try testing.expect(eql(enum {}, &.{ undefined, undefined }, &.{ undefined, undefined }));
3323 try testing.expect(!eql(enum {}, &.{undefined}, &.{ undefined, undefined }));
3324
3325 try testing.expect(eql(void, &.{ {}, {} }, &.{ {}, {} }));
3326 try testing.expect(!eql(void, &.{{}}, &.{ {}, {} }));
3327
3328 try testing.expect(eql(@TypeOf(null), &.{ null, null }, &.{ null, null }));
3329 try testing.expect(!eql(@TypeOf(null), &.{null}, &.{ null, null }));
3299}3330}
33003331
3301fn moreReadIntTests() !void {3332fn moreReadIntTests() !void {