From 2c4cb179bcf7851471862c83e8519327439b9cb2 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 9 Feb 2026 09:27:00 +0700 Subject: [PATCH] (multi_)lookup first impl --- develop/testing/lookup_tests.lua | 122 +++++++++++++++++++------ evolved.lua | 151 +++++++++++++++++++++++++++++-- 2 files changed, 237 insertions(+), 36 deletions(-) diff --git a/develop/testing/lookup_tests.lua b/develop/testing/lookup_tests.lua index a6c0441..bc1374d 100644 --- a/develop/testing/lookup_tests.lua +++ b/develop/testing/lookup_tests.lua @@ -6,85 +6,85 @@ do local e1, e2, e3 = evo.id(3) do - assert(evo.lookup('hello') == nil) - assert(evo.lookup('world') == nil) + assert(evo.lookup('lookup_hello') == nil) + assert(evo.lookup('lookup_world') == nil) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 0 and entity_count == 0) end do - local entity_list, entity_count = evo.multi_lookup('world') + local entity_list, entity_count = evo.multi_lookup('lookup_world') assert(entity_list and #entity_list == 0 and entity_count == 0) end end - evo.set(e1, evo.NAME, 'hello') + evo.set(e1, evo.NAME, 'lookup_hello') do - assert(evo.lookup('hello') == e1) - assert(evo.lookup('world') == nil) + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == nil) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 1 and entity_count == 1) assert(entity_list[1] == e1) end do - local entity_list, entity_count = evo.multi_lookup('world') + local entity_list, entity_count = evo.multi_lookup('lookup_world') assert(entity_list and #entity_list == 0 and entity_count == 0) end end - evo.set(e2, evo.NAME, 'hello') - evo.set(e3, evo.NAME, 'hello') + evo.set(e2, evo.NAME, 'lookup_hello') + evo.set(e3, evo.NAME, 'lookup_hello') do - assert(evo.lookup('hello') == e3) - assert(evo.lookup('world') == nil) + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == nil) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 3 and entity_count == 3) assert(entity_list[1] == e1 and entity_list[2] == e2 and entity_list[3] == e3) end end - evo.set(e2, evo.NAME, 'world') + evo.set(e2, evo.NAME, 'lookup_world') do - assert(evo.lookup('hello') == e3) - assert(evo.lookup('world') == e2) + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == e2) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 2 and entity_count == 2) assert(entity_list[1] == e1 and entity_list[2] == e3) end do - local entity_list, entity_count = evo.multi_lookup('world') + local entity_list, entity_count = evo.multi_lookup('lookup_world') assert(entity_list and #entity_list == 1 and entity_count == 1) assert(entity_list[1] == e2) end end - evo.set(e3, evo.NAME, 'world') + evo.set(e3, evo.NAME, 'lookup_world') do - assert(evo.lookup('hello') == e1) - assert(evo.lookup('world') == e3) + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == e2) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 1 and entity_count == 1) assert(entity_list[1] == e1) end do - local entity_list, entity_count = evo.multi_lookup('world') + local entity_list, entity_count = evo.multi_lookup('lookup_world') assert(entity_list and #entity_list == 2 and entity_count == 2) assert(entity_list[1] == e2 or entity_list[1] == e3) end @@ -93,18 +93,84 @@ do evo.remove(e1, evo.NAME) do - assert(evo.lookup('hello') == nil) - assert(evo.lookup('world') == e3) + assert(evo.lookup('lookup_hello') == nil) + assert(evo.lookup('lookup_world') == e2) do - local entity_list, entity_count = evo.multi_lookup('hello') + local entity_list, entity_count = evo.multi_lookup('lookup_hello') assert(entity_list and #entity_list == 0 and entity_count == 0) end do - local entity_list, entity_count = evo.multi_lookup('world') + local entity_list, entity_count = evo.multi_lookup('lookup_world') assert(entity_list and #entity_list == 2 and entity_count == 2) assert(entity_list[1] == e2 or entity_list[1] == e3) end end end + +do + local e1, e2, e3 = evo.id(3) + + evo.set(e1, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e1) + end + + evo.set(e2, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e1 and entity_list[2] == e2) + end + + evo.set(e3, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 3 and entity_count == 3) + assert(entity_list[1] == e1 and entity_list[2] == e2 and entity_list[3] == e3) + end + + evo.clear(e1, e2, e3) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + + evo.set(e3, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e3) + end + + evo.set(e2, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e3 and entity_list[2] == e2) + end + + evo.set(e1, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 3 and entity_count == 3) + assert(entity_list[1] == e3 and entity_list[2] == e2 and entity_list[3] == e1) + end + + evo.destroy(e3, e2, e1) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end +end diff --git a/evolved.lua b/evolved.lua index a94d03f..451369b 100644 --- a/evolved.lua +++ b/evolved.lua @@ -144,6 +144,9 @@ local __major_queries = {} ---@type table +local __named_entities = {} ---@type table> + local __sorted_includes = {} ---@type table> local __sorted_excludes = {} ---@type table> local __sorted_variants = {} ---@type table> @@ -896,6 +899,22 @@ function __assoc_list_fns.new(reserve) } end +---@generic K +---@param ... K +---@return evolved.assoc_list +---@nodiscard +function __assoc_list_fns.from(...) + local item_count = __lua_select('#', ...) + + local al = __assoc_list_fns.new(item_count) + + for item_index = 1, item_count do + __assoc_list_fns.insert(al, __lua_select(item_index, ...)) + end + + return al +end + ---@generic K ---@param src_item_list K[] ---@param src_item_first integer @@ -1039,6 +1058,46 @@ function __assoc_list_fns.remove_ex(al_item_set, al_item_list, al_item_count, it return al_item_count end +---@generic K +---@param al evolved.assoc_list +---@param item K +---@return integer new_al_count +function __assoc_list_fns.unordered_remove(al, item) + local new_al_count = __assoc_list_fns.unordered_remove_ex( + al.__item_set, al.__item_list, al.__item_count, + item) + + al.__item_count = new_al_count + return new_al_count +end + +---@generic K +---@param al_item_set table +---@param al_item_list K[] +---@param al_item_count integer +---@param item K +---@return integer new_al_count +---@nodiscard +function __assoc_list_fns.unordered_remove_ex(al_item_set, al_item_list, al_item_count, item) + local item_index = al_item_set[item] + + if not item_index then + return al_item_count + end + + if item_index ~= al_item_count then + local al_last_item = al_item_list[al_item_count] + al_item_set[al_last_item] = item_index + al_item_list[item_index] = al_last_item + end + + al_item_set[item] = nil + al_item_list[al_item_count] = nil + al_item_count = al_item_count - 1 + + return al_item_count +end + --- --- --- @@ -1090,6 +1149,11 @@ local __DESTRUCTION_POLICY_REMOVE_FRAGMENT = __acquire_id() --- local __safe_tbls = { + __EMPTY_ENTITY_LIST = __lua_setmetatable({}, { + __tostring = function() return 'empty entity list' end, + __newindex = function() __error_fmt 'attempt to modify empty entity list' end + }) --[=[@as evolved.id[]]=], + __EMPTY_FRAGMENT_SET = __lua_setmetatable({}, { __tostring = function() return 'empty fragment set' end, __newindex = function() __error_fmt 'attempt to modify empty fragment set' end @@ -4860,7 +4924,7 @@ end ---@return integer entity_count function __evolved_multi_spawn(entity_count, component_table, component_mapper) if entity_count <= 0 then - return {}, 0 + return __safe_tbls.__EMPTY_ENTITY_LIST, 0 end if __debug_mode then @@ -4941,7 +5005,7 @@ end ---@return integer entity_count function __evolved_multi_clone(entity_count, prefab, component_table, component_mapper) if entity_count <= 0 then - return {}, 0 + return __safe_tbls.__EMPTY_ENTITY_LIST, 0 end if __debug_mode then @@ -6093,6 +6157,7 @@ end ---@return evolved.entity? entity ---@nodiscard function __evolved_lookup(name) + return __named_entity[name] end ---@param name string @@ -6100,6 +6165,25 @@ end ---@return integer entity_count ---@nodiscard function __evolved_multi_lookup(name) + do + local named_entities = __named_entities[name] + local named_entity_list = named_entities and named_entities.__item_list + local named_entity_count = named_entities and named_entities.__item_count or 0 + + if named_entity_count > 0 then + return __list_fns.dup(named_entity_list, named_entity_count), named_entity_count + end + end + + do + local named_entity = __named_entity[name] + + if named_entity then + return { named_entity }, 1 + end + end + + return __safe_tbls.__EMPTY_ENTITY_LIST, 0 end ---@param ... evolved.system systems @@ -6497,7 +6581,7 @@ end ---@return integer entity_count function __builder_mt:multi_spawn(entity_count, component_mapper) if entity_count <= 0 then - return {}, 0 + return __safe_tbls.__EMPTY_ENTITY_LIST, 0 end local chunk = self.__chunk @@ -6581,7 +6665,7 @@ end ---@return integer entity_count function __builder_mt:multi_clone(entity_count, prefab, component_mapper) if entity_count <= 0 then - return {}, 0 + return __safe_tbls.__EMPTY_ENTITY_LIST, 0 end local component_table = self.__component_table @@ -7169,18 +7253,69 @@ __evolved_set(__ON_REMOVE, __UNIQUE) --- --- +---@param name string ---@param entity evolved.entity ----@param new_name string ----@param old_name string +local function __insert_named_entity(name, entity) + ---@type evolved.entity? + local named_entity = __named_entity[name] + + if not named_entity then + __named_entity[name] = entity + return + end + + ---@type evolved.assoc_list? + local named_entities = __named_entities[name] + + if not named_entities then + __named_entities[name] = __assoc_list_fns.from(named_entity, entity) + return + end + + __assoc_list_fns.insert(named_entities, entity) +end + +---@param name string +---@param entity evolved.entity +local function __remove_named_entity(name, entity) + ---@type evolved.assoc_list? + local named_entities = __named_entities[name] + + if named_entities then + if __assoc_list_fns.remove(named_entities, entity) == 0 then + __named_entities[name], named_entities = nil, nil + end + end + + ---@type evolved.entity? + local named_entity = __named_entity[name] + + if named_entity == entity then + __named_entity[name] = named_entities and named_entities.__item_list[1] or nil + end +end + +---@param entity evolved.entity +---@param new_name? string +---@param old_name? string __evolved_set(__NAME, __ON_SET, function(entity, _, new_name, old_name) + if old_name then + __remove_named_entity(old_name, entity) + end + + if new_name then + __insert_named_entity(new_name, entity) + end end) ---@param entity evolved.entity ----@param old_name string +---@param old_name? string __evolved_set(__NAME, __ON_REMOVE, function(entity, _, old_name) + if old_name then + __remove_named_entity(old_name, entity) + end end) - --- --- ---