udpate to Zig master

master
Mike 4 years ago
parent f2a302b7a4
commit bdb4b0537d

@ -1,6 +1,8 @@
// ecs // ecs
pub const EntityTraitsType = @import("ecs/entity.zig").EntityTraitsType; 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 Entity = @import("ecs/registry.zig").Entity;
pub const Registry = @import("ecs/registry.zig").Registry; pub const Registry = @import("ecs/registry.zig").Registry;
pub const BasicView = @import("ecs/views.zig").BasicView; 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 // 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. // 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? // Perhaps we should just allocate instances with a dummy allocator or the tmp allocator?
comptime var CompOrAlmostEmptyT = CompT; comptime var CompOrAlmostEmptyT = if (is_empty_struct) struct { dummy: u1 } else CompT;
if (is_empty_struct)
CompOrAlmostEmptyT = struct { dummy: u1 };
return struct { return struct {
const Self = @This(); const Self = @This();
@ -27,7 +25,8 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
set: *SparseSet(EntityT), set: *SparseSet(EntityT),
instances: std.ArrayList(CompOrAlmostEmptyT), instances: std.ArrayList(CompOrAlmostEmptyT),
allocator: ?*std.mem.Allocator, 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_deinit: fn (*Self) void,
safe_swap: fn (*Self, EntityT, EntityT) void, safe_swap: fn (*Self, EntityT, EntityT) void,
construction: Signal(EntityT), construction: Signal(EntityT),
@ -40,14 +39,16 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
.instances = undefined, .instances = undefined,
.safe_deinit = struct { .safe_deinit = struct {
fn deinit(self: *Self) void { fn deinit(self: *Self) void {
if (!is_empty_struct) if (!is_empty_struct) {
self.instances.deinit(); self.instances.deinit();
}
} }
}.deinit, }.deinit,
.safe_swap = struct { .safe_swap = struct {
fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void { 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)]); std.mem.swap(CompT, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]);
}
self.set.swap(lhs, rhs); self.set.swap(lhs, rhs);
} }
}.swap, }.swap,
@ -57,8 +58,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
.destruction = Signal(EntityT).init(allocator), .destruction = Signal(EntityT).init(allocator),
}; };
if (!is_empty_struct) if (!is_empty_struct) {
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator); store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
}
return store; return store;
} }
@ -66,8 +68,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
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).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;
store.super = 0; store.super = 0;
store.construction = Signal(EntityT).init(allocator); store.construction = Signal(EntityT).init(allocator);
@ -77,8 +80,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
// since we are stored as a pointer, we need to catpure this // since we are stored as a pointer, we need to catpure this
store.safe_deinit = struct { store.safe_deinit = struct {
fn deinit(self: *Self) void { fn deinit(self: *Self) void {
if (!is_empty_struct) if (!is_empty_struct) {
self.instances.deinit(); self.instances.deinit();
}
} }
}.deinit; }.deinit;
@ -157,7 +161,12 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type {
} }
pub usingnamespace if (is_empty_struct) 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 else
struct { struct {
/// Direct access to the array of objects /// 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 { pub fn tryGetConst(self: *Self, entity: EntityT) ?CompT {
return if (self.set.contains(entity)) self.instances.items[self.set.index(entity)] else null; 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 /// 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 { pub fn clear(self: *Self) void {
if (!is_empty_struct) if (!is_empty_struct) {
self.instances.items.len = 0; self.instances.items.len = 0;
}
self.set.clear(); self.set.clear();
} }
}; };
@ -251,12 +276,15 @@ test "iterate" {
store.add(7, 66.45); store.add(7, 66.45);
for (store.data()) |entity, i| { for (store.data()) |entity, i| {
if (i == 0) if (i == 0) {
std.testing.expectEqual(entity, 3); std.testing.expectEqual(entity, 3);
if (i == 1) }
if (i == 1) {
std.testing.expectEqual(entity, 5); std.testing.expectEqual(entity, 5);
if (i == 2) }
if (i == 2) {
std.testing.expectEqual(entity, 7); std.testing.expectEqual(entity, 7);
}
} }
} }
@ -300,3 +328,54 @@ test "signals" {
store.replace(4, 45.64); store.replace(4, 45.64);
store.remove(4); 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); allocator.destroy(self);
} }
fn maybeValidIf(self: *GroupData, entity: Entity) void { pub fn maybeValidIf(self: *GroupData, entity: Entity) void {
const isValid: bool = blk: { const isValid: bool = blk: {
for (self.owned) |tid| { for (self.owned) |tid| {
const ptr = self.registry.components.getValue(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.owned.len == 0) {
if (self.entity_set.contains(entity)) if (self.entity_set.contains(entity))
self.entity_set.remove(entity); self.entity_set.remove(entity);
@ -608,7 +608,7 @@ pub const Registry = struct {
inline fn concatTypes(comptime types: var) []const u8 { inline fn concatTypes(comptime types: var) []const u8 {
comptime { comptime {
const impl = struct { 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); return std.mem.lessThan(u8, lhs, rhs);
} }
}; };
@ -618,7 +618,7 @@ pub const Registry = struct {
name.* = @typeName(types[i]); 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 = ""; comptime var res: []const u8 = "";
inline for (names) |name| res = res ++ name; inline for (names) |name| res = res ++ name;

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

@ -49,13 +49,13 @@ pub fn ReverseSliceIterator(comptime T: type) type {
} }
/// sorts items using lessThan and keeps sub_items with the same sort /// 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; var i: usize = 1;
while (i < items.len) : (i += 1) { while (i < items.len) : (i += 1) {
const x = items[i]; const x = items[i];
const y = sub_items[i]; const y = sub_items[i];
var j: usize = 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]; items[j] = items[j - 1];
sub_items[j] = sub_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 { fn printStore(store: var, name: []const u8) void {
warn("--- {} ---\n", .{name}); warn("--- {} ---\n", .{name});
for (store.set.dense.items) |e, i| { for (store.set.dense.items) |e, i| {
warn("{:3.0}", .{e}); warn("[{}] {}", .{e, store.set.sparse.items[store.set.page(store.set.dense.items[i])]});
warn(" ({d:3.0})", .{store.instances.items[i]}); warn(" ({d:.2}) ", .{store.instances.items[i]});
} }
warn("\n", .{}); 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" { test "nested OwningGroups add/remove components" {
var reg = Registry.init(std.testing.allocator); var reg = Registry.init(std.testing.allocator);
defer reg.deinit(); defer reg.deinit();

Loading…
Cancel
Save