udpate to Zig master

master
Mike 5 years ago
parent f2a302b7a4
commit bdb4b0537d

@ -1,6 +1,8 @@
// ecs
pub const EntityTraitsType = @import("ecs/entity.zig").EntityTraitsType;
pub const ComponentStorage = @import("ecs/component_storage.zig").ComponentStorage;
pub const Entity = @import("ecs/registry.zig").Entity;
pub const Registry = @import("ecs/registry.zig").Registry;
pub const BasicView = @import("ecs/views.zig").BasicView;

@ -17,9 +17,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
// non-zero sized type. That will make is_empty_struct false in deinit always so we can't use it. Instead, we stick
// a small dummy struct in the instances ArrayList so it can safely be deallocated.
// Perhaps we should just allocate instances with a dummy allocator or the tmp allocator?
comptime var CompOrAlmostEmptyT = CompT;
if (is_empty_struct)
CompOrAlmostEmptyT = struct { dummy: u1 };
comptime var CompOrAlmostEmptyT = if (is_empty_struct) struct { dummy: u1 } else CompT;
return struct {
const Self = @This();
@ -27,7 +25,8 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
set: *SparseSet(EntityT),
instances: std.ArrayList(CompOrAlmostEmptyT),
allocator: ?*std.mem.Allocator,
super: usize = 0, /// doesnt really belong here...used to denote group ownership
/// doesnt really belong here...used to denote group ownership
super: usize = 0,
safe_deinit: fn (*Self) void,
safe_swap: fn (*Self, EntityT, EntityT) void,
construction: Signal(EntityT),
@ -40,14 +39,16 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
.instances = undefined,
.safe_deinit = struct {
fn deinit(self: *Self) void {
if (!is_empty_struct)
if (!is_empty_struct) {
self.instances.deinit();
}
}
}.deinit,
.safe_swap = struct {
fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void {
if (!is_empty_struct)
if (!is_empty_struct) {
std.mem.swap(CompT, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]);
}
self.set.swap(lhs, rhs);
}
}.swap,
@ -57,8 +58,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
.destruction = Signal(EntityT).init(allocator),
};
if (!is_empty_struct)
if (!is_empty_struct) {
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
}
return store;
}
@ -66,8 +68,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
pub fn initPtr(allocator: *std.mem.Allocator) *Self {
var store = allocator.create(Self) catch unreachable;
store.set = SparseSet(EntityT).initPtr(allocator);
if (!is_empty_struct)
if (!is_empty_struct) {
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
}
store.allocator = allocator;
store.super = 0;
store.construction = Signal(EntityT).init(allocator);
@ -77,9 +80,10 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
// since we are stored as a pointer, we need to catpure this
store.safe_deinit = struct {
fn deinit(self: *Self) void {
if (!is_empty_struct)
if (!is_empty_struct) {
self.instances.deinit();
}
}
}.deinit;
store.safe_swap = struct {
@ -157,7 +161,12 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
}
pub usingnamespace if (is_empty_struct)
struct {}
struct {
/// Sort Entities according to the given comparison function
pub fn sort(self: Self, comptime sortFn: fn (void, EntityT, EntityT) bool) void {
self.set.sort(sortFn);
}
}
else
struct {
/// Direct access to the array of objects
@ -189,6 +198,21 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
pub fn tryGetConst(self: *Self, entity: EntityT) ?CompT {
return if (self.set.contains(entity)) self.instances.items[self.set.index(entity)] else null;
}
/// Sort Entities or Components according to the given comparison function
pub fn sort(self: Self, comptime T: type, comptime sortFn: fn (void, T, T) bool) void {
std.debug.assert(T == EntityT or T == CompT);
if (T == EntityT) {
self.set.sortSub(sortFn, CompT, self.instances.items);
} else if (T == CompT) {
// essentially need to be able to call a sort method with a bound fn. That fn would then use sortFn along
// with self.instances.
// fn sorter(self: Self, a: T, b: T, sortFn) bool {
// return sortFn(self.instances[a], self.instances[b]);
// }
//return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)]));
}
}
};
/// Direct access to the array of entities
@ -207,8 +231,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
}
pub fn clear(self: *Self) void {
if (!is_empty_struct)
if (!is_empty_struct) {
self.instances.items.len = 0;
}
self.set.clear();
}
};
@ -251,14 +276,17 @@ test "iterate" {
store.add(7, 66.45);
for (store.data()) |entity, i| {
if (i == 0)
if (i == 0) {
std.testing.expectEqual(entity, 3);
if (i == 1)
}
if (i == 1) {
std.testing.expectEqual(entity, 5);
if (i == 2)
}
if (i == 2) {
std.testing.expectEqual(entity, 7);
}
}
}
test "empty component" {
const Empty = struct {};
@ -300,3 +328,54 @@ test "signals" {
store.replace(4, 45.64);
store.remove(4);
}
const asc_u32 = std.sort.asc(u32);
const desc_u32 = std.sort.desc(u32);
test "sort empty component" {
const Empty = struct {};
var store = ComponentStorage(Empty, u32).initPtr(std.testing.allocator);
defer store.deinit();
store.add(1, Empty{});
store.add(2, Empty{});
store.add(0, Empty{});
store.sort(asc_u32);
for (store.data()) |e, i| {
std.testing.expectEqual(@intCast(u32, i), e);
}
store.sort(desc_u32);
var counter: u32 = 2;
for (store.data()) |e, i| {
std.testing.expectEqual(counter, e);
if (counter > 0) counter -= 1;
}
}
const asc_f32 = std.sort.asc(f32);
const desc_f32 = std.sort.desc(f32);
test "sort component" {
std.debug.warn("\n", .{});
var store = ComponentStorage(f32, u32).initPtr(std.testing.allocator);
defer store.deinit();
store.add(1, @as(f32, 1.1));
store.add(2, @as(f32, 2.2));
store.add(0, @as(f32, 0.0));
store.sort(f32, asc_f32);
for (store.raw()) |e, i| {
// std.debug.warn("{}: {}\n", .{i, e});
// std.testing.expectEqual(@intCast(u32, i), e);
}
store.sort(f32, desc_f32);
for (store.raw()) |e, i| {
// std.testing.expectEqual(counter, e);
}
}

@ -78,7 +78,7 @@ pub const Registry = struct {
allocator.destroy(self);
}
fn maybeValidIf(self: *GroupData, entity: Entity) void {
pub fn maybeValidIf(self: *GroupData, entity: Entity) void {
const isValid: bool = blk: {
for (self.owned) |tid| {
const ptr = self.registry.components.getValue(tid).?;
@ -120,7 +120,7 @@ pub const Registry = struct {
}
}
fn discardIf(self: *GroupData, entity: Entity) void {
pub fn discardIf(self: *GroupData, entity: Entity) void {
if (self.owned.len == 0) {
if (self.entity_set.contains(entity))
self.entity_set.remove(entity);
@ -608,7 +608,7 @@ pub const Registry = struct {
inline fn concatTypes(comptime types: var) []const u8 {
comptime {
const impl = struct {
fn asc(lhs: []const u8, rhs: []const u8) bool {
fn asc(context: void, lhs: []const u8, rhs: []const u8) bool {
return std.mem.lessThan(u8, lhs, rhs);
}
};
@ -618,7 +618,7 @@ pub const Registry = struct {
name.* = @typeName(types[i]);
}
std.sort.sort([]const u8, &names, impl.asc);
std.sort.sort([]const u8, &names, {}, impl.asc);
comptime var res: []const u8 = "";
inline for (names) |name| res = res ++ name;

@ -1,5 +1,6 @@
const std = @import("std");
const warn = std.debug.warn;
const utils = @import("utils.zig");
const ReverseSliceIterator = @import("utils.zig").ReverseSliceIterator;
// TODO: fix entity_mask. it should come from EntityTraitsDefinition.
@ -38,7 +39,7 @@ pub fn SparseSet(comptime SparseT: type) type {
allocator.destroy(self);
}
fn page(self: Self, sparse: SparseT) usize {
pub fn page(self: Self, sparse: SparseT) usize {
// TODO: support paging
// return (sparse & EntityTraits.entity_mask) / sparse_per_page;
return sparse & self.entity_mask;
@ -141,10 +142,19 @@ pub fn SparseSet(comptime SparseT: type) type {
}
/// Sort elements according to the given comparison function
pub fn sort(self: *Self, sortFn: fn (SparseT, SparseT) bool) void {
std.sort.insertionSort(SparseT, self.dense.items, sortFn);
pub fn sort(self: *Self, comptime sortFn: fn (void, SparseT, SparseT) bool) void {
std.sort.insertionSort(SparseT, self.dense.items, {}, sortFn);
for (self.dense.items) |sparse| {
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse);
self.sparse.items[self.page(sparse)] = @intCast(SparseT, sparse);
}
}
/// Sort elements according to the given comparison function and keeps sub_items with the same sort
pub fn sortSub(self: *Self, comptime sortFn: fn (void, SparseT, SparseT) bool, comptime T: type, sub_items: []T) void {
utils.sortSub(SparseT, T, self.dense.items, sub_items, sortFn);
var i = @as(usize, 0);
for (self.dense.items) |sparse| {
// self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse);
self.sparse.items[self.page(sparse)] = @intCast(SparseT, sparse);
@ -290,6 +300,8 @@ test "respect 1" {
std.testing.expectEqual(set1.dense.items[1], set2.dense.items[2]);
}
const desc_u32 = std.sort.desc(u32);
test "respect 2" {
var set = SparseSet(u32).initPtr(std.testing.allocator);
defer set.deinit();
@ -300,7 +312,7 @@ test "respect 2" {
set.add(1);
set.add(3);
set.sort(std.sort.desc(u32));
set.sort(desc_u32);
for (set.dense.items) |item, i| {
if (i < set.dense.items.len - 1) {

@ -49,13 +49,13 @@ pub fn ReverseSliceIterator(comptime T: type) type {
}
/// sorts items using lessThan and keeps sub_items with the same sort
pub fn sortSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T2, lessThan: fn (lhs: T1, rhs: T1) bool) void {
pub fn sortSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T2, lessThan: fn (void, lhs: T1, rhs: T1) bool) void {
var i: usize = 1;
while (i < items.len) : (i += 1) {
const x = items[i];
const y = sub_items[i];
var j: usize = i;
while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
while (j > 0 and lessThan({}, x, items[j - 1])) : (j -= 1) {
items[j] = items[j - 1];
sub_items[j] = sub_items[j - 1];
}

@ -14,12 +14,41 @@ const Rotation = struct { x: f32 = 0 };
fn printStore(store: var, name: []const u8) void {
warn("--- {} ---\n", .{name});
for (store.set.dense.items) |e, i| {
warn("{:3.0}", .{e});
warn(" ({d:3.0})", .{store.instances.items[i]});
warn("[{}] {}", .{e, store.set.sparse.items[store.set.page(store.set.dense.items[i])]});
warn(" ({d:.2}) ", .{store.instances.items[i]});
}
warn("\n", .{});
}
const asc_u32 = std.sort.asc(u32);
const desc_u32 = std.sort.desc(f32);
test "sort component" {
std.debug.warn("\n", .{});
var store = ecs.ComponentStorage(f32, u32).initPtr(std.testing.allocator);
defer store.deinit();
store.add(1, @as(f32, 1.1));
store.add(2, @as(f32, 2.2));
store.add(0, @as(f32, 0.0));
printStore(store, "Fucker");
store.sort(u32, asc_u32);
for (store.raw()) |e, i| {
// std.debug.warn("{}: {}\n", .{i, e});
// std.testing.expectEqual(@intCast(u32, i), e);
}
printStore(store, "Fucker");
store.sort(f32, desc_u32);
for (store.raw()) |e, i| {
// std.testing.expectEqual(counter, e);
}
}
test "nested OwningGroups add/remove components" {
var reg = Registry.init(std.testing.allocator);
defer reg.deinit();

Loading…
Cancel
Save