one embedded defer instead separated

This commit is contained in:
BlackMATov
2024-12-24 11:53:40 +07:00
parent 14c4506d10
commit 4f68cd9c75
3 changed files with 219 additions and 280 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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<evolved.fragment, evolved.chunk>
local __major_chunks = {} ---@type table<evolved.fragment, evolved.chunk[]>
@@ -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<evolved.entity, any[]>
---@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