libstd: add ArrayHashMap.popOrNull function

which internally calls `ArrayHashMap.pop`, however, returns `?KV`
instead and performs the bounds checking automatically.

This function correponds to `ArrayList.popOrNull` and is meant
to fill the gap for situations where we want the quick lookup offered
by the hash map with elegant ability to iterate and pop of the
container with automatic bound checking that plugs in well with
a `while`-loop such as

```zig
var map = std.ArrayHashMap(K, V).init(allocator);
map.deinit();
while (map.popOrNull()) |entry| {
  // ... do something
}
assert(map.count() == 0);
```
This commit is contained in:
Jakub Konka 2021-08-04 00:29:39 +02:00
parent aad4598367
commit ee6f7fee29

View File

@ -414,6 +414,12 @@ pub fn ArrayHashMap(
pub fn pop(self: *Self) KV {
return self.unmanaged.popContext(self.ctx);
}
/// Removes the last inserted `Entry` in the hash map and returns it if count is nonzero.
/// Otherwise returns null.
pub fn popOrNull(self: *Self) ?KV {
return self.unmanaged.popOrNullContext(self.ctx);
}
};
}
@ -1181,6 +1187,17 @@ pub fn ArrayHashMapUnmanaged(
};
}
/// Removes the last inserted `Entry` in the hash map and returns it if count is nonzero.
/// Otherwise returns null.
pub fn popOrNull(self: *Self) ?KV {
if (@sizeOf(ByIndexContext) != 0)
@compileError("Cannot infer context " ++ @typeName(Context) ++ ", call popContext instead.");
return self.popOrNullContext(undefined);
}
pub fn popOrNullContext(self: *Self, ctx: Context) ?KV {
return if (self.entries.len == 0) null else self.popContext(ctx);
}
// ------------------ No pub fns below this point ------------------
fn fetchRemoveByKey(self: *Self, key: anytype, key_ctx: anytype, ctx: ByIndexContext, comptime removal_type: RemovalType) ?KV {
@ -2094,6 +2111,26 @@ test "pop" {
}
}
test "popOrNull" {
var map = AutoArrayHashMap(i32, i32).init(std.testing.allocator);
defer map.deinit();
// Insert just enough entries so that the map expands. Afterwards,
// pop all entries out of the map.
var i: i32 = 0;
while (i < 9) : (i += 1) {
try testing.expect((try map.fetchPut(i, i)) == null);
}
while (map.popOrNull()) |pop| {
try testing.expect(pop.key == i - 1 and pop.value == i - 1);
i -= 1;
}
try testing.expect(map.count() == 0);
}
test "reIndex" {
var map = ArrayHashMap(i32, i32, AutoContext(i32), true).init(std.testing.allocator);
defer map.deinit();