DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

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 }