mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 10:16:12 +03:00
terminal/new: everything is OffsetBuf based
This commit is contained in:
@ -41,6 +41,7 @@ const Wyhash = std.hash.Wyhash;
|
||||
|
||||
const Offset = @import("size.zig").Offset;
|
||||
const OffsetBuf = @import("size.zig").OffsetBuf;
|
||||
const getOffset = @import("size.zig").getOffset;
|
||||
|
||||
pub fn AutoOffsetHashMap(comptime K: type, comptime V: type) type {
|
||||
return OffsetHashMap(K, V, AutoContext(K));
|
||||
@ -70,6 +71,7 @@ pub fn OffsetHashMap(
|
||||
|
||||
/// This is the pointer-based map that we're wrapping.
|
||||
pub const Unmanaged = HashMapUnmanaged(K, V, Context);
|
||||
pub const Layout = Unmanaged.Layout;
|
||||
|
||||
/// This is the alignment that the base pointer must have.
|
||||
pub const base_align = Unmanaged.base_align;
|
||||
@ -79,19 +81,21 @@ pub fn OffsetHashMap(
|
||||
/// Returns the total size of the backing memory required for a
|
||||
/// HashMap with the given capacity. The base ptr must also be
|
||||
/// aligned to base_align.
|
||||
pub fn bufferSize(cap: Unmanaged.Size) usize {
|
||||
const layout = Unmanaged.layoutForCapacity(cap);
|
||||
return layout.total_size;
|
||||
pub fn layout(cap: Unmanaged.Size) Layout {
|
||||
return Unmanaged.layoutForCapacity(cap);
|
||||
}
|
||||
|
||||
/// Initialize a new HashMap with the given capacity and backing
|
||||
/// memory. The backing memory must be aligned to base_align.
|
||||
pub fn init(cap: Unmanaged.Size, buf: []u8) Self {
|
||||
assert(@intFromPtr(buf.ptr) % base_align == 0);
|
||||
pub fn init(buf: OffsetBuf, l: Layout) Self {
|
||||
assert(@intFromPtr(buf.start()) % base_align == 0);
|
||||
|
||||
const m = Unmanaged.init(cap, buf);
|
||||
const offset = @intFromPtr(m.metadata.?) - @intFromPtr(buf.ptr);
|
||||
return .{ .metadata = .{ .offset = @intCast(offset) } };
|
||||
const m = Unmanaged.init(buf, l);
|
||||
return .{ .metadata = getOffset(
|
||||
Unmanaged.Metadata,
|
||||
buf,
|
||||
@ptrCast(m.metadata.?),
|
||||
) };
|
||||
}
|
||||
|
||||
/// Returns the pointer-based map from a base pointer.
|
||||
@ -283,21 +287,19 @@ fn HashMapUnmanaged(
|
||||
|
||||
/// Initialize a hash map with a given capacity and a buffer. The
|
||||
/// buffer must fit within the size defined by `layoutForCapacity`.
|
||||
pub fn init(new_capacity: Size, buf: []u8) Self {
|
||||
assert(@intFromPtr(buf.ptr) % base_align == 0);
|
||||
const layout = layoutForCapacity(new_capacity);
|
||||
assert(buf.len >= layout.total_size);
|
||||
pub fn init(buf: OffsetBuf, layout: Layout) Self {
|
||||
assert(@intFromPtr(buf.start()) % base_align == 0);
|
||||
|
||||
// Get all our main pointers
|
||||
const metadata_ptr: [*]Metadata = @ptrFromInt(@intFromPtr(buf.ptr) + @sizeOf(Header));
|
||||
const metadata_ptr: [*]Metadata = @ptrCast(buf.start() + @sizeOf(Header));
|
||||
|
||||
// Build our map
|
||||
var map: Self = .{ .metadata = metadata_ptr };
|
||||
const hdr = map.header();
|
||||
hdr.capacity = new_capacity;
|
||||
hdr.capacity = layout.capacity;
|
||||
hdr.size = 0;
|
||||
if (@sizeOf([*]K) != 0) hdr.keys = .{ .offset = @intCast(layout.keys_start) };
|
||||
if (@sizeOf([*]V) != 0) hdr.values = .{ .offset = @intCast(layout.vals_start) };
|
||||
if (@sizeOf([*]K) != 0) hdr.keys = buf.member(K, layout.keys_start);
|
||||
if (@sizeOf([*]V) != 0) hdr.values = buf.member(V, layout.vals_start);
|
||||
map.initMetadatas();
|
||||
|
||||
return map;
|
||||
@ -853,7 +855,7 @@ fn HashMapUnmanaged(
|
||||
/// The actual size may be able to fit more than the given capacity
|
||||
/// because capacity is rounded up to the next power of two. This is
|
||||
/// a design requirement for this hash map implementation.
|
||||
fn layoutForCapacity(new_capacity: Size) Layout {
|
||||
pub fn layoutForCapacity(new_capacity: Size) Layout {
|
||||
assert(std.math.isPowerOfTwo(new_capacity));
|
||||
|
||||
// Pack our metadata, keys, and values.
|
||||
@ -893,10 +895,11 @@ test "HashMap basic usage" {
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const cap = 16;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
const count = 5;
|
||||
var i: u32 = 0;
|
||||
@ -927,9 +930,10 @@ test "HashMap ensureTotalCapacity" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
const initial_capacity = map.capacity();
|
||||
try testing.expect(initial_capacity >= 20);
|
||||
@ -946,9 +950,10 @@ test "HashMap ensureUnusedCapacity with tombstones" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: i32 = 0;
|
||||
while (i < 100) : (i += 1) {
|
||||
@ -963,9 +968,10 @@ test "HashMap clearRetainingCapacity" {
|
||||
const cap = 16;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
map.clearRetainingCapacity();
|
||||
|
||||
@ -993,9 +999,10 @@ test "HashMap ensureTotalCapacity with existing elements" {
|
||||
const cap = Map.minimal_capacity;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
try map.put(0, 0);
|
||||
try expectEqual(map.count(), 1);
|
||||
@ -1011,9 +1018,10 @@ test "HashMap remove" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
@ -1048,9 +1056,10 @@ test "HashMap reverse removes" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
@ -1075,9 +1084,10 @@ test "HashMap multiple removes on same metadata" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
@ -1117,9 +1127,10 @@ test "HashMap put and remove loop in random order" {
|
||||
const cap = 64;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var keys = std.ArrayList(u32).init(alloc);
|
||||
defer keys.deinit();
|
||||
@ -1154,9 +1165,10 @@ test "HashMap put" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
@ -1184,13 +1196,10 @@ test "HashMap put full load" {
|
||||
const cap = 16;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alignedAlloc(
|
||||
u8,
|
||||
Map.base_align,
|
||||
Map.layoutForCapacity(cap).total_size,
|
||||
);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
for (0..cap) |i| try map.put(i, i);
|
||||
for (0..cap) |i| try expectEqual(map.get(i).?, i);
|
||||
@ -1203,9 +1212,10 @@ test "HashMap putAssumeCapacity" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 20) : (i += 1) {
|
||||
@ -1237,9 +1247,10 @@ test "HashMap repeat putAssumeCapacity/remove" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
const limit = cap;
|
||||
|
||||
@ -1272,9 +1283,10 @@ test "HashMap getOrPut" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
@ -1300,9 +1312,10 @@ test "HashMap basic hash map usage" {
|
||||
const cap = 32;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
try testing.expect((try map.fetchPut(1, 11)) == null);
|
||||
try testing.expect((try map.fetchPut(2, 22)) == null);
|
||||
@ -1350,9 +1363,10 @@ test "HashMap ensureUnusedCapacity" {
|
||||
const cap = 64;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
try map.ensureUnusedCapacity(32);
|
||||
try testing.expectError(error.OutOfMemory, map.ensureUnusedCapacity(cap + 1));
|
||||
@ -1363,9 +1377,10 @@ test "HashMap removeByPtr" {
|
||||
const cap = 64;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
var i: i32 = undefined;
|
||||
i = 0;
|
||||
@ -1393,9 +1408,10 @@ test "HashMap removeByPtr 0 sized key" {
|
||||
const cap = 64;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
try map.put(0, 0);
|
||||
|
||||
@ -1416,9 +1432,10 @@ test "HashMap repeat fetchRemove" {
|
||||
const cap = 64;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const buf = try alloc.alloc(u8, Map.layoutForCapacity(cap).total_size);
|
||||
const layout = Map.layoutForCapacity(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, Map.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
var map = Map.init(cap, buf);
|
||||
var map = Map.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
map.putAssumeCapacity(0, {});
|
||||
map.putAssumeCapacity(1, {});
|
||||
@ -1440,13 +1457,13 @@ test "HashMap repeat fetchRemove" {
|
||||
|
||||
test "OffsetHashMap basic usage" {
|
||||
const OffsetMap = AutoOffsetHashMap(u32, u32);
|
||||
const cap = 16;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const cap = 16;
|
||||
const buf = try alloc.alloc(u8, OffsetMap.Unmanaged.layoutForCapacity(cap).total_size);
|
||||
const layout = OffsetMap.layout(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, OffsetMap.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
|
||||
var offset_map = OffsetMap.init(cap, buf);
|
||||
var offset_map = OffsetMap.init(OffsetBuf.init(buf), layout);
|
||||
var map = offset_map.map(buf.ptr);
|
||||
|
||||
const count = 5;
|
||||
@ -1475,13 +1492,13 @@ test "OffsetHashMap basic usage" {
|
||||
|
||||
test "OffsetHashMap remake map" {
|
||||
const OffsetMap = AutoOffsetHashMap(u32, u32);
|
||||
const cap = 16;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
const cap = 16;
|
||||
const buf = try alloc.alloc(u8, OffsetMap.Unmanaged.layoutForCapacity(cap).total_size);
|
||||
const layout = OffsetMap.layout(cap);
|
||||
const buf = try alloc.alignedAlloc(u8, OffsetMap.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
|
||||
var offset_map = OffsetMap.init(cap, buf);
|
||||
var offset_map = OffsetMap.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
{
|
||||
var map = offset_map.map(buf.ptr);
|
||||
|
@ -36,16 +36,23 @@ pub fn Offset(comptime T: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
/// A type that is used to intitialize offset-based structures.
|
||||
/// This allows for tracking the base pointer, the offset into
|
||||
/// the base pointer we're starting, and the memory layout of
|
||||
/// components.
|
||||
/// Represents a buffer that is offset from some base pointer.
|
||||
/// Offset-based structures should use this as their initialization
|
||||
/// parameter so that they can know what segment of memory they own
|
||||
/// while at the same time initializing their offset fields to be
|
||||
/// against the true base.
|
||||
///
|
||||
/// The term "true base" is used to describe the base address of
|
||||
/// the allocation, which i.e. can include memory that you do NOT
|
||||
/// own and is used by some other structures. All offsets are against
|
||||
/// this "true base" so that to determine addresses structures don't
|
||||
/// need to add up all the intermediary offsets.
|
||||
pub const OffsetBuf = struct {
|
||||
/// The true base pointer to the backing memory. This is
|
||||
/// "byte zero" of the allocation. This plus the offset make
|
||||
/// it easy to pass in the base pointer in all usage to this
|
||||
/// structure and the offsets are correct.
|
||||
base: [*]u8 = 0,
|
||||
base: [*]u8,
|
||||
|
||||
/// Offset from base where the beginning of /this/ data
|
||||
/// structure is located. We use this so that we can slowly
|
||||
@ -53,11 +60,45 @@ pub const OffsetBuf = struct {
|
||||
/// have the base pointer sent into functions be the true base.
|
||||
offset: usize = 0,
|
||||
|
||||
pub fn offsetBase(comptime T: type, self: OffsetBuf) [*]T {
|
||||
/// Initialize a zero-offset buffer from a base.
|
||||
pub fn init(base: anytype) OffsetBuf {
|
||||
return initOffset(base, 0);
|
||||
}
|
||||
|
||||
/// Initialize from some base pointer and offset.
|
||||
pub fn initOffset(base: anytype, offset: usize) OffsetBuf {
|
||||
return .{
|
||||
.base = @ptrFromInt(intFromBase(base)),
|
||||
.offset = offset,
|
||||
};
|
||||
}
|
||||
|
||||
/// The base address for the start of the data for the user
|
||||
/// of this OffsetBuf. This is where your data structure should
|
||||
/// begin; anything before this is NOT your memory.
|
||||
pub fn start(self: OffsetBuf) [*]u8 {
|
||||
const ptr = self.base + self.offset;
|
||||
assert(@intFromPtr(ptr) % @alignOf(T) == 0);
|
||||
return @ptrCast(ptr);
|
||||
}
|
||||
|
||||
/// Returns an Offset calculation for some child member of
|
||||
/// your struct. The offset is against the true base pointer
|
||||
/// so that future callers can pass that in as the base.
|
||||
pub fn member(
|
||||
self: OffsetBuf,
|
||||
comptime T: type,
|
||||
len: usize,
|
||||
) Offset(T) {
|
||||
return .{ .offset = @intCast(self.offset + len) };
|
||||
}
|
||||
|
||||
/// Add an offset to the current offset.
|
||||
pub fn add(self: OffsetBuf, offset: usize) OffsetBuf {
|
||||
return .{
|
||||
.base = self.base,
|
||||
.offset = self.offset + offset,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the offset for a given type from some base pointer to the
|
||||
@ -74,7 +115,8 @@ pub fn getOffset(
|
||||
}
|
||||
|
||||
fn intFromBase(base: anytype) usize {
|
||||
return switch (@typeInfo(@TypeOf(base))) {
|
||||
const T = @TypeOf(base);
|
||||
return switch (@typeInfo(T)) {
|
||||
.Pointer => |v| switch (v.size) {
|
||||
.One,
|
||||
.Many,
|
||||
@ -84,7 +126,11 @@ fn intFromBase(base: anytype) usize {
|
||||
.Slice => @intFromPtr(base.ptr),
|
||||
},
|
||||
|
||||
else => @compileError("invalid base type"),
|
||||
else => switch (T) {
|
||||
OffsetBuf => @intFromPtr(base.base),
|
||||
|
||||
else => @compileError("invalid base type"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ const color = @import("../color.zig");
|
||||
const sgr = @import("../sgr.zig");
|
||||
const size = @import("size.zig");
|
||||
const Offset = size.Offset;
|
||||
const OffsetBuf = size.OffsetBuf;
|
||||
const hash_map = @import("hash_map.zig");
|
||||
const AutoOffsetHashMap = hash_map.AutoOffsetHashMap;
|
||||
|
||||
@ -49,6 +50,8 @@ pub const Style = struct {
|
||||
|
||||
/// A set of styles.
|
||||
pub const Set = struct {
|
||||
pub const base_align = @max(MetadataMap.base_align, IdMap.base_align);
|
||||
|
||||
/// The mapping of a style to associated metadata. This is
|
||||
/// the map that contains the actual style definitions
|
||||
/// (in the form of the key).
|
||||
@ -74,42 +77,40 @@ pub const Set = struct {
|
||||
/// determine how much memory to allocate, and the layout must
|
||||
/// be used to initialize the set so that the set knows all
|
||||
/// the offsets for the various buffers.
|
||||
pub fn layoutForCapacity(base: usize, cap: usize) Layout {
|
||||
const md_start = std.mem.alignForward(usize, base, MetadataMap.base_align);
|
||||
const md_end = md_start + MetadataMap.bufferSize(@intCast(cap));
|
||||
pub fn layout(cap: usize) Layout {
|
||||
const md_layout = MetadataMap.layout(@intCast(cap));
|
||||
const md_start = 0;
|
||||
const md_end = md_start + md_layout.total_size;
|
||||
|
||||
const id_layout = IdMap.layout(@intCast(cap));
|
||||
const id_start = std.mem.alignForward(usize, md_end, IdMap.base_align);
|
||||
const id_end = id_start + IdMap.bufferSize(@intCast(cap));
|
||||
const id_end = id_start + id_layout.total_size;
|
||||
|
||||
const total_size = id_end - base;
|
||||
const total_size = id_end;
|
||||
|
||||
return .{
|
||||
.cap = cap,
|
||||
.md_start = md_start,
|
||||
.md_layout = md_layout,
|
||||
.id_start = id_start,
|
||||
.id_layout = id_layout,
|
||||
.total_size = total_size,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Layout = struct {
|
||||
cap: usize,
|
||||
md_start: usize,
|
||||
md_layout: MetadataMap.Layout,
|
||||
id_start: usize,
|
||||
id_layout: IdMap.Layout,
|
||||
total_size: usize,
|
||||
};
|
||||
|
||||
pub fn init(base: []u8, layout: Layout) Set {
|
||||
assert(base.len >= layout.total_size);
|
||||
|
||||
var styles = MetadataMap.init(@intCast(layout.cap), base[layout.md_start..]);
|
||||
styles.metadata.offset += @intCast(layout.md_start);
|
||||
|
||||
var id_map = IdMap.init(@intCast(layout.cap), base[layout.id_start..]);
|
||||
id_map.metadata.offset += @intCast(layout.id_start);
|
||||
|
||||
pub fn init(base: OffsetBuf, l: Layout) Set {
|
||||
const styles_buf = base.add(l.md_start);
|
||||
const id_buf = base.add(l.id_start);
|
||||
return .{
|
||||
.styles = styles,
|
||||
.id_map = id_map,
|
||||
.styles = MetadataMap.init(styles_buf, l.md_layout),
|
||||
.id_map = IdMap.init(id_buf, l.id_layout),
|
||||
};
|
||||
}
|
||||
|
||||
@ -179,13 +180,13 @@ test {
|
||||
test "Set basic usage" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
const layout = Set.layoutForCapacity(0, 16);
|
||||
const buf = try alloc.alloc(u8, layout.total_size);
|
||||
const layout = Set.layout(16);
|
||||
const buf = try alloc.alignedAlloc(u8, Set.base_align, layout.total_size);
|
||||
defer alloc.free(buf);
|
||||
|
||||
const style: Style = .{ .flags = .{ .bold = true } };
|
||||
|
||||
var set = Set.init(buf, layout);
|
||||
var set = Set.init(OffsetBuf.init(buf), layout);
|
||||
|
||||
// Upsert
|
||||
const meta = try set.upsert(buf, style);
|
||||
|
Reference in New Issue
Block a user