Commit ee6f7fee29

Jakub Konka <kubkon@jakubkonka.com>
2021-08-04 00:29:39
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); ```
1 parent aad4598
Changed files (1)
lib/std/array_hash_map.zig
@@ -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();