simplify sparse set
This commit is contained in:
parent
b32e907fd4
commit
faeedaf43d
@ -6,9 +6,8 @@ const SparseSet = @import("sparse_set.zig").SparseSet;
|
||||
const Signal = @import("../signals/signal.zig").Signal;
|
||||
const Sink = @import("../signals/sink.zig").Sink;
|
||||
|
||||
/// Stores an ArrayList of components along with a SparseSet of entities. The max amount that can be stored is
|
||||
/// based on the max value of DenseT
|
||||
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime DenseT: type) type {
|
||||
/// Stores an ArrayList of components along with a SparseSet of entities
|
||||
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
|
||||
std.debug.assert(!utils.isComptime(CompT));
|
||||
|
||||
// empty (zero-sized) structs will not have an array created
|
||||
@ -25,7 +24,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
set: *SparseSet(EntityT, DenseT),
|
||||
set: *SparseSet(EntityT),
|
||||
instances: std.ArrayList(CompOrAlmostEmptyT),
|
||||
allocator: ?*std.mem.Allocator,
|
||||
safe_deinit: fn (*Self) void,
|
||||
@ -36,7 +35,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) Self {
|
||||
var store = Self{
|
||||
.set = SparseSet(EntityT, DenseT).initPtr(allocator),
|
||||
.set = SparseSet(EntityT).initPtr(allocator),
|
||||
.instances = undefined,
|
||||
.safe_deinit = struct {
|
||||
fn deinit(self: *Self) void {
|
||||
@ -65,7 +64,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
||||
|
||||
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
|
||||
var store = allocator.create(Self) catch unreachable;
|
||||
store.set = SparseSet(EntityT, DenseT).initPtr(allocator);
|
||||
store.set = SparseSet(EntityT).initPtr(allocator);
|
||||
if (!is_empty_struct)
|
||||
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
|
||||
store.allocator = allocator;
|
||||
@ -204,7 +203,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
||||
}
|
||||
|
||||
test "add/try-get/remove/clear" {
|
||||
var store = ComponentStorage(f32, u32, u8).init(std.testing.allocator);
|
||||
var store = ComponentStorage(f32, u32).init(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
store.add(3, 66.45);
|
||||
@ -220,7 +219,7 @@ test "add/try-get/remove/clear" {
|
||||
}
|
||||
|
||||
test "add/get/remove" {
|
||||
var store = ComponentStorage(f32, u32, u8).init(std.testing.allocator);
|
||||
var store = ComponentStorage(f32, u32).init(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
store.add(3, 66.45);
|
||||
@ -232,7 +231,7 @@ test "add/get/remove" {
|
||||
}
|
||||
|
||||
test "iterate" {
|
||||
var store = ComponentStorage(f32, u32, u8).initPtr(std.testing.allocator);
|
||||
var store = ComponentStorage(f32, u32).initPtr(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
store.add(3, 66.45);
|
||||
@ -252,7 +251,7 @@ test "iterate" {
|
||||
test "empty component" {
|
||||
const Empty = struct {};
|
||||
|
||||
var store = ComponentStorage(Empty, u32, u8).initPtr(std.testing.allocator);
|
||||
var store = ComponentStorage(Empty, u32).initPtr(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
store.add(3, Empty{});
|
||||
@ -270,7 +269,7 @@ fn destruct(e: u32) void {
|
||||
}
|
||||
|
||||
test "signals" {
|
||||
var store = ComponentStorage(f32, u32, u8).init(std.testing.allocator);
|
||||
var store = ComponentStorage(f32, u32).init(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
store.onConstruct().connect(construct);
|
||||
|
@ -11,7 +11,7 @@ pub fn BasicGroup(comptime n_includes: usize, comptime n_excludes: usize) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
entity_set: *SparseSet(Entity, u16),
|
||||
entity_set: *SparseSet(Entity),
|
||||
registry: *Registry,
|
||||
type_ids: [n_includes]u32,
|
||||
exclude_type_ids: [n_excludes]u32,
|
||||
@ -41,7 +41,7 @@ pub fn BasicGroup(comptime n_includes: usize, comptime n_excludes: usize) type {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(entity_set: *SparseSet(Entity, u16), registry: *Registry, type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
|
||||
pub fn init(entity_set: *SparseSet(Entity), registry: *Registry, type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
|
||||
return Self{
|
||||
.entity_set = entity_set,
|
||||
.registry = registry,
|
||||
|
@ -22,7 +22,7 @@ pub const OwningGroup = @import("groups.zig").OwningGroup;
|
||||
|
||||
/// Stores an ArrayList of components. The max amount that can be stored is based on the type below
|
||||
pub fn Storage(comptime CompT: type) type {
|
||||
return ComponentStorage(CompT, Entity, u16); // 65,535 components
|
||||
return ComponentStorage(CompT, Entity);
|
||||
}
|
||||
|
||||
/// the registry is the main gateway to all ecs functionality. It assumes all internal allocations will succeed and returns
|
||||
@ -38,7 +38,7 @@ pub const Registry = struct {
|
||||
/// internal, persistant data structure to manage the entities in a group
|
||||
const GroupData = struct {
|
||||
hash: u32,
|
||||
entity_set: SparseSet(Entity, u16) = undefined, // TODO: dont hardcode this. put it in EntityTraits maybe. All SparseSets would need to use the value.
|
||||
entity_set: SparseSet(Entity) = undefined, /// optional. there will be an entity_set for non-owning groups and current for owning
|
||||
owned: []u32,
|
||||
include: []u32,
|
||||
exclude: []u32,
|
||||
@ -53,7 +53,7 @@ pub const Registry = struct {
|
||||
var group_data = allocator.create(GroupData) catch unreachable;
|
||||
group_data.hash = hash;
|
||||
if (owned.len == 0) {
|
||||
group_data.entity_set = SparseSet(Entity, u16).init(allocator);
|
||||
group_data.entity_set = SparseSet(Entity).init(allocator);
|
||||
}
|
||||
group_data.owned = std.mem.dupe(allocator, u32, owned) catch unreachable;
|
||||
group_data.include = std.mem.dupe(allocator, u32, include) catch unreachable;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user