first queries wip

This commit is contained in:
BlackMATov
2024-12-26 00:48:48 +07:00
parent 27484ceeca
commit 755c3ddfff
3 changed files with 284 additions and 0 deletions

View File

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

View File

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

View File

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