From ad766bc1e830736e3a10facb51153f9fed4fd9b4 Mon Sep 17 00:00:00 2001 From: yuzu Date: Tue, 27 May 2025 22:46:07 -0500 Subject: [PATCH] . --- intern_pool.zig | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ language.zig | 4 +++ 2 files changed, 74 insertions(+) create mode 100644 intern_pool.zig diff --git a/intern_pool.zig b/intern_pool.zig new file mode 100644 index 0000000..ee2b46e --- /dev/null +++ b/intern_pool.zig @@ -0,0 +1,70 @@ +//! Reference counted, owned, and interned strings + +const std = @import("std"); +const Allocator = std.mem.Allocator; + +bytes: std.ArrayListUnmanaged(u8), +map: std.StringHashMapUnmanaged(void), + +// Construct new empty string intern pool +pub const empty: @This() = .{ .bytes = .empty, .map = .empty }; + +// Free all memory allocated by the intern pool. Additionally, ensure +// all memory allocated by the pool in it's lifetime is also freed. +pub fn deinit(self: *@This(), gpa: Allocator) void { + self.bytes.deinit(gpa); + self.map.deinit(gpa); + self.* = undefined; +} + +// Add a string to the intern pool, returning a stable pointer to the string. +// The pointer will last as far as the string is not removed with `remove()`. +pub fn add(self: *@This(), gpa: Allocator, str: []const u8) ![]const u8 { + if (self.map.getKey(str)) |entry| { + // Return pre-existing + return entry; + } + + // Allocate memory for & copy the string + const str_start_idx = self.bytes.items.len; + try self.bytes.appendSlice(gpa, str); + const entry_str = self.bytes.items[str_start_idx..]; + errdefer self.bytes.items.len = str_start_idx; + + // Add the entry to our map, use the owned string + try self.map.putNoClobber(gpa, entry_str, void{}); + + // Return the stable pointer + return entry_str; +} + +test "Intern Pool" { + const gpa = std.testing.allocator; + try generalWorkload(gpa); + + try std.testing.checkAllAllocationFailures(gpa, generalWorkload, .{}); +} + +fn generalWorkload(gpa: Allocator) !void { + var pool: @This() = .empty; + defer pool.deinit(gpa); + + // Inserting elements + const a = try pool.add(gpa, "x"); + const b = try pool.add(gpa, "y"); + const c = try pool.add(gpa, "z"); + const d = try pool.add(gpa, "z"); + const e = try pool.add(gpa, "y"); + + try std.testing.expectEqualSlices(u8, "x", a); + try std.testing.expectEqualSlices(u8, "y", b); + try std.testing.expectEqualSlices(u8, "z", c); + try std.testing.expectEqualSlices(u8, "z", d); + try std.testing.expectEqualSlices(u8, "y", e); + + try std.testing.expectEqual(b.ptr, e.ptr); + try std.testing.expectEqual(c.ptr, d.ptr); + + try std.testing.expectEqual(pool.map.size, 3); + try std.testing.expectEqualSlices(u8, "xyz", pool.bytes.items); +} diff --git a/language.zig b/language.zig index 19248e7..fcb4f25 100644 --- a/language.zig +++ b/language.zig @@ -112,7 +112,11 @@ pub const ObjectEntry = struct { }; pub const Flags = packed struct { + allow_comments: bool = false, allow_trailing_comma: bool = false, + enums_are_strings: bool = false, + unions_are_strings: bool = false, + packed_structs_are_ints: bool = false, }; pub const Options = struct {