From 3f0ee34560b618552eb456958649c3c92e38b1bf Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 16 Mar 2025 21:45:53 +0700 Subject: [PATCH 1/3] unroll has_all/any --- develop/untests.lua | 58 +++++++++++++++++++++++++++++++++++ evolved.lua | 74 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 118 insertions(+), 14 deletions(-) diff --git a/develop/untests.lua b/develop/untests.lua index 2734574..3851185 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -7701,3 +7701,61 @@ do assert(not evo.is_empty(f1, e1, e2, f2, e3)) assert(not evo.is_empty(f1, e1, e2, f2, e3, f1)) end + +do + local f1, f2, f3, f4, f5, f6 = evo.id(6) + + local e2 = evo.spawn_with({ f1, f2 }) + local e5 = evo.spawn_with({ f1, f2, f3, f4, f5 }) + + assert(evo.has_all(e2, f1)) + assert(evo.has_all(e2, f1, f2)) + assert(evo.has_all(e2, f2, f1)) + assert(evo.has_all(e2, f2, f1, f2)) + assert(not evo.has_all(e2, f1, f2, f3)) + + assert(evo.has_all(e5, f1)) + assert(evo.has_all(e5, f1, f2)) + assert(evo.has_all(e5, f1, f2, f3)) + assert(evo.has_all(e5, f1, f2, f3, f4)) + assert(evo.has_all(e5, f1, f2, f3, f4, f5)) + + assert(not evo.has_all(e5, f6, f1, f2, f3, f4, f5)) + assert(not evo.has_all(e5, f1, f2, f3, f4, f5, f6)) + assert(not evo.has_all(e5, f1, f2, f6, f3, f4, f5)) +end + +do + local f1, f2, f3, f4, f5, f6, f7 = evo.id(7) + + local e2 = evo.spawn_with({ f1, f2 }) + local e5 = evo.spawn_with({ f1, f2, f3, f4, f5 }) + + assert(evo.has_all(e2)) + assert(not evo.has_any(e2)) + + assert(evo.has_any(e2, f1)) + assert(evo.has_any(e2, f1, f2)) + assert(evo.has_any(e2, f2, f1)) + assert(evo.has_any(e2, f2, f1, f2)) + assert(evo.has_any(e2, f1, f2, f3)) + assert(evo.has_any(e2, f3, f4, f5, f6, f7, f1)) + + assert(not evo.has_any(e2, f3)) + assert(not evo.has_any(e2, f3, f4)) + assert(not evo.has_any(e2, f3, f7, f4)) + + assert(evo.has_any(e5, f1)) + assert(evo.has_any(e5, f1, f2)) + assert(evo.has_any(e5, f1, f2, f3)) + assert(evo.has_any(e5, f1, f2, f3, f4)) + assert(evo.has_any(e5, f1, f2, f3, f4, f5)) + + assert(evo.has_any(e5, f6, f1, f2, f3, f4, f5)) + assert(evo.has_any(e5, f1, f2, f3, f4, f5, f6)) + assert(evo.has_any(e5, f1, f2, f6, f3, f4, f5)) + + assert(not evo.has_any(e5, f7)) + assert(not evo.has_any(e5, f7, f7)) + assert(not evo.has_any(e5, f7, f7, f6)) +end diff --git a/evolved.lua b/evolved.lua index b13b057..b17c318 100644 --- a/evolved.lua +++ b/evolved.lua @@ -1239,16 +1239,39 @@ end ---@return boolean ---@nodiscard local function __chunk_has_all_fragments(chunk, ...) - local fragment_set = chunk.__fragment_set + local fragment_count = __lua_select('#', ...) - for i = 1, __lua_select('#', ...) do - local fragment = __lua_select(i, ...) - if not fragment_set[fragment] then - return false - end + if fragment_count == 0 then + return true end - return true + local fs = chunk.__fragment_set + + if fragment_count == 1 then + local f1 = ... + return fs[f1] ~= nil + end + + if fragment_count == 2 then + local f1, f2 = ... + return fs[f1] ~= nil and fs[f2] ~= nil + end + + if fragment_count == 3 then + local f1, f2, f3 = ... + return fs[f1] ~= nil and fs[f2] ~= nil and fs[f3] ~= nil + end + + if fragment_count == 4 then + local f1, f2, f3, f4 = ... + return fs[f1] ~= nil and fs[f2] ~= nil and fs[f3] ~= nil and fs[f4] ~= nil + end + + do + local f1, f2, f3, f4 = ... + return fs[f1] ~= nil and fs[f2] ~= nil and fs[f3] ~= nil and fs[f4] ~= nil and + __chunk_has_all_fragments(chunk, __lua_select(5, ...)) + end end ---@param chunk evolved.chunk @@ -1274,16 +1297,39 @@ end ---@return boolean ---@nodiscard local function __chunk_has_any_fragments(chunk, ...) - local fragment_set = chunk.__fragment_set + local fragment_count = __lua_select('#', ...) - for i = 1, __lua_select('#', ...) do - local fragment = __lua_select(i, ...) - if fragment_set[fragment] then - return true - end + if fragment_count == 0 then + return false end - return false + local fs = chunk.__fragment_set + + if fragment_count == 1 then + local f1 = ... + return fs[f1] ~= nil + end + + if fragment_count == 2 then + local f1, f2 = ... + return fs[f1] ~= nil or fs[f2] ~= nil + end + + if fragment_count == 3 then + local f1, f2, f3 = ... + return fs[f1] ~= nil or fs[f2] ~= nil or fs[f3] ~= nil + end + + if fragment_count == 4 then + local f1, f2, f3, f4 = ... + return fs[f1] ~= nil or fs[f2] ~= nil or fs[f3] ~= nil or fs[f4] ~= nil + end + + do + local f1, f2, f3, f4 = ... + return fs[f1] ~= nil or fs[f2] ~= nil or fs[f3] ~= nil or fs[f4] ~= nil or + __chunk_has_any_fragments(chunk, __lua_select(5, ...)) + end end ---@param chunk evolved.chunk From 4a384017c7838235dc5a2f5e68442c8dff003f0c Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 16 Mar 2025 23:23:56 +0700 Subject: [PATCH 2/3] reduce the number of local variables --- evolved.lua | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/evolved.lua b/evolved.lua index b17c318..fe6b7f3 100644 --- a/evolved.lua +++ b/evolved.lua @@ -126,16 +126,12 @@ local __query_sorted_excludes = {} ---@type table', __lua_table_concat(items, ', ')) + return string.format('<%s>', table.concat(items, ', ')) end ---@param self table @@ -840,11 +836,11 @@ function __debug_mts.chunk_fragment_set_mt.__tostring(self) local items = {} ---@type string[] for fragment, fragment_index in __lua_pairs(self) do - items[fragment_index] = __lua_string_format('(%s -> %d)', + items[fragment_index] = string.format('(%s -> %d)', __id_name(fragment), fragment_index) end - return __lua_string_format('{%s}', __lua_table_concat(items, ', ')) + return string.format('{%s}', table.concat(items, ', ')) end ---@param self evolved.fragment[] @@ -852,11 +848,11 @@ function __debug_mts.chunk_fragment_list_mt.__tostring(self) local items = {} ---@type string[] for fragment_index, fragment in __lua_ipairs(self) do - items[fragment_index] = __lua_string_format('(%d -> %s)', + items[fragment_index] = string.format('(%d -> %s)', fragment_index, __id_name(fragment)) end - return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) + return string.format('[%s]', table.concat(items, ', ')) end ---@param self table @@ -864,11 +860,11 @@ function __debug_mts.chunk_component_indices_mt.__tostring(self) local items = {} ---@type string[] for component_fragment, component_index in __lua_pairs(self) do - items[component_index] = __lua_string_format('(%s -> %d)', + items[component_index] = string.format('(%s -> %d)', __id_name(component_fragment), component_index) end - return __lua_string_format('{%s}', __lua_table_concat(items, ', ')) + return string.format('{%s}', table.concat(items, ', ')) end ---@param self evolved.storage[] @@ -876,11 +872,11 @@ function __debug_mts.chunk_component_storages_mt.__tostring(self) local items = {} ---@type string[] for component_index, component_storage in __lua_ipairs(self) do - items[component_index] = __lua_string_format('(%d -> #%d)', + items[component_index] = string.format('(%d -> #%d)', component_index, #component_storage) end - return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) + return string.format('[%s]', table.concat(items, ', ')) end ---@param self evolved.fragment[] @@ -888,11 +884,11 @@ function __debug_mts.chunk_component_fragments_mt.__tostring(self) local items = {} ---@type string[] for component_index, component_fragment in __lua_ipairs(self) do - items[component_index] = __lua_string_format('(%d -> %s)', + items[component_index] = string.format('(%d -> %s)', component_index, __id_name(component_fragment)) end - return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) + return string.format('[%s]', table.concat(items, ', ')) end --- @@ -3397,7 +3393,7 @@ local function __phase_process(phase) local cycled_system_mark = sorting_marks[cycled_system_mark_index] if cycled_system_mark == 1 then - sorting_cycle_path = __lua_string_format('%s -> %s', + sorting_cycle_path = string.format('%s -> %s', sorting_cycle_path, cycled_system) if cycled_system == dependency then From c115fcf42f3b4ccd2cb1e4b2b8bd8bcebcdfe1f9 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 17 Mar 2025 00:14:14 +0700 Subject: [PATCH 3/3] is_alive_all/any, is_empty_all/any --- README.md | 9 ++- develop/untests.lua | 108 ++++++++++++++++++++++--------- evolved.lua | 152 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 232 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index ef79422..5788b18 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,13 @@ unpack :: id -> integer, integer defer :: boolean commit :: boolean -is_alive :: entity... -> boolean -is_empty :: entity... -> boolean +is_alive :: entity -> boolean +is_alive_all :: entity... -> boolean +is_alive_any :: entity... -> boolean + +is_empty :: entity -> boolean +is_empty_all :: entity... -> boolean +is_empty_any :: entity... -> boolean get :: entity, fragment... -> component... has :: entity, fragment -> boolean diff --git a/develop/untests.lua b/develop/untests.lua index 3851185..6aa8ac5 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -7647,59 +7647,105 @@ end do local a1, a2, a3, a4, a5 = evo.id(5) - assert(evo.is_alive()) assert(evo.is_alive(a1)) - assert(evo.is_alive(a1, a2)) - assert(evo.is_alive(a1, a2, a3)) - assert(evo.is_alive(a1, a2, a3, a4)) - assert(evo.is_alive(a1, a2, a3, a4, a5)) + assert(evo.is_alive_all()) + assert(evo.is_alive_all(a1)) + assert(evo.is_alive_all(a1, a2)) + assert(evo.is_alive_all(a1, a2, a3)) + assert(evo.is_alive_all(a1, a2, a3, a4)) + assert(evo.is_alive_all(a1, a2, a3, a4, a5)) + + assert(not evo.is_alive_any()) + assert(evo.is_alive_any(a1)) + assert(evo.is_alive_any(a1, a2)) + assert(evo.is_alive_any(a1, a2, a3)) + assert(evo.is_alive_any(a1, a2, a3, a4)) + assert(evo.is_alive_any(a1, a2, a3, a4, a5)) local d1, d2 = evo.id(2) assert(evo.destroy(d1, d2)) assert(not evo.is_alive(d1)) - assert(not evo.is_alive(d1, d2)) - assert(not evo.is_alive(d1, a1)) - assert(not evo.is_alive(a1, d1)) - assert(not evo.is_alive(d1, d2, a1)) - assert(not evo.is_alive(d1, a1, a2)) - assert(not evo.is_alive(d1, a1, a2, d2, a3)) - assert(not evo.is_alive(d1, a1, a2, d2, a3, d1)) + assert(not evo.is_alive_all(d1)) + assert(not evo.is_alive_all(d1, d2)) + assert(not evo.is_alive_all(d1, a1)) + assert(not evo.is_alive_all(a1, d1)) + assert(not evo.is_alive_all(d1, d2, a1)) + assert(not evo.is_alive_all(d1, a1, a2)) + assert(not evo.is_alive_all(d1, a1, a2, d2, a3)) + assert(not evo.is_alive_all(d1, a1, a2, d2, a3, d1)) + + assert(not evo.is_alive_any(d1)) + assert(not evo.is_alive_any(d1, d2)) + assert(evo.is_alive_any(d1, a1)) + assert(evo.is_alive_any(a1, d1)) + assert(evo.is_alive_any(d1, d2, a1)) + assert(evo.is_alive_any(d1, a1, a2)) + assert(evo.is_alive_any(d1, a1, a2, d2, a3)) + assert(evo.is_alive_any(d1, a1, a2, d2, a3, d1)) end do local e1, e2, e3, e4, e5 = evo.id(5) - assert(evo.is_empty()) assert(evo.is_empty(e1)) - assert(evo.is_empty(e1, e2)) - assert(evo.is_empty(e1, e2, e3)) - assert(evo.is_empty(e1, e2, e3, e4)) - assert(evo.is_empty(e1, e2, e3, e4, e5)) + assert(evo.is_empty_all()) + assert(evo.is_empty_all(e1)) + assert(evo.is_empty_all(e1, e2)) + assert(evo.is_empty_all(e1, e2, e3)) + assert(evo.is_empty_all(e1, e2, e3, e4)) + assert(evo.is_empty_all(e1, e2, e3, e4, e5)) + + assert(not evo.is_empty_any()) + assert(evo.is_empty_any(e1)) + assert(evo.is_empty_any(e1, e2)) + assert(evo.is_empty_any(e1, e2, e3)) + assert(evo.is_empty_any(e1, e2, e3, e4)) + assert(evo.is_empty_any(e1, e2, e3, e4, e5)) local d1, d2 = evo.id(2) assert(evo.destroy(d1, d2)) assert(evo.is_empty(d1)) - assert(evo.is_empty(d1, d2)) - assert(evo.is_empty(d1, e1)) - assert(evo.is_empty(e1, d1)) - assert(evo.is_empty(d1, d2, e1)) - assert(evo.is_empty(d1, e1, e2)) - assert(evo.is_empty(d1, e1, e2, d2, e3)) - assert(evo.is_empty(d1, e1, e2, d2, e3, d1)) + assert(evo.is_empty_all(d1)) + assert(evo.is_empty_all(d1, d2)) + assert(evo.is_empty_all(d1, e1)) + assert(evo.is_empty_all(e1, d1)) + assert(evo.is_empty_all(d1, d2, e1)) + assert(evo.is_empty_all(d1, e1, e2)) + assert(evo.is_empty_all(d1, e1, e2, d2, e3)) + assert(evo.is_empty_all(d1, e1, e2, d2, e3, d1)) + + assert(evo.is_empty_any(d1)) + assert(evo.is_empty_any(d1, d2)) + assert(evo.is_empty_any(d1, e1)) + assert(evo.is_empty_any(e1, d1)) + assert(evo.is_empty_any(d1, d2, e1)) + assert(evo.is_empty_any(d1, e1, e2)) + assert(evo.is_empty_any(d1, e1, e2, d2, e3)) + assert(evo.is_empty_any(d1, e1, e2, d2, e3, d1)) local f1, f2 = evo.id(2) assert(evo.insert(f1, f1) and evo.insert(f2, f2)) assert(not evo.is_empty(f1)) - assert(not evo.is_empty(f1, f2)) - assert(not evo.is_empty(f1, e1)) - assert(not evo.is_empty(e1, f1)) - assert(not evo.is_empty(f1, f2, e1)) - assert(not evo.is_empty(f1, e1, e2)) - assert(not evo.is_empty(f1, e1, e2, f2, e3)) - assert(not evo.is_empty(f1, e1, e2, f2, e3, f1)) + assert(not evo.is_empty_all(f1)) + assert(not evo.is_empty_all(f1, f2)) + assert(not evo.is_empty_all(f1, e1)) + assert(not evo.is_empty_all(e1, f1)) + assert(not evo.is_empty_all(f1, f2, e1)) + assert(not evo.is_empty_all(f1, e1, e2)) + assert(not evo.is_empty_all(f1, e1, e2, f2, e3)) + assert(not evo.is_empty_all(f1, e1, e2, f2, e3, f1)) + + assert(not evo.is_empty_any(f1)) + assert(not evo.is_empty_any(f1, f2)) + assert(evo.is_empty_any(f1, e1)) + assert(evo.is_empty_any(e1, f1)) + assert(evo.is_empty_any(f1, f2, e1)) + assert(evo.is_empty_any(f1, e1, e2)) + assert(evo.is_empty_any(f1, e1, e2, f2, e3)) + assert(evo.is_empty_any(f1, e1, e2, f2, e3, f1)) end do diff --git a/evolved.lua b/evolved.lua index fe6b7f3..f92dbd0 100644 --- a/evolved.lua +++ b/evolved.lua @@ -639,7 +639,12 @@ local __evolved_defer local __evolved_commit local __evolved_is_alive +local __evolved_is_alive_all +local __evolved_is_alive_any + local __evolved_is_empty +local __evolved_is_empty_all +local __evolved_is_empty_any local __evolved_get local __evolved_has @@ -4907,10 +4912,18 @@ __evolved_commit = function() return __commit() end +---@param entity evolved.entity +---@return boolean +---@nodiscard +__evolved_is_alive = function(entity) + local entity_index = entity % 0x100000 + return __freelist_ids[entity_index] == entity +end + ---@param ... evolved.entity entities ---@return boolean ---@nodiscard -__evolved_is_alive = function(...) +__evolved_is_alive_all = function(...) local entity_count = __lua_select('#', ...) if entity_count == 0 then @@ -4961,14 +4974,81 @@ __evolved_is_alive = function(...) (ids[i2] == e2) and (ids[i3] == e3) and (ids[i4] == e4) and - __evolved_is_alive(__lua_select(5, ...)) + __evolved_is_alive_all(__lua_select(5, ...)) end end ---@param ... evolved.entity entities ---@return boolean ---@nodiscard -__evolved_is_empty = function(...) +__evolved_is_alive_any = function(...) + local entity_count = __lua_select('#', ...) + + if entity_count == 0 then + return false + end + + local ids = __freelist_ids + + if entity_count == 1 then + local e1 = ... + local i1 = e1 % 0x100000 + return + (ids[i1] == e1) + end + + if entity_count == 2 then + local e1, e2 = ... + local i1, i2 = e1 % 0x100000, e2 % 0x100000 + return + (ids[i1] == e1) or + (ids[i2] == e2) + end + + if entity_count == 3 then + local e1, e2, e3 = ... + local i1, i2, i3 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000 + return + (ids[i1] == e1) or + (ids[i2] == e2) or + (ids[i3] == e3) + end + + if entity_count == 4 then + local e1, e2, e3, e4 = ... + local i1, i2, i3, i4 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000, e4 % 0x100000 + return + (ids[i1] == e1) or + (ids[i2] == e2) or + (ids[i3] == e3) or + (ids[i4] == e4) + end + + do + local e1, e2, e3, e4 = ... + local i1, i2, i3, i4 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000, e4 % 0x100000 + return + (ids[i1] == e1) or + (ids[i2] == e2) or + (ids[i3] == e3) or + (ids[i4] == e4) or + __evolved_is_alive_any(__lua_select(5, ...)) + end +end + +---@param entity evolved.entity +---@return boolean +---@nodiscard +__evolved_is_empty = function(entity) + local entity_index = entity % 0x100000 + return __freelist_ids[entity_index] ~= entity + or not __entity_chunks[entity_index] +end + +---@param ... evolved.entity entities +---@return boolean +---@nodiscard +__evolved_is_empty_all = function(...) local entity_count = __lua_select('#', ...) if entity_count == 0 then @@ -5020,7 +5100,66 @@ __evolved_is_empty = function(...) (ids[i2] ~= e2 or not ecs[i2]) and (ids[i3] ~= e3 or not ecs[i3]) and (ids[i4] ~= e4 or not ecs[i4]) and - __evolved_is_empty(__lua_select(5, ...)) + __evolved_is_empty_all(__lua_select(5, ...)) + end +end + +---@param ... evolved.entity entities +---@return boolean +---@nodiscard +__evolved_is_empty_any = function(...) + local entity_count = __lua_select('#', ...) + + if entity_count == 0 then + return false + end + + local ids = __freelist_ids + local ecs = __entity_chunks + + if entity_count == 1 then + local e1 = ... + local i1 = e1 % 0x100000 + return + (ids[i1] ~= e1 or not ecs[i1]) + end + + if entity_count == 2 then + local e1, e2 = ... + local i1, i2 = e1 % 0x100000, e2 % 0x100000 + return + (ids[i1] ~= e1 or not ecs[i1]) or + (ids[i2] ~= e2 or not ecs[i2]) + end + + if entity_count == 3 then + local e1, e2, e3 = ... + local i1, i2, i3 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000 + return + (ids[i1] ~= e1 or not ecs[i1]) or + (ids[i2] ~= e2 or not ecs[i2]) or + (ids[i3] ~= e3 or not ecs[i3]) + end + + if entity_count == 4 then + local e1, e2, e3, e4 = ... + local i1, i2, i3, i4 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000, e4 % 0x100000 + return + (ids[i1] ~= e1 or not ecs[i1]) or + (ids[i2] ~= e2 or not ecs[i2]) or + (ids[i3] ~= e3 or not ecs[i3]) or + (ids[i4] ~= e4 or not ecs[i4]) + end + + do + local e1, e2, e3, e4 = ... + local i1, i2, i3, i4 = e1 % 0x100000, e2 % 0x100000, e3 % 0x100000, e4 % 0x100000 + return + (ids[i1] ~= e1 or not ecs[i1]) or + (ids[i2] ~= e2 or not ecs[i2]) or + (ids[i3] ~= e3 or not ecs[i3]) or + (ids[i4] ~= e4 or not ecs[i4]) or + __evolved_is_empty_any(__lua_select(5, ...)) end end @@ -8320,7 +8459,12 @@ evolved.defer = __evolved_defer evolved.commit = __evolved_commit evolved.is_alive = __evolved_is_alive +evolved.is_alive_all = __evolved_is_alive_all +evolved.is_alive_any = __evolved_is_alive_any + evolved.is_empty = __evolved_is_empty +evolved.is_empty_all = __evolved_is_empty_all +evolved.is_empty_any = __evolved_is_empty_any evolved.get = __evolved_get evolved.has = __evolved_has