diff options
Diffstat (limited to 'src/comptime_map.zig')
| -rw-r--r-- | src/comptime_map.zig | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/src/comptime_map.zig b/src/comptime_map.zig index d41f6f8..3d61bd6 100644 --- a/src/comptime_map.zig +++ b/src/comptime_map.zig | |||
| @@ -38,7 +38,7 @@ pub fn ComptimeHashMap(comptime K: type, comptime V: type, comptime ctx: type, c | |||
| 38 | var key: K = kv.@"0"; | 38 | var key: K = kv.@"0"; |
| 39 | var value: V = kv.@"1"; | 39 | var value: V = kv.@"1"; |
| 40 | 40 | ||
| 41 | const start_index = @as(usize, ctx.hash(undefined, key)) & (size - 1); | 41 | const start_index = reduceMulHi(ctx.hash(undefined, key), size); |
| 42 | 42 | ||
| 43 | var roll_over = 0; | 43 | var roll_over = 0; |
| 44 | var distance_from_start_index = 0; | 44 | var distance_from_start_index = 0; |
| @@ -88,7 +88,7 @@ pub fn ComptimeHashMap(comptime K: type, comptime V: type, comptime ctx: type, c | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | pub fn get(key: K) ?*const V { | 90 | pub fn get(key: K) ?*const V { |
| 91 | const start_index = @as(usize, ctx.hash(undefined, key)) & (size - 1); | 91 | const start_index = reduceMulHi(ctx.hash(undefined, key), size); |
| 92 | { | 92 | { |
| 93 | var roll_over: usize = 0; | 93 | var roll_over: usize = 0; |
| 94 | while (roll_over <= max_distance_from_start_index) : (roll_over += 1) { | 94 | while (roll_over <= max_distance_from_start_index) : (roll_over += 1) { |
| @@ -104,6 +104,11 @@ pub fn ComptimeHashMap(comptime K: type, comptime V: type, comptime ctx: type, c | |||
| 104 | }; | 104 | }; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | fn reduceMulHi(h: u64, m: u64) u64 { | ||
| 108 | // floor((h * m) / 2^64) | ||
| 109 | return @as(u64, @truncate((@as(u128, h) * @as(u128, m)) >> 64)); | ||
| 110 | } | ||
| 111 | |||
| 107 | test "basic usage" { | 112 | test "basic usage" { |
| 108 | const map = ComptimeStringHashMap(usize, .{ | 113 | const map = ComptimeStringHashMap(usize, .{ |
| 109 | .{ "foo", 1 }, | 114 | .{ "foo", 1 }, |
| @@ -157,6 +162,20 @@ test "array pair comptime hash map" { | |||
| 157 | try testing.expect(map.has(.{ 2, 4 })); | 162 | try testing.expect(map.has(.{ 2, 4 })); |
| 158 | } | 163 | } |
| 159 | 164 | ||
| 165 | test "Next version tripwire" { | ||
| 166 | // Check for the bug on each version bump, if it goes away, | ||
| 167 | // well, that's useful information. | ||
| 168 | const v = @import("builtin").zig_version; | ||
| 169 | if (v.major == 0 and v.minor <= 15) return; | ||
| 170 | const map = AutoComptimeHashMap([2]u21, u21, .{ | ||
| 171 | .{ .{ 2, 3 }, 5 }, | ||
| 172 | .{ .{ 42, 56 }, 12 }, | ||
| 173 | .{ .{ 2, 4 }, 6 }, | ||
| 174 | }); | ||
| 175 | try testing.expect(map.has(.{ 2, 3 })); // Still buggy :/ | ||
| 176 | try testing.expect(map.has(.{ 23, 42 })); // No bug! :D | ||
| 177 | } | ||
| 178 | |||
| 160 | const std = @import("std"); | 179 | const std = @import("std"); |
| 161 | const hash_map = std.hash_map; | 180 | const hash_map = std.hash_map; |
| 162 | const testing = std.testing; | 181 | const testing = std.testing; |
| @@ -183,4 +202,3 @@ const math = std.math; | |||
| 183 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 202 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 184 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 203 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 185 | // SOFTWARE. | 204 | // SOFTWARE. |
| 186 | |||