authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-05-02 17:01:30-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-05-02 17:01:30-07:00
log4d42275d03a3f24beca2d93e02ff12e52a48a91b
tree44b5daaee620929669e6ed9f229e9982050c1631
parent0afa2d040a6f51b5423269cb588f4fa483e8cfba

std.HashMap: make ensureCapacity optimize for the expected count, add ensureCapacityExact


1 files changed, 29 insertions(+), 11 deletions(-)

std/hash_map.zig+29-11
...@@ -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 }
137137
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 new158 /// 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 two168
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 table172 // 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
236254
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 capacity259 // 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 }
246264