obj::string.zig (4712B)
1 const std = @import("std"); 2 3 const table = @import("lib::table.zig"); 4 const utils = @import("lib::utils.zig"); 5 const hash = @import("hash.zig"); 6 const value = @import("value.zig"); 7 8 const Obj = @import("obj.zig").Obj; 9 10 pub fn String(fields: anytype) type { 11 const Super = Obj(fields); 12 13 return packed struct { 14 const Self = @This(); 15 16 pub const Arg = []const []const u8; 17 pub const Error = error{ OutOfMemory, IndexOutOfBounds }; 18 19 pub const Pool = struct { 20 pub const Table = table.Table(*Self, void, hash.hash_t(*const Self), Self.eql); 21 pub const Error = Table.Error; 22 23 table: Table, 24 25 pub fn init(allocator: std.mem.Allocator) Pool { 26 return .{ .table = Table.init(allocator) }; 27 } 28 29 fn check(arg: Arg, len: usize, hsh: u32) struct { 30 arg: Arg, 31 len: usize, 32 hash: u32, 33 34 pub fn check(self: *const @This(), other: *const Self) bool { 35 if (other.hash == self.hash and other.len == self.len) { 36 var idx: usize = 0; 37 for (self.arg) |el| { 38 if (!std.mem.eql(u8, other.data()[idx .. idx + el.len], el)) 39 return false; 40 idx += el.len; 41 } 42 return true; 43 } 44 return false; 45 } 46 } { 47 return @TypeOf(check(arg, len, hsh)){ 48 .arg = arg, 49 .len = len, 50 .hash = hsh, 51 }; 52 } 53 54 pub fn put(self: *Pool, str: *Self) !void { 55 _ = try self.table.set(str, {}); 56 } 57 58 pub fn find(self: *Pool, arg: Arg) ?*Self { 59 if (self.table.count == 0) return null; 60 61 const pre = Self.prehash(arg); 62 63 const entry = Table.find_(self.table.entries, pre.hash, check(arg, pre.len, pre.hash)); 64 65 return if (entry.* != .some) null else entry.some.key; 66 } 67 68 pub fn free(self: *Pool) void { 69 self.table.deinit(); 70 } 71 }; 72 73 obj: Super, 74 len: usize = 0, 75 hash: u32, 76 77 fn data(self: anytype) utils.copy_const(@TypeOf(self), [*]u8) { 78 const p: utils.copy_const(@TypeOf(self), [*]u8) = @ptrCast(self); 79 return p + @sizeOf(Self); 80 } 81 82 fn new(arg: Arg, len: usize, hsh: u32, allocator: std.mem.Allocator) Error!*Self { 83 const ret: *Self = @ptrCast(try allocator.alignedAlloc(u8, std.mem.Alignment.of(Self), @sizeOf(Self) + len)); 84 ret.* = Self{ 85 .obj = Super.make(Self), 86 .hash = hsh, 87 }; 88 for (arg) |el| { 89 @memcpy(ret.data() + ret.len, el); 90 ret.len += el.len; 91 } 92 return ret; 93 } 94 95 pub fn slice(self: *const Self) []const u8 { 96 return self.data()[0..self.len]; 97 } 98 99 pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) { 100 return @ptrCast(self); 101 } 102 103 pub fn format(self: *const Self, writer: *std.Io.Writer) !void { 104 _ = try writer.writeAll(self.slice()); 105 } 106 pub fn eql(self: *const Self, other: *const Self) bool { 107 return @intFromPtr(self) == @intFromPtr(other); 108 } 109 pub fn get(self: *const Self, index: value.Value) Error!value.Value { 110 if (!index.is(value.Value.number) or index.number >= @as( 111 value.Value.tagType(value.Value.number), 112 @floatFromInt(self.len), 113 ) or index.number < 0) { 114 return Error.IndexOutOfBounds; 115 } 116 return value.Value.init(self.data()[@intFromFloat(index.number)]); 117 } 118 119 fn prehash(arg: Arg) struct { len: usize, hash: u32 } { 120 var len: usize = 0; 121 var hsh = hash.hash_t([]const u8)(&.{}); 122 123 for (arg) |el| { 124 len += el.len; 125 hsh = hash.hash_append(hsh, el); 126 } 127 return .{ .len = len, .hash = hsh }; 128 } 129 130 pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { 131 const pre = Self.prehash(arg); 132 133 return new(arg, pre.len, pre.hash, allocator); 134 } 135 136 pub fn free(self: *const Self, allocator: std.mem.Allocator) void { 137 const p: [*]align(@alignOf(Self)) const u8 = @ptrCast(self); 138 allocator.free(p[0 .. @sizeOf(Self) + self.len]); 139 } 140 }; 141 }