| ... | ... | @@ -56,9 +56,6 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy) |
| 56 | 56 | pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 57 | 57 | switch (strat) { |
| 58 | 58 | .Shallow => { |
| 59 | | // TODO detect via a trait when Key has no padding bits to |
| 60 | | // hash it as an array of bytes. |
| 61 | | // Otherwise, hash every element. |
| 62 | 59 | for (key) |element| { |
| 63 | 60 | hash(hasher, element, .Shallow); |
| 64 | 61 | } |
| ... | ... | @@ -75,30 +72,34 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo |
| 75 | 72 | /// Strategy is provided to determine if pointers should be followed or not. |
| 76 | 73 | pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 77 | 74 | const Key = @TypeOf(key); |
| 75 | |
| 76 | if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) { |
| 77 | @call(.{ .modifier = .always_inline }, hasher.update, .{mem.asBytes(&key)}); |
| 78 | return; |
| 79 | } |
| 80 | |
| 78 | 81 | switch (@typeInfo(Key)) { |
| 79 | 82 | .NoReturn, |
| 80 | 83 | .Opaque, |
| 81 | 84 | .Undefined, |
| 82 | 85 | .Void, |
| 83 | 86 | .Null, |
| 84 | | .BoundFn, |
| 85 | 87 | .ComptimeFloat, |
| 86 | 88 | .ComptimeInt, |
| 87 | 89 | .Type, |
| 88 | 90 | .EnumLiteral, |
| 89 | 91 | .Frame, |
| 92 | .Float, |
| 90 | 93 | => @compileError("cannot hash this type"), |
| 91 | 94 | |
| 92 | 95 | // Help the optimizer see that hashing an int is easy by inlining! |
| 93 | 96 | // TODO Check if the situation is better after #561 is resolved. |
| 94 | 97 | .Int => @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)}), |
| 95 | 98 | |
| 96 | | .Float => |info| hash(hasher, @bitCast(std.meta.Int(false, info.bits), key), strat), |
| 97 | | |
| 98 | 99 | .Bool => hash(hasher, @boolToInt(key), strat), |
| 99 | 100 | .Enum => hash(hasher, @enumToInt(key), strat), |
| 100 | 101 | .ErrorSet => hash(hasher, @errorToInt(key), strat), |
| 101 | | .AnyFrame, .Fn => hash(hasher, @ptrToInt(key), strat), |
| 102 | .AnyFrame, .BoundFn, .Fn => hash(hasher, @ptrToInt(key), strat), |
| 102 | 103 | |
| 103 | 104 | .Pointer => @call(.{ .modifier = .always_inline }, hashPointer, .{ hasher, key, strat }), |
| 104 | 105 | |
| ... | ... | @@ -121,9 +122,6 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 121 | 122 | }, |
| 122 | 123 | |
| 123 | 124 | .Struct => |info| { |
| 124 | | // TODO detect via a trait when Key has no padding bits to |
| 125 | | // hash it as an array of bytes. |
| 126 | | // Otherwise, hash every field. |
| 127 | 125 | inline for (info.fields) |field| { |
| 128 | 126 | // We reuse the hash of the previous field as the seed for the |
| 129 | 127 | // next one so that they're dependant. |
| ... | ... | @@ -266,12 +264,12 @@ test "hash slice deep" { |
| 266 | 264 | test "hash struct deep" { |
| 267 | 265 | const Foo = struct { |
| 268 | 266 | a: u32, |
| 269 | | b: f64, |
| 267 | b: u16, |
| 270 | 268 | c: *bool, |
| 271 | 269 | |
| 272 | 270 | const Self = @This(); |
| 273 | 271 | |
| 274 | | pub fn init(allocator: *mem.Allocator, a_: u32, b_: f64, c_: bool) !Self { |
| 272 | pub fn init(allocator: *mem.Allocator, a_: u32, b_: u16, c_: bool) !Self { |
| 275 | 273 | const ptr = try allocator.create(bool); |
| 276 | 274 | ptr.* = c_; |
| 277 | 275 | return Self{ .a = a_, .b = b_, .c = ptr }; |
| ... | ... | @@ -279,9 +277,9 @@ test "hash struct deep" { |
| 279 | 277 | }; |
| 280 | 278 | |
| 281 | 279 | const allocator = std.testing.allocator; |
| 282 | | const foo = try Foo.init(allocator, 123, 1.0, true); |
| 283 | | const bar = try Foo.init(allocator, 123, 1.0, true); |
| 284 | | const baz = try Foo.init(allocator, 123, 1.0, false); |
| 280 | const foo = try Foo.init(allocator, 123, 10, true); |
| 281 | const bar = try Foo.init(allocator, 123, 10, true); |
| 282 | const baz = try Foo.init(allocator, 123, 10, false); |
| 285 | 283 | defer allocator.destroy(foo.c); |
| 286 | 284 | defer allocator.destroy(bar.c); |
| 287 | 285 | defer allocator.destroy(baz.c); |
| ... | ... | @@ -338,12 +336,12 @@ test "testHash struct" { |
| 338 | 336 | test "testHash union" { |
| 339 | 337 | const Foo = union(enum) { |
| 340 | 338 | A: u32, |
| 341 | | B: f32, |
| 339 | B: bool, |
| 342 | 340 | C: u32, |
| 343 | 341 | }; |
| 344 | 342 | |
| 345 | 343 | const a = Foo{ .A = 18 }; |
| 346 | | var b = Foo{ .B = 12.34 }; |
| 344 | var b = Foo{ .B = true }; |
| 347 | 345 | const c = Foo{ .C = 18 }; |
| 348 | 346 | testing.expect(testHash(a) == testHash(a)); |
| 349 | 347 | testing.expect(testHash(a) != testHash(b)); |