| ... | @@ -169,21 +169,31 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -169,21 +169,31 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 169 | } | 169 | } |
| 170 | } | 170 | } |
| 171 | | 171 | |
| | 172 | fn 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 | return false; |
| | 185 | } |
| | 186 | } |
| | 187 | |
| 172 | /// Provides generic hashing for any eligible type. | 188 | /// Provides generic hashing for any eligible type. |
| 173 | /// Only hashes `key` itself, pointers are not followed. | 189 | /// Only hashes `key` itself, pointers are not followed. |
| 174 | /// Slices are rejected to avoid ambiguity on the user's intention. | 190 | /// Slices and structs containing slices are rejected to avoid ambiguity on the |
| | 191 | /// user's intention. |
| 175 | pub fn autoHash(hasher: anytype, key: anytype) void { | 192 | pub fn autoHash(hasher: anytype, key: anytype) void { |
| 176 | const Key = @TypeOf(key); | 193 | const Key = @TypeOf(key); |
| 177 | if (comptime meta.trait.isSlice(Key)) { | 194 | if (comptime typeContainsSlice(Key)) { |
| 178 | comptime assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated | 195 | @compileError("std.auto_hash.autoHash does not allow slices or structs containing slices here (" ++ @typeName(Key) ++ |
| 179 | const extra_help = if (Key == []const u8) | 196 | ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); |
| 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); | | |
| 187 | } | 197 | } |
| 188 | | 198 | |
| 189 | hash(hasher, key, .Shallow); | 199 | hash(hasher, key, .Shallow); |
| ... | @@ -220,6 +230,23 @@ fn testHashDeepRecursive(key: anytype) u64 { | ... | @@ -220,6 +230,23 @@ fn testHashDeepRecursive(key: anytype) u64 { |
| 220 | return hasher.final(); | 230 | return hasher.final(); |
| 221 | } | 231 | } |
| 222 | | 232 | |
| | 233 | test "typeContainsSlice" { |
| | 234 | comptime { |
| | 235 | testing.expect(!typeContainsSlice(@TagType(std.builtin.TypeInfo))); |
| | 236 | |
| | 237 | testing.expect(typeContainsSlice([]const u8)); |
| | 238 | testing.expect(!typeContainsSlice(u8)); |
| | 239 | const A = struct { x: []const u8 }; |
| | 240 | const B = struct { a: A }; |
| | 241 | const C = struct { b: B }; |
| | 242 | const D = struct { x: u8 }; |
| | 243 | testing.expect(typeContainsSlice(A)); |
| | 244 | testing.expect(typeContainsSlice(B)); |
| | 245 | testing.expect(typeContainsSlice(C)); |
| | 246 | testing.expect(!typeContainsSlice(D)); |
| | 247 | } |
| | 248 | } |
| | 249 | |
| 223 | test "hash pointer" { | 250 | test "hash pointer" { |
| 224 | const array = [_]u32{ 123, 123, 123 }; | 251 | const array = [_]u32{ 123, 123, 123 }; |
| 225 | const a = &array[0]; | 252 | const a = &array[0]; |