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
137137
138138 fn optimizedCapacity(expected_count: usize) usize {
139139 // ensure that the hash map will be at most 60% full if
140 // new_capacity items are put into the hash map
140 // expected_count items are put into it
141141 var optimized_capacity = expected_count * 5 / 3;
142142 // 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;
143 const pow = math.log2_int_ceil(usize, optimized_capacity);
144 return math.pow(usize, 2, pow);
149145 }
150146
151 /// Increase capacity so that the hash map will be at most
147 /// Increases capacity so that the hash map will be at most
152148 /// 60% full when expected_count items are put into it
153149 pub fn ensureCapacity(self: *Self, expected_count: usize) !void {
154150 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
168164
169165 const old_entries = self.entries;
170166 try self.initCapacity(new_capacity);
167 self.incrementModificationCount();
171168 if (old_entries.len > 0) {
172169 // dump all of the old elements into the new table
173170 for (old_entries) |*old_entry| {
......@@ -467,6 +464,24 @@ test "iterator hash map" {
467464 testing.expect(entry.value == values[0]);
468465}
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
470485pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
471486 return struct {
472487 fn hash(key: K) u32 {