simplify sparse set

master
Mike 5 years ago
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…
Cancel
Save