Just added proper iterator's for [SlotMap, KeyedSlotMap] 🥀
This commit is contained in:
parent
0aef87a252
commit
5ae089628b
5 changed files with 295 additions and 24 deletions
|
|
@ -108,6 +108,7 @@ pub fn FixedArrayList(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
/// Prefer for iteration
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn items(self: *Self) []T {
|
pub fn items(self: *Self) []T {
|
||||||
return self.data[0..self.cursor];
|
return self.data[0..self.cursor];
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,89 @@ pub fn FixedSlotMap(
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Entry = struct {
|
||||||
|
value: *T,
|
||||||
|
handle: Handle(T),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live entries, yielding the value and its handle
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Iterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *Iterator) ?Entry {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return .{
|
||||||
|
.value = &self.values[i],
|
||||||
|
.handle = .{ .idx = @intCast(i), .gen = self.generations[i] },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live handles
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const HandleIterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *HandleIterator) ?Handle(T) {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return .{ .idx = @intCast(i), .gen = self.generations[i] };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live values
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const ValueIterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *ValueIterator) ?*T {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return &self.values[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Next live index, or null
|
||||||
|
/// Skips slots that live on the free list ( `` tombstones `` )
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn nextLive(
|
||||||
|
len: usize,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: *usize,
|
||||||
|
) ?usize {
|
||||||
|
while (index.* < len) : (index.* += 1) {
|
||||||
|
if (std.mem.indexOfScalar(u32, free_list, @intCast(index.*)) == null) {
|
||||||
|
const i = index.*;
|
||||||
|
index.* += 1;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// FIELDS
|
// FIELDS
|
||||||
//
|
//
|
||||||
|
|
@ -118,6 +201,42 @@ pub fn FixedSlotMap(
|
||||||
self.free_list.clear();
|
self.free_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn contains(self: *Self, handle: Handle(T)) bool {
|
||||||
|
return self.get(handle) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn iterator(self: *Self) Iterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items(),
|
||||||
|
.generations = self.generations.items(),
|
||||||
|
.free_list = self.free_list.items(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn handleIterator(self: *Self) HandleIterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items(),
|
||||||
|
.generations = self.generations.items(),
|
||||||
|
.free_list = self.free_list.items(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn valueIterator(self: *Self) ValueIterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items(),
|
||||||
|
.generations = self.generations.items(),
|
||||||
|
.free_list = self.free_list.items(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
fn mint(self: *Self) u32 {
|
fn mint(self: *Self) u32 {
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ test "SlotMap" {
|
||||||
defer a.end();
|
defer a.end();
|
||||||
|
|
||||||
// --- # ---
|
// --- # ---
|
||||||
for (materials.values.items) |material| {
|
var it = materials.valueIterator();
|
||||||
|
while (it.next()) |material| {
|
||||||
if (a.section(.debug, "", ansi.cyan)) |b| {
|
if (a.section(.debug, "", ansi.cyan)) |b| {
|
||||||
defer b.end();
|
defer b.end();
|
||||||
|
|
||||||
|
|
@ -194,4 +195,7 @@ test "FixedSlotMap" {
|
||||||
if (materials.get(handle)) |v| {
|
if (materials.get(handle)) |v| {
|
||||||
std.debug.print("Material: {}\n", .{v.unique.topology});
|
std.debug.print("Material: {}\n", .{v.unique.topology});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var it = materials.valueIterator();
|
||||||
|
while (it.next()) |_| {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,13 +47,33 @@ pub fn KeyedSlotMap(
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const Iterator = struct {
|
pub const Iterator = struct {
|
||||||
entries: []Entry,
|
entries: []Entry,
|
||||||
|
generations: []const u32,
|
||||||
free_list: []const u32,
|
free_list: []const u32,
|
||||||
index: usize = 0,
|
index: usize = 0,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn next(self: *Iterator) ?*Entry {
|
pub fn next(self: *Iterator) ?*Entry {
|
||||||
return advance(self.entries, self.free_list, &self.index);
|
const i = nextLive(self.entries.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return &self.entries[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live handles
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const HandleIterator = struct {
|
||||||
|
entries: []Entry,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *HandleIterator) ?Handle(V) {
|
||||||
|
const i = nextLive(self.entries.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return .{ .idx = @intCast(i), .gen = self.generations[i] };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -62,14 +82,15 @@ pub fn KeyedSlotMap(
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const KeyIterator = struct {
|
pub const KeyIterator = struct {
|
||||||
entries: []Entry,
|
entries: []Entry,
|
||||||
|
generations: []const u32,
|
||||||
free_list: []const u32,
|
free_list: []const u32,
|
||||||
index: usize = 0,
|
index: usize = 0,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn next(self: *KeyIterator) ?*K {
|
pub fn next(self: *KeyIterator) ?*K {
|
||||||
const entry = advance(self.entries, self.free_list, &self.index) orelse return null;
|
const i = nextLive(self.entries.len, self.free_list, &self.index) orelse return null;
|
||||||
return &entry.key;
|
return &self.entries[i].key;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,30 +99,33 @@ pub fn KeyedSlotMap(
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const ValueIterator = struct {
|
pub const ValueIterator = struct {
|
||||||
entries: []Entry,
|
entries: []Entry,
|
||||||
|
generations: []const u32,
|
||||||
free_list: []const u32,
|
free_list: []const u32,
|
||||||
index: usize = 0,
|
index: usize = 0,
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn next(self: *ValueIterator) ?*V {
|
pub fn next(self: *ValueIterator) ?*V {
|
||||||
const entry = advance(self.entries, self.free_list, &self.index) orelse return null;
|
const i = nextLive(self.entries.len, self.free_list, &self.index) orelse return null;
|
||||||
return &entry.value;
|
return &self.entries[i].value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// Skips slots that live on the free list (tombstones)
|
/// Next live index, or null
|
||||||
|
/// Skips slots that live on the free list ( `` tombstones `` rip-bozo 😭 )
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
fn advance(
|
fn nextLive(
|
||||||
entries: []Entry,
|
len: usize,
|
||||||
free_list: []const u32,
|
free_list: []const u32,
|
||||||
index: *usize,
|
index: *usize,
|
||||||
) ?*Entry {
|
) ?usize {
|
||||||
while (index.* < entries.len) : (index.* += 1) {
|
while (index.* < len) : (index.* += 1) {
|
||||||
if (std.mem.indexOfScalar(u32, free_list, @intCast(index.*)) != null) continue;
|
if (std.mem.indexOfScalar(u32, free_list, @intCast(index.*)) == null) {
|
||||||
const entry = &entries[index.*];
|
const i = index.*;
|
||||||
index.* += 1;
|
index.* += 1;
|
||||||
return entry;
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -245,36 +269,40 @@ pub fn KeyedSlotMap(
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn items(self: *Self) []Entry {
|
|
||||||
return self.slot_map.values.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
/// Skips slots that live on the free list (tombstones)
|
|
||||||
/// ----------------------------------------------------
|
|
||||||
pub fn iterator(self: *Self) Iterator {
|
pub fn iterator(self: *Self) Iterator {
|
||||||
return .{
|
return .{
|
||||||
.entries = self.slot_map.values.items,
|
.entries = self.slot_map.values.items,
|
||||||
|
.generations = self.slot_map.generations.items,
|
||||||
.free_list = self.slot_map.free_list.items,
|
.free_list = self.slot_map.free_list.items,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// Skips slots that live on the free list (tombstones)
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn keyIterator(self: *Self) KeyIterator {
|
pub fn keyIterator(self: *Self) KeyIterator {
|
||||||
return .{
|
return .{
|
||||||
.entries = self.slot_map.values.items,
|
.entries = self.slot_map.values.items,
|
||||||
|
.generations = self.slot_map.generations.items,
|
||||||
.free_list = self.slot_map.free_list.items,
|
.free_list = self.slot_map.free_list.items,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// Skips slots that live on the free list (tombstones)
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub fn valueIterator(self: *Self) ValueIterator {
|
pub fn valueIterator(self: *Self) ValueIterator {
|
||||||
return .{
|
return .{
|
||||||
.entries = self.slot_map.values.items,
|
.entries = self.slot_map.values.items,
|
||||||
|
.generations = self.slot_map.generations.items,
|
||||||
|
.free_list = self.slot_map.free_list.items,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn handleIterator(self: *Self) HandleIterator {
|
||||||
|
return .{
|
||||||
|
.entries = self.slot_map.values.items,
|
||||||
|
.generations = self.slot_map.generations.items,
|
||||||
.free_list = self.slot_map.free_list.items,
|
.free_list = self.slot_map.free_list.items,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
119
src/slot_map.zig
119
src/slot_map.zig
|
|
@ -21,6 +21,89 @@ pub fn SlotMap(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Entry = struct {
|
||||||
|
value: *T,
|
||||||
|
handle: Handle(T),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live entries, yielding the value and its handle
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Iterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *Iterator) ?Entry {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return .{
|
||||||
|
.value = &self.values[i],
|
||||||
|
.handle = .{ .idx = @intCast(i), .gen = self.generations[i] },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live handles
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const HandleIterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *HandleIterator) ?Handle(T) {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return .{ .idx = @intCast(i), .gen = self.generations[i] };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Cursor over live values
|
||||||
|
/// Removed (freed) slots are skipped
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const ValueIterator = struct {
|
||||||
|
values: []T,
|
||||||
|
generations: []const u32,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: usize = 0,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(self: *ValueIterator) ?*T {
|
||||||
|
const i = nextLive(self.values.len, self.free_list, &self.index) orelse return null;
|
||||||
|
return &self.values[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Next live index, or null
|
||||||
|
/// Skips slots that live on the free list ( `` tombstones `` )
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn nextLive(
|
||||||
|
len: usize,
|
||||||
|
free_list: []const u32,
|
||||||
|
index: *usize,
|
||||||
|
) ?usize {
|
||||||
|
while (index.* < len) : (index.* += 1) {
|
||||||
|
if (std.mem.indexOfScalar(u32, free_list, @intCast(index.*)) == null) {
|
||||||
|
const i = index.*;
|
||||||
|
index.* += 1;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// FIELDS
|
// FIELDS
|
||||||
//
|
//
|
||||||
|
|
@ -118,6 +201,42 @@ pub fn SlotMap(comptime T: type) type {
|
||||||
return &self.values.items[handle.idx];
|
return &self.values.items[handle.idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn contains(self: *Self, handle: Handle(T)) bool {
|
||||||
|
return self.get(handle) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn iterator(self: *Self) Iterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items,
|
||||||
|
.generations = self.generations.items,
|
||||||
|
.free_list = self.free_list.items,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn handleIterator(self: *Self) HandleIterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items,
|
||||||
|
.generations = self.generations.items,
|
||||||
|
.free_list = self.free_list.items,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn valueIterator(self: *Self) ValueIterator {
|
||||||
|
return .{
|
||||||
|
.values = self.values.items,
|
||||||
|
.generations = self.generations.items,
|
||||||
|
.free_list = self.free_list.items,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// Reduce length to 0
|
/// Reduce length to 0
|
||||||
/// Invalidates all element pointers and handles
|
/// Invalidates all element pointers and handles
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue