GTL/src/fixed_slot_map.zig

106 lines
3.2 KiB
Zig
Raw Normal View History

const std = @import("std");
const FixedArrayList = @import("fixed_array_list.zig").FixedArrayList;
const Handle = @import("handle.zig").Handle;
/// ----------------------------------------------------
/// # Example
///
/// ```zig
/// ```
/// ----------------------------------------------------
pub fn FixedSlotMap(
comptime T: type,
comptime Capacity: usize,
) type {
return struct {
const Self = @This();
//
// FIELDS
//
// --- VALUES ---
values: FixedArrayList(T, Capacity),
// --- LIFE TIMES ---
generations: FixedArrayList(u32, Capacity),
free_list: FixedArrayList(u32, Capacity),
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const empty = Self{
.values = .empty,
.generations = .empty,
.free_list = .empty,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn put(
self: *Self,
value: T,
) error{Full}!Handle(T) {
// --- NEW GENERATION ---
if (self.free_list.pop()) |idx| {
self.values.data[@intCast(idx)] = value;
self.generations.data[@intCast(idx)] += 1;
return .{
.idx = idx,
.gen = self.generations.data[idx],
};
}
// --- METADATA ---
const idx = self.values.len();
const handle: Handle(T) = .{
.idx = @intCast(idx),
.gen = 1,
};
// --- NEW VALUE ---
try self.values.append(value);
errdefer _ = self.values.swapRemove(idx);
// --- NEW GENERATION ---
try self.generations.append(1);
// --- RESULT ---
return handle;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn remove(
self: *Self,
handle: Handle(T),
) void {
const idx: u32 = handle.idx;
// --- CHECK IF STALE ---
if (idx >= self.generations.len()) return;
if (self.generations.data[idx] != handle.gen) return;
// --- GENERATION ---
self.generations.data[idx] +|= 1;
self.free_list.append(idx) catch |err| {
std.debug.print("[SLOTMAP_ERROR] {s}\n", .{@errorName(err)});
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn get(self: *Self, handle: Handle(T)) ?*T {
if (handle.idx >= self.values.len()) return null;
if (self.generations.data[handle.idx] != handle.gen) return null;
return &self.values.data[handle.idx];
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn items(self: *Self) []T {
return self.values.items();
}
};
}