From f89005d485fd7257b5e169dcba980120f24963ec Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 21 Dec 2024 21:27:56 +0700 Subject: [PATCH] simple defer impl --- .luarc.json | 17 ++++ README.md | 12 +++ develop/untests.lua | 43 +++++++++ evolved.lua | 228 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+) diff --git a/.luarc.json b/.luarc.json index 9738417..a493161 100644 --- a/.luarc.json +++ b/.luarc.json @@ -3,6 +3,23 @@ "completion": { "autoRequire": false }, + "diagnostics": { + "groupSeverity": { + "ambiguity": "Warning", + "await": "Warning", + "codestyle": "Warning", + "conventions": "Warning", + "duplicate": "Warning", + "global": "Warning", + "luadoc": "Warning", + "redefined": "Warning", + "strict": "Warning", + "strong": "Warning", + "type-check": "Warning", + "unbalanced": "Warning", + "unused": "Warning" + } + }, "runtime": { "version": "LuaJIT", "pathStrict": true diff --git a/README.md b/README.md index 42a5086..030e31d 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,16 @@ remove :: entity, fragment... -> () clear :: entity -> () ``` +``` +defer :: defer + +defer:set :: id, fragment, component, any... -> defer +defer:assign :: id, fragment, component, any... -> defer +defer:insert :: id, fragment, component, any... -> defer +defer:remove :: id, fragment... -> defer +defer:clear :: id -> defer +defer:destroy :: id -> defer +defer:playback :: () +``` + ## [License (MIT)](./LICENSE.md) diff --git a/develop/untests.lua b/develop/untests.lua index 28a3c84..77dca4b 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -513,3 +513,46 @@ do assert(not evo.has(e, f)) assert(not evo.alive(e)) end + +do + local f1, f2, f3 = evo.id(3) + + 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)) + assert(evo.insert(e2, f3, 47)) + + assert(evo.insert(e3, f1, 45)) + assert(evo.insert(e3, f2, 46)) + assert(evo.insert(e3, f3, 47)) + + assert(d == d:playback()) + + assert(evo.get(e1, f1) == 42) + assert(evo.get(e1, f2) == 43) + assert(evo.get(e1, f3) == 44) + + assert(evo.get(e2, f1) == nil) + assert(evo.get(e2, f2) == nil) + assert(evo.get(e2, f3) == 48) + + assert(evo.get(e3, f1) == 48) + assert(evo.get(e3, f2) == nil) + assert(evo.get(e3, f3) == nil) + + assert(not evo.alive(e4)) +end diff --git a/evolved.lua b/evolved.lua index ae3b6d5..16e295b 100644 --- a/evolved.lua +++ b/evolved.lua @@ -39,6 +39,20 @@ local __structural_changes = 0 ---@type integer --- --- +local __lua_pack = table.pack or function(...) + return { n = select('#', ...), ... } +end + +local __lua_unpack = table.unpack or function(list, i, j) + return unpack(list, i, j) +end + +--- +--- +--- +--- +--- + ---@param index integer ---@param version integer ---@return evolved.id @@ -904,4 +918,218 @@ function evolved.clear(entity) __structural_changes = __structural_changes + 1 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 id evolved.id +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +---@return evolved.defer +function evolved_defer_mt:set(id, fragment, component, ...) + component = __construct(id, fragment, component, ...) + + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = 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 id evolved.id +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +---@return evolved.defer +function evolved_defer_mt:assign(id, fragment, component, ...) + component = __construct(id, fragment, component, ...) + + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = 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 id evolved.id +---@param fragment evolved.fragment +---@param component evolved.component +---@param ... any construct additional parameters +---@return evolved.defer +function evolved_defer_mt:insert(id, fragment, component, ...) + component = __construct(id, fragment, component, ...) + + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = 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 id evolved.id +---@param ... evolved.fragment fragments +---@return evolved.defer +function evolved_defer_mt:remove(id, ...) + local fragment_count = select('#', ...) + if fragment_count == 0 then return self end + + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = 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 id evolved.id +---@return evolved.defer +function evolved_defer_mt:clear(id) + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = bytecode + end + + local bytecode_size = #bytecode + + bytecode[bytecode_size + 1] = evolved_defer_op.clear + + return self +end + +---@param id evolved.id +---@return evolved.defer +function evolved_defer_mt:destroy(id) + local bytecode = self.__bytecodes[id] + + if not bytecode then + bytecode = {} + self.__bytecodes[id] = 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 id, 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(id, 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(id, 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(id, 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(id, __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(id) + elseif bytecode_op == evolved_defer_op.destroy then + bytecode_index = bytecode_index + 1 + evolved.destroy(id) + end + end + end + + return self +end + +--- +--- +--- +--- +--- + return evolved