diff options
| author | Veikka Tuominen <git@vexu.eu> | 2020-12-28 01:13:23 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-28 01:13:23 +0200 |
| commit | 8aab1e2e8ad1451a22a48109006babf463a09e9e (patch) | |
| tree | 2daf9dd81e470b7f13562caa592449097c69c5ec /lib/std | |
| parent | 3fb0288d87b1142bd3d416b0a6df7aa32dd7a943 (diff) | |
| parent | f9506e9155d93c14958f9cd559b855a00bf96e11 (diff) | |
| download | zig-8aab1e2e8ad1451a22a48109006babf463a09e9e.tar.gz zig-8aab1e2e8ad1451a22a48109006babf463a09e9e.zip | |
Merge pull request #7483 from indocomsoft/autohashmap
Make hasUniqueRepresentation false for slices
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/hash/auto_hash.zig | 56 | ||||
| -rw-r--r-- | lib/std/meta/trait.zig | 46 |
2 files changed, 90 insertions, 12 deletions
diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index e42d55a0a9..3d1d491675 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -169,21 +169,38 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { } } +fn typeContainsSlice(comptime K: type) bool { + comptime { + if (meta.trait.isSlice(K)) { + return true; + } + if (meta.trait.is(.Struct)(K)) { + inline for (@typeInfo(K).Struct.fields) |field| { + if (typeContainsSlice(field.field_type)) { + return true; + } + } + } + if (meta.trait.is(.Union)(K)) { + inline for (@typeInfo(K).Union.fields) |field| { + if (typeContainsSlice(field.field_type)) { + return true; + } + } + } + return false; + } +} + /// Provides generic hashing for any eligible type. /// Only hashes `key` itself, pointers are not followed. -/// Slices are rejected to avoid ambiguity on the user's intention. +/// Slices as well as unions and structs containing slices are rejected to avoid +/// ambiguity on the user's intention. pub fn autoHash(hasher: anytype, key: anytype) void { const Key = @TypeOf(key); - if (comptime meta.trait.isSlice(Key)) { - comptime assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated - const extra_help = if (Key == []const u8) - " Consider std.StringHashMap for hashing the contents of []const u8." - else - ""; - - @compileError("std.auto_hash.autoHash does not allow slices (here " ++ @typeName(Key) ++ - ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead." ++ - extra_help); + if (comptime typeContainsSlice(Key)) { + @compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++ + ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); } hash(hasher, key, .Shallow); @@ -220,6 +237,23 @@ fn testHashDeepRecursive(key: anytype) u64 { return hasher.final(); } +test "typeContainsSlice" { + comptime { + testing.expect(!typeContainsSlice(@TagType(std.builtin.TypeInfo))); + + testing.expect(typeContainsSlice([]const u8)); + testing.expect(!typeContainsSlice(u8)); + const A = struct { x: []const u8 }; + const B = struct { a: A }; + const C = struct { b: B }; + const D = struct { x: u8 }; + testing.expect(typeContainsSlice(A)); + testing.expect(typeContainsSlice(B)); + testing.expect(typeContainsSlice(C)); + testing.expect(!typeContainsSlice(D)); + } +} + test "hash pointer" { const array = [_]u32{ 123, 123, 123 }; const a = &array[0]; diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index ae3b77b8cc..180e0b8664 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -480,7 +480,6 @@ pub fn hasUniqueRepresentation(comptime T: type) bool { .Enum, .ErrorSet, .Fn, - .Pointer, => return true, .Bool => return false, @@ -489,6 +488,8 @@ pub fn hasUniqueRepresentation(comptime T: type) bool { .Int => |info| return (info.bits % 8) == 0 and (info.bits == 0 or std.math.isPowerOfTwo(info.bits)), + .Pointer => |info| return info.size != .Slice, + .Array => |info| return comptime hasUniqueRepresentation(info.child), .Struct => |info| { @@ -529,10 +530,53 @@ test "std.meta.trait.hasUniqueRepresentation" { testing.expect(hasUniqueRepresentation(TestStruct3)); + const TestStruct4 = struct { + a: []const u8 + }; + + testing.expect(!hasUniqueRepresentation(TestStruct4)); + + const TestStruct5 = struct { + a: TestStruct4 + }; + + testing.expect(!hasUniqueRepresentation(TestStruct5)); + + const TestUnion1 = packed union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion1)); + + const TestUnion2 = extern union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion2)); + + const TestUnion3 = union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion3)); + + const TestUnion4 = union(enum) { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion4)); + inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| { testing.expect(hasUniqueRepresentation(T)); } inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| { testing.expect(!hasUniqueRepresentation(T)); } + + testing.expect(!hasUniqueRepresentation([]u8)); + testing.expect(!hasUniqueRepresentation([]const u8)); } |
