| ... | ... | @@ -169,21 +169,38 @@ 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 | 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 | |
| 172 | 195 | /// Provides generic hashing for any eligible type. |
| 173 | 196 | /// 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. |
| 175 | 199 | pub fn autoHash(hasher: anytype, key: anytype) void { |
| 176 | 200 | 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."); |
| 187 | 204 | } |
| 188 | 205 | |
| 189 | 206 | hash(hasher, key, .Shallow); |
| ... | ... | @@ -220,6 +237,23 @@ fn testHashDeepRecursive(key: anytype) u64 { |
| 220 | 237 | return hasher.final(); |
| 221 | 238 | } |
| 222 | 239 | |
| 240 | test "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 | |
| 223 | 257 | test "hash pointer" { |
| 224 | 258 | const array = [_]u32{ 123, 123, 123 }; |
| 225 | 259 | const a = &array[0]; |