From 4f68cd9c7554838f5a149800567c17c4a9824236 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 24 Dec 2024 11:53:40 +0700 Subject: [PATCH] one embedded defer instead separated --- README.md | 26 +-- develop/untests.lua | 38 ++-- evolved.lua | 435 +++++++++++++++++++------------------------- 3 files changed, 219 insertions(+), 280 deletions(-) diff --git a/README.md b/README.md index 1679ec2..6d3db6e 100644 --- a/README.md +++ b/README.md @@ -2,36 +2,26 @@ ``` id :: id + pack :: integer, integer -> id unpack :: id -> integer, integer -alive :: id -> boolean + +defer :: () +commit :: () + get :: entity, fragment... -> component... has :: entity, fragment -> boolean has_all :: entity, fragment... -> boolean has_any :: entity, fragment... -> boolean + set :: entity, fragment, component, any... -> boolean, boolean assign :: entity, fragment, component, any... -> boolean, boolean insert :: entity, fragment, component, any... -> boolean, boolean remove :: entity, fragment... -> boolean, boolean clear :: entity -> boolean, boolean + +alive :: entity -> boolean destroy :: entity -> boolean, boolean ``` -``` -defer_begin :: () -defer_end :: () -``` - -``` -defer :: defer - -defer:set :: entity, fragment, component, any... -> defer -defer:assign :: entity, fragment, component, any... -> defer -defer:insert :: entity, fragment, component, any... -> defer -defer:remove :: entity, fragment... -> defer -defer:clear :: entity -> defer -defer:destroy :: entity -> defer -defer:playback :: () -``` - ## [License (MIT)](./LICENSE.md) diff --git a/develop/untests.lua b/develop/untests.lua index 89ad962..c942bdf 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -557,18 +557,7 @@ do local e1, e2, e3, e4 = evo.id(4) - local d = evo.defer() - :set(e1, f1, 42) - :set(e1, f2, 43) - :remove(e2, f1, f2) - :assign(e2, f3, 48) - :clear(e3) - :insert(e3, f1, 48) - :insert(e3, f1, 49) - :destroy(e4) - assert(evo.insert(e1, f3, 44)) - assert(not evo.has_any(e1, f1, f2)) assert(evo.insert(e2, f1, 45)) assert(evo.insert(e2, f2, 46)) @@ -578,7 +567,32 @@ do assert(evo.insert(e3, f2, 46)) assert(evo.insert(e3, f3, 47)) - assert(d == d:playback()) + assert(evo.defer()) + assert(not evo.defer()) + + evo.set(e1, f1, 42) + evo.set(e1, f2, 43) + evo.remove(e2, f1, f2) + evo.assign(e2, f3, 48) + evo.clear(e3) + evo.insert(e3, f1, 48) + evo.insert(e3, f1, 49) + evo.destroy(e4) + + assert(evo.get(e1, f1) == nil) + assert(evo.get(e1, f2) == nil) + assert(evo.get(e1, f3) == 44) + + assert(evo.get(e2, f1) == 45) + assert(evo.get(e2, f2) == 46) + assert(evo.get(e2, f3) == 47) + + assert(evo.get(e3, f1) == 45) + assert(evo.get(e3, f2) == 46) + assert(evo.get(e3, f3) == 47) + + assert(not evo.commit()) + assert(evo.commit()) assert(evo.get(e1, f1) == 42) assert(evo.get(e1, f2) == 43) diff --git a/evolved.lua b/evolved.lua index 4dd4422..bf2eb53 100644 --- a/evolved.lua +++ b/evolved.lua @@ -26,7 +26,8 @@ local __freelist_ids = {} ---@type evolved.id[] local __available_idx = 0 ---@type integer local __defer_depth = 0 ---@type integer -local __global_defer = nil ---@type evolved.defer +local __defer_bytecode = {} ---@type any[] +local __defer_bytecode_length = 0 ---@type integer local __root_chunks = {} ---@type table local __major_chunks = {} ---@type table @@ -533,6 +534,162 @@ end --- --- +---@enum evolved.defer_op +local __defer_op = { + set = 1, + assign = 2, + insert = 3, + remove = 4, + clear = 5, + destroy = 6, +} + +---@return boolean started +local function __defer() + assert(__defer_depth >= 0, 'unbalanced defer/commit') + __defer_depth = __defer_depth + 1 + return __defer_depth == 1 +end + +---@return boolean committed +local function __defer_commit() + assert(__defer_depth > 0, 'unbalanced defer/commit') + __defer_depth = __defer_depth - 1 + + if __defer_depth > 0 then + return false + end + + local bytecode = __defer_bytecode + local bytecode_length = __defer_bytecode_length + + __defer_bytecode = {} + __defer_bytecode_length = 0 + + local bytecode_index = 1 + while bytecode_index <= bytecode_length do + local op = bytecode[bytecode_index] + if op == __defer_op.set then + local entity = bytecode[bytecode_index + 1] + local fragment = bytecode[bytecode_index + 2] + local component = bytecode[bytecode_index + 3] + bytecode_index = bytecode_index + 4 + evolved.set(entity, fragment, component) + elseif op == __defer_op.assign then + local entity = bytecode[bytecode_index + 1] + local fragment = bytecode[bytecode_index + 2] + local component = bytecode[bytecode_index + 3] + bytecode_index = bytecode_index + 4 + evolved.assign(entity, fragment, component) + elseif op == __defer_op.insert then + local entity = bytecode[bytecode_index + 1] + local fragment = bytecode[bytecode_index + 2] + local component = bytecode[bytecode_index + 3] + bytecode_index = bytecode_index + 4 + evolved.insert(entity, fragment, component) + elseif op == __defer_op.remove then + local entity = bytecode[bytecode_index + 1] + local fragment_count = bytecode[bytecode_index + 2] + bytecode_index = bytecode_index + 3 + fragment_count + evolved.remove(entity, __lua_unpack(bytecode, bytecode_index - fragment_count, bytecode_index - 1)) + elseif op == __defer_op.clear then + local entity = bytecode[bytecode_index + 1] + bytecode_index = bytecode_index + 2 + evolved.clear(entity) + elseif op == __defer_op.destroy then + local entity = bytecode[bytecode_index + 1] + bytecode_index = bytecode_index + 2 + evolved.destroy(entity) + end + end + + return true +end + +---@param entity evolved.entity +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +local function __defer_set(entity, fragment, component, ...) + component = __construct(entity, fragment, component, ...) + + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.set + __defer_bytecode[__defer_bytecode_length + 2] = entity + __defer_bytecode[__defer_bytecode_length + 3] = fragment + __defer_bytecode[__defer_bytecode_length + 4] = component + + __defer_bytecode_length = __defer_bytecode_length + 4 +end + +---@param entity evolved.entity +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +local function __defer_assign(entity, fragment, component, ...) + component = __construct(entity, fragment, component, ...) + + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.assign + __defer_bytecode[__defer_bytecode_length + 2] = entity + __defer_bytecode[__defer_bytecode_length + 3] = fragment + __defer_bytecode[__defer_bytecode_length + 4] = component + + __defer_bytecode_length = __defer_bytecode_length + 4 +end + +---@param entity evolved.entity +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +local function __defer_insert(entity, fragment, component, ...) + component = __construct(entity, fragment, component, ...) + + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.insert + __defer_bytecode[__defer_bytecode_length + 2] = entity + __defer_bytecode[__defer_bytecode_length + 3] = fragment + __defer_bytecode[__defer_bytecode_length + 4] = component + + __defer_bytecode_length = __defer_bytecode_length + 4 +end + +---@param entity evolved.entity +---@param ... evolved.fragment fragments +local function __defer_remove(entity, ...) + local fragment_count = select('#', ...) + if fragment_count == 0 then return end + + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.remove + __defer_bytecode[__defer_bytecode_length + 2] = entity + __defer_bytecode[__defer_bytecode_length + 3] = fragment_count + + for i = 1, fragment_count do + __defer_bytecode[__defer_bytecode_length + 3 + i] = select(i, ...) + end + + __defer_bytecode_length = __defer_bytecode_length + 3 + fragment_count +end + +---@param entity evolved.entity +local function __defer_clear(entity) + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.clear + __defer_bytecode[__defer_bytecode_length + 2] = entity + + __defer_bytecode_length = __defer_bytecode_length + 2 +end + +---@param entity evolved.entity +local function __defer_destroy(entity) + __defer_bytecode[__defer_bytecode_length + 1] = __defer_op.destroy + __defer_bytecode[__defer_bytecode_length + 2] = entity + + __defer_bytecode_length = __defer_bytecode_length + 2 +end + +--- +--- +--- +--- +--- + ---@param count? integer ---@return evolved.id ... ---@nodiscard @@ -577,11 +734,14 @@ function evolved.unpack(id) return __unpack_id(id) end ----@param id evolved.id ----@return boolean ----@nodiscard -function evolved.alive(id) - return __alive_id(id) +---@return boolean started +function evolved.defer() + return __defer() +end + +---@return boolean committed +function evolved.commit() + return __defer_commit() end ---@param entity evolved.entity @@ -671,7 +831,7 @@ function evolved.set(entity, fragment, component, ...) component = __construct(entity, fragment, component, ...) if __defer_depth > 0 then - __global_defer:set(entity, fragment, component) + __defer_set(entity, fragment, component) return false, true end @@ -731,7 +891,7 @@ function evolved.assign(entity, fragment, component, ...) component = __construct(entity, fragment, component, ...) if __defer_depth > 0 then - __global_defer:assign(entity, fragment, component) + __defer_assign(entity, fragment, component) return false, true end @@ -765,7 +925,7 @@ function evolved.insert(entity, fragment, component, ...) component = __construct(entity, fragment, component, ...) if __defer_depth > 0 then - __global_defer:insert(entity, fragment, component) + __defer_insert(entity, fragment, component) return false, true end @@ -817,7 +977,7 @@ end ---@return boolean is_deferred function evolved.remove(entity, ...) if __defer_depth > 0 then - __global_defer:remove(entity, ...) + __defer_remove(entity, ...) return false, true end @@ -837,7 +997,7 @@ function evolved.remove(entity, ...) return true, false end - evolved.defer_begin() + __defer() do local old_chunk_fragments = old_chunk.__fragments local old_chunk_components = old_chunk.__components @@ -869,7 +1029,7 @@ function evolved.remove(entity, ...) __structural_changes = __structural_changes + 1 end - evolved.defer_end() + __defer_commit() return true, false end @@ -878,7 +1038,7 @@ end ---@return boolean is_deferred function evolved.clear(entity) if __defer_depth > 0 then - __global_defer:clear(entity) + __defer_clear(entity) return false, true end @@ -895,7 +1055,7 @@ function evolved.clear(entity) return true, false end - evolved.defer_begin() + __defer() do local old_chunk_fragments = old_chunk.__fragments local old_chunk_components = old_chunk.__components @@ -907,16 +1067,23 @@ function evolved.clear(entity) __detach_entity(entity) end - evolved.defer_end() + __defer_commit() return true, false end +---@param entity evolved.entity +---@return boolean +---@nodiscard +function evolved.alive(entity) + return __alive_id(entity) +end + ---@param entity evolved.entity ---@return boolean is_destroyed ---@return boolean is_deferred function evolved.destroy(entity) if __defer_depth > 0 then - __global_defer:destroy(entity) + __defer_destroy(entity) return false, true end @@ -934,7 +1101,7 @@ function evolved.destroy(entity) return true, false end - evolved.defer_begin() + __defer() do local old_chunk_fragments = old_chunk.__fragments local old_chunk_components = old_chunk.__components @@ -947,7 +1114,7 @@ function evolved.destroy(entity) __detach_entity(entity) __release_id(entity) end - evolved.defer_end() + __defer_commit() return true, false end @@ -957,236 +1124,4 @@ end --- --- -function evolved.defer_begin() - assert(__defer_depth >= 0, 'unbalanced defer_begin/defer_end') - __defer_depth = __defer_depth + 1 - - if __defer_depth == 1 and not __global_defer then - __global_defer = evolved.defer() - end -end - -function evolved.defer_end() - assert(__defer_depth > 0, 'unbalanced defer_begin/defer_end') - __defer_depth = __defer_depth - 1 - - if __defer_depth == 0 and __global_defer then - __global_defer:playback() - end -end - ---- ---- ---- ---- ---- - ----@enum evolved.defer_op -local evolved_defer_op = { - set = 1, - assign = 2, - insert = 3, - remove = 4, - clear = 5, - destroy = 6, -} - ----@class (exact) evolved.__defer ----@field __bytecodes table - ----@class evolved.defer : evolved.__defer -local evolved_defer_mt = {} -evolved_defer_mt.__index = evolved_defer_mt - ----@return evolved.defer ----@nodiscard -function evolved.defer() - ---@type evolved.__defer - local defer = { - __bytecodes = {}, - } - ---@cast defer evolved.defer - return setmetatable(defer, evolved_defer_mt) -end - ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param component evolved.component ----@param ... any construct additional parameters ----@return evolved.defer -function evolved_defer_mt:set(entity, fragment, component, ...) - component = __construct(entity, fragment, component, ...) - - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.set - bytecode[bytecode_size + 2] = fragment - bytecode[bytecode_size + 3] = component - - return self -end - ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param component evolved.component ----@param ... any construct additional parameters ----@return evolved.defer -function evolved_defer_mt:assign(entity, fragment, component, ...) - component = __construct(entity, fragment, component, ...) - - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.assign - bytecode[bytecode_size + 2] = fragment - bytecode[bytecode_size + 3] = component - - return self -end - ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param component evolved.component ----@param ... any construct additional parameters ----@return evolved.defer -function evolved_defer_mt:insert(entity, fragment, component, ...) - component = __construct(entity, fragment, component, ...) - - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.insert - bytecode[bytecode_size + 2] = fragment - bytecode[bytecode_size + 3] = component - - return self -end - ----@param entity evolved.entity ----@param ... evolved.fragment fragments ----@return evolved.defer -function evolved_defer_mt:remove(entity, ...) - local fragment_count = select('#', ...) - if fragment_count == 0 then return self end - - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.remove - bytecode[bytecode_size + 2] = fragment_count - - for i = 1, fragment_count do - bytecode[bytecode_size + 2 + i] = select(i, ...) - end - - return self -end - ----@param entity evolved.entity ----@return evolved.defer -function evolved_defer_mt:clear(entity) - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.clear - - return self -end - ----@param entity evolved.entity ----@return evolved.defer -function evolved_defer_mt:destroy(entity) - local bytecode = self.__bytecodes[entity] - - if not bytecode then - bytecode = {} - self.__bytecodes[entity] = bytecode - end - - local bytecode_size = #bytecode - - bytecode[bytecode_size + 1] = evolved_defer_op.destroy - - return self -end - ----@return evolved.defer -function evolved_defer_mt:playback() - local bytecodes = self.__bytecodes - self.__bytecodes = {} - - for entity, bytecode in pairs(bytecodes) do - local bytecode_index = 1 - local bytecode_size = #bytecode - while bytecode_index <= bytecode_size do - local bytecode_op = bytecode[bytecode_index] - if bytecode_op == evolved_defer_op.set then - local fragment = bytecode[bytecode_index + 1] - local component = bytecode[bytecode_index + 2] - bytecode_index = bytecode_index + 3 - evolved.set(entity, fragment, component) - elseif bytecode_op == evolved_defer_op.assign then - local fragment = bytecode[bytecode_index + 1] - local component = bytecode[bytecode_index + 2] - bytecode_index = bytecode_index + 3 - evolved.assign(entity, fragment, component) - elseif bytecode_op == evolved_defer_op.insert then - local fragment = bytecode[bytecode_index + 1] - local component = bytecode[bytecode_index + 2] - bytecode_index = bytecode_index + 3 - evolved.insert(entity, fragment, component) - elseif bytecode_op == evolved_defer_op.remove then - local fragment_count = bytecode[bytecode_index + 1] - bytecode_index = bytecode_index + 2 + fragment_count - evolved.remove(entity, __lua_unpack(bytecode, bytecode_index - fragment_count, bytecode_index - 1)) - elseif bytecode_op == evolved_defer_op.clear then - bytecode_index = bytecode_index + 1 - evolved.clear(entity) - elseif bytecode_op == evolved_defer_op.destroy then - bytecode_index = bytecode_index + 1 - evolved.destroy(entity) - end - end - end - - return self -end - ---- ---- ---- ---- ---- - return evolved