# std.HashMap / std.AutoHashMap Hash maps for key-value storage. Use `AutoHashMap` for simple keys, `StringHashMap` for string keys. ## Types Overview ```zig // AutoHashMap - automatic hash/eql for simple types std.AutoHashMap(KeyType, ValueType) std.AutoHashMapUnmanaged(KeyType, ValueType) // no stored allocator // StringHashMap - optimized for string keys std.StringHashMap(ValueType) std.StringHashMapUnmanaged(ValueType) // ArrayHashMap - Zig 0.16 unmanaged ordered maps std.array_hash_map.Auto(K, V) std.array_hash_map.String(V) std.array_hash_map.Custom(K, V, Context, store_hash) ``` ## AutoHashMap Usage ```zig // Initialization var map = std.AutoHashMap(u32, []const u8).init(allocator); defer map.deinit(); // Insert try map.put(42, "answer"); // Get if (map.get(42)) |value| { // value is []const u8 } // Get pointer (for modification) if (map.getPtr(42)) |ptr| { ptr.* = "new value"; } // Remove if (map.fetchRemove(42)) |kv| { // kv.key, kv.value - removed entry } _ = map.remove(42); // returns bool // Check existence const exists = map.contains(42); // Count const n = map.count(); ``` ## Unmanaged Variant ```zig // No stored allocator - pass it to operations that allocate or release memory var map: std.AutoHashMapUnmanaged(u32, []const u8) = .empty; defer map.deinit(allocator); try map.put(allocator, 42, "answer"); const val = map.get(42); ``` ## StringHashMap ```zig var map = std.StringHashMap(i32).init(allocator); defer map.deinit(); try map.put("foo", 123); const val = map.get("foo"); // ?i32 ``` ## getOrPut Pattern Efficient insert-or-update without double lookup: ```zig const gop = try map.getOrPut(key); if (gop.found_existing) { // Update existing gop.value_ptr.* += 1; } else { // Initialize new entry gop.value_ptr.* = 1; } ``` ## Iteration ```zig // Iterate entries var iter = map.iterator(); while (iter.next()) |entry| { const key = entry.key_ptr.*; const value = entry.value_ptr.*; } // Keys only var keys = map.keyIterator(); while (keys.next()) |key_ptr| { _ = key_ptr.*; } // Values only var values = map.valueIterator(); while (values.next()) |value_ptr| { _ = value_ptr.*; } ``` Any modification invalidates iterators. Growth or rehashing can invalidate returned key/value pointers; removal immediately invalidates the removed entry's pointers. ## Capacity ```zig try map.ensureTotalCapacity(100); map.clearRetainingCapacity(); map.clearAndFree(); ``` ## Custom Context For custom hash/equality functions: ```zig const Context = struct { pub fn hash(self: @This(), key: MyKey) u64 { _ = self; // compute hash } pub fn eql(self: @This(), a: MyKey, b: MyKey) bool { _ = self; // compare } }; var map = std.HashMap(MyKey, Value, Context, 80).init(allocator); // Or with context instance: var map = std.HashMap(MyKey, Value, Context, 80).initContext(allocator, context); ``` ## ArrayHashMap (Ordered) Preserves insertion order, supports indexed access: ```zig var map: std.array_hash_map.String(i32) = .empty; defer map.deinit(allocator); try map.put(allocator, "b", 2); try map.put(allocator, "a", 1); // Iterate in insertion order: "b", "a" for (map.keys(), map.values()) |k, v| { } // Index access const key = map.keys()[0]; // "b" const val = map.values()[0]; // 2 // Swap remove (O(1) but changes order) _ = map.swapRemove("b"); // Ordered remove (O(n) but preserves order) _ = map.orderedRemove("a"); ``` ## Common Patterns ```zig // Word frequency counter var counts = std.StringHashMap(usize).init(allocator); for (words) |word| { const gop = try counts.getOrPut(word); if (gop.found_existing) { gop.value_ptr.* += 1; } else { gop.value_ptr.* = 1; } } // Cache with owned keys var cache = std.StringHashMap(Data).init(allocator); defer cache.deinit(); defer { var owned_keys = cache.keyIterator(); while (owned_keys.next()) |key_ptr| allocator.free(key_ptr.*); } // When inserting, dupe the key if needed: const key_copy = try allocator.dupe(u8, external_key); errdefer allocator.free(key_copy); try cache.put(key_copy, data); ``` On removal, free the duplicated key returned by `fetchRemove`. Before clearing or deinitializing the map, iterate and free every remaining owned key as above; the map does not own string storage automatically.