| ... | ... | @@ -139,9 +139,9 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 139 | 139 | // ensure that the hash map will be at most 60% full if |
| 140 | 140 | // expected_count items are put into it |
| 141 | 141 | var optimized_capacity = expected_count * 5 / 3; |
| 142 | | // round capacity to the next power of two |
| 143 | | const pow = math.log2_int_ceil(usize, optimized_capacity); |
| 144 | | return math.pow(usize, 2, pow); |
| 142 | // an overflow here would mean the amount of memory required would not |
| 143 | // be representable in the address space |
| 144 | return math.ceilPowerOfTwo(usize, optimized_capacity) catch unreachable; |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | /// Increases capacity so that the hash map will be at most |
| ... | ... | @@ -155,6 +155,8 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 155 | 155 | /// capacity is greater than the current capacity. |
| 156 | 156 | /// New capacity must be a power of two. |
| 157 | 157 | fn ensureCapacityExact(self: *Self, new_capacity: usize) !void { |
| 158 | // capacity must always be a power of two to allow for modulo |
| 159 | // optimization in the constrainIndex fn |
| 158 | 160 | const is_power_of_two = new_capacity & (new_capacity - 1) == 0; |
| 159 | 161 | assert(is_power_of_two); |
| 160 | 162 | |
| ... | ... | @@ -209,7 +211,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 209 | 211 | { |
| 210 | 212 | var roll_over: usize = 0; |
| 211 | 213 | while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) { |
| 212 | | const index = (start_index + roll_over) % hm.entries.len; |
| 214 | const index = hm.constrainIndex(start_index + roll_over); |
| 213 | 215 | var entry = &hm.entries[index]; |
| 214 | 216 | |
| 215 | 217 | if (!entry.used) return null; |
| ... | ... | @@ -218,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 218 | 220 | |
| 219 | 221 | const removed_kv = entry.kv; |
| 220 | 222 | while (roll_over < hm.entries.len) : (roll_over += 1) { |
| 221 | | const next_index = (start_index + roll_over + 1) % hm.entries.len; |
| 223 | const next_index = hm.constrainIndex(start_index + roll_over + 1); |
| 222 | 224 | const next_entry = &hm.entries[next_index]; |
| 223 | 225 | if (!next_entry.used or next_entry.distance_from_start_index == 0) { |
| 224 | 226 | entry.used = false; |
| ... | ... | @@ -301,7 +303,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 301 | 303 | roll_over += 1; |
| 302 | 304 | distance_from_start_index += 1; |
| 303 | 305 | }) { |
| 304 | | const index = (start_index + roll_over) % self.entries.len; |
| 306 | const index = self.constrainIndex(start_index + roll_over); |
| 305 | 307 | const entry = &self.entries[index]; |
| 306 | 308 | |
| 307 | 309 | if (entry.used and !eql(entry.kv.key, key)) { |
| ... | ... | @@ -358,7 +360,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 358 | 360 | { |
| 359 | 361 | var roll_over: usize = 0; |
| 360 | 362 | while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) { |
| 361 | | const index = (start_index + roll_over) % hm.entries.len; |
| 363 | const index = hm.constrainIndex(start_index + roll_over); |
| 362 | 364 | const entry = &hm.entries[index]; |
| 363 | 365 | |
| 364 | 366 | if (!entry.used) return null; |
| ... | ... | @@ -369,7 +371,13 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 369 | 371 | } |
| 370 | 372 | |
| 371 | 373 | fn keyToIndex(hm: Self, key: K) usize { |
| 372 | | return usize(hash(key)) % hm.entries.len; |
| 374 | return hm.constrainIndex(usize(hash(key))); |
| 375 | } |
| 376 | |
| 377 | fn constrainIndex(hm: Self, i: usize) usize { |
| 378 | // this is an optimization for modulo of power of two integers; |
| 379 | // it requires hm.entries.len to always be a power of two |
| 380 | return i & (hm.entries.len - 1); |
| 373 | 381 | } |
| 374 | 382 | }; |
| 375 | 383 | } |