mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-14 12:10:23 +07:00
first queries wip
This commit is contained in:
@@ -22,6 +22,8 @@ clear :: entity -> boolean, boolean
|
||||
|
||||
alive :: entity -> boolean
|
||||
destroy :: entity -> boolean, boolean
|
||||
|
||||
execute :: query -> {execution_state? -> chunk?}, execution_state?
|
||||
```
|
||||
|
||||
## [License (MIT)](./LICENSE.md)
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
---@generic V
|
||||
---@param list V[]
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
local function __is_sorted(list)
|
||||
for i = 1, #list - 1 do
|
||||
if list[i] > list[i + 1] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
do
|
||||
local e1, e2 = evo.id(), evo.id()
|
||||
assert(e1 ~= e2)
|
||||
@@ -663,3 +676,74 @@ do
|
||||
assert(evo.get(e, f2) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3, f4 = evo.id(4)
|
||||
|
||||
do
|
||||
local q = evo.id()
|
||||
evo.set(q, evo.INCLUDE_LIST)
|
||||
assert(evo.has_all(q, evo.INCLUDE_LIST, evo.EXCLUDE_LIST))
|
||||
|
||||
local include_list, exclude_list = evo.get(q, evo.INCLUDE_LIST, evo.EXCLUDE_LIST)
|
||||
assert(type(include_list) == "table" and next(include_list) == nil)
|
||||
assert(type(exclude_list) == "table" and next(exclude_list) == nil)
|
||||
end
|
||||
|
||||
do
|
||||
local q = evo.id()
|
||||
evo.set(q, evo.EXCLUDE_LIST)
|
||||
assert(evo.has_all(q, evo.EXCLUDE_LIST, evo.INCLUDE_LIST))
|
||||
|
||||
local include_list, exclude_list = evo.get(q, evo.INCLUDE_LIST, evo.EXCLUDE_LIST)
|
||||
assert(type(include_list) == "table" and next(include_list) == nil)
|
||||
assert(type(exclude_list) == "table" and next(exclude_list) == nil)
|
||||
end
|
||||
|
||||
do
|
||||
local q = evo.id()
|
||||
|
||||
evo.set(q, evo.INCLUDE_LIST, { f2, f1 })
|
||||
assert(__is_sorted(evo.get(q, evo.INCLUDE_LIST)))
|
||||
|
||||
evo.set(q, evo.EXCLUDE_LIST, { f4, f3 })
|
||||
assert(__is_sorted(evo.get(q, evo.EXCLUDE_LIST)))
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3, f4 = evo.id(4)
|
||||
|
||||
local q = evo.id()
|
||||
evo.set(q, evo.INCLUDE_LIST, { f2, f1 })
|
||||
evo.set(q, evo.EXCLUDE_LIST, { f3 })
|
||||
|
||||
do
|
||||
local e1 = evo.id()
|
||||
assert(evo.insert(e1, f1, 41))
|
||||
|
||||
local e2 = evo.id()
|
||||
assert(evo.insert(e2, f1, 41))
|
||||
assert(evo.insert(e2, f2, 42))
|
||||
|
||||
local e3 = evo.id()
|
||||
assert(evo.insert(e3, f1, 43))
|
||||
assert(evo.insert(e3, f2, 44))
|
||||
assert(evo.insert(e3, f3, 45))
|
||||
|
||||
local e4 = evo.id()
|
||||
assert(evo.insert(e4, f1, 45))
|
||||
assert(evo.insert(e4, f2, 46))
|
||||
assert(evo.insert(e4, f3, 47))
|
||||
assert(evo.insert(e4, f4, 48))
|
||||
|
||||
local e5 = evo.id()
|
||||
assert(evo.insert(e5, f1, 49))
|
||||
assert(evo.insert(e5, f2, 50))
|
||||
assert(evo.insert(e5, f4, 51))
|
||||
|
||||
for chunk in evo.execute(q) do
|
||||
print(chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
198
evolved.lua
198
evolved.lua
@@ -2,6 +2,7 @@
|
||||
local evolved = {}
|
||||
|
||||
---@alias evolved.id integer
|
||||
---@alias evolved.query evolved.id
|
||||
---@alias evolved.entity evolved.id
|
||||
---@alias evolved.fragment evolved.id
|
||||
---@alias evolved.component any
|
||||
@@ -16,6 +17,10 @@ local evolved = {}
|
||||
---@field __with_fragment_edges table<evolved.fragment, evolved.chunk>
|
||||
---@field __without_fragment_edges table<evolved.fragment, evolved.chunk>
|
||||
|
||||
---@alias evolved.execution_stack evolved.chunk[]
|
||||
---@alias evolved.execution_state [integer, table<evolved.entity, boolean>, evolved.execution_stack]
|
||||
---@alias evolved.execution_iterator fun(state: evolved.execution_state?): evolved.chunk?
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
@@ -35,6 +40,9 @@ local __major_chunks = {} ---@type table<evolved.fragment, evolved.chunk[]>
|
||||
local __entity_chunks = {} ---@type table<integer, evolved.chunk>
|
||||
local __entity_places = {} ---@type table<integer, integer>
|
||||
|
||||
local __execution_stacks = {} ---@type evolved.execution_stack[]
|
||||
local __execution_states = {} ---@type evolved.execution_state[]
|
||||
|
||||
local __structural_changes = 0 ---@type integer
|
||||
|
||||
---
|
||||
@@ -142,6 +150,9 @@ evolved.ON_ASSIGN = __acquire_id()
|
||||
evolved.ON_INSERT = __acquire_id()
|
||||
evolved.ON_REMOVE = __acquire_id()
|
||||
|
||||
evolved.INCLUDE_LIST = __acquire_id()
|
||||
evolved.EXCLUDE_LIST = __acquire_id()
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
@@ -1152,4 +1163,191 @@ end
|
||||
---
|
||||
---
|
||||
|
||||
local __INCLUDE_SET = __acquire_id()
|
||||
local __EXCLUDE_SET = __acquire_id()
|
||||
|
||||
---@param in_list? evolved.fragment[]
|
||||
assert(evolved.insert(evolved.INCLUDE_LIST, evolved.CONSTRUCT, function(_, in_list)
|
||||
if not in_list then
|
||||
return {}
|
||||
end
|
||||
|
||||
local out_list = {}
|
||||
|
||||
for i = 1, #in_list do
|
||||
out_list[i] = in_list[i]
|
||||
end
|
||||
|
||||
table.sort(out_list)
|
||||
return out_list
|
||||
end))
|
||||
|
||||
---@param query evolved.query
|
||||
---@param include_list evolved.entity[]
|
||||
assert(evolved.insert(evolved.INCLUDE_LIST, evolved.ON_SET, function(query, _, include_list)
|
||||
---@type table<evolved.entity, boolean>
|
||||
local include_set = {}
|
||||
|
||||
for i = 1, #include_list do
|
||||
include_set[include_list[i]] = true
|
||||
end
|
||||
|
||||
evolved.set(query, __INCLUDE_SET, include_set)
|
||||
evolved.insert(query, evolved.EXCLUDE_LIST)
|
||||
end))
|
||||
|
||||
---@param in_list? evolved.fragment[]
|
||||
assert(evolved.insert(evolved.EXCLUDE_LIST, evolved.CONSTRUCT, function(_, in_list)
|
||||
if not in_list then
|
||||
return {}
|
||||
end
|
||||
|
||||
local out_list = {}
|
||||
|
||||
for i = 1, #in_list do
|
||||
out_list[i] = in_list[i]
|
||||
end
|
||||
|
||||
table.sort(out_list)
|
||||
return out_list
|
||||
end))
|
||||
|
||||
---@param query evolved.query
|
||||
---@param exclude_list evolved.entity[]
|
||||
assert(evolved.insert(evolved.EXCLUDE_LIST, evolved.ON_SET, function(query, _, exclude_list)
|
||||
---@type table<evolved.entity, boolean>
|
||||
local exclude_set = {}
|
||||
|
||||
for i = 1, #exclude_list do
|
||||
exclude_set[exclude_list[i]] = true
|
||||
end
|
||||
|
||||
evolved.set(query, __EXCLUDE_SET, exclude_set)
|
||||
evolved.insert(query, evolved.INCLUDE_LIST)
|
||||
end))
|
||||
|
||||
---@return evolved.execution_stack
|
||||
---@nodiscard
|
||||
local function __acquire_execution_stack()
|
||||
local execution_stacks = __execution_stacks
|
||||
|
||||
if #execution_stacks == 0 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local stack = execution_stacks[#execution_stacks]
|
||||
execution_stacks[#execution_stacks] = nil
|
||||
|
||||
return stack
|
||||
end
|
||||
|
||||
---@param stack evolved.execution_stack
|
||||
local function __release_execution_stack(stack)
|
||||
for i = #stack, 1, -1 do stack[i] = nil end
|
||||
__execution_stacks[#__execution_stacks + 1] = stack
|
||||
end
|
||||
|
||||
---@param exclude_set table<evolved.fragment, boolean>
|
||||
---@return evolved.execution_state
|
||||
---@return evolved.execution_stack
|
||||
---@nodiscard
|
||||
local function __acquire_execution_state(exclude_set)
|
||||
local execution_states = __execution_states
|
||||
|
||||
if #execution_states == 0 then
|
||||
local stack = __acquire_execution_stack()
|
||||
return { __structural_changes, exclude_set, stack }, stack
|
||||
end
|
||||
|
||||
local state = execution_states[#execution_states]
|
||||
execution_states[#execution_states] = nil
|
||||
|
||||
local stack = __acquire_execution_stack()
|
||||
state[1], state[2], state[3] = __structural_changes, exclude_set, stack
|
||||
return state, stack
|
||||
end
|
||||
|
||||
---@param state evolved.execution_state
|
||||
local function __release_execution_state(state)
|
||||
__release_execution_stack(state[3]); state[3] = nil
|
||||
__execution_states[#__execution_states + 1] = state
|
||||
end
|
||||
|
||||
---@type evolved.execution_iterator
|
||||
local function __execution_iterator(execution_state)
|
||||
if not execution_state then return end
|
||||
|
||||
local structural_changes, exclude_set, execution_stack =
|
||||
execution_state[1], execution_state[2], execution_state[3]
|
||||
|
||||
if structural_changes ~= __structural_changes then
|
||||
error('structural changes are prohibited during execution', 2)
|
||||
end
|
||||
|
||||
while #execution_stack > 0 do
|
||||
local matched_chunk = execution_stack[#execution_stack]
|
||||
execution_stack[#execution_stack] = nil
|
||||
|
||||
for _, matched_chunk_child in ipairs(matched_chunk.__children) do
|
||||
if not exclude_set[matched_chunk_child.__fragment] then
|
||||
execution_stack[#execution_stack + 1] = matched_chunk_child
|
||||
end
|
||||
end
|
||||
|
||||
if #matched_chunk.__entities > 0 then
|
||||
return matched_chunk
|
||||
end
|
||||
end
|
||||
|
||||
__release_execution_state(execution_state)
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
---@param query evolved.query
|
||||
---@return evolved.execution_iterator
|
||||
---@return evolved.execution_state?
|
||||
---@nodiscard
|
||||
function evolved.execute(query)
|
||||
local include_list =
|
||||
evolved.get(query, evolved.INCLUDE_LIST)
|
||||
|
||||
if not include_list or #include_list == 0 then
|
||||
return __execution_iterator, nil
|
||||
end
|
||||
|
||||
local exclude_set, exclude_list =
|
||||
evolved.get(query, __EXCLUDE_SET, evolved.EXCLUDE_LIST)
|
||||
|
||||
local major_fragment = include_list[#include_list]
|
||||
local major_fragment_chunks = __major_chunks[major_fragment]
|
||||
|
||||
if not major_fragment_chunks then
|
||||
return __execution_iterator, nil
|
||||
end
|
||||
|
||||
local execution_state, execution_stack =
|
||||
__acquire_execution_state(exclude_set)
|
||||
|
||||
for _, major_fragment_chunk in ipairs(major_fragment_chunks) do
|
||||
if __chunk_has_all_fragment_list(major_fragment_chunk, include_list) then
|
||||
if not __chunk_has_any_fragment_list(major_fragment_chunk, exclude_list) then
|
||||
execution_stack[#execution_stack + 1] = major_fragment_chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return __execution_iterator, execution_state
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
return evolved
|
||||
|
||||
Reference in New Issue
Block a user