authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-05-03 21:15:00-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2019-05-03 21:15:00-07:00
logcf8dde2d686199474847c6c4e342dc1ac46a435b
tree5cfe5b3a15d3c396d77acc578408f359bb98799b
parent13a7b8586a600c117cc2d090a283e5a6344d42c4

std.HashMap: cleanup ensureCapacity + add test

- Cleaned up some comments - Removed the "is power of two" check from optimizedCapacity since the * 5 / 3 is unlikely to end up with a power of two, so it's a wasted check the majority of the time - Made ensureCapacity/ensureCapacityExact increment the modification count if they resize the hash map so that we can catch resizes while iterating, which would likely break the iterator state

1 files changed, 23 insertions(+), 8 deletions(-)

std/hash_map.zig+23-8
...@@ -137,18 +137,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3...@@ -137,18 +137,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
137137
138 fn optimizedCapacity(expected_count: usize) usize {138 fn optimizedCapacity(expected_count: usize) usize {
139 // ensure that the hash map will be at most 60% full if139 // ensure that the hash map will be at most 60% full if
140 // new_capacity items are put into the hash map140 // expected_count items are put into it
141 var optimized_capacity = expected_count * 5 / 3;141 var optimized_capacity = expected_count * 5 / 3;
142 // round capacity to the next power of two142 // round capacity to the next power of two
143 const is_power_of_two = optimized_capacity & (optimized_capacity-1) == 0;143 const pow = math.log2_int_ceil(usize, optimized_capacity);
144 if (!is_power_of_two) {144 return math.pow(usize, 2, pow);
145 const pow = math.log2_int_ceil(usize, optimized_capacity);
146 optimized_capacity = math.pow(usize, 2, pow);
147 }
148 return optimized_capacity;
149 }145 }
150146
151 /// Increase capacity so that the hash map will be at most147 /// Increases capacity so that the hash map will be at most
152 /// 60% full when expected_count items are put into it148 /// 60% full when expected_count items are put into it
153 pub fn ensureCapacity(self: *Self, expected_count: usize) !void {149 pub fn ensureCapacity(self: *Self, expected_count: usize) !void {
154 const optimized_capacity = optimizedCapacity(expected_count);150 const optimized_capacity = optimizedCapacity(expected_count);
...@@ -168,6 +164,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3...@@ -168,6 +164,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
168164
169 const old_entries = self.entries;165 const old_entries = self.entries;
170 try self.initCapacity(new_capacity);166 try self.initCapacity(new_capacity);
167 self.incrementModificationCount();
171 if (old_entries.len > 0) {168 if (old_entries.len > 0) {
172 // dump all of the old elements into the new table169 // dump all of the old elements into the new table
173 for (old_entries) |*old_entry| {170 for (old_entries) |*old_entry| {
...@@ -467,6 +464,24 @@ test "iterator hash map" {...@@ -467,6 +464,24 @@ test "iterator hash map" {
467 testing.expect(entry.value == values[0]);464 testing.expect(entry.value == values[0]);
468}465}
469466
467test "ensure capacity" {
468 var direct_allocator = std.heap.DirectAllocator.init();
469 defer direct_allocator.deinit();
470
471 var map = AutoHashMap(i32, i32).init(&direct_allocator.allocator);
472 defer map.deinit();
473
474 try map.ensureCapacity(20);
475 const initialCapacity = map.entries.len;
476 testing.expect(initialCapacity >= 20);
477 var i : i32 = 0;
478 while (i < 20) : (i += 1) {
479 testing.expect(map.putAssumeCapacity(i, i+10) == null);
480 }
481 // shouldn't resize from putAssumeCapacity
482 testing.expect(initialCapacity == map.entries.len);
483}
484
470pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {485pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
471 return struct {486 return struct {
472 fn hash(key: K) u32 {487 fn hash(key: K) u32 {