83 lines
2.4 KiB
Zig
83 lines
2.4 KiB
Zig
|
const std = @import("std");
|
||
|
|
||
|
pub const Fields = struct {
|
||
|
const HashContext = struct {
|
||
|
const hash_seed = 1;
|
||
|
pub fn eql(_: @This(), lhs: []const u8, rhs: []const u8) bool {
|
||
|
return std.ascii.eqlIgnoreCase(lhs, rhs);
|
||
|
}
|
||
|
pub fn hash(_: @This(), s: []const u8) u64 {
|
||
|
var h = std.hash.Wyhash.init(hash_seed);
|
||
|
for (s) |ch| {
|
||
|
const c = [1]u8{std.ascii.toLower(ch)};
|
||
|
h.update(&c);
|
||
|
}
|
||
|
return h.final();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const HashMap = std.HashMapUnmanaged(
|
||
|
[]const u8,
|
||
|
[]const u8,
|
||
|
HashContext,
|
||
|
std.hash_map.default_max_load_percentage,
|
||
|
);
|
||
|
|
||
|
unmanaged: HashMap,
|
||
|
allocator: std.mem.Allocator,
|
||
|
|
||
|
pub fn init(allocator: std.mem.Allocator) Fields {
|
||
|
return Fields{
|
||
|
.unmanaged = .{},
|
||
|
.allocator = allocator,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub fn deinit(self: *Fields) void {
|
||
|
var hash_iter = self.unmanaged.iterator();
|
||
|
while (hash_iter.next()) |entry| {
|
||
|
self.allocator.free(entry.key_ptr.*);
|
||
|
self.allocator.free(entry.value_ptr.*);
|
||
|
}
|
||
|
|
||
|
self.unmanaged.deinit(self.allocator);
|
||
|
}
|
||
|
|
||
|
pub fn iterator(self: Fields) HashMap.Iterator {
|
||
|
return self.unmanaged.iterator();
|
||
|
}
|
||
|
|
||
|
pub fn get(self: Fields, key: []const u8) ?[]const u8 {
|
||
|
return self.unmanaged.get(key);
|
||
|
}
|
||
|
|
||
|
pub fn put(self: *Fields, key: []const u8, val: []const u8) !void {
|
||
|
const key_clone = try self.allocator.alloc(u8, key.len);
|
||
|
std.mem.copy(u8, key_clone, key);
|
||
|
errdefer self.allocator.free(key_clone);
|
||
|
|
||
|
const val_clone = try self.allocator.alloc(u8, val.len);
|
||
|
std.mem.copy(u8, val_clone, val);
|
||
|
errdefer self.allocator.free(val_clone);
|
||
|
|
||
|
if (try self.unmanaged.fetchPut(self.allocator, key_clone, val_clone)) |entry| {
|
||
|
self.allocator.free(entry.key);
|
||
|
self.allocator.free(entry.value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn append(self: *Fields, key: []const u8, val: []const u8) !void {
|
||
|
if (self.unmanaged.getEntry(key)) |entry| {
|
||
|
const new_val = try std.mem.join(self.allocator, ", ", &.{ entry.value_ptr.*, val });
|
||
|
self.allocator.free(entry.value_ptr.*);
|
||
|
entry.value_ptr.* = new_val;
|
||
|
} else {
|
||
|
try self.put(key, val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn count(self: Fields) usize {
|
||
|
return self.unmanaged.count();
|
||
|
}
|
||
|
};
|