| ... | @@ -135,21 +135,39 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 | ... | @@ -135,21 +135,39 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 135 | return res.kv; | 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 | /// Sets the capacity to the new capacity if the new | 158 | /// Sets the capacity to the new capacity if the new |
| 139 | /// capacity is greater than the current capacity. | 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 | if (new_capacity <= self.entries.len) { | 165 | if (new_capacity <= self.entries.len) { |
| 142 | return; | 166 | return; |
| 143 | } | 167 | } |
| 144 | // make sure capacity is a power of two | 168 | |
| 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 | } | | |
| 151 | const old_entries = self.entries; | 169 | const old_entries = self.entries; |
| 152 | try self.initCapacity(capacity); | 170 | try self.initCapacity(new_capacity); |
| 153 | if (old_entries.len > 0) { | 171 | if (old_entries.len > 0) { |
| 154 | // dump all of the old elements into the new table | 172 | // dump all of the old elements into the new table |
| 155 | for (old_entries) |*old_entry| { | 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,11 +254,11 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 236 | | 254 | |
| 237 | fn autoCapacity(self: *Self) !void { | 255 | fn autoCapacity(self: *Self) !void { |
| 238 | if (self.entries.len == 0) { | 256 | if (self.entries.len == 0) { |
| 239 | return self.ensureCapacity(16); | 257 | return self.ensureCapacityExact(16); |
| 240 | } | 258 | } |
| 241 | // if we get too full (60%), double the capacity | 259 | // if we get too full (60%), double the capacity |
| 242 | if (self.size * 5 >= self.entries.len * 3) { | 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 | |