2026-07-12 19:46:40 +01:00
|
|
|
const std = @import("std");
|
|
|
|
|
const Handle = @import("handle.zig").Handle;
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
2026-07-12 21:22:53 +01:00
|
|
|
pub fn SlotMap(comptime T: type) type {
|
2026-07-12 19:46:40 +01:00
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// FIELDS
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// --- VALUES ---
|
2026-07-12 21:22:53 +01:00
|
|
|
values: std.ArrayList(T),
|
2026-07-12 19:46:40 +01:00
|
|
|
|
|
|
|
|
// --- LIFE TIMES ---
|
|
|
|
|
generations: std.ArrayList(u32),
|
|
|
|
|
free_list: std.ArrayList(u32),
|
|
|
|
|
|
2026-07-12 21:22:53 +01:00
|
|
|
// --- MEMORY ---
|
2026-07-12 19:46:40 +01:00
|
|
|
alloc: std.mem.Allocator,
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
pub fn init(alloc: std.mem.Allocator) Self {
|
|
|
|
|
return .{
|
|
|
|
|
.values = .empty,
|
|
|
|
|
|
|
|
|
|
.generations = .empty,
|
|
|
|
|
.free_list = .empty,
|
|
|
|
|
|
|
|
|
|
.alloc = alloc,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
pub fn deinit(self: *Self) void {
|
|
|
|
|
self.values.deinit(self.alloc);
|
|
|
|
|
self.generations.deinit(self.alloc);
|
|
|
|
|
self.free_list.deinit(self.alloc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
pub fn put(
|
|
|
|
|
self: *Self,
|
2026-07-12 21:22:53 +01:00
|
|
|
value: T,
|
|
|
|
|
) error{ Duplicate, OutOfMemory }!Handle(T) {
|
2026-07-12 19:46:40 +01:00
|
|
|
// --- NEW GENERATION ---
|
|
|
|
|
if (self.free_list.pop()) |idx| {
|
2026-07-12 21:22:53 +01:00
|
|
|
self.values.items[@intCast(idx)] = value;
|
2026-07-12 19:46:40 +01:00
|
|
|
self.generations.items[@intCast(idx)] += 1;
|
|
|
|
|
|
|
|
|
|
return .{
|
|
|
|
|
.idx = idx,
|
|
|
|
|
.gen = self.generations.items[idx],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- METADATA ---
|
|
|
|
|
const idx = self.values.items.len;
|
2026-07-12 21:22:53 +01:00
|
|
|
const handle: Handle(T) = .{
|
2026-07-12 19:46:40 +01:00
|
|
|
.idx = @intCast(idx),
|
|
|
|
|
.gen = 1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- NEW VALUE ---
|
2026-07-12 21:22:53 +01:00
|
|
|
try self.values.append(self.alloc, value);
|
2026-07-12 19:46:40 +01:00
|
|
|
errdefer _ = self.values.swapRemove(idx);
|
|
|
|
|
|
|
|
|
|
// --- NEW GENERATION ---
|
|
|
|
|
try self.generations.append(self.alloc, 1);
|
|
|
|
|
|
|
|
|
|
// --- RESULT ---
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
pub fn remove(
|
|
|
|
|
self: *Self,
|
2026-07-12 21:22:53 +01:00
|
|
|
handle: Handle(T),
|
2026-07-12 19:46:40 +01:00
|
|
|
) void {
|
|
|
|
|
const idx: u32 = handle.idx;
|
|
|
|
|
|
|
|
|
|
// --- CHECK IF STALE ---
|
|
|
|
|
if (idx >= self.generations.items.len) return;
|
|
|
|
|
if (self.generations.items[idx] != handle.gen) return;
|
|
|
|
|
|
|
|
|
|
// --- GENERATION ---
|
|
|
|
|
self.generations.items[idx] +|= 1;
|
|
|
|
|
self.free_list.append(self.alloc, idx) catch unreachable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
2026-07-12 21:22:53 +01:00
|
|
|
pub fn get(self: *Self, handle: Handle(T)) ?*T {
|
2026-07-12 19:46:40 +01:00
|
|
|
if (handle.idx >= self.values.items.len) return null;
|
|
|
|
|
if (self.generations.items[handle.idx] != handle.gen) return null;
|
2026-07-12 21:22:53 +01:00
|
|
|
return &self.values.items[handle.idx];
|
2026-07-12 19:46:40 +01:00
|
|
|
}
|
2026-07-13 00:50:40 +01:00
|
|
|
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
/// ----------------------------------------------------
|
|
|
|
|
pub fn items(self: *Self) []T {
|
|
|
|
|
return self.values.items;
|
|
|
|
|
}
|
2026-07-12 19:46:40 +01:00
|
|
|
};
|
|
|
|
|
}
|