185 lines
4.4 KiB
Markdown
185 lines
4.4 KiB
Markdown
# std.BufMap / std.BufSet
|
|
|
|
String-keyed maps and sets that own their strings. Automatically copy and free string keys/values.
|
|
|
|
## When to Use
|
|
|
|
- Environment variable storage
|
|
- String-to-string mapping with ownership
|
|
- Set of unique strings with automatic memory management
|
|
- When you don't want to manage string lifetime manually
|
|
|
|
## BufMap (String -> String)
|
|
|
|
```zig
|
|
const std = @import("std");
|
|
|
|
var map = std.BufMap.init(allocator);
|
|
defer map.deinit(); // frees all stored strings
|
|
|
|
// Put copies a new key and value. Replacing an existing key retains the stored
|
|
// key allocation and copies only the new value.
|
|
try map.put("HOME", "/Users/alice");
|
|
try map.put("PATH", "/usr/bin");
|
|
|
|
// Get
|
|
if (map.get("HOME")) |home| {
|
|
std.debug.print("home: {s}\n", .{home});
|
|
}
|
|
|
|
// Replace through the public ownership-aware operation.
|
|
try map.put("PATH", "/new/path");
|
|
|
|
// Remove (frees both key and value)
|
|
map.remove("PATH");
|
|
|
|
// Count
|
|
const n = map.count();
|
|
```
|
|
|
|
## BufMap: Move Ownership
|
|
|
|
```zig
|
|
// putMove takes ownership instead of copying
|
|
const key = try allocator.dupe(u8, "MY_KEY");
|
|
const value = try allocator.dupe(u8, "my_value");
|
|
map.putMove(key, value) catch |err| {
|
|
allocator.free(key);
|
|
allocator.free(value);
|
|
return err;
|
|
};
|
|
// On success, the map owns both buffers.
|
|
```
|
|
|
|
## BufMap: Iteration
|
|
|
|
```zig
|
|
var it = map.iterator();
|
|
while (it.next()) |entry| {
|
|
const key = entry.key_ptr.*;
|
|
const value = entry.value_ptr.*;
|
|
std.debug.print("{s}={s}\n", .{ key, value });
|
|
}
|
|
```
|
|
|
|
## BufSet (Set of Strings)
|
|
|
|
```zig
|
|
var set = std.BufSet.init(allocator);
|
|
defer set.deinit(); // frees all stored strings
|
|
|
|
// Insert (copies the string)
|
|
try set.insert("apple");
|
|
try set.insert("banana");
|
|
try set.insert("apple"); // no-op, already exists
|
|
|
|
// Check membership
|
|
if (set.contains("apple")) {
|
|
// it's in the set
|
|
}
|
|
|
|
// Remove (frees the string)
|
|
set.remove("banana");
|
|
|
|
// Count
|
|
const n = set.count();
|
|
```
|
|
|
|
## BufSet: Iteration
|
|
|
|
```zig
|
|
var it = set.iterator();
|
|
while (it.next()) |key| {
|
|
std.debug.print("{s}\n", .{key.*});
|
|
}
|
|
```
|
|
|
|
## BufSet: Clone
|
|
|
|
```zig
|
|
// Create independent copy
|
|
var copy = try set.clone();
|
|
defer copy.deinit();
|
|
|
|
// Clone with different allocator
|
|
var arena_copy = try set.cloneWithAllocator(arena.allocator());
|
|
// No need to deinit if using arena
|
|
```
|
|
|
|
## Complete Example: Environment Variables
|
|
|
|
```zig
|
|
const std = @import("std");
|
|
|
|
pub fn main() !void {
|
|
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
|
defer _ = gpa.deinit();
|
|
const alloc = gpa.allocator();
|
|
|
|
var env = std.BufMap.init(alloc);
|
|
defer env.deinit();
|
|
|
|
// Set some variables
|
|
try env.put("APP_NAME", "MyApp");
|
|
try env.put("APP_VERSION", "1.0.0");
|
|
try env.put("DEBUG", "true");
|
|
|
|
// Update a value
|
|
try env.put("DEBUG", "false"); // replaces, frees old value
|
|
|
|
// Print all
|
|
var it = env.iterator();
|
|
while (it.next()) |entry| {
|
|
std.debug.print("{s}={s}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
|
|
}
|
|
|
|
// Check and use
|
|
if (env.get("DEBUG")) |debug| {
|
|
if (std.mem.eql(u8, debug, "true")) {
|
|
std.debug.print("Debug mode enabled\n", .{});
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Complete Example: Unique Words
|
|
|
|
```zig
|
|
const std = @import("std");
|
|
|
|
pub fn main() !void {
|
|
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
|
defer _ = gpa.deinit();
|
|
|
|
var words = std.BufSet.init(gpa.allocator());
|
|
defer words.deinit();
|
|
|
|
const text = "the quick brown fox jumps over the lazy dog";
|
|
var tokens = std.mem.tokenizeScalar(u8, text, ' ');
|
|
|
|
while (tokens.next()) |word| {
|
|
try words.insert(word); // duplicates automatically ignored
|
|
}
|
|
|
|
std.debug.print("Unique words: {}\n", .{words.count()}); // 8
|
|
|
|
var it = words.iterator();
|
|
while (it.next()) |word| {
|
|
std.debug.print(" {s}\n", .{word.*});
|
|
}
|
|
}
|
|
```
|
|
|
|
## Notes
|
|
|
|
- A new insertion copies both strings. Replacing an existing key retains its
|
|
stored key and replaces the owned value.
|
|
- `putMove` transfers ownership only on success; on error the caller retains it.
|
|
- A slice from `get()` is invalidated by replacing/removing its key or
|
|
deinitializing the map.
|
|
- A pointer from `getPtr()` is invalidated by resize, removal of that entry, or
|
|
deinitialization. Replacing the value updates the existing slot.
|
|
- Iteration order is arbitrary; do not rely on insertion order, and do not
|
|
modify a `BufMap` or `BufSet` while an iterator is live.
|
|
- For non-owning string maps, use `std.StringHashMap`
|