batch-multi-api: batch_multi_remove impl

This commit is contained in:
BlackMATov
2025-01-18 05:16:43 +07:00
parent 738a4fd7b1
commit d2bdaf03c6
2 changed files with 248 additions and 1 deletions

View File

@@ -3710,3 +3710,152 @@ do
assert(evo.has(e2, f4) and evo.get(e2, f4) == nil)
end
end
do
local f1, f2, f3, f4, f5 = evo.id(5)
local e1 = evo.entity():set(f1, 11):build()
local e2 = evo.entity():set(f1, 21):set(f2, 22):build()
local e3 = evo.entity():set(f1, 31):set(f2, 32):set(f3, 33):build()
local e4 = evo.entity():set(f1, 41):set(f2, 42):set(f3, 43):set(f4, 44):build()
do
local q = evo.query():include(f1):build()
assert(evo.batch_multi_remove(q, {}) == 0)
assert(evo.batch_multi_remove(q, { f5 }) == 0)
end
do
local q = evo.query():include(f3):build()
assert(evo.batch_multi_remove(q, { f4 }) == 1)
assert(evo.has_all(e4, f1, f2, f3) and not evo.has(e4, f4))
assert(evo.get(e4, f1) == 41)
assert(evo.get(e4, f2) == 42)
assert(evo.get(e4, f3) == 43)
assert(evo.get(e4, f4) == nil)
for chunk in evo.execute(q) do
assert(next(evo.select(chunk, f4)) == nil)
end
do
local chunk, entities = evo.chunk(f1, f2, f3)
assert(chunk and entities)
assert(#entities == 2)
assert(entities[1] == e3, entities[2] == e4)
assert(evo.select(chunk, f3)[1] == 33)
assert(evo.select(chunk, f3)[2] == 43)
end
do
local chunk, entities = evo.chunk(f1, f2, f3, f4)
assert(chunk)
assert(next(evo.select(chunk, f4)) == nil)
assert(#entities == 0)
end
end
do
local q = evo.query():include(f2):build()
assert(evo.batch_multi_remove(q, { f1 }) == 3)
assert(evo.has_all(e1, f1) and not evo.has_any(e1, f2, f3, f4))
assert(evo.has_all(e2, f2) and not evo.has_any(e2, f1, f3, f4))
assert(evo.has_all(e3, f2, f3) and not evo.has_any(e3, f1, f4))
assert(evo.has_all(e4, f2, f3) and not evo.has_any(e4, f1, f4))
for chunk in evo.execute(q) do
assert(next(evo.select(chunk, f1)) == nil)
end
assert(evo.batch_multi_remove(q, { f2, f3 }) == 3)
assert(evo.has_all(e1, f1) and not evo.has_any(e1, f2, f3, f4))
assert(not evo.has_any(e2, f1, f2, f3, f4))
assert(not evo.has_any(e3, f1, f2, f3, f4))
assert(not evo.has_any(e4, f1, f2, f3, f4))
for chunk in evo.execute(q) do
assert(next(evo.select(chunk, f2)) == nil)
assert(next(evo.select(chunk, f3)) == nil)
end
do
local chunk, entities = evo.chunk(f1, f2)
assert(chunk)
assert(next(evo.select(chunk, f1)) == nil)
assert(next(evo.select(chunk, f2)) == nil)
assert(#entities == 0)
end
do
local chunk, entities = evo.chunk(f1, f2, f3)
assert(chunk)
assert(next(evo.select(chunk, f1)) == nil)
assert(next(evo.select(chunk, f2)) == nil)
assert(next(evo.select(chunk, f3)) == nil)
assert(#entities == 0)
end
end
do
local q = evo.query():include(f1):build()
assert(evo.defer())
assert(evo.batch_multi_remove(q, { f1 }) == 0)
assert(evo.has(e1, f1))
assert(evo.commit())
assert(not evo.has(e1, f1))
end
end
do
local f1, f2 = evo.id(2)
evo.set(f2, evo.TAG)
local last_remove_entity = 0
local last_remove_component = 0
local sum_removed_components = 0
evo.set(f1, evo.ON_REMOVE, function(e, f, c)
assert(f == f1)
last_remove_entity = e
last_remove_component = c
sum_removed_components = sum_removed_components + c
end)
evo.set(f2, evo.ON_REMOVE, function(e, f, c)
assert(f == f2)
last_remove_entity = e
last_remove_component = c
end)
local _ = evo.spawn_with({ f1 }, { 11 })
local e2 = evo.spawn_with({ f1, f2 }, { 21, 22 })
assert(last_remove_entity == 0 and last_remove_component == 0)
do
last_remove_entity = 0
last_remove_component = 0
sum_removed_components = 0
local q = evo.query():include(f1):build()
assert(evo.batch_multi_remove(q, { f1, f1 }) == 2)
assert(last_remove_entity == e2 and last_remove_component == 21)
assert(sum_removed_components == 11 + 21)
end
do
last_remove_entity = 0
last_remove_component = 0
sum_removed_components = 0
local q = evo.query():include(f2):build()
assert(evo.batch_multi_remove(q, { f2 }) == 1)
assert(last_remove_entity == e2 and last_remove_component == nil)
assert(sum_removed_components == 0)
end
end

View File

@@ -1377,7 +1377,105 @@ end
---@param fragments evolved.fragment[]
---@return integer removed_count
local function __chunk_multi_remove(chunk, fragments)
error('not implemented yet', 2)
if __defer_depth <= 0 then
error('batched chunk operations should be deferred', 2)
end
local fragment_count = #fragments
if fragment_count == 0 then
return 0
end
local old_chunk = chunk
local new_chunk = __chunk_without_fragment_list(chunk, fragments)
if old_chunk == new_chunk then
return 0
end
local old_entities = old_chunk.__entities
local old_size = #old_entities
local old_fragment_set = old_chunk.__fragment_set
local old_component_indices = old_chunk.__component_indices
local old_component_storages = old_chunk.__component_storages
if old_chunk.__has_remove_hooks then
local removed_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET, 0, fragment_count)
for i = 1, fragment_count do
local fragment = fragments[i]
if not removed_set[fragment] and old_fragment_set[fragment] and __fragment_has_remove_hook(fragment) then
removed_set[fragment] = true
local old_component_index = old_component_indices[fragment]
if old_component_index then
local old_component_storage = old_component_storages[old_component_index]
for old_place = 1, old_size do
local entity = old_entities[old_place]
local old_component = old_component_storage[old_place]
__fragment_call_remove_hook(entity, fragment, old_component)
end
else
for place = 1, old_size do
local entity = old_entities[place]
__fragment_call_remove_hook(entity, fragment)
end
end
end
end
end
if new_chunk then
local new_entities = new_chunk.__entities
local new_size = #new_entities
local new_component_storages = new_chunk.__component_storages
local new_component_fragments = new_chunk.__component_fragments
__table_move(
old_entities, 1, old_size,
new_size + 1, new_entities)
for i = 1, #new_component_fragments do
local new_f = new_component_fragments[i]
local new_cs = new_component_storages[i]
local old_ci = old_component_indices[new_f]
if old_ci then
local old_cs = old_component_storages[old_ci]
__table_move(old_cs, 1, old_size, new_size + 1, new_cs)
end
end
for new_place = new_size + 1, new_size + old_size do
local entity = new_entities[new_place]
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = new_chunk
__entity_places[entity_index] = new_place
end
else
for old_place = 1, old_size do
local entity = old_entities[old_place]
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = nil
__entity_places[entity_index] = nil
end
end
do
old_chunk.__entities = {}
for i = 1, #old_component_storages do
old_component_storages[i] = {}
end
end
__structural_changes = __structural_changes + old_size
return old_size
end
---