mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2026-03-22 04:44:06 +07:00
Merge branch 'feature/variants' into dev
This commit is contained in:
26
README.md
26
README.md
@@ -588,16 +588,22 @@ evolved.set(entity, fragment, 42)
|
||||
|
||||
One of the most important features of any ECS library is the ability to process entities by filters or queries. `evolved.lua` provides a simple and efficient way to do this.
|
||||
|
||||
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes). These fragments expect a list of fragments as their components.
|
||||
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants). These fragments expect a list of fragments as their components.
|
||||
|
||||
- [`evolved.INCLUDES`](#evolvedincludes) is used to specify fragments that must be present in the entity;
|
||||
- [`evolved.EXCLUDES`](#evolvedexcludes) is used to specify fragments that must not be present in the entity;
|
||||
- [`evolved.VARIANTS`](#evolvedvariants) is used to specify fragments where at least one must be present in the entity.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local health, poisoned, resistant = evolved.id(3)
|
||||
local alive, undead = evolved.id(2)
|
||||
|
||||
local query = evolved.id()
|
||||
evolved.set(query, evolved.INCLUDES, { health, poisoned })
|
||||
evolved.set(query, evolved.EXCLUDES, { resistant })
|
||||
evolved.set(query, evolved.VARIANTS, { alive, undead })
|
||||
```
|
||||
|
||||
The builder interface can be used to create queries too. It is more convenient to use, because the builder has special methods for including and excluding fragments. Here is a simple example of this:
|
||||
@@ -606,10 +612,11 @@ The builder interface can be used to create queries too. It is more convenient t
|
||||
local query = evolved.builder()
|
||||
:include(health, poisoned)
|
||||
:exclude(resistant)
|
||||
:variant(alive, undead)
|
||||
:build()
|
||||
```
|
||||
|
||||
We don't have to set both [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
|
||||
We don't have to set all of [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
|
||||
|
||||
After the query is created, we are ready to process our filtered by this query entities. You can do this by using the [`evolved.execute`](#evolvedexecute) function. This function takes a query as an argument and returns an iterator that can be used to iterate over all matching with the query chunks.
|
||||
|
||||
@@ -788,7 +795,7 @@ The [`evolved.process`](#evolvedprocess) function is used to process systems. It
|
||||
function evolved.process(...) end
|
||||
```
|
||||
|
||||
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES` and `evolved.EXCLUDES` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
|
||||
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES`, `evolved.EXCLUDES`, and `evolved.VARIANTS` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
@@ -1198,6 +1205,7 @@ DISABLED :: fragment
|
||||
|
||||
INCLUDES :: fragment
|
||||
EXCLUDES :: fragment
|
||||
VARIANTS :: fragment
|
||||
REQUIRES :: fragment
|
||||
|
||||
ON_SET :: fragment
|
||||
@@ -1332,6 +1340,7 @@ builder_mt:disabled :: builder
|
||||
|
||||
builder_mt:include :: fragment... -> builder
|
||||
builder_mt:exclude :: fragment... -> builder
|
||||
builder_mt:variant :: fragment... -> builder
|
||||
builder_mt:require :: fragment... -> builder
|
||||
|
||||
builder_mt:on_set :: {entity, fragment, component, component} -> builder
|
||||
@@ -1354,6 +1363,7 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### vX.Y.Z
|
||||
|
||||
- Added the new [`evolved.VARIANTS`](#evolvedvariants) query fragment that allows specifying any of multiple fragments in queries
|
||||
- Added the new [`evolved.process_with`](#evolvedprocess_with) function that allows passing payloads to processing systems
|
||||
|
||||
### v1.6.0
|
||||
@@ -1428,6 +1438,8 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### `evolved.EXCLUDES`
|
||||
|
||||
### `evolved.VARIANTS`
|
||||
|
||||
### `evolved.REQUIRES`
|
||||
|
||||
### `evolved.ON_SET`
|
||||
@@ -2065,6 +2077,14 @@ function evolved.builder_mt:include(...) end
|
||||
function evolved.builder_mt:exclude(...) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:variant`
|
||||
|
||||
```lua
|
||||
---@param ... evolved.fragment fragments
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:variant(...) end
|
||||
```
|
||||
|
||||
### `evolved.builder_mt:require`
|
||||
|
||||
```lua
|
||||
|
||||
@@ -56,6 +56,20 @@ local function generate_query(query)
|
||||
end
|
||||
end
|
||||
|
||||
local variant_set = {}
|
||||
local variant_list = {}
|
||||
local variant_count = 0
|
||||
|
||||
for _ = 1, math.random(0, #all_fragment_list) do
|
||||
local variant = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if not variant_set[variant] then
|
||||
variant_count = variant_count + 1
|
||||
variant_set[variant] = variant_count
|
||||
variant_list[variant_count] = variant
|
||||
end
|
||||
end
|
||||
|
||||
if include_count > 0 then
|
||||
evo.set(query, evo.INCLUDES, include_list)
|
||||
end
|
||||
@@ -63,6 +77,10 @@ local function generate_query(query)
|
||||
if exclude_count > 0 then
|
||||
evo.set(query, evo.EXCLUDES, exclude_list)
|
||||
end
|
||||
|
||||
if variant_count > 0 then
|
||||
evo.set(query, evo.VARIANTS, variant_list)
|
||||
end
|
||||
end
|
||||
|
||||
---@param query_count integer
|
||||
@@ -173,12 +191,22 @@ local function execute_query(query)
|
||||
|
||||
local query_include_list = evo.get(query, evo.INCLUDES) or {}
|
||||
local query_exclude_list = evo.get(query, evo.EXCLUDES) or {}
|
||||
local query_variant_list = evo.get(query, evo.VARIANTS) or {}
|
||||
|
||||
local query_include_count = #query_include_list
|
||||
local query_exclude_count = #query_exclude_list
|
||||
local query_variant_count = #query_variant_list
|
||||
|
||||
local query_include_set = {}
|
||||
for _, include in ipairs(query_include_list) do
|
||||
query_include_set[include] = true
|
||||
end
|
||||
|
||||
local query_variant_set = {}
|
||||
for _, variant in ipairs(query_variant_list) do
|
||||
query_variant_set[variant] = true
|
||||
end
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(query) do
|
||||
assert(not query_chunk_set[chunk])
|
||||
query_chunk_set[chunk] = true
|
||||
@@ -189,19 +217,29 @@ local function execute_query(query)
|
||||
query_entity_set[entity] = true
|
||||
end
|
||||
|
||||
assert(chunk:has_all(__table_unpack(query_include_list)))
|
||||
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
|
||||
if query_include_count > 0 then
|
||||
assert(chunk:has_all(__table_unpack(query_include_list)))
|
||||
end
|
||||
|
||||
if query_exclude_count > 0 then
|
||||
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
|
||||
end
|
||||
|
||||
if query_variant_count > 0 then
|
||||
assert(chunk:has_any(__table_unpack(query_variant_list)))
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, all_entity_count do
|
||||
local entity = all_entity_list[i]
|
||||
|
||||
local is_entity_matched =
|
||||
evo.has_all(entity, __table_unpack(query_include_list))
|
||||
and not evo.has_any(entity, __table_unpack(query_exclude_list))
|
||||
(query_variant_count == 0 or evo.has_any(entity, __table_unpack(query_variant_list))) and
|
||||
(query_include_count == 0 or evo.has_all(entity, __table_unpack(query_include_list))) and
|
||||
(query_exclude_count == 0 or not evo.has_any(entity, __table_unpack(query_exclude_list)))
|
||||
|
||||
for fragment in evo.each(entity) do
|
||||
if evo.has(fragment, evo.EXPLICIT) and not query_include_set[fragment] then
|
||||
if evo.has(fragment, evo.EXPLICIT) and not query_variant_set[fragment] and not query_include_set[fragment] then
|
||||
is_entity_matched = false
|
||||
end
|
||||
end
|
||||
@@ -236,10 +274,13 @@ for _ = 1, math.random(1, 5) do
|
||||
if math.random(1, 2) == 1 then
|
||||
generate_query(query)
|
||||
else
|
||||
if math.random(1, 2) == 1 then
|
||||
local r = math.random(1, 3)
|
||||
if r == 1 then
|
||||
evo.remove(query, evo.INCLUDES)
|
||||
else
|
||||
elseif r == 2 then
|
||||
evo.remove(query, evo.EXCLUDES)
|
||||
else
|
||||
evo.remove(query, evo.VARIANTS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
|
||||
include: function(self: Builder, ...: Fragment): Builder
|
||||
exclude: function(self: Builder, ...: Fragment): Builder
|
||||
variant: function(self: Builder, ...: Fragment): Builder
|
||||
require: function(self: Builder, ...: Fragment): Builder
|
||||
|
||||
on_set: function<Component>(self: Builder, on_set: function(Entity, Fragment, ? Component, ? Component)): Builder
|
||||
@@ -102,6 +103,7 @@
|
||||
|
||||
INCLUDES: Fragment
|
||||
EXCLUDES: Fragment
|
||||
VARIANTS: Fragment
|
||||
REQUIRES: Fragment
|
||||
|
||||
ON_SET: Fragment
|
||||
|
||||
297
evolved.lua
297
evolved.lua
@@ -81,7 +81,9 @@ local evolved = {
|
||||
---@field package [1] integer structural_changes
|
||||
---@field package [2] evolved.chunk[] chunk_stack
|
||||
---@field package [3] integer chunk_stack_size
|
||||
---@field package [4] table<evolved.fragment, integer>? exclude_set
|
||||
---@field package [4] table<evolved.fragment, integer>? include_set
|
||||
---@field package [5] table<evolved.fragment, integer>? exclude_set
|
||||
---@field package [6] table<evolved.fragment, integer>? variant_set
|
||||
|
||||
---@alias evolved.each_iterator fun(
|
||||
--- state: evolved.each_state?):
|
||||
@@ -135,6 +137,7 @@ local __entity_places = {} ---@type table<integer, integer>
|
||||
|
||||
local __sorted_includes = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
|
||||
local __sorted_excludes = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
|
||||
local __sorted_variants = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
|
||||
local __sorted_requires = {} ---@type table<evolved.fragment, evolved.assoc_list<evolved.fragment>>
|
||||
|
||||
local __subsystem_groups = {} ---@type table<evolved.system, evolved.system>
|
||||
@@ -973,6 +976,7 @@ local __DISABLED = __acquire_id()
|
||||
|
||||
local __INCLUDES = __acquire_id()
|
||||
local __EXCLUDES = __acquire_id()
|
||||
local __VARIANTS = __acquire_id()
|
||||
local __REQUIRES = __acquire_id()
|
||||
|
||||
local __ON_SET = __acquire_id()
|
||||
@@ -1106,6 +1110,9 @@ local __trace_minor_chunks
|
||||
local __cache_query_chunks
|
||||
local __reset_query_chunks
|
||||
|
||||
local __query_major_matches
|
||||
local __query_minor_matches
|
||||
|
||||
local __update_major_chunks
|
||||
local __update_major_chunks_trace
|
||||
|
||||
@@ -1115,7 +1122,6 @@ local __chunk_without_fragment
|
||||
local __chunk_without_fragments
|
||||
local __chunk_without_unique_fragments
|
||||
|
||||
local __chunk_matches
|
||||
local __chunk_requires
|
||||
local __chunk_fragments
|
||||
local __chunk_components
|
||||
@@ -1397,7 +1403,7 @@ function __update_chunk_queries(chunk)
|
||||
local major_query_chunks = __query_chunks[major_query]
|
||||
|
||||
if major_query_chunks then
|
||||
if __chunk_matches(chunk, major_query) then
|
||||
if __query_major_matches(chunk, major_query) then
|
||||
__assoc_list_insert(major_query_chunks, chunk)
|
||||
else
|
||||
__assoc_list_remove(major_query_chunks, chunk)
|
||||
@@ -1574,16 +1580,15 @@ function __cache_query_chunks(query)
|
||||
local query_include_list = query_includes and query_includes.__item_list
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
if query_include_count == 0 then
|
||||
__error_fmt('the query (%s) has no include fragments and cannot be cached',
|
||||
__id_name(query))
|
||||
end
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_list = query_variants and query_variants.__item_list
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
---@type evolved.assoc_list<evolved.chunk>
|
||||
local query_chunks = __assoc_list_new(4)
|
||||
__query_chunks[query] = query_chunks
|
||||
|
||||
do
|
||||
if query_include_count > 0 then
|
||||
local query_major = query_include_list[query_include_count]
|
||||
|
||||
local major_chunks = __major_chunks[query_major]
|
||||
@@ -1593,12 +1598,30 @@ function __cache_query_chunks(query)
|
||||
for major_chunk_index = 1, major_chunk_count do
|
||||
local major_chunk = major_chunk_list[major_chunk_index]
|
||||
|
||||
if __chunk_matches(major_chunk, query) then
|
||||
if __query_major_matches(major_chunk, query) then
|
||||
__assoc_list_insert(query_chunks, major_chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for query_variant_index = 1, query_variant_count do
|
||||
local query_variant = query_variant_list[query_variant_index]
|
||||
|
||||
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
|
||||
local major_chunks = __major_chunks[query_variant]
|
||||
local major_chunk_list = major_chunks and major_chunks.__item_list
|
||||
local major_chunk_count = major_chunks and major_chunks.__item_count or 0
|
||||
|
||||
for major_chunk_index = 1, major_chunk_count do
|
||||
local major_chunk = major_chunk_list[major_chunk_index]
|
||||
|
||||
if __query_major_matches(major_chunk, query) then
|
||||
__assoc_list_insert(query_chunks, major_chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return query_chunks
|
||||
end
|
||||
|
||||
@@ -1607,6 +1630,87 @@ function __reset_query_chunks(query)
|
||||
__query_chunks[query] = nil
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@param query evolved.query
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function __query_major_matches(chunk, query)
|
||||
local query_includes = __sorted_includes[query]
|
||||
local query_include_set = query_includes and query_includes.__item_set
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_set = query_variants and query_variants.__item_set
|
||||
local query_variant_list = query_variants and query_variants.__item_list
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
local query_include_index = query_include_count > 0 and query_include_set[chunk.__fragment] or nil
|
||||
local query_variant_index = query_variant_count > 0 and query_variant_set[chunk.__fragment] or nil
|
||||
|
||||
return (
|
||||
(query_include_index ~= nil and query_include_index == query_include_count) or
|
||||
(query_variant_index ~= nil and not __chunk_has_any_fragment_list(chunk, query_variant_list, query_variant_index - 1))
|
||||
) and __query_minor_matches(chunk, query)
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@param query evolved.query
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function __query_minor_matches(chunk, query)
|
||||
local query_includes = __sorted_includes[query]
|
||||
local query_include_set = query_includes and query_includes.__item_set
|
||||
local query_include_list = query_includes and query_includes.__item_list
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
if query_include_count > 0 then
|
||||
if not __chunk_has_all_fragment_list(chunk, query_include_list, query_include_count) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local query_excludes = __sorted_excludes[query]
|
||||
local query_exclude_list = query_excludes and query_excludes.__item_list
|
||||
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
|
||||
|
||||
if query_exclude_count > 0 then
|
||||
if __chunk_has_any_fragment_list(chunk, query_exclude_list, query_exclude_count) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_set = query_variants and query_variants.__item_set
|
||||
local query_variant_list = query_variants and query_variants.__item_list
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
if query_variant_count > 0 then
|
||||
if not __chunk_has_any_fragment_list(chunk, query_variant_list, query_variant_count) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.__has_explicit_fragments then
|
||||
local chunk_fragment_list = chunk.__fragment_list
|
||||
local chunk_fragment_count = chunk.__fragment_count
|
||||
|
||||
for chunk_fragment_index = 1, chunk_fragment_count do
|
||||
local chunk_fragment = chunk_fragment_list[chunk_fragment_index]
|
||||
|
||||
local is_chunk_fragment_matched =
|
||||
(not __evolved_has(chunk_fragment, __EXPLICIT)) or
|
||||
(query_variant_count > 0 and query_variant_set[chunk_fragment]) or
|
||||
(query_include_count > 0 and query_include_set[chunk_fragment])
|
||||
|
||||
if not is_chunk_fragment_matched then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@param major evolved.fragment
|
||||
function __update_major_chunks(major)
|
||||
if __defer_depth > 0 then
|
||||
@@ -1787,50 +1891,6 @@ function __chunk_without_unique_fragments(chunk)
|
||||
return sib_chunk
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@param query evolved.query
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function __chunk_matches(chunk, query)
|
||||
local query_includes = __sorted_includes[query]
|
||||
local query_include_set = query_includes and query_includes.__item_set
|
||||
local query_include_list = query_includes and query_includes.__item_list
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
if query_include_count > 0 then
|
||||
if not __chunk_has_all_fragment_list(chunk, query_include_list, query_include_count) then
|
||||
return false
|
||||
end
|
||||
elseif chunk.__has_explicit_fragments then
|
||||
return false
|
||||
end
|
||||
|
||||
local query_excludes = __sorted_excludes[query]
|
||||
local query_exclude_list = query_excludes and query_excludes.__item_list
|
||||
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
|
||||
|
||||
if query_exclude_count > 0 then
|
||||
if __chunk_has_any_fragment_list(chunk, query_exclude_list, query_exclude_count) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if chunk.__has_explicit_fragments then
|
||||
local chunk_fragment_list = chunk.__fragment_list
|
||||
local chunk_fragment_count = chunk.__fragment_count
|
||||
|
||||
for chunk_fragment_index = 1, chunk_fragment_count do
|
||||
local chunk_fragment = chunk_fragment_list[chunk_fragment_index]
|
||||
|
||||
if not query_include_set[chunk_fragment] and __evolved_has(chunk_fragment, __EXPLICIT) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@return evolved.chunk
|
||||
---@nodiscard
|
||||
@@ -3862,7 +3922,9 @@ function __iterator_fns.__execute_iterator(execute_state)
|
||||
local structural_changes = execute_state[1]
|
||||
local chunk_stack = execute_state[2]
|
||||
local chunk_stack_size = execute_state[3]
|
||||
local exclude_set = execute_state[4]
|
||||
local include_set = execute_state[4]
|
||||
local exclude_set = execute_state[5]
|
||||
local variant_set = execute_state[6]
|
||||
|
||||
if structural_changes ~= __structural_changes then
|
||||
__error_fmt('structural changes are prohibited during iteration')
|
||||
@@ -3882,7 +3944,9 @@ function __iterator_fns.__execute_iterator(execute_state)
|
||||
local chunk_child_fragment = chunk_child.__fragment
|
||||
|
||||
local is_chunk_child_matched =
|
||||
(not chunk_child.__has_explicit_major) and
|
||||
(not chunk_child.__has_explicit_major or (
|
||||
(include_set and include_set[chunk_child_fragment]) or
|
||||
(variant_set and variant_set[chunk_child_fragment]))) and
|
||||
(not exclude_set or not exclude_set[chunk_child_fragment])
|
||||
|
||||
if is_chunk_child_matched then
|
||||
@@ -5232,13 +5296,18 @@ function __evolved_execute(query)
|
||||
local chunk_stack_size = 0
|
||||
|
||||
local query_includes = __sorted_includes[query]
|
||||
local query_include_set = query_includes and query_includes.__item_set
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
local query_excludes = __sorted_excludes[query]
|
||||
local query_exclude_set = query_excludes and query_excludes.__item_set
|
||||
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
|
||||
|
||||
if query_include_count > 0 then
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_set = query_variants and query_variants.__item_set
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
if query_include_count > 0 or query_variant_count > 0 then
|
||||
local query_chunks = __query_chunks[query] or __cache_query_chunks(query)
|
||||
local query_chunk_list = query_chunks and query_chunks.__item_list
|
||||
local query_chunk_count = query_chunks and query_chunks.__item_count or 0
|
||||
@@ -5279,7 +5348,9 @@ function __evolved_execute(query)
|
||||
execute_state[1] = __structural_changes
|
||||
execute_state[2] = chunk_stack
|
||||
execute_state[3] = chunk_stack_size
|
||||
execute_state[4] = query_exclude_set
|
||||
execute_state[4] = query_include_set
|
||||
execute_state[5] = query_exclude_set
|
||||
execute_state[6] = query_variant_set
|
||||
|
||||
return __iterator_fns.__execute_iterator, execute_state
|
||||
end
|
||||
@@ -6040,6 +6111,31 @@ function __builder_mt:exclude(...)
|
||||
return self:set(__EXCLUDES, exclude_list)
|
||||
end
|
||||
|
||||
---@param ... evolved.fragment fragments
|
||||
---@return evolved.builder builder
|
||||
function __builder_mt:variant(...)
|
||||
local argument_count = __lua_select('#', ...)
|
||||
|
||||
if argument_count == 0 then
|
||||
return self
|
||||
end
|
||||
|
||||
local variant_list = self:get(__VARIANTS)
|
||||
local variant_count = variant_list and #variant_list or 0
|
||||
|
||||
if variant_count == 0 then
|
||||
variant_list = __list_new(argument_count)
|
||||
end
|
||||
|
||||
for argument_index = 1, argument_count do
|
||||
---@type evolved.fragment
|
||||
local fragment = __lua_select(argument_index, ...)
|
||||
variant_list[variant_count + argument_index] = fragment
|
||||
end
|
||||
|
||||
return self:set(__VARIANTS, variant_list)
|
||||
end
|
||||
|
||||
---@param ... evolved.fragment fragments
|
||||
---@return evolved.builder builder
|
||||
function __builder_mt:require(...)
|
||||
@@ -6188,6 +6284,7 @@ __evolved_set(__DISABLED, __NAME, 'DISABLED')
|
||||
|
||||
__evolved_set(__INCLUDES, __NAME, 'INCLUDES')
|
||||
__evolved_set(__EXCLUDES, __NAME, 'EXCLUDES')
|
||||
__evolved_set(__VARIANTS, __NAME, 'VARIANTS')
|
||||
__evolved_set(__REQUIRES, __NAME, 'REQUIRES')
|
||||
|
||||
__evolved_set(__ON_SET, __NAME, 'ON_SET')
|
||||
@@ -6228,6 +6325,7 @@ __evolved_set(__DISABLED, __INTERNAL)
|
||||
|
||||
__evolved_set(__INCLUDES, __INTERNAL)
|
||||
__evolved_set(__EXCLUDES, __INTERNAL)
|
||||
__evolved_set(__VARIANTS, __INTERNAL)
|
||||
__evolved_set(__REQUIRES, __INTERNAL)
|
||||
|
||||
__evolved_set(__ON_SET, __INTERNAL)
|
||||
@@ -6277,6 +6375,9 @@ __evolved_set(__INCLUDES, __DUPLICATE, __list_dup)
|
||||
__evolved_set(__EXCLUDES, __DEFAULT, __list_new())
|
||||
__evolved_set(__EXCLUDES, __DUPLICATE, __list_dup)
|
||||
|
||||
__evolved_set(__VARIANTS, __DEFAULT, __list_new())
|
||||
__evolved_set(__VARIANTS, __DUPLICATE, __list_dup)
|
||||
|
||||
__evolved_set(__REQUIRES, __DEFAULT, __list_new())
|
||||
__evolved_set(__REQUIRES, __DUPLICATE, __list_dup)
|
||||
|
||||
@@ -6297,17 +6398,38 @@ local function __insert_query(query)
|
||||
local query_include_list = query_includes and query_includes.__item_list
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_list = query_variants and query_variants.__item_list
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
if query_include_count > 0 then
|
||||
local query_major = query_include_list[query_include_count]
|
||||
local major_queries = __major_queries[query_major]
|
||||
|
||||
if not major_queries then
|
||||
---@type evolved.assoc_list<evolved.query>
|
||||
major_queries = __assoc_list_new(4)
|
||||
__major_queries[query_major] = major_queries
|
||||
end
|
||||
|
||||
__assoc_list_insert(major_queries, query)
|
||||
end
|
||||
|
||||
for query_variant_index = 1, query_variant_count do
|
||||
local query_variant = query_variant_list[query_variant_index]
|
||||
|
||||
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
|
||||
local major_queries = __major_queries[query_variant]
|
||||
|
||||
if not major_queries then
|
||||
---@type evolved.assoc_list<evolved.query>
|
||||
major_queries = __assoc_list_new(4)
|
||||
__major_queries[query_variant] = major_queries
|
||||
end
|
||||
|
||||
__assoc_list_insert(major_queries, query)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param query evolved.query
|
||||
@@ -6316,6 +6438,10 @@ local function __remove_query(query)
|
||||
local query_include_list = query_includes and query_includes.__item_list
|
||||
local query_include_count = query_includes and query_includes.__item_count or 0
|
||||
|
||||
local query_variants = __sorted_variants[query]
|
||||
local query_variant_list = query_variants and query_variants.__item_list
|
||||
local query_variant_count = query_variants and query_variants.__item_count or 0
|
||||
|
||||
if query_include_count > 0 then
|
||||
local query_major = query_include_list[query_include_count]
|
||||
local major_queries = __major_queries[query_major]
|
||||
@@ -6325,9 +6451,27 @@ local function __remove_query(query)
|
||||
end
|
||||
end
|
||||
|
||||
for query_variant_index = 1, query_variant_count do
|
||||
local query_variant = query_variant_list[query_variant_index]
|
||||
|
||||
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
|
||||
local major_queries = __major_queries[query_variant]
|
||||
|
||||
if major_queries and __assoc_list_remove(major_queries, query) == 0 then
|
||||
__major_queries[query_variant] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
__reset_query_chunks(query)
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
---@param query evolved.query
|
||||
---@param include_list evolved.fragment[]
|
||||
__evolved_set(__INCLUDES, __ON_SET, function(query, _, include_list)
|
||||
@@ -6404,6 +6548,44 @@ end)
|
||||
---
|
||||
---
|
||||
|
||||
---@param query evolved.query
|
||||
---@param variant_list evolved.fragment[]
|
||||
__evolved_set(__VARIANTS, __ON_SET, function(query, _, variant_list)
|
||||
__remove_query(query)
|
||||
|
||||
local variant_count = #variant_list
|
||||
|
||||
if variant_count > 0 then
|
||||
---@type evolved.assoc_list<evolved.fragment>
|
||||
local sorted_variants = __assoc_list_new(variant_count)
|
||||
|
||||
__assoc_list_move(variant_list, 1, variant_count, sorted_variants)
|
||||
__assoc_list_sort(sorted_variants)
|
||||
|
||||
__sorted_variants[query] = sorted_variants
|
||||
else
|
||||
__sorted_variants[query] = nil
|
||||
end
|
||||
|
||||
__insert_query(query)
|
||||
__update_major_chunks(query)
|
||||
end)
|
||||
|
||||
__evolved_set(__VARIANTS, __ON_REMOVE, function(query)
|
||||
__remove_query(query)
|
||||
|
||||
__sorted_variants[query] = nil
|
||||
|
||||
__insert_query(query)
|
||||
__update_major_chunks(query)
|
||||
end)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
---@param fragment evolved.fragment
|
||||
---@param require_list evolved.fragment[]
|
||||
__evolved_set(__REQUIRES, __ON_SET, function(fragment, _, require_list)
|
||||
@@ -6506,6 +6688,7 @@ evolved.DISABLED = __DISABLED
|
||||
|
||||
evolved.INCLUDES = __INCLUDES
|
||||
evolved.EXCLUDES = __EXCLUDES
|
||||
evolved.VARIANTS = __VARIANTS
|
||||
evolved.REQUIRES = __REQUIRES
|
||||
|
||||
evolved.ON_SET = __ON_SET
|
||||
|
||||
Reference in New Issue
Block a user