From 1d1c761c1514e0bffecff5e71196d77346f501e3 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 3 Jun 2020 20:13:16 -0700 Subject: [PATCH] sort and respect --- zig-ecs/src/ecs/registry.zig | 1 + zig-ecs/src/ecs/sparse_set.zig | 92 ++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/zig-ecs/src/ecs/registry.zig b/zig-ecs/src/ecs/registry.zig index 03cf99c..827b9a3 100644 --- a/zig-ecs/src/ecs/registry.zig +++ b/zig-ecs/src/ecs/registry.zig @@ -36,6 +36,7 @@ pub const Registry = struct { groups: std.ArrayList(*GroupData), allocator: *std.mem.Allocator, + /// internal, persistant data structure to manage the entities in a group const GroupData = struct { hash: u32, entity_set: SparseSet(Entity, u16), // TODO: dont hardcode this. put it in EntityTraits maybe. All SparseSets would need to use the value. diff --git a/zig-ecs/src/ecs/sparse_set.zig b/zig-ecs/src/ecs/sparse_set.zig index 70a7f33..76c01ab 100644 --- a/zig-ecs/src/ecs/sparse_set.zig +++ b/zig-ecs/src/ecs/sparse_set.zig @@ -43,6 +43,12 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { return sparse & self.entity_mask; } + fn offset(self: Self, sparse: SparseT) usize { + // TODO: support paging + // return entt & (sparse_per_page - 1) + return sparse & self.entity_mask; + } + fn assure(self: *Self, pos: usize) []DenseT { // TODO: support paging if (self.sparse.capacity <= pos or self.sparse.capacity == 0) { @@ -58,12 +64,6 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { return self.sparse.items; } - fn offset(self: Self, sparse: SparseT) usize { - // TODO: support paging - // return entt & (sparse_per_page - 1) - return sparse & self.entity_mask; - } - /// Increases the capacity of a sparse sets index array pub fn reserve(self: *Self, cap: usize) void { self.sparse.resize(cap) catch unreachable; @@ -126,7 +126,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { _ = self.dense.pop(); } - /// Swaps two entities in the internal packed array + /// Swaps two entities in the internal packed and sparse arrays pub fn swap(self: *Self, sparse_l: SparseT, sparse_r: SparseT) void { var from = &self.sparse.items[sparse_l]; var to = &self.sparse.items[sparse_r]; @@ -136,13 +136,28 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { } /// Sort elements according to the given comparison function - pub fn sort(self: *Self) void { - unreachable; + pub fn sort(self: *Self, sortFn: fn (SparseT, SparseT) bool) void { + std.sort.insertionSort(SparseT, self.dense.items, sortFn); + + var i = @as(usize, 0); + for (self.dense.items) |sparse| { + // self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(DenseT, sparse); + self.sparse.items[self.page(sparse)] = @intCast(DenseT, sparse); + } } - /// Sort entities according to their order in another sparse set + /// Sort entities according to their order in another sparse set. Other is the master in this case. pub fn respect(self: *Self, other: *Self) void { - unreachable; + var pos = @as(DenseT, 0); + var i = @as(DenseT, 0); + while (i < other.dense.items.len) : (i += 1) { + if (self.contains(other.dense.items[i])) { + if (other.dense.items[i] != self.dense.items[pos]) { + self.swap(self.dense.items[pos], other.dense.items[i]); + } + pos += 1; + } + } } pub fn clear(self: *Self) void { @@ -152,6 +167,19 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { }; } +fn printSet(set: *SparseSet(u32, u8)) void { + std.debug.warn("\nsparse -----\n", .{}); + for (set.sparse.items) |sparse| { + std.debug.warn("{}\t", .{sparse}); + } + + std.debug.warn("\ndense -----\n", .{}); + for (set.dense.items) |dense| { + std.debug.warn("{}\t", .{dense}); + } + std.debug.warn("\n\n", .{}); +} + test "add/remove/clear" { var set = SparseSet(u32, u8).initPtr(std.testing.allocator); defer set.deinit(); @@ -212,3 +240,45 @@ test "data() synced" { set.remove(1); std.testing.expectEqual(set.len(), data.len); } + +test "respect" { + var set1 = SparseSet(u32, u8).initPtr(std.testing.allocator); + defer set1.deinit(); + + var set2 = SparseSet(u32, u8).initPtr(std.testing.allocator); + defer set2.deinit(); + + set1.add(3); + set1.add(4); + set1.add(5); + set1.add(6); + set1.add(7); + + set2.add(8); + set2.add(6); + set2.add(4); + + set1.respect(set2); + + std.testing.expectEqual(set1.dense.items[0], set2.dense.items[1]); + std.testing.expectEqual(set1.dense.items[1], set2.dense.items[2]); +} + +test "respect" { + var set = SparseSet(u32, u8).initPtr(std.testing.allocator); + defer set.deinit(); + + set.add(5); + set.add(2); + set.add(4); + set.add(1); + set.add(3); + + set.sort(std.sort.desc(u32)); + + for (set.dense.items) |item, i| { + if (i < set.dense.items.len - 1) { + std.debug.assert(item > set.dense.items[i + 1]); + } + } +} \ No newline at end of file