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(); } }; }