From e07f11d195a56a9708a6280a4dedba137d4d5f76 Mon Sep 17 00:00:00 2001 From: "Caleb J. Gardner" Date: Sat, 4 Apr 2026 01:37:36 -0500 Subject: [PATCH] Lookup tables! --- src/archive.zig | 4 +- src/tables.zig | 87 +++++++++++++++++++++++++++++++++++++++++++ src/util/metadata.zig | 4 +- 3 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/tables.zig diff --git a/src/archive.zig b/src/archive.zig index 87a4572..f69b7d3 100644 --- a/src/archive.zig +++ b/src/archive.zig @@ -2,8 +2,8 @@ const std = @import("std"); const DecompTypes = @import("decomp/types.zig"); const Decompressor = @import("decomp.zig"); -const Inode = @import("inode.zig"); const ExtractionOptions = @import("options.zig"); +const Inode = @import("inode.zig"); pub const Error = error{ BadMagic, @@ -33,7 +33,7 @@ pub fn init(fil: std.fs.File, offset: u64) !Archive { }; } -pub fn extract(self: Archive, alloc: std.mem.Allocator, path: []const u8, options: ExtractionOptions) !void{ +pub fn extract(self: Archive, alloc: std.mem.Allocator, path: []const u8, options: ExtractionOptions) !void { _ = self; _ = alloc; _ = path; diff --git a/src/tables.zig b/src/tables.zig new file mode 100644 index 0000000..e05e66f --- /dev/null +++ b/src/tables.zig @@ -0,0 +1,87 @@ +const std = @import("std"); + +const Decompressor = @import("decomp.zig"); +const MetadataReader = @import("util/metadata.zig"); +const OffsetFile = @import("util/offset_file.zig"); + +pub fn stateless(comptime T: anytype, fil: OffsetFile, decomp: *const Decompressor, table_start: u64, idx: u32) !T { + const VALS_PER_BLOCK = 8192 / @sizeOf(T); + const block = idx / VALS_PER_BLOCK; + const block_idx = idx % VALS_PER_BLOCK; + + const offset = try fil.valueAt(u64, table_start + (8 * block)); + var buf: [8192]u8 = undefined; + var rdr = try fil.readerAt(offset, &buf); + var meta_rdr: MetadataReader = .init(&rdr.interface, decomp); + try meta_rdr.interface.discardAll(@sizeOf(T) * block_idx); + + var out: T = undefined; + try meta_rdr.interface.readSliceEndian(T, @ptrCast(&out), .little); + return out; +} + +pub fn Table(comptime T: anytype) type { + return struct { + const Self = @This(); + + const VALS_PER_BLOCK = 8192 / @sizeOf(T); + + alloc: std.mem.Allocator, + decomp: *const Decompressor, + + fil: OffsetFile, + table_start: u64, + num: u32, + + cache: std.AutoHashMap(u32, []T), + cache_mut: std.Thread.Mutex = .{}, + + pub fn init(alloc: std.mem.Allocator, decomp: *const Decompressor, fil: OffsetFile, table_offset: u64, num: u32) !Self { + return .{ + .alloc = alloc, + .decomp = decomp, + + .fil = fil, + .table_start = table_offset, + .num = num, + + .cache = .init(alloc), + }; + } + pub fn deinit(self: *Self) void { + var values = self.cache.valueIterator(); + while (values.next()) |val| + self.alloc.free(val); + self.cache.deinit(); + } + + pub fn get(self: *Self, idx: u32) !T { + const block = idx / VALS_PER_BLOCK; + const block_idx = idx % VALS_PER_BLOCK; + + if (self.cache.get(block)) |val| + return val[block_idx]; + + self.cache_mut.lock(); + defer self.cache_mut.unlock(); + + // Double check in case another thread was doing your work. + if (self.cache.get(block)) |val| + return val[block_idx]; + + const offset = try self.fil.valueAt(u64, self.table_start + (8 * block)); + var buf: [8192]u8 = undefined; + var rdr = try self.fil.readerAt(offset, &buf); + var meta_rdr: MetadataReader = .init(&rdr.interface, self.decomp); + const block_size = if (block == (self.num - 1) / VALS_PER_BLOCK) + self.num % VALS_PER_BLOCK + else + VALS_PER_BLOCK; + const new_block = try self.alloc.alloc(T, block_size); + errdefer self.alloc.free(new_block); + try meta_rdr.interface.readSliceEndian(T, new_block, .little); + try self.cache.put(block, new_block); + return new_block[block_idx]; + } + }; +} diff --git a/src/util/metadata.zig b/src/util/metadata.zig index 5e075c5..f6fb78e 100644 --- a/src/util/metadata.zig +++ b/src/util/metadata.zig @@ -13,7 +13,7 @@ const Header = packed struct { const MetadataReader = @This(); rdr: *Reader, -decomp: *Decompressor, +decomp: *const Decompressor, read_buf: [8192]u8 = undefined, interface: Reader = .{ @@ -27,7 +27,7 @@ interface: Reader = .{ }, }, -pub fn init(rdr: *Reader, decomp: *Decompressor) MetadataReader { +pub fn init(rdr: *Reader, decomp: *const Decompressor) MetadataReader { return .{ .rdr = rdr, .decomp = decomp }; } fn advanceBuffer(self: *MetadataReader) Reader.Error!void {