Current section
Files
Jump to
Current section
Files
zig/opentui/mem-registry.zig
const std = @import("std");
const Allocator = std.mem.Allocator;
pub const MemRegistryError = error{
OutOfMemory,
InvalidMemId,
};
/// Memory buffer reference in the registry
pub const MemBuffer = struct {
data: []const u8,
owned: bool,
active: bool, // Track if slot is in use
};
/// Registry for multiple memory buffers
pub const MemRegistry = struct {
buffers: std.ArrayListUnmanaged(MemBuffer),
free_slots: std.ArrayListUnmanaged(u8), // Track free slot indices
allocator: Allocator,
pub fn init(allocator: Allocator) MemRegistry {
return .{
.buffers = .{},
.free_slots = .{},
.allocator = allocator,
};
}
pub fn deinit(self: *MemRegistry) void {
for (self.buffers.items) |mem_buf| {
if (mem_buf.active and mem_buf.owned) {
self.allocator.free(mem_buf.data);
}
}
self.buffers.deinit(self.allocator);
self.free_slots.deinit(self.allocator);
}
pub fn register(self: *MemRegistry, data: []const u8, owned: bool) MemRegistryError!u8 {
// Try to reuse a free slot first
if (self.free_slots.items.len > 0) {
const id = self.free_slots.items[self.free_slots.items.len - 1];
_ = self.free_slots.pop();
self.buffers.items[id] = MemBuffer{
.data = data,
.owned = owned,
.active = true,
};
return id;
}
// No free slots, allocate a new one
if (self.buffers.items.len >= 255) {
return MemRegistryError.OutOfMemory;
}
const id: u8 = @intCast(self.buffers.items.len);
try self.buffers.append(self.allocator, MemBuffer{
.data = data,
.owned = owned,
.active = true,
});
return id;
}
pub fn get(self: *const MemRegistry, id: u8) ?[]const u8 {
if (id >= self.buffers.items.len) return null;
const buf = self.buffers.items[id];
if (!buf.active) return null;
return buf.data;
}
pub fn replace(self: *MemRegistry, id: u8, data: []const u8, owned: bool) MemRegistryError!void {
if (id >= self.buffers.items.len) return MemRegistryError.InvalidMemId;
const prev = self.buffers.items[id];
if (!prev.active) return MemRegistryError.InvalidMemId;
if (prev.owned) {
self.allocator.free(prev.data);
}
self.buffers.items[id] = .{ .data = data, .owned = owned, .active = true };
}
pub fn unregister(self: *MemRegistry, id: u8) MemRegistryError!void {
if (id >= self.buffers.items.len) return MemRegistryError.InvalidMemId;
var buf = &self.buffers.items[id];
if (!buf.active) return MemRegistryError.InvalidMemId;
// Free owned memory
if (buf.owned) {
self.allocator.free(buf.data);
}
// Mark slot as inactive
buf.active = false;
buf.data = &[_]u8{};
buf.owned = false;
// Add to free slots list
try self.free_slots.append(self.allocator, id);
}
pub fn clear(self: *MemRegistry) void {
for (self.buffers.items) |mem_buf| {
if (mem_buf.active and mem_buf.owned) {
self.allocator.free(mem_buf.data);
}
}
self.buffers.clearRetainingCapacity();
self.free_slots.clearRetainingCapacity();
}
pub fn getUsedSlots(self: *const MemRegistry) usize {
// Count only active slots
var count: usize = 0;
for (self.buffers.items) |buf| {
if (buf.active) count += 1;
}
return count;
}
pub fn getFreeSlots(self: *const MemRegistry) usize {
// Total capacity (255) minus buffers allocated plus explicitly freed slots
return 255 - self.buffers.items.len + self.free_slots.items.len;
}
};