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 Signal = @import("../signals/signal.zig").Signal;
|
||||||
const Sink = @import("../signals/sink.zig").Sink;
|
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
|
/// Stores an ArrayList of components along with a SparseSet of entities
|
||||||
/// based on the max value of DenseT
|
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
|
||||||
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime DenseT: type) type {
|
|
||||||
std.debug.assert(!utils.isComptime(CompT));
|
std.debug.assert(!utils.isComptime(CompT));
|
||||||
|
|
||||||
// empty (zero-sized) structs will not have an array created
|
// 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 {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
set: *SparseSet(EntityT, DenseT),
|
set: *SparseSet(EntityT),
|
||||||
instances: std.ArrayList(CompOrAlmostEmptyT),
|
instances: std.ArrayList(CompOrAlmostEmptyT),
|
||||||
allocator: ?*std.mem.Allocator,
|
allocator: ?*std.mem.Allocator,
|
||||||
safe_deinit: fn (*Self) void,
|
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 {
|
pub fn init(allocator: *std.mem.Allocator) Self {
|
||||||
var store = Self{
|
var store = Self{
|
||||||
.set = SparseSet(EntityT, DenseT).initPtr(allocator),
|
.set = SparseSet(EntityT).initPtr(allocator),
|
||||||
.instances = undefined,
|
.instances = undefined,
|
||||||
.safe_deinit = struct {
|
.safe_deinit = struct {
|
||||||
fn deinit(self: *Self) void {
|
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 {
|
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
|
||||||
var store = allocator.create(Self) catch unreachable;
|
var store = allocator.create(Self) catch unreachable;
|
||||||
store.set = SparseSet(EntityT, DenseT).initPtr(allocator);
|
store.set = SparseSet(EntityT).initPtr(allocator);
|
||||||
if (!is_empty_struct)
|
if (!is_empty_struct)
|
||||||
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
|
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
|
||||||
store.allocator = 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" {
|
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();
|
defer store.deinit();
|
||||||
|
|
||||||
store.add(3, 66.45);
|
store.add(3, 66.45);
|
||||||
@ -220,7 +219,7 @@ test "add/try-get/remove/clear" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "add/get/remove" {
|
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();
|
defer store.deinit();
|
||||||
|
|
||||||
store.add(3, 66.45);
|
store.add(3, 66.45);
|
||||||
@ -232,7 +231,7 @@ test "add/get/remove" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "iterate" {
|
test "iterate" {
|
||||||
var store = ComponentStorage(f32, u32, u8).initPtr(std.testing.allocator);
|
var store = ComponentStorage(f32, u32).initPtr(std.testing.allocator);
|
||||||
defer store.deinit();
|
defer store.deinit();
|
||||||
|
|
||||||
store.add(3, 66.45);
|
store.add(3, 66.45);
|
||||||
@ -252,7 +251,7 @@ test "iterate" {
|
|||||||
test "empty component" {
|
test "empty component" {
|
||||||
const Empty = struct {};
|
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();
|
defer store.deinit();
|
||||||
|
|
||||||
store.add(3, Empty{});
|
store.add(3, Empty{});
|
||||||
@ -270,7 +269,7 @@ fn destruct(e: u32) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "signals" {
|
test "signals" {
|
||||||
var store = ComponentStorage(f32, u32, u8).init(std.testing.allocator);
|
var store = ComponentStorage(f32, u32).init(std.testing.allocator);
|
||||||
defer store.deinit();
|
defer store.deinit();
|
||||||
|
|
||||||
store.onConstruct().connect(construct);
|
store.onConstruct().connect(construct);
|
||||||
|
@ -11,7 +11,7 @@ pub fn BasicGroup(comptime n_includes: usize, comptime n_excludes: usize) type {
|
|||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
entity_set: *SparseSet(Entity, u16),
|
entity_set: *SparseSet(Entity),
|
||||||
registry: *Registry,
|
registry: *Registry,
|
||||||
type_ids: [n_includes]u32,
|
type_ids: [n_includes]u32,
|
||||||
exclude_type_ids: [n_excludes]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{
|
return Self{
|
||||||
.entity_set = entity_set,
|
.entity_set = entity_set,
|
||||||
.registry = registry,
|
.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
|
/// 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 {
|
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
|
/// 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
|
/// internal, persistant data structure to manage the entities in a group
|
||||||
const GroupData = struct {
|
const GroupData = struct {
|
||||||
hash: u32,
|
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,
|
owned: []u32,
|
||||||
include: []u32,
|
include: []u32,
|
||||||
exclude: []u32,
|
exclude: []u32,
|
||||||
@ -53,7 +53,7 @@ pub const Registry = struct {
|
|||||||
var group_data = allocator.create(GroupData) catch unreachable;
|
var group_data = allocator.create(GroupData) catch unreachable;
|
||||||
group_data.hash = hash;
|
group_data.hash = hash;
|
||||||
if (owned.len == 0) {
|
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.owned = std.mem.dupe(allocator, u32, owned) catch unreachable;
|
||||||
group_data.include = std.mem.dupe(allocator, u32, include) 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;
|
const warn = std.debug.warn;
|
||||||
|
|
||||||
// TODO: fix entity_mask. it should come from EntityTraitsDefinition.
|
// 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 {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
sparse: std.ArrayList(DenseT),
|
sparse: std.ArrayList(SparseT),
|
||||||
dense: std.ArrayList(SparseT),
|
dense: std.ArrayList(SparseT),
|
||||||
entity_mask: SparseT,
|
entity_mask: SparseT,
|
||||||
allocator: ?*std.mem.Allocator,
|
allocator: ?*std.mem.Allocator,
|
||||||
|
|
||||||
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
|
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
|
||||||
var set = allocator.create(Self) catch unreachable;
|
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.dense = std.ArrayList(SparseT).init(allocator);
|
||||||
set.entity_mask = std.math.maxInt(SparseT);
|
set.entity_mask = std.math.maxInt(SparseT);
|
||||||
set.allocator = allocator;
|
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 {
|
pub fn init(allocator: *std.mem.Allocator) Self {
|
||||||
return Self{
|
return Self{
|
||||||
.sparse = std.ArrayList(DenseT).init(allocator),
|
.sparse = std.ArrayList(SparseT).init(allocator),
|
||||||
.dense = std.ArrayList(SparseT).init(allocator),
|
.dense = std.ArrayList(SparseT).init(allocator),
|
||||||
.entity_mask = std.math.maxInt(SparseT),
|
.entity_mask = std.math.maxInt(SparseT),
|
||||||
.allocator = null,
|
.allocator = null,
|
||||||
@ -49,7 +49,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|||||||
return sparse & self.entity_mask;
|
return sparse & self.entity_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assure(self: *Self, pos: usize) []DenseT {
|
fn assure(self: *Self, pos: usize) []SparseT {
|
||||||
// TODO: support paging
|
// TODO: support paging
|
||||||
if (self.sparse.capacity <= pos or self.sparse.capacity == 0) {
|
if (self.sparse.capacity <= pos or self.sparse.capacity == 0) {
|
||||||
const amount = pos + 1 - self.sparse.capacity;
|
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;
|
const old_len = self.sparse.items.len;
|
||||||
self.sparse.resize(self.sparse.items.len + amount) catch unreachable;
|
self.sparse.resize(self.sparse.items.len + amount) catch unreachable;
|
||||||
self.sparse.expandToCapacity();
|
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;
|
return self.sparse.items;
|
||||||
@ -93,11 +93,11 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// testing against maxInt permits to avoid accessing the packed array
|
// 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
|
/// 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));
|
std.debug.assert(self.contains(sparse));
|
||||||
return self.sparse.items[self.offset(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));
|
std.debug.assert(!self.contains(sparse));
|
||||||
|
|
||||||
// assure(page(entt))[offset(entt)] = packed.size()
|
// 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;
|
_ = 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.dense.items[self.sparse.items[curr]] = last_dense;
|
||||||
self.sparse.items[self.page(last_dense)] = self.sparse.items[curr];
|
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();
|
_ = self.dense.pop();
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type {
|
|||||||
var to = &self.sparse.items[sparse_r];
|
var to = &self.sparse.items[sparse_r];
|
||||||
|
|
||||||
std.mem.swap(SparseT, &self.dense.items[from.*], &self.dense.items[to.*]);
|
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
|
/// 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);
|
var i = @as(usize, 0);
|
||||||
for (self.dense.items) |sparse| {
|
for (self.dense.items) |sparse| {
|
||||||
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(DenseT, sparse);
|
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse);
|
||||||
self.sparse.items[self.page(sparse)] = @intCast(DenseT, 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.
|
/// 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 {
|
pub fn respect(self: *Self, other: *Self) void {
|
||||||
var pos = @as(DenseT, 0);
|
var pos = @as(SparseT, 0);
|
||||||
var i = @as(DenseT, 0);
|
var i = @as(SparseT, 0);
|
||||||
while (i < other.dense.items.len) : (i += 1) {
|
while (i < other.dense.items.len) : (i += 1) {
|
||||||
if (self.contains(other.dense.items[i])) {
|
if (self.contains(other.dense.items[i])) {
|
||||||
if (other.dense.items[i] != self.dense.items[pos]) {
|
if (other.dense.items[i] != self.dense.items[pos]) {
|
||||||
@ -181,7 +181,7 @@ fn printSet(set: *SparseSet(u32, u8)) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "add/remove/clear" {
|
test "add/remove/clear" {
|
||||||
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set.deinit();
|
defer set.deinit();
|
||||||
|
|
||||||
set.add(4);
|
set.add(4);
|
||||||
@ -198,7 +198,7 @@ test "add/remove/clear" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "grow" {
|
test "grow" {
|
||||||
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set.deinit();
|
defer set.deinit();
|
||||||
|
|
||||||
var i = @as(usize, std.math.maxInt(u8));
|
var i = @as(usize, std.math.maxInt(u8));
|
||||||
@ -210,7 +210,7 @@ test "grow" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "swap" {
|
test "swap" {
|
||||||
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set.deinit();
|
defer set.deinit();
|
||||||
|
|
||||||
set.add(4);
|
set.add(4);
|
||||||
@ -224,7 +224,7 @@ test "swap" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "data() synced" {
|
test "data() synced" {
|
||||||
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set.deinit();
|
defer set.deinit();
|
||||||
|
|
||||||
set.add(0);
|
set.add(0);
|
||||||
@ -242,10 +242,10 @@ test "data() synced" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "respect" {
|
test "respect" {
|
||||||
var set1 = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set1 = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set1.deinit();
|
defer set1.deinit();
|
||||||
|
|
||||||
var set2 = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set2 = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set2.deinit();
|
defer set2.deinit();
|
||||||
|
|
||||||
set1.add(3);
|
set1.add(3);
|
||||||
@ -265,7 +265,7 @@ test "respect" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "respect" {
|
test "respect" {
|
||||||
var set = SparseSet(u32, u8).initPtr(std.testing.allocator);
|
var set = SparseSet(u32).initPtr(std.testing.allocator);
|
||||||
defer set.deinit();
|
defer set.deinit();
|
||||||
|
|
||||||
set.add(5);
|
set.add(5);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user