From 96385b6c61155cc57448b2398deb087dfe111658 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 13 Jun 2020 14:53:14 -0700 Subject: [PATCH] cleanup sort --- zig-ecs/src/ecs/component_storage.zig | 49 +++++++++++++++++---------- zig-ecs/src/ecs/sparse_set.zig | 30 ++-------------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/zig-ecs/src/ecs/component_storage.zig b/zig-ecs/src/ecs/component_storage.zig index ba64cfb..7de8234 100644 --- a/zig-ecs/src/ecs/component_storage.zig +++ b/zig-ecs/src/ecs/component_storage.zig @@ -204,24 +204,39 @@ 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. pub fn sort(self: *Self, comptime T: type, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), T, T) bool) void { 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 + // case of a Component sort we also wrap that into the struct so we can get the Component data to pass to the + // lessThan method passed in. if (T == Entity) { - // wtf? When an OwningGroup calls us we are gonna be fake-typed and if we are fake-typed its not safe to pass our slice to - // the SparseSet and let it handle sorting. Instead, we'll use swap _without a set swap_ and do it ourselves. - if (Component == u1) { - const SortContext = struct { - storage: *Self, - - pub fn swap(this: @This(), a: Entity, b: Entity) void { - this.storage.safe_swap(this.storage, a, b, true); - } - }; - const swap_context = SortContext{.storage = self}; - self.set.sortSwap(length, context, lessThan, swap_context); - } else { - self.set.sortSub(length, context, lessThan, Component, self.instances.items); - } - } else if (T == Component) { - self.set.sortSubSub(length, context, Component, lessThan, self.instances.items); + const SortContext = struct { + storage: *Self, + + pub fn swap(this: @This(), a: Entity, b: Entity) void { + this.storage.safe_swap(this.storage, a, b, true); + } + }; + const swap_context = SortContext{.storage = self}; + self.set.arrange(length, context, lessThan, swap_context); + } else { + const SortContext = struct { + storage: *Self, + wrapped_context: @TypeOf(context), + lessThan: fn (@TypeOf(context), T, T) bool, + + fn sort(this: @This(), a: Entity, b: Entity) bool { + const real_a = this.storage.getConst(a); + const real_b = this.storage.getConst(b); + return this.lessThan(this.wrapped_context, real_a, real_b); + } + + pub fn swap(this: @This(), a: Entity, b: Entity) void { + this.storage.safe_swap(this.storage, a, b, true); + } + }; + + const swap_context = SortContext{.storage = self, .wrapped_context = context, .lessThan = lessThan}; + self.set.arrange(length, swap_context, SortContext.sort, swap_context); } } }; diff --git a/zig-ecs/src/ecs/sparse_set.zig b/zig-ecs/src/ecs/sparse_set.zig index d0660b4..91dbe43 100644 --- a/zig-ecs/src/ecs/sparse_set.zig +++ b/zig-ecs/src/ecs/sparse_set.zig @@ -143,11 +143,6 @@ pub fn SparseSet(comptime SparseT: type) type { std.mem.swap(SparseT, &self.dense.items[from.*], &self.dense.items[to.*]); std.mem.swap(SparseT, from, to); - - // auto &from = sparse[page(lhs)][offset(lhs)]; - // auto &to = sparse[page(rhs)][offset(rhs)]; - // std::swap(packed[size_type(from)], packed[size_type(to)]); - // std::swap(from, to); } /// Sort elements according to the given comparison function @@ -155,32 +150,14 @@ pub fn SparseSet(comptime SparseT: type) type { std.sort.insertionSort(SparseT, self.dense.items, context, lessThan); for (self.dense.items) |sparse, i| { - // sparse[page(packed[pos])][offset(packed[pos])] = entity_type(pos); const item = @intCast(SparseT, i); self.sparse.items[self.page(self.dense.items[self.page(item)])].?[self.offset(self.dense.items[self.page(item)])] = @intCast(SparseT, i); } } - /// Sort elements according to the given comparison function and keeps sub_items with the same sort - pub fn sortSub(self: *Self, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool, comptime T: type, sub_items: []T) void { - std.sort.insertionSort(SparseT, self.dense.items[0..length], context, lessThan); - - for (self.dense.items[0..length]) |sparse, pos| { - var curr = @intCast(SparseT, pos); - var next = self.index(self.dense.items[curr]); - - while (curr != next) { - std.mem.swap(T, &sub_items[self.index(self.dense.items[curr])], &sub_items[self.index(self.dense.items[next])]); - self.sparse.items[self.page(self.dense.items[curr])].?[self.offset(self.dense.items[curr])] = curr; - - curr = next; - next = self.index(self.dense.items[curr]); - } - } - } - - /// Sort elements according to the given comparison function and keeps sub_items with the same sort - pub fn sortSwap(self: *Self, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool, swap_context: var) void { + /// 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 + pub fn arrange(self: *Self, length: usize, context: var, comptime lessThan: fn (@TypeOf(context), SparseT, SparseT) bool, swap_context: var) void { std.sort.insertionSort(SparseT, self.dense.items[0..length], context, lessThan); for (self.dense.items[0..length]) |sparse, pos| { @@ -189,7 +166,6 @@ pub fn SparseSet(comptime SparseT: type) type { while (curr != next) { swap_context.swap(self.dense.items[curr], self.dense.items[next]); - // self.sparse.items[self.dense.items[self.page(@intCast(SparseT, curr))]] = @intCast(SparseT, curr); self.sparse.items[self.page(self.dense.items[curr])].?[self.offset(self.dense.items[curr])] = curr; curr = next;