update to latest zig version
This commit is contained in:
parent
76e322a49c
commit
9ca3e90b7b
46
zig-ecs/README.md
Normal file
46
zig-ecs/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Zig ECS
|
||||||
|
This is a zigification of the fantasic [Entt](https://github.com/skypjack/entt). Entt is _highly_ templated C++ code which depending on your opinion is either a good thing or satan itself in code form. Zig doesn't have the same concept as C++ templates (thank goodness!) so the templated code was changed over to use Zig's generics and compile time metaprogramming.
|
||||||
|
|
||||||
|
## What does a zigified Entt look like?
|
||||||
|
Below are examples of a View and a Group, the two main ways to work with entities in the ecs along with the scaffolding code.
|
||||||
|
|
||||||
|
Declare some structs to work with:
|
||||||
|
```
|
||||||
|
pub const Velocity = struct { x: f32, y: f32 };
|
||||||
|
pub const Position = struct { x: f32, y: f32 };
|
||||||
|
```
|
||||||
|
|
||||||
|
Setup the Registry, which holds the entity data and is where we run our queries:
|
||||||
|
```
|
||||||
|
var reg = ecs.Registry.init(std.testing.allocator);
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a couple entities and add some components to them
|
||||||
|
```
|
||||||
|
var entity = reg.create();
|
||||||
|
reg.add(entity, Position{ .x = 0, .y = 0 });
|
||||||
|
reg.add(entity, Velocity{ .x = 5, .y = 7 });
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Create and iterate a View that matches all entities with a `Velocity` and `Position` component:
|
||||||
|
```
|
||||||
|
var view = reg.view(.{ Velocity, Position }, .{});
|
||||||
|
|
||||||
|
var iter = view.iterator();
|
||||||
|
while (iter.next()) |entity| {
|
||||||
|
const pos = view.getConst(Position, entity); // readonly copy
|
||||||
|
var vel = view.get(Velocity, entity); // mutable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The same example using a non-owning Group:
|
||||||
|
```
|
||||||
|
var group = reg.group(.{}, .{ Velocity, Position }, .{});
|
||||||
|
group.each(each);
|
||||||
|
|
||||||
|
fn each(e: struct { vel: *Velocity, pos: *Position }) void {
|
||||||
|
e.pos.*.x += e.vel.x;
|
||||||
|
e.pos.*.y += e.vel.y;
|
||||||
|
}
|
||||||
|
```
|
@ -32,7 +32,7 @@ fn createEntities(reg: *ecs.Registry) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var end = timer.lap();
|
var end = timer.lap();
|
||||||
std.debug.warn("create entities: {d}\n", .{@intToFloat(f64, end) / 1000000000});
|
std.debug.warn("create {d} entities: {d}\n", .{total_entities, @intToFloat(f64, end) / 1000000000});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn owningGroup(reg: *ecs.Registry) void {
|
fn owningGroup(reg: *ecs.Registry) void {
|
||||||
|
@ -18,7 +18,7 @@ pub const Actor = struct {
|
|||||||
self.registry.destroy(self.entity);
|
self.registry.destroy(self.entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self: *Actor, value: var) void {
|
pub fn add(self: *Actor, value: anytype) void {
|
||||||
self.registry.add(self.entity, value);
|
self.registry.add(self.entity, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type {
|
|||||||
struct {
|
struct {
|
||||||
/// Sort Entities according to the given comparison function. Only T == Entity is allowed. The constraint param only exists for
|
/// Sort Entities according to the given comparison function. Only T == Entity is allowed. The constraint param only exists for
|
||||||
/// parity with non-empty Components
|
/// parity with non-empty Components
|
||||||
pub fn sort(self: Self, comptime T: type, context: var, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
pub fn sort(self: Self, comptime T: type, context: anytype, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
||||||
std.debug.assert(T == Entity);
|
std.debug.assert(T == Entity);
|
||||||
self.set.sort(context, lessThan);
|
self.set.sort(context, lessThan);
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sort Entities or Components according to the given comparison function. Valid types for T are Entity or Component.
|
/// Sort Entities or Components according to the given comparison function. Valid types for T are Entity or Component.
|
||||||
pub fn sort(self: *Self, comptime T: type, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
pub fn sort(self: *Self, comptime T: type, length: usize, context: anytype, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
||||||
std.debug.assert(T == Entity or T == Component);
|
std.debug.assert(T == Entity or T == Component);
|
||||||
|
|
||||||
// we have to perform a swap after the sort for all moved entities so we make a helper struct for that. In the
|
// we have to perform a swap after the sort for all moved entities so we make a helper struct for that. In the
|
||||||
|
@ -42,7 +42,7 @@ pub const BasicGroup = struct {
|
|||||||
return self.group_data.entity_set.reverseIterator();
|
return self.group_data.entity_set.reverseIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(self: BasicGroup, comptime T: type, context: var, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
pub fn sort(self: BasicGroup, comptime T: type, context: anytype, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
||||||
if (T == Entity) {
|
if (T == Entity) {
|
||||||
self.group_data.entity_set.sort(context, lessThan);
|
self.group_data.entity_set.sort(context, lessThan);
|
||||||
} else {
|
} else {
|
||||||
@ -73,7 +73,7 @@ pub const OwningGroup = struct {
|
|||||||
/// being iterated is available via the entity() method, useful for accessing non-owned component data. The get() method can
|
/// being iterated is available via the entity() method, useful for accessing non-owned component data. The get() method can
|
||||||
/// also be used to fetch non-owned component data for the currently iterated Entity.
|
/// also be used to fetch non-owned component data for the currently iterated Entity.
|
||||||
/// TODO: support const types in the Components struct in addition to the current ptrs
|
/// TODO: support const types in the Components struct in addition to the current ptrs
|
||||||
fn Iterator(comptime Components: var) type {
|
fn Iterator(comptime Components: anytype) type {
|
||||||
return struct {
|
return struct {
|
||||||
group: OwningGroup,
|
group: OwningGroup,
|
||||||
index: usize,
|
index: usize,
|
||||||
@ -136,7 +136,7 @@ pub const OwningGroup = struct {
|
|||||||
|
|
||||||
/// grabs an untyped (u1) reference to the first Storage(T) in the owned array
|
/// grabs an untyped (u1) reference to the first Storage(T) in the owned array
|
||||||
fn firstOwnedStorage(self: OwningGroup) *Storage(u1) {
|
fn firstOwnedStorage(self: OwningGroup) *Storage(u1) {
|
||||||
const ptr = self.registry.components.getValue(self.group_data.owned[0]).?;
|
const ptr = self.registry.components.get(self.group_data.owned[0]).?;
|
||||||
return @intToPtr(*Storage(u1), ptr);
|
return @intToPtr(*Storage(u1), ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ pub const OwningGroup = struct {
|
|||||||
return storage.contains(entity) and storage.set.index(entity) < self.len();
|
return storage.contains(entity) and storage.set.index(entity) < self.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(self: OwningGroup, comptime Components: var) void {
|
fn validate(self: OwningGroup, comptime Components: anytype) void {
|
||||||
if (std.builtin.mode == .Debug and self.group_data.owned.len > 0) {
|
if (std.builtin.mode == .Debug and self.group_data.owned.len > 0) {
|
||||||
std.debug.assert(@typeInfo(Components) == .Struct);
|
std.debug.assert(@typeInfo(Components) == .Struct);
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ pub const OwningGroup = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOwned(self: OwningGroup, entity: Entity, comptime Components: var) Components {
|
pub fn getOwned(self: OwningGroup, entity: Entity, comptime Components: anytype) Components {
|
||||||
self.validate(Components);
|
self.validate(Components);
|
||||||
const component_info = @typeInfo(Components).Struct;
|
const component_info = @typeInfo(Components).Struct;
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ pub const OwningGroup = struct {
|
|||||||
return comps;
|
return comps;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each(self: OwningGroup, comptime func: var) void {
|
pub fn each(self: OwningGroup, comptime func: anytype) void {
|
||||||
const Components = switch (@typeInfo(@TypeOf(func))) {
|
const Components = switch (@typeInfo(@TypeOf(func))) {
|
||||||
.BoundFn => |func_info| func_info.args[1].arg_type.?,
|
.BoundFn => |func_info| func_info.args[1].arg_type.?,
|
||||||
.Fn => |func_info| func_info.args[0].arg_type.?,
|
.Fn => |func_info| func_info.args[0].arg_type.?,
|
||||||
@ -223,7 +223,7 @@ pub const OwningGroup = struct {
|
|||||||
/// returns an iterator with optimized access to the owend Components. Note that Components should be a struct with
|
/// returns an iterator with optimized access to the owend Components. Note that Components should be a struct with
|
||||||
/// fields that are pointers to the component types that you want to fetch. Only types that are owned are valid! Non-owned
|
/// fields that are pointers to the component types that you want to fetch. Only types that are owned are valid! Non-owned
|
||||||
/// types should be fetched via Iterator.get.
|
/// types should be fetched via Iterator.get.
|
||||||
pub fn iterator(self: OwningGroup, comptime Components: var) Iterator(Components) {
|
pub fn iterator(self: OwningGroup, comptime Components: anytype) Iterator(Components) {
|
||||||
self.validate(Components);
|
self.validate(Components);
|
||||||
return Iterator(Components).init(self);
|
return Iterator(Components).init(self);
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ pub const OwningGroup = struct {
|
|||||||
return utils.ReverseSliceIterator(Entity).init(self.firstOwnedStorage().set.dense.items[0..self.group_data.current]);
|
return utils.ReverseSliceIterator(Entity).init(self.firstOwnedStorage().set.dense.items[0..self.group_data.current]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(self: OwningGroup, comptime T: type, context: var, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
pub fn sort(self: OwningGroup, comptime T: type, context: anytype, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
|
||||||
var first_storage = self.firstOwnedStorage();
|
var first_storage = self.firstOwnedStorage();
|
||||||
|
|
||||||
if (T == Entity) {
|
if (T == Entity) {
|
||||||
@ -264,7 +264,7 @@ pub const OwningGroup = struct {
|
|||||||
|
|
||||||
// skip the first one since its what we are using to sort with
|
// skip the first one since its what we are using to sort with
|
||||||
for (self.group_data.owned[1..]) |type_id| {
|
for (self.group_data.owned[1..]) |type_id| {
|
||||||
var other_ptr = self.registry.components.getValue(type_id).?;
|
var other_ptr = self.registry.components.get(type_id).?;
|
||||||
var storage = @intToPtr(*Storage(u1), other_ptr);
|
var storage = @intToPtr(*Storage(u1), other_ptr);
|
||||||
storage.swap(storage.data()[pos], entity);
|
storage.swap(storage.data()[pos], entity);
|
||||||
}
|
}
|
||||||
|
@ -81,19 +81,19 @@ pub const Registry = struct {
|
|||||||
pub 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.get(tid).?;
|
||||||
if (!@intToPtr(*Storage(u1), ptr).contains(entity))
|
if (!@intToPtr(*Storage(u1), ptr).contains(entity))
|
||||||
break :blk false;
|
break :blk false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.include) |tid| {
|
for (self.include) |tid| {
|
||||||
const ptr = self.registry.components.getValue(tid).?;
|
const ptr = self.registry.components.get(tid).?;
|
||||||
if (!@intToPtr(*Storage(u1), ptr).contains(entity))
|
if (!@intToPtr(*Storage(u1), ptr).contains(entity))
|
||||||
break :blk false;
|
break :blk false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.exclude) |tid| {
|
for (self.exclude) |tid| {
|
||||||
const ptr = self.registry.components.getValue(tid).?;
|
const ptr = self.registry.components.get(tid).?;
|
||||||
if (@intToPtr(*Storage(u1), ptr).contains(entity))
|
if (@intToPtr(*Storage(u1), ptr).contains(entity))
|
||||||
break :blk false;
|
break :blk false;
|
||||||
}
|
}
|
||||||
@ -106,11 +106,11 @@ pub const Registry = struct {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
const ptr = self.registry.components.getValue(self.owned[0]).?;
|
const ptr = self.registry.components.get(self.owned[0]).?;
|
||||||
if (!(@intToPtr(*Storage(u1), ptr).set.index(entity) < self.current)) {
|
if (!(@intToPtr(*Storage(u1), ptr).set.index(entity) < self.current)) {
|
||||||
for (self.owned) |tid| {
|
for (self.owned) |tid| {
|
||||||
// store.swap hides a safe version that types it correctly
|
// store.swap hides a safe version that types it correctly
|
||||||
const store_ptr = self.registry.components.getValue(tid).?;
|
const store_ptr = self.registry.components.get(tid).?;
|
||||||
var store = @intToPtr(*Storage(u1), store_ptr);
|
var store = @intToPtr(*Storage(u1), store_ptr);
|
||||||
store.swap(store.data()[self.current], entity);
|
store.swap(store.data()[self.current], entity);
|
||||||
}
|
}
|
||||||
@ -127,12 +127,12 @@ pub const Registry = struct {
|
|||||||
self.entity_set.remove(entity);
|
self.entity_set.remove(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const ptr = self.registry.components.getValue(self.owned[0]).?;
|
const ptr = self.registry.components.get(self.owned[0]).?;
|
||||||
var store = @intToPtr(*Storage(u1), ptr);
|
var store = @intToPtr(*Storage(u1), ptr);
|
||||||
if (store.contains(entity) and store.set.index(entity) < self.current) {
|
if (store.contains(entity) and store.set.index(entity) < self.current) {
|
||||||
self.current -= 1;
|
self.current -= 1;
|
||||||
for (self.owned) |tid| {
|
for (self.owned) |tid| {
|
||||||
const store_ptr = self.registry.components.getValue(tid).?;
|
const store_ptr = self.registry.components.get(tid).?;
|
||||||
store = @intToPtr(*Storage(u1), store_ptr);
|
store = @intToPtr(*Storage(u1), store_ptr);
|
||||||
store.swap(store.data()[self.current], entity);
|
store.swap(store.data()[self.current], entity);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ pub const Registry = struct {
|
|||||||
|
|
||||||
pub fn assure(self: *Registry, comptime T: type) *Storage(T) {
|
pub fn assure(self: *Registry, comptime T: type) *Storage(T) {
|
||||||
var type_id = utils.typeId(T);
|
var type_id = utils.typeId(T);
|
||||||
if (self.components.get(type_id)) |kv| {
|
if (self.components.getEntry(type_id)) |kv| {
|
||||||
return @intToPtr(*Storage(T), kv.value);
|
return @intToPtr(*Storage(T), kv.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ pub const Registry = struct {
|
|||||||
return self.handles.iterator();
|
return self.handles.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self: *Registry, entity: Entity, value: var) void {
|
pub fn add(self: *Registry, entity: Entity, value: anytype) void {
|
||||||
assert(self.valid(entity));
|
assert(self.valid(entity));
|
||||||
self.assure(@TypeOf(value)).add(entity, value);
|
self.assure(@TypeOf(value)).add(entity, value);
|
||||||
}
|
}
|
||||||
@ -292,14 +292,14 @@ pub const Registry = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// adds all the component types passed in as zero-initialized values
|
/// adds all the component types passed in as zero-initialized values
|
||||||
pub fn addTypes(self: *Registry, entity: Entity, comptime types: var) void {
|
pub fn addTypes(self: *Registry, entity: Entity, comptime types: anytype) void {
|
||||||
inline for (types) |t| {
|
inline for (types) |t| {
|
||||||
self.assure(t).add(entity, std.mem.zeroes(t));
|
self.assure(t).add(entity, std.mem.zeroes(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the given component for an entity
|
/// Replaces the given component for an entity
|
||||||
pub fn replace(self: *Registry, entity: Entity, value: var) void {
|
pub fn replace(self: *Registry, entity: Entity, value: anytype) void {
|
||||||
assert(self.valid(entity));
|
assert(self.valid(entity));
|
||||||
self.assure(@TypeOf(value)).replace(entity, value);
|
self.assure(@TypeOf(value)).replace(entity, value);
|
||||||
}
|
}
|
||||||
@ -309,7 +309,7 @@ pub const Registry = struct {
|
|||||||
self.replace(entity, value);
|
self.replace(entity, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addOrReplace(self: *Registry, entity: Entity, value: var) void {
|
pub fn addOrReplace(self: *Registry, entity: Entity, value: anytype) void {
|
||||||
assert(self.valid(entity));
|
assert(self.valid(entity));
|
||||||
|
|
||||||
const store = self.assure(@TypeOf(value));
|
const store = self.assure(@TypeOf(value));
|
||||||
@ -393,7 +393,7 @@ pub const Registry = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Binds an object to the context of the registry
|
/// Binds an object to the context of the registry
|
||||||
pub fn setContext(self: *Registry, context: var) void {
|
pub fn setContext(self: *Registry, context: anytype) void {
|
||||||
std.debug.assert(@typeInfo(@TypeOf(context)) == .Pointer);
|
std.debug.assert(@typeInfo(@TypeOf(context)) == .Pointer);
|
||||||
|
|
||||||
var type_id = utils.typeId(@typeInfo(@TypeOf(context)).Pointer.child);
|
var type_id = utils.typeId(@typeInfo(@TypeOf(context)).Pointer.child);
|
||||||
@ -432,7 +432,7 @@ pub const Registry = struct {
|
|||||||
return self.assure(T).super == 0;
|
return self.assure(T).super == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(self: *Registry, comptime includes: var, comptime excludes: var) ViewType(includes, excludes) {
|
pub fn view(self: *Registry, comptime includes: anytype, comptime excludes: anytype) ViewType(includes, excludes) {
|
||||||
std.debug.assert(@typeInfo(@TypeOf(includes)) == .Struct);
|
std.debug.assert(@typeInfo(@TypeOf(includes)) == .Struct);
|
||||||
std.debug.assert(@typeInfo(@TypeOf(excludes)) == .Struct);
|
std.debug.assert(@typeInfo(@TypeOf(excludes)) == .Struct);
|
||||||
std.debug.assert(includes.len > 0);
|
std.debug.assert(includes.len > 0);
|
||||||
@ -457,13 +457,13 @@ pub const Registry = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// returns the Type that a view will be based on the includes and excludes
|
/// returns the Type that a view will be based on the includes and excludes
|
||||||
fn ViewType(comptime includes: var, comptime excludes: var) type {
|
fn ViewType(comptime includes: anytype, comptime excludes: anytype) type {
|
||||||
if (includes.len == 1 and excludes.len == 0) return BasicView(includes[0]);
|
if (includes.len == 1 and excludes.len == 0) return BasicView(includes[0]);
|
||||||
return MultiView(includes.len, excludes.len);
|
return MultiView(includes.len, excludes.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// creates an optimized group for iterating components
|
/// creates an optimized group for iterating components
|
||||||
pub fn group(self: *Registry, comptime owned: var, comptime includes: var, comptime excludes: var) (if (owned.len == 0) BasicGroup else OwningGroup) {
|
pub fn group(self: *Registry, comptime owned: anytype, comptime includes: anytype, comptime excludes: anytype) (if (owned.len == 0) BasicGroup else OwningGroup) {
|
||||||
std.debug.assert(@typeInfo(@TypeOf(owned)) == .Struct);
|
std.debug.assert(@typeInfo(@TypeOf(owned)) == .Struct);
|
||||||
std.debug.assert(@typeInfo(@TypeOf(includes)) == .Struct);
|
std.debug.assert(@typeInfo(@TypeOf(includes)) == .Struct);
|
||||||
std.debug.assert(@typeInfo(@TypeOf(excludes)) == .Struct);
|
std.debug.assert(@typeInfo(@TypeOf(excludes)) == .Struct);
|
||||||
@ -593,7 +593,7 @@ pub const Registry = struct {
|
|||||||
|
|
||||||
/// given the 3 group Types arrays, generates a (mostly) unique u64 hash. Simultaneously ensures there are no duped types between
|
/// given the 3 group Types arrays, generates a (mostly) unique u64 hash. Simultaneously ensures there are no duped types between
|
||||||
/// the 3 groups.
|
/// the 3 groups.
|
||||||
inline fn hashGroupTypes(comptime owned: var, comptime includes: var, comptime excludes: var) u64 {
|
inline fn hashGroupTypes(comptime owned: anytype, comptime includes: anytype, comptime excludes: anytype) u64 {
|
||||||
comptime {
|
comptime {
|
||||||
for (owned) |t1| {
|
for (owned) |t1| {
|
||||||
for (includes) |t2| {
|
for (includes) |t2| {
|
||||||
@ -615,7 +615,7 @@ pub const Registry = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// expects a tuple of types. Convertes them to type names, sorts them then concatenates and returns the string.
|
/// expects a tuple of types. Convertes them to type names, sorts them then concatenates and returns the string.
|
||||||
inline fn concatTypes(comptime types: var) []const u8 {
|
inline fn concatTypes(comptime types: anytype) []const u8 {
|
||||||
comptime {
|
comptime {
|
||||||
if (types.len == 0) return "_";
|
if (types.len == 0) return "_";
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ 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, context: var, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool) void {
|
pub fn sort(self: *Self, context: anytype, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool) void {
|
||||||
std.sort.insertionSort(SparseT, self.dense.items, context, lessThan);
|
std.sort.insertionSort(SparseT, self.dense.items, context, lessThan);
|
||||||
|
|
||||||
for (self.dense.items) |sparse, i| {
|
for (self.dense.items) |sparse, i| {
|
||||||
@ -159,7 +159,7 @@ pub fn SparseSet(comptime SparseT: type) type {
|
|||||||
|
|
||||||
/// Sort elements according to the given comparison function. Use this when a data array needs to stay in sync with the SparseSet
|
/// Sort elements according to the given comparison function. Use this when a data array needs to stay in sync with the SparseSet
|
||||||
/// by passing in a "swap_context" that contains a "swap" method with a sig of fn(ctx,SparseT,SparseT)void
|
/// by passing in a "swap_context" that contains a "swap" method with a sig of fn(ctx,SparseT,SparseT)void
|
||||||
pub fn arrange(self: *Self, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool, swap_context: var) void {
|
pub fn arrange(self: *Self, length: usize, context: anytype, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool, swap_context: anytype) void {
|
||||||
std.sort.insertionSort(SparseT, self.dense.items[0..length], context, lessThan);
|
std.sort.insertionSort(SparseT, self.dense.items[0..length], context, lessThan);
|
||||||
|
|
||||||
for (self.dense.items[0..length]) |sparse, pos| {
|
for (self.dense.items[0..length]) |sparse, pos| {
|
||||||
|
@ -13,7 +13,7 @@ pub const TypeStore = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: TypeStore) void {
|
pub fn deinit(self: *TypeStore) void {
|
||||||
var iter = self.map.iterator();
|
var iter = self.map.iterator();
|
||||||
while (iter.next()) |kv| {
|
while (iter.next()) |kv| {
|
||||||
self.allocator.free(kv.value);
|
self.allocator.free(kv.value);
|
||||||
@ -22,7 +22,7 @@ pub const TypeStore = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// adds instance, returning a pointer to the item as it lives in the store
|
/// adds instance, returning a pointer to the item as it lives in the store
|
||||||
pub fn add(self: *TypeStore, instance: var) void {
|
pub fn add(self: *TypeStore, instance: anytype) void {
|
||||||
var bytes = self.allocator.alloc(u8, @sizeOf(@TypeOf(instance))) catch unreachable;
|
var bytes = self.allocator.alloc(u8, @sizeOf(@TypeOf(instance))) catch unreachable;
|
||||||
std.mem.copy(u8, bytes, std.mem.asBytes(&instance));
|
std.mem.copy(u8, bytes, std.mem.asBytes(&instance));
|
||||||
_ = self.map.put(utils.typeId(@TypeOf(instance)), bytes) catch unreachable;
|
_ = self.map.put(utils.typeId(@TypeOf(instance)), bytes) catch unreachable;
|
||||||
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||||||
pub const ErasedPtr = struct {
|
pub const ErasedPtr = struct {
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
|
||||||
pub fn init(ptr: var) ErasedPtr {
|
pub fn init(ptr: anytype) ErasedPtr {
|
||||||
if (@sizeOf(@TypeOf(ptr)) == 0) {
|
if (@sizeOf(@TypeOf(ptr)) == 0) {
|
||||||
return .{ .ptr = undefined };
|
return .{ .ptr = undefined };
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ pub fn sortSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sortSubSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T2, context: var, comptime lessThan: fn (@TypeOf(context), lhs: T1, rhs: T1) bool) void {
|
pub fn sortSubSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T2, context: anytype, comptime lessThan: fn (@TypeOf(context), 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];
|
||||||
|
@ -15,7 +15,7 @@ pub const Scheduler = struct {
|
|||||||
allocator: *std.mem.Allocator,
|
allocator: *std.mem.Allocator,
|
||||||
|
|
||||||
/// helper to create and prepare a process
|
/// helper to create and prepare a process
|
||||||
fn createProcessHandler(comptime T: type, data: var, allocator: *std.mem.Allocator) *Process {
|
fn createProcessHandler(comptime T: type, data: anytype, allocator: *std.mem.Allocator) *Process {
|
||||||
var proc = allocator.create(T) catch unreachable;
|
var proc = allocator.create(T) catch unreachable;
|
||||||
proc.initialize(data);
|
proc.initialize(data);
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ pub const Scheduler = struct {
|
|||||||
return .{ .process = process, .allocator = allocator };
|
return .{ .process = process, .allocator = allocator };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(self: *@This(), comptime T: type, data: var) *@This() {
|
pub fn next(self: *@This(), comptime T: type, data: anytype) *@This() {
|
||||||
self.process.next = createProcessHandler(T, data, self.allocator);
|
self.process.next = createProcessHandler(T, data, self.allocator);
|
||||||
self.process = self.process.next.?;
|
self.process = self.process.next.?;
|
||||||
return self;
|
return self;
|
||||||
@ -61,7 +61,7 @@ pub const Scheduler = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Schedules a process for the next tick
|
/// Schedules a process for the next tick
|
||||||
pub fn attach(self: *Scheduler, comptime T: type, data: var) Continuation {
|
pub fn attach(self: *Scheduler, comptime T: type, data: anytype) Continuation {
|
||||||
std.debug.assert(@hasDecl(T, "initialize"));
|
std.debug.assert(@hasDecl(T, "initialize"));
|
||||||
std.debug.assert(@hasField(T, "process"));
|
std.debug.assert(@hasField(T, "process"));
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ test "" {
|
|||||||
process: Process,
|
process: Process,
|
||||||
fart: usize,
|
fart: usize,
|
||||||
|
|
||||||
pub fn initialize(self: *@This(), data: var) void {
|
pub fn initialize(self: *@This(), data: anytype) void {
|
||||||
self.process = .{
|
self.process = .{
|
||||||
.startFn = start,
|
.startFn = start,
|
||||||
.updateFn = update,
|
.updateFn = update,
|
||||||
@ -190,7 +190,7 @@ test "scheduler.clear" {
|
|||||||
const Tester = struct {
|
const Tester = struct {
|
||||||
process: Process,
|
process: Process,
|
||||||
|
|
||||||
pub fn initialize(self: *@This(), data: var) void {
|
pub fn initialize(self: *@This(), data: anytype) void {
|
||||||
self.process = .{ .updateFn = update };
|
self.process = .{ .updateFn = update };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ test "scheduler.attach.next" {
|
|||||||
process: Process,
|
process: Process,
|
||||||
counter: *usize,
|
counter: *usize,
|
||||||
|
|
||||||
pub fn initialize(self: *@This(), data: var) void {
|
pub fn initialize(self: *@This(), data: anytype) void {
|
||||||
self.process = .{ .updateFn = update };
|
self.process = .{ .updateFn = update };
|
||||||
self.counter = data;
|
self.counter = data;
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,11 @@ pub const Assets = struct {
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(self: *Assets, id: u16, comptime loader: var) ReturnType(loader, false) {
|
pub fn load(self: *Assets, id: u16, comptime loader: anytype) ReturnType(loader, false) {
|
||||||
return self.get(ReturnType(loader, true)).load(id, loader);
|
return self.get(ReturnType(loader, true)).load(id, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ReturnType(comptime loader: var, strip_ptr: bool) type {
|
fn ReturnType(comptime loader: anytype, strip_ptr: bool) type {
|
||||||
var ret = @typeInfo(@TypeOf(@field(loader, "load"))).BoundFn.return_type.?;
|
var ret = @typeInfo(@TypeOf(@field(loader, "load"))).BoundFn.return_type.?;
|
||||||
if (strip_ptr) {
|
if (strip_ptr) {
|
||||||
return ret.Child;
|
return ret.Child;
|
||||||
|
@ -42,7 +42,7 @@ pub fn Cache(comptime T: type) type {
|
|||||||
self.safe_deinit(self);
|
self.safe_deinit(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(self: *@This(), id: u32, comptime loader: var) @typeInfo(@TypeOf(@field(loader, "load"))).BoundFn.return_type.? {
|
pub fn load(self: *@This(), id: u32, comptime loader: anytype) @typeInfo(@TypeOf(@field(loader, "load"))).BoundFn.return_type.? {
|
||||||
if (self.resources.getValue(id)) |resource| {
|
if (self.resources.getValue(id)) |resource| {
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub fn Delegate(comptime Event: type) type {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// sets a bound function as the Delegate callback
|
/// sets a bound function as the Delegate callback
|
||||||
pub fn initBound(ctx: var, comptime fn_name: []const u8) Self {
|
pub fn initBound(ctx: anytype, comptime fn_name: []const u8) Self {
|
||||||
std.debug.assert(@typeInfo(@TypeOf(ctx)) == .Pointer);
|
std.debug.assert(@typeInfo(@TypeOf(ctx)) == .Pointer);
|
||||||
std.debug.assert(@ptrToInt(ctx) != 0);
|
std.debug.assert(@ptrToInt(ctx) != 0);
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ pub fn Delegate(comptime Event: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn containsBound(self: Self, ctx: var) bool {
|
pub fn containsBound(self: Self, ctx: anytype) bool {
|
||||||
std.debug.assert(@ptrToInt(ctx) != 0);
|
std.debug.assert(@ptrToInt(ctx) != 0);
|
||||||
std.debug.assert(@typeInfo(@TypeOf(ctx)) == .Pointer);
|
std.debug.assert(@typeInfo(@TypeOf(ctx)) == .Pointer);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ pub fn Sink(comptime Event: type) type {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beforeBound(self: Self, ctx: var) Self {
|
pub fn beforeBound(self: Self, ctx: anytype) Self {
|
||||||
if (@typeInfo(@TypeOf(ctx)) == .Pointer) {
|
if (@typeInfo(@TypeOf(ctx)) == .Pointer) {
|
||||||
if (self.indexOfBound(ctx)) |index| {
|
if (self.indexOfBound(ctx)) |index| {
|
||||||
return Self{ .insert_index = index };
|
return Self{ .insert_index = index };
|
||||||
@ -41,7 +41,7 @@ pub fn Sink(comptime Event: type) type {
|
|||||||
_ = owning_signal.calls.insert(self.insert_index, Delegate(Event).initFree(callback)) catch unreachable;
|
_ = owning_signal.calls.insert(self.insert_index, Delegate(Event).initFree(callback)) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connectBound(self: Self, ctx: var, comptime fn_name: []const u8) void {
|
pub fn connectBound(self: Self, ctx: anytype, comptime fn_name: []const u8) void {
|
||||||
std.debug.assert(self.indexOfBound(ctx) == null);
|
std.debug.assert(self.indexOfBound(ctx) == null);
|
||||||
_ = owning_signal.calls.insert(self.insert_index, Delegate(Event).initBound(ctx, fn_name)) catch unreachable;
|
_ = owning_signal.calls.insert(self.insert_index, Delegate(Event).initBound(ctx, fn_name)) catch unreachable;
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ pub fn Sink(comptime Event: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disconnectBound(self: Self, ctx: var) void {
|
pub fn disconnectBound(self: Self, ctx: anytype) void {
|
||||||
if (self.indexOfBound(ctx)) |index| {
|
if (self.indexOfBound(ctx)) |index| {
|
||||||
_ = owning_signal.calls.swapRemove(index);
|
_ = owning_signal.calls.swapRemove(index);
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ pub fn Sink(comptime Event: type) type {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indexOfBound(self: Self, ctx: var) ?usize {
|
fn indexOfBound(self: Self, ctx: anytype) ?usize {
|
||||||
for (owning_signal.calls.items) |call, i| {
|
for (owning_signal.calls.items) |call, i| {
|
||||||
if (call.containsBound(ctx)) {
|
if (call.containsBound(ctx)) {
|
||||||
return i;
|
return i;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user