authorgravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2020-07-26 22:08:48+02:00
committergravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2020-07-26 23:04:33+02:00
logf67ce1e35fe3ecf19b50f64b9fe2d85747f7934d
treeae29d6c2a1444ed46641cb4500673bff61e6badd
parent345cb3200c353d6fb7aeb0e058986d8ca59ced1e

make use of hasUniqueRepresentation to speed up hashing facilities, fastpath in getAutoHashFn is particularly important for hashmap performance

gives a 1.18x speedup on gotta-go-fast hashmap bench

2 files changed, 14 insertions(+), 9 deletions(-)

lib/std/hash/auto_hash.zig+6-6
......@@ -56,9 +56,6 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
5656pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
5757 switch (strat) {
5858 .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.
6259 for (key) |element| {
6360 hash(hasher, element, .Shallow);
6461 }
......@@ -75,6 +72,12 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo
7572/// Strategy is provided to determine if pointers should be followed or not.
7673pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
7774 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
7881 switch (@typeInfo(Key)) {
7982 .NoReturn,
8083 .Opaque,
......@@ -119,9 +122,6 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
119122 },
120123
121124 .Struct => |info| {
122 // TODO detect via a trait when Key has no padding bits to
123 // hash it as an array of bytes.
124 // Otherwise, hash every field.
125125 inline for (info.fields) |field| {
126126 // We reuse the hash of the previous field as the seed for the
127127 // next one so that they're dependant.
lib/std/hash_map.zig+8-3
......@@ -5,6 +5,7 @@ const testing = std.testing;
55const math = std.math;
66const mem = std.mem;
77const meta = std.meta;
8const trait = meta.trait;
89const autoHash = std.hash.autoHash;
910const Wyhash = std.hash.Wyhash;
1011const Allocator = mem.Allocator;
......@@ -1023,9 +1024,13 @@ pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) {
10231024pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
10241025 return struct {
10251026 fn hash(key: K) u32 {
1026 var hasher = Wyhash.init(0);
1027 autoHash(&hasher, key);
1028 return @truncate(u32, hasher.final());
1027 if (comptime trait.hasUniqueRepresentation(K)) {
1028 return @truncate(u32, Wyhash.hash(0, std.mem.asBytes(&key)));
1029 } else {
1030 var hasher = Wyhash.init(0);
1031 autoHash(&hasher, key);
1032 return @truncate(u32, hasher.final());
1033 }
10291034 }
10301035 }.hash;
10311036}