TypeMap gone

master
Mike 5 years ago
parent df29819b11
commit b32e907fd4

@ -4,7 +4,6 @@ const utils = @import("utils.zig");
const Handles = @import("handles.zig").Handles; const Handles = @import("handles.zig").Handles;
const SparseSet = @import("sparse_set.zig").SparseSet; const SparseSet = @import("sparse_set.zig").SparseSet;
const TypeMap = @import("type_map.zig").TypeMap;
const ComponentStorage = @import("component_storage.zig").ComponentStorage; const ComponentStorage = @import("component_storage.zig").ComponentStorage;
const Sink = @import("../signals/sink.zig").Sink; const Sink = @import("../signals/sink.zig").Sink;
@ -30,10 +29,9 @@ pub fn Storage(comptime CompT: type) type {
/// no errors to keep the API clean and because if a component array cant be allocated you've got bigger problems. /// no errors to keep the API clean and because if a component array cant be allocated you've got bigger problems.
/// Stores a maximum of u8 (256) component Storage(T). /// Stores a maximum of u8 (256) component Storage(T).
pub const Registry = struct { pub const Registry = struct {
typemap: TypeMap,
handles: EntityHandles, handles: EntityHandles,
components: std.AutoHashMap(u8, usize), components: std.AutoHashMap(u32, usize),
contexts: std.AutoHashMap(u8, usize), contexts: std.AutoHashMap(u32, usize),
groups: std.ArrayList(*GroupData), groups: std.ArrayList(*GroupData),
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
@ -80,19 +78,19 @@ pub const Registry = struct {
fn maybeValidIf(self: *GroupData, entity: Entity) void { 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(@intCast(u8, tid)).?; const ptr = self.registry.components.getValue(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(@intCast(u8, tid)).?; const ptr = self.registry.components.getValue(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(@intCast(u8, tid)).?; const ptr = self.registry.components.getValue(tid).?;
if (@intToPtr(*Storage(u1), ptr).contains(entity)) if (@intToPtr(*Storage(u1), ptr).contains(entity))
break :blk false; break :blk false;
} }
@ -104,10 +102,10 @@ pub const Registry = struct {
self.entity_set.add(entity); self.entity_set.add(entity);
} else { } else {
if (isValid) { if (isValid) {
const ptr = self.registry.components.getValue(@intCast(u8, self.owned[0])).?; const ptr = self.registry.components.getValue(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| {
const store_ptr = self.registry.components.getValue(@intCast(u8, tid)).?; const store_ptr = self.registry.components.getValue(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);
} }
@ -123,14 +121,13 @@ pub const Registry = struct {
if (self.entity_set.contains(entity)) if (self.entity_set.contains(entity))
self.entity_set.remove(entity); self.entity_set.remove(entity);
} else { } else {
const ptr = self.registry.components.getValue(@intCast(u8, self.owned[0])).?; const ptr = self.registry.components.getValue(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(@intCast(u8, tid)).?; const store_ptr = self.registry.components.getValue(tid).?;
store = @intToPtr(*Storage(u1), store_ptr); store = @intToPtr(*Storage(u1), store_ptr);
std.debug.warn("\n-------- len: {}, curr: {}, ent: {} \n", .{store.data().*.len, self.current, entity});
store.swap(store.data().*[self.current], entity); store.swap(store.data().*[self.current], entity);
} }
} }
@ -140,10 +137,9 @@ pub const Registry = struct {
pub fn init(allocator: *std.mem.Allocator) Registry { pub fn init(allocator: *std.mem.Allocator) Registry {
return Registry{ return Registry{
.typemap = TypeMap.init(allocator),
.handles = EntityHandles.init(allocator), .handles = EntityHandles.init(allocator),
.components = std.AutoHashMap(u8, usize).init(allocator), .components = std.AutoHashMap(u32, usize).init(allocator),
.contexts = std.AutoHashMap(u8, usize).init(allocator), .contexts = std.AutoHashMap(u32, usize).init(allocator),
.groups = std.ArrayList(*GroupData).init(allocator), .groups = std.ArrayList(*GroupData).init(allocator),
.allocator = allocator, .allocator = allocator,
}; };
@ -164,23 +160,21 @@ pub const Registry = struct {
self.components.deinit(); self.components.deinit();
self.contexts.deinit(); self.contexts.deinit();
self.groups.deinit(); self.groups.deinit();
self.typemap.deinit();
self.handles.deinit(); self.handles.deinit();
} }
pub fn assure(self: *Registry, comptime T: type) *Storage(T) { pub fn assure(self: *Registry, comptime T: type) *Storage(T) {
var type_id: u8 = undefined; var type_id = utils.typeId(T);
if (!self.typemap.getOrPut(T, &type_id)) { if (self.components.get(type_id)) |kv| {
return @intToPtr(*Storage(T), kv.value);
}
var comp_set = Storage(T).initPtr(self.allocator); var comp_set = Storage(T).initPtr(self.allocator);
var comp_set_ptr = @ptrToInt(comp_set); var comp_set_ptr = @ptrToInt(comp_set);
_ = self.components.put(type_id, comp_set_ptr) catch unreachable; _ = self.components.put(type_id, comp_set_ptr) catch unreachable;
return comp_set; return comp_set;
} }
const ptr = self.components.getValue(type_id).?;
return @intToPtr(*Storage(T), ptr);
}
/// Prepares a pool for the given type if required /// Prepares a pool for the given type if required
pub fn prepare(self: *Registry, comptime T: type) void { pub fn prepare(self: *Registry, comptime T: type) void {
_ = self.assure(T); _ = self.assure(T);
@ -339,27 +333,21 @@ pub const Registry = struct {
pub fn setContext(self: *Registry, context: var) void { pub fn setContext(self: *Registry, context: var) void {
std.debug.assert(@typeInfo(@TypeOf(context)) == .Pointer); std.debug.assert(@typeInfo(@TypeOf(context)) == .Pointer);
var type_id: u8 = undefined; var type_id = utils.typeId(@typeInfo(@TypeOf(context)).Pointer.child);
_ = self.typemap.getOrPut(@typeInfo(@TypeOf(context)).Pointer.child, &type_id);
_ = self.contexts.put(type_id, @ptrToInt(context)) catch unreachable; _ = self.contexts.put(type_id, @ptrToInt(context)) catch unreachable;
} }
/// Unsets a context variable if it exists /// Unsets a context variable if it exists
pub fn unsetContext(self: *Registry, comptime T: type) void { pub fn unsetContext(self: *Registry, comptime T: type) void {
std.debug.assert(@typeInfo(T) != .Pointer); std.debug.assert(@typeInfo(T) != .Pointer);
_ = self.contexts.put(utils.typeId(T), 0) catch unreachable;
var type_id: u8 = undefined;
_ = self.typemap.getOrPut(T, &type_id);
_ = self.contexts.put(type_id, 0) catch unreachable;
} }
/// Returns a pointer to an object in the context of the registry /// Returns a pointer to an object in the context of the registry
pub fn getContext(self: *Registry, comptime T: type) ?*T { pub fn getContext(self: *Registry, comptime T: type) ?*T {
std.debug.assert(@typeInfo(T) != .Pointer); std.debug.assert(@typeInfo(T) != .Pointer);
var type_id: u8 = undefined; return if (self.contexts.get(utils.typeId(T))) |ptr|
_ = self.typemap.getOrPut(T, &type_id);
return if (self.contexts.get(type_id)) |ptr|
return if (ptr.value > 0) @intToPtr(*T, ptr.value) else null return if (ptr.value > 0) @intToPtr(*T, ptr.value) else null
else else
null; null;
@ -383,13 +371,13 @@ pub const Registry = struct {
var includes_arr: [includes.len]u32 = undefined; var includes_arr: [includes.len]u32 = undefined;
inline for (includes) |t, i| { inline for (includes) |t, i| {
_ = self.assure(t); _ = self.assure(t);
includes_arr[i] = @as(u32, self.typemap.get(t)); includes_arr[i] = utils.typeId(t);
} }
var excludes_arr: [excludes.len]u32 = undefined; var excludes_arr: [excludes.len]u32 = undefined;
inline for (excludes) |t, i| { inline for (excludes) |t, i| {
_ = self.assure(t); _ = self.assure(t);
excludes_arr[i] = @as(u32, self.typemap.get(t)); excludes_arr[i] = utils.typeId(t);
} }
return MultiView(includes.len, excludes.len).init(self, includes_arr, excludes_arr); return MultiView(includes.len, excludes.len).init(self, includes_arr, excludes_arr);
@ -414,19 +402,19 @@ pub const Registry = struct {
var owned_arr: [owned.len]u32 = undefined; var owned_arr: [owned.len]u32 = undefined;
inline for (owned) |t, i| { inline for (owned) |t, i| {
_ = self.assure(t); _ = self.assure(t);
owned_arr[i] = @as(u32, self.typemap.get(t)); owned_arr[i] = utils.typeId(t);
} }
var includes_arr: [includes.len]u32 = undefined; var includes_arr: [includes.len]u32 = undefined;
inline for (includes) |t, i| { inline for (includes) |t, i| {
_ = self.assure(t); _ = self.assure(t);
includes_arr[i] = @as(u32, self.typemap.get(t)); includes_arr[i] = utils.typeId(t);
} }
var excludes_arr: [excludes.len]u32 = undefined; var excludes_arr: [excludes.len]u32 = undefined;
inline for (excludes) |t, i| { inline for (excludes) |t, i| {
_ = self.assure(t); _ = self.assure(t);
excludes_arr[i] = @as(u32, self.typemap.get(t)); excludes_arr[i] = utils.typeId(t);
} }
// create a unique hash to identify the group // create a unique hash to identify the group
@ -470,9 +458,7 @@ pub const Registry = struct {
while (view_iter.next()) |entity| { while (view_iter.next()) |entity| {
new_group_data.entity_set.add(entity); new_group_data.entity_set.add(entity);
} }
} else { } else {}
}
if (owned.len == 0) { if (owned.len == 0) {
return BasicGroup(includes.len, excludes.len).init(&new_group_data.entity_set, self, includes_arr, excludes_arr); return BasicGroup(includes.len, excludes.len).init(&new_group_data.entity_set, self, includes_arr, excludes_arr);

@ -1,53 +0,0 @@
const std = @import("std");
const utils = @import("utils.zig");
pub const TypeMap = struct {
map: std.AutoHashMap(u32, u8),
counter: u8 = 0,
pub fn init(allocator: *std.mem.Allocator) TypeMap {
return TypeMap{
.map = std.AutoHashMap(u32, u8).init(allocator),
};
}
pub fn deinit(self: TypeMap) void {
self.map.deinit();
}
pub fn contains(self: TypeMap, comptime T: type) bool {
return self.map.contains(@truncate(u32, utils.typeHash(T)));
}
/// gets the value for T. It MUST exist if you use this method to get it.
pub fn get(self: *TypeMap, comptime T: type) u8 {
return self.map.get(@truncate(u32, utils.typeHash(T))).?.value;
}
/// gets the value for T if it exists. If it doesnt, it is registered and the value returned.
pub fn getOrPut(self: *TypeMap, comptime T: type, type_id: *u8) bool {
// TODO: is it safe to truncate to u32 here?
var res = self.map.getOrPut(@truncate(u32, utils.typeHash(T))) catch unreachable;
if (!res.found_existing) {
res.kv.value = self.counter;
self.counter += 1;
}
type_id.* = res.kv.value;
return res.found_existing;
}
};
test "TypeMap" {
var map = TypeMap.init(std.testing.allocator);
defer map.deinit();
var type_id: u8 = undefined;
_ = map.getOrPut(usize, &type_id);
std.testing.expectEqual(@as(u8, 0), type_id);
_ = map.getOrPut(f32, &type_id);
std.testing.expectEqual(@as(u8, 1), type_id);
_ = map.getOrPut(usize, &type_id);
std.testing.expectEqual(@as(u8, 0), type_id);
}

@ -1,3 +1,4 @@
const std = @import("std");
/// 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 (lhs: T1, rhs: T1) bool) void {
@ -16,12 +17,16 @@ pub fn sortSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T
} }
/// comptime string hashing for the type names /// comptime string hashing for the type names
pub fn typeHash(comptime T: type) comptime_int { pub fn typeId(comptime T: type) u32 {
return stringHash(@typeName(T)); return hashString(@typeName(T));
} }
/// comptime string hashing, djb2 by Dan Bernstein pub fn hashString(comptime str: []const u8) u32 {
pub fn stringHash(comptime str: []const u8) comptime_int { return @truncate(u32, std.hash.Wyhash.hash(0, str));
}
/// comptime string hashing, djb2 by Dan Bernstein. Fails on large strings.
pub fn hashStringDjb2(comptime str: []const u8) comptime_int {
var hash: comptime_int = 5381; var hash: comptime_int = 5381;
for (str) |c| { for (str) |c| {
hash = ((hash << 5) + hash) + @intCast(comptime_int, c); hash = ((hash << 5) + hash) + @intCast(comptime_int, c);

@ -57,7 +57,7 @@ pub fn MultiView(comptime n_includes: usize, comptime n_excludes: usize) type {
entities: *const []Entity, entities: *const []Entity,
pub fn init(view: *Self) Iterator { pub fn init(view: *Self) Iterator {
const ptr = view.registry.components.getValue(@intCast(u8, view.type_ids[0])).?; const ptr = view.registry.components.getValue(view.type_ids[0]).?;
return .{ return .{
.view = view, .view = view,
.entities = @intToPtr(*Storage(u8), ptr).data(), .entities = @intToPtr(*Storage(u8), ptr).data(),
@ -72,7 +72,7 @@ pub fn MultiView(comptime n_includes: usize, comptime n_excludes: usize) type {
// entity must be in all other Storages // entity must be in all other Storages
for (it.view.type_ids) |tid| { for (it.view.type_ids) |tid| {
const ptr = it.view.registry.components.getValue(@intCast(u8, tid)).?; const ptr = it.view.registry.components.getValue(tid).?;
if (!@intToPtr(*Storage(u1), ptr).contains(entity)) { if (!@intToPtr(*Storage(u1), ptr).contains(entity)) {
break :blk; break :blk;
} }
@ -80,7 +80,7 @@ pub fn MultiView(comptime n_includes: usize, comptime n_excludes: usize) type {
// entity must not be in all other excluded Storages // entity must not be in all other excluded Storages
for (it.view.exclude_type_ids) |tid| { for (it.view.exclude_type_ids) |tid| {
const ptr = it.view.registry.components.getValue(@intCast(u8, tid)).?; const ptr = it.view.registry.components.getValue(tid).?;
if (@intToPtr(*Storage(u1), ptr).contains(entity)) { if (@intToPtr(*Storage(u1), ptr).contains(entity)) {
break :blk; break :blk;
} }
@ -119,7 +119,7 @@ pub fn MultiView(comptime n_includes: usize, comptime n_excludes: usize) type {
// get our component counts in an array so we can sort the type_ids based on how many entities are in each // get our component counts in an array so we can sort the type_ids based on how many entities are in each
var sub_items: [n_includes]usize = undefined; var sub_items: [n_includes]usize = undefined;
for (self.type_ids) |tid, i| { for (self.type_ids) |tid, i| {
const ptr = self.registry.components.getValue(@intCast(u8, tid)).?; const ptr = self.registry.components.getValue(tid).?;
const store = @intToPtr(*Storage(u8), ptr); const store = @intToPtr(*Storage(u8), ptr);
sub_items[i] = store.len(); sub_items[i] = store.len();
} }

@ -1,17 +1,15 @@
const std = @import("std"); const std = @import("std");
const Sink = @import("sink.zig").Sink; const Sink = @import("sink.zig").Sink;
const Signal = @import("signal.zig").Signal; const Signal = @import("signal.zig").Signal;
const TypeMap = @import("../ecs/type_map.zig").TypeMap; const utils = @import("../ecs/utils.zig");
pub const Dispatcher = struct { pub const Dispatcher = struct {
typemap: TypeMap, signals: std.AutoHashMap(u32, usize),
signals: std.AutoHashMap(u8, usize),
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
pub fn init(allocator: *std.mem.Allocator) Dispatcher { pub fn init(allocator: *std.mem.Allocator) Dispatcher {
return Dispatcher{ return Dispatcher{
.typemap = TypeMap.init(allocator), .signals = std.AutoHashMap(u32, usize).init(allocator),
.signals = std.AutoHashMap(u8, usize).init(allocator),
.allocator = allocator, .allocator = allocator,
}; };
} }
@ -24,23 +22,21 @@ pub const Dispatcher = struct {
signal.deinit(); signal.deinit();
} }
self.typemap.deinit();
self.signals.deinit(); self.signals.deinit();
} }
fn assure(self: *Dispatcher, comptime T: type) *Signal(T) { fn assure(self: *Dispatcher, comptime T: type) *Signal(T) {
var type_id: u8 = undefined; var type_id = utils.typeId(T);
if (!self.typemap.getOrPut(T, &type_id)) { if (self.signals.get(type_id)) |kv| {
return @intToPtr(*Signal(T), kv.value);
}
var signal = Signal(T).create(self.allocator); var signal = Signal(T).create(self.allocator);
var signal_ptr = @ptrToInt(signal); var signal_ptr = @ptrToInt(signal);
_ = self.signals.put(type_id, signal_ptr) catch unreachable; _ = self.signals.put(type_id, signal_ptr) catch unreachable;
return signal; return signal;
} }
const ptr = self.signals.getValue(type_id).?;
return @intToPtr(*Signal(T), ptr);
}
pub fn sink(self: *Dispatcher, comptime T: type) Sink(T) { pub fn sink(self: *Dispatcher, comptime T: type) Sink(T) {
return self.assure(T).sink(); return self.assure(T).sink();
} }

@ -6,7 +6,6 @@ comptime {
_ = @import("ecs/entity.zig"); _ = @import("ecs/entity.zig");
_ = @import("ecs/handles.zig"); _ = @import("ecs/handles.zig");
_ = @import("ecs/sparse_set.zig"); _ = @import("ecs/sparse_set.zig");
_ = @import("ecs/type_map.zig");
_ = @import("ecs/views.zig"); _ = @import("ecs/views.zig");
_ = @import("ecs/groups.zig"); _ = @import("ecs/groups.zig");

Loading…
Cancel
Save