|
|
|
@ -2,18 +2,18 @@ const std = @import("std");
|
|
|
|
|
const warn = std.debug.warn;
|
|
|
|
|
|
|
|
|
|
// TODO: fix entity_mask. it should come from EntityTraitsDefinition.
|
|
|
|
|
pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
pub fn SparseSet(comptime SparseT: type) type {
|
|
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
|
|
sparse: std.ArrayList(DenseT),
|
|
|
|
|
sparse: std.ArrayList(SparseT),
|
|
|
|
|
dense: std.ArrayList(SparseT),
|
|
|
|
|
entity_mask: SparseT,
|
|
|
|
|
allocator: ?*std.mem.Allocator,
|
|
|
|
|
|
|
|
|
|
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
|
|
|
|
|
var set = allocator.create(Self) catch unreachable;
|
|
|
|
|
set.sparse = std.ArrayList(DenseT).init(allocator);
|
|
|
|
|
set.sparse = std.ArrayList(SparseT).init(allocator);
|
|
|
|
|
set.dense = std.ArrayList(SparseT).init(allocator);
|
|
|
|
|
set.entity_mask = std.math.maxInt(SparseT);
|
|
|
|
|
set.allocator = allocator;
|
|
|
|
@ -22,7 +22,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
|
|
|
|
|
pub fn init(allocator: *std.mem.Allocator) Self {
|
|
|
|
|
return Self{
|
|
|
|
|
.sparse = std.ArrayList(DenseT).init(allocator),
|
|
|
|
|
.sparse = std.ArrayList(SparseT).init(allocator),
|
|
|
|
|
.dense = std.ArrayList(SparseT).init(allocator),
|
|
|
|
|
.entity_mask = std.math.maxInt(SparseT),
|
|
|
|
|
.allocator = null,
|
|
|
|
@ -49,7 +49,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
return sparse & self.entity_mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn assure(self: *Self, pos: usize) []DenseT {
|
|
|
|
|
fn assure(self: *Self, pos: usize) []SparseT {
|
|
|
|
|
// TODO: support paging
|
|
|
|
|
if (self.sparse.capacity <= pos or self.sparse.capacity == 0) {
|
|
|
|
|
const amount = pos + 1 - self.sparse.capacity;
|
|
|
|
@ -58,7 +58,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
const old_len = self.sparse.items.len;
|
|
|
|
|
self.sparse.resize(self.sparse.items.len + amount) catch unreachable;
|
|
|
|
|
self.sparse.expandToCapacity();
|
|
|
|
|
std.mem.set(DenseT, self.sparse.items[old_len..self.sparse.items.len], std.math.maxInt(DenseT));
|
|
|
|
|
std.mem.set(SparseT, self.sparse.items[old_len..self.sparse.items.len], std.math.maxInt(SparseT));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self.sparse.items;
|
|
|
|
@ -93,11 +93,11 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// testing against maxInt permits to avoid accessing the packed array
|
|
|
|
|
return curr < self.sparse.items.len and self.sparse.items[curr] != std.math.maxInt(DenseT);
|
|
|
|
|
return curr < self.sparse.items.len and self.sparse.items[curr] != std.math.maxInt(SparseT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the position of an entity in a sparse set
|
|
|
|
|
pub fn index(self: Self, sparse: SparseT) DenseT {
|
|
|
|
|
pub fn index(self: Self, sparse: SparseT) SparseT {
|
|
|
|
|
std.debug.assert(self.contains(sparse));
|
|
|
|
|
return self.sparse.items[self.offset(sparse)];
|
|
|
|
|
}
|
|
|
|
@ -107,7 +107,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
std.debug.assert(!self.contains(sparse));
|
|
|
|
|
|
|
|
|
|
// assure(page(entt))[offset(entt)] = packed.size()
|
|
|
|
|
self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(DenseT, self.dense.items.len);
|
|
|
|
|
self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, self.dense.items.len);
|
|
|
|
|
_ = self.dense.append(sparse) catch unreachable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -121,7 +121,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
|
|
|
|
|
self.dense.items[self.sparse.items[curr]] = last_dense;
|
|
|
|
|
self.sparse.items[self.page(last_dense)] = self.sparse.items[curr];
|
|
|
|
|
self.sparse.items[curr] = std.math.maxInt(DenseT);
|
|
|
|
|
self.sparse.items[curr] = std.math.maxInt(SparseT);
|
|
|
|
|
|
|
|
|
|
_ = self.dense.pop();
|
|
|
|
|
}
|
|
|
|
@ -132,7 +132,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
var to = &self.sparse.items[sparse_r];
|
|
|
|
|
|
|
|
|
|
std.mem.swap(SparseT, &self.dense.items[from.*], &self.dense.items[to.*]);
|
|
|
|
|
std.mem.swap(DenseT, from, to);
|
|
|
|
|
std.mem.swap(SparseT, from, to);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sort elements according to the given comparison function
|
|
|
|
@ -141,15 +141,15 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|
|
|
|
|
|
|
|
|
var i = @as(usize, 0);
|
|
|
|
|
for (self.dense.items) |sparse| {
|
|
|
|
|
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(DenseT, sparse);
|
|
|
|
|
self.sparse.items[self.page(sparse)] = @intCast(DenseT, sparse);
|
|
|
|
|
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse);
|
|
|
|
|
self.sparse.items[self.page(sparse)] = @intCast(SparseT, sparse);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sort entities according to their order in another sparse set. Other is the master in this case.
|
|
|
|
|
pub fn respect(self: *Self, other: *Self) void {
|
|
|
|
|
var pos = @as(DenseT, 0);
|
|
|
|
|
var i = @as(DenseT, 0);
|
|
|
|
|
var pos = @as(SparseT, 0);
|
|
|
|
|
var i = @as(SparseT, 0);
|
|
|
|
|
while (i < other.dense.items.len) : (i += 1) {
|
|
|
|
|
if (self.contains(other.dense.items[i])) {
|
|
|
|
|
if (other.dense.items[i] != self.dense.items[pos]) {
|
|
|
|
@ -181,7 +181,7 @@ fn printSet(set: *SparseSet(u32, u8)) void {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "add/remove/clear" {
|
|
|
|
|
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set.deinit();
|
|
|
|
|
|
|
|
|
|
set.add(4);
|
|
|
|
@ -198,7 +198,7 @@ test "add/remove/clear" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "grow" {
|
|
|
|
|
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set.deinit();
|
|
|
|
|
|
|
|
|
|
var i = @as(usize, std.math.maxInt(u8));
|
|
|
|
@ -210,7 +210,7 @@ test "grow" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "swap" {
|
|
|
|
|
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set.deinit();
|
|
|
|
|
|
|
|
|
|
set.add(4);
|
|
|
|
@ -224,7 +224,7 @@ test "swap" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "data() synced" {
|
|
|
|
|
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set.deinit();
|
|
|
|
|
|
|
|
|
|
set.add(0);
|
|
|
|
@ -242,10 +242,10 @@ test "data() synced" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "respect" {
|
|
|
|
|
var set1 = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set1 = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set1.deinit();
|
|
|
|
|
|
|
|
|
|
var set2 = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set2 = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set2.deinit();
|
|
|
|
|
|
|
|
|
|
set1.add(3);
|
|
|
|
@ -265,7 +265,7 @@ test "respect" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "respect" {
|
|
|
|
|
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
|
|
|
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
|
|
|
|
defer set.deinit();
|
|
|
|
|
|
|
|
|
|
set.add(5);
|
|
|
|
|