authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-12-28 01:13:23+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-12-28 01:13:23+02:00
log8aab1e2e8ad1451a22a48109006babf463a09e9e
tree2daf9dd81e470b7f13562caa592449097c69c5ec
parent3fb0288d87b1142bd3d416b0a6df7aa32dd7a943
parentf9506e9155d93c14958f9cd559b855a00bf96e11
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7483 from indocomsoft/autohashmap

Make hasUniqueRepresentation false for slices

2 files changed, 90 insertions(+), 12 deletions(-)

lib/std/hash/auto_hash.zig+45-11
......@@ -169,21 +169,38 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
169169 }
170170}
171171
172fn typeContainsSlice(comptime K: type) bool {
173 comptime {
174 if (meta.trait.isSlice(K)) {
175 return true;
176 }
177 if (meta.trait.is(.Struct)(K)) {
178 inline for (@typeInfo(K).Struct.fields) |field| {
179 if (typeContainsSlice(field.field_type)) {
180 return true;
181 }
182 }
183 }
184 if (meta.trait.is(.Union)(K)) {
185 inline for (@typeInfo(K).Union.fields) |field| {
186 if (typeContainsSlice(field.field_type)) {
187 return true;
188 }
189 }
190 }
191 return false;
192 }
193}
194
172195/// Provides generic hashing for any eligible type.
173196/// Only hashes `key` itself, pointers are not followed.
174/// Slices are rejected to avoid ambiguity on the user's intention.
197/// Slices as well as unions and structs containing slices are rejected to avoid
198/// ambiguity on the user's intention.
175199pub fn autoHash(hasher: anytype, key: anytype) void {
176200 const Key = @TypeOf(key);
177 if (comptime meta.trait.isSlice(Key)) {
178 comptime assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated
179 const extra_help = if (Key == []const u8)
180 " Consider std.StringHashMap for hashing the contents of []const u8."
181 else
182 "";
183
184 @compileError("std.auto_hash.autoHash does not allow slices (here " ++ @typeName(Key) ++
185 ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead." ++
186 extra_help);
201 if (comptime typeContainsSlice(Key)) {
202 @compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++
203 ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead.");
187204 }
188205
189206 hash(hasher, key, .Shallow);
......@@ -220,6 +237,23 @@ fn testHashDeepRecursive(key: anytype) u64 {
220237 return hasher.final();
221238}
222239
240test "typeContainsSlice" {
241 comptime {
242 testing.expect(!typeContainsSlice(@TagType(std.builtin.TypeInfo)));
243
244 testing.expect(typeContainsSlice([]const u8));
245 testing.expect(!typeContainsSlice(u8));
246 const A = struct { x: []const u8 };
247 const B = struct { a: A };
248 const C = struct { b: B };
249 const D = struct { x: u8 };
250 testing.expect(typeContainsSlice(A));
251 testing.expect(typeContainsSlice(B));
252 testing.expect(typeContainsSlice(C));
253 testing.expect(!typeContainsSlice(D));
254 }
255}
256
223257test "hash pointer" {
224258 const array = [_]u32{ 123, 123, 123 };
225259 const a = &array[0];
lib/std/meta/trait.zig+45-1
......@@ -480,7 +480,6 @@ pub fn hasUniqueRepresentation(comptime T: type) bool {
480480 .Enum,
481481 .ErrorSet,
482482 .Fn,
483 .Pointer,
484483 => return true,
485484
486485 .Bool => return false,
......@@ -489,6 +488,8 @@ pub fn hasUniqueRepresentation(comptime T: type) bool {
489488 .Int => |info| return (info.bits % 8) == 0 and
490489 (info.bits == 0 or std.math.isPowerOfTwo(info.bits)),
491490
491 .Pointer => |info| return info.size != .Slice,
492
492493 .Array => |info| return comptime hasUniqueRepresentation(info.child),
493494
494495 .Struct => |info| {
......@@ -529,10 +530,53 @@ test "std.meta.trait.hasUniqueRepresentation" {
529530
530531 testing.expect(hasUniqueRepresentation(TestStruct3));
531532
533 const TestStruct4 = struct {
534 a: []const u8
535 };
536
537 testing.expect(!hasUniqueRepresentation(TestStruct4));
538
539 const TestStruct5 = struct {
540 a: TestStruct4
541 };
542
543 testing.expect(!hasUniqueRepresentation(TestStruct5));
544
545 const TestUnion1 = packed union {
546 a: u32,
547 b: u16,
548 };
549
550 testing.expect(!hasUniqueRepresentation(TestUnion1));
551
552 const TestUnion2 = extern union {
553 a: u32,
554 b: u16,
555 };
556
557 testing.expect(!hasUniqueRepresentation(TestUnion2));
558
559 const TestUnion3 = union {
560 a: u32,
561 b: u16,
562 };
563
564 testing.expect(!hasUniqueRepresentation(TestUnion3));
565
566 const TestUnion4 = union(enum) {
567 a: u32,
568 b: u16,
569 };
570
571 testing.expect(!hasUniqueRepresentation(TestUnion4));
572
532573 inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
533574 testing.expect(hasUniqueRepresentation(T));
534575 }
535576 inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
536577 testing.expect(!hasUniqueRepresentation(T));
537578 }
579
580 testing.expect(!hasUniqueRepresentation([]u8));
581 testing.expect(!hasUniqueRepresentation([]const u8));
538582}