| ... | ... | @@ -135,21 +135,39 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 135 | 135 | return res.kv; |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | fn optimizedCapacity(expected_count: usize) usize { |
| 139 | // ensure that the hash map will be at most 60% full if |
| 140 | // new_capacity items are put into the hash map |
| 141 | var optimized_capacity = expected_count * 5 / 3; |
| 142 | // round capacity to the next power of two |
| 143 | const is_power_of_two = optimized_capacity & (optimized_capacity-1) == 0; |
| 144 | if (!is_power_of_two) { |
| 145 | const pow = math.log2_int_ceil(usize, optimized_capacity); |
| 146 | optimized_capacity = math.pow(usize, 2, pow); |
| 147 | } |
| 148 | return optimized_capacity; |
| 149 | } |
| 150 | |
| 151 | /// Increase capacity so that the hash map will be at most |
| 152 | /// 60% full when expected_count items are put into it |
| 153 | pub fn ensureCapacity(self: *Self, expected_count: usize) !void { |
| 154 | const optimized_capacity = optimizedCapacity(expected_count); |
| 155 | return self.ensureCapacityExact(optimized_capacity); |
| 156 | } |
| 157 | |
| 138 | 158 | /// Sets the capacity to the new capacity if the new |
| 139 | 159 | /// capacity is greater than the current capacity. |
| 140 | | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { |
| 160 | /// New capacity must be a power of two. |
| 161 | pub fn ensureCapacityExact(self: *Self, new_capacity: usize) !void { |
| 162 | const is_power_of_two = new_capacity & (new_capacity-1) == 0; |
| 163 | assert(is_power_of_two); |
| 164 | |
| 141 | 165 | if (new_capacity <= self.entries.len) { |
| 142 | 166 | return; |
| 143 | 167 | } |
| 144 | | // make sure capacity is a power of two |
| 145 | | var capacity = new_capacity; |
| 146 | | const is_power_of_two = capacity & (capacity-1) == 0; |
| 147 | | if (!is_power_of_two) { |
| 148 | | const pow = math.log2_int_ceil(usize, capacity); |
| 149 | | capacity = math.pow(usize, 2, pow); |
| 150 | | } |
| 168 | |
| 151 | 169 | const old_entries = self.entries; |
| 152 | | try self.initCapacity(capacity); |
| 170 | try self.initCapacity(new_capacity); |
| 153 | 171 | if (old_entries.len > 0) { |
| 154 | 172 | // dump all of the old elements into the new table |
| 155 | 173 | for (old_entries) |*old_entry| { |
| ... | ... | @@ -236,11 +254,11 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 236 | 254 | |
| 237 | 255 | fn autoCapacity(self: *Self) !void { |
| 238 | 256 | if (self.entries.len == 0) { |
| 239 | | return self.ensureCapacity(16); |
| 257 | return self.ensureCapacityExact(16); |
| 240 | 258 | } |
| 241 | 259 | // if we get too full (60%), double the capacity |
| 242 | 260 | if (self.size * 5 >= self.entries.len * 3) { |
| 243 | | return self.ensureCapacity(self.entries.len * 2); |
| 261 | return self.ensureCapacityExact(self.entries.len * 2); |
| 244 | 262 | } |
| 245 | 263 | } |
| 246 | 264 | |