Specialize iterator

This commit is contained in:
Ukendio 2024-07-31 18:48:34 +02:00
parent c486e85d43
commit 7476952f89
2 changed files with 212 additions and 121 deletions

View file

@ -739,7 +739,6 @@ do
local lastArchetype: number local lastArchetype: number
local archetype: Archetype local archetype: Archetype
local queryOutput: { any } local queryOutput: { any }
local queryLength: number
local entities: { number } local entities: { number }
local i: number local i: number
@ -747,7 +746,7 @@ do
local ids: { number } local ids: { number }
local columns local columns
local A, B, C, D, E, F, G, H local A, B, C, D, E, F, G, H, I
local a, b, c, d, e, f, g, h local a, b, c, d, e, f, g, h
local init local init
@ -820,7 +819,11 @@ do
end end
end end
local function world_query_iter_next(): any local world_query_iter_next
local function world_query_iter_create()
if not B then
function world_query_iter_next(): any
local entityId = entities[i] local entityId = entities[i]
while entityId == nil do while entityId == nil do
lastArchetype += 1 lastArchetype += 1
@ -837,21 +840,119 @@ do
entityId = entities[i] entityId = entities[i]
columns = archetype.columns columns = archetype.columns
local records = archetype.records local records = archetype.records
if not B then
a = columns[records[A]] a = columns[records[A]]
end
local row = i
i-=1
return entityId, a[row]
end
elseif not C then elseif not C then
function world_query_iter_next(): any
local entityId = entities[i]
while entityId == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entityId = entities[i]
columns = archetype.columns
local records = archetype.records
a = columns[records[A]] a = columns[records[A]]
b = columns[records[B]] b = columns[records[B]]
end
local row = i
i-=1
return entityId, a[row], b[row]
end
elseif not D then elseif not D then
function world_query_iter_next(): any
local entityId = entities[i]
while entityId == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entityId = entities[i]
columns = archetype.columns
local records = archetype.records
a = columns[records[A]] a = columns[records[A]]
b = columns[records[B]] b = columns[records[B]]
c = columns[records[C]] c = columns[records[C]]
end
local row = i
i-=1
return entityId, a[row], b[row], c[row]
end
elseif not E then elseif not E then
function world_query_iter_next(): any
local entityId = entities[i]
while entityId == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entityId = entities[i]
columns = archetype.columns
local records = archetype.records
a = columns[records[A]] a = columns[records[A]]
b = columns[records[B]] b = columns[records[B]]
c = columns[records[C]] c = columns[records[C]]
d = columns[records[D]] d = columns[records[D]]
elseif not F then end
local row = i
i-=1
return entityId, a[row], b[row], c[row], d[row]
end
else
function world_query_iter_next(): any
local entityId = entities[i]
while entityId == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entityId = entities[i]
columns = archetype.columns
local records = archetype.records
if not F then
a = columns[records[A]] a = columns[records[A]]
b = columns[records[B]] b = columns[records[B]]
c = columns[records[C]] c = columns[records[C]]
@ -886,48 +987,14 @@ do
local row = i local row = i
i-=1 i-=1
if queryLength == 1 then if not F then
return entityId, a[row] return entityId, a[row], b[row], c[row], d[row], e[row]
elseif queryLength == 2 then elseif not G then
return entityId, a[row], b[row] return entityId, a[row], b[row], c[row], d[row], e[row], f[row]
elseif queryLength == 3 then elseif not H then
return entityId, a[row], b[row], c[row] return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row]
elseif queryLength == 4 then elseif not I then
return entityId, a[row], b[row], c[row], d[row] return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row]
elseif queryLength == 5 then
return entityId,
a[row],
b[row],
c[row],
d[row],
e[row]
elseif queryLength == 6 then
return entityId,
a[row],
b[row],
c[row],
d[row],
e[row],
f[row]
elseif queryLength == 7 then
return entityId,
a[row],
b[row],
c[row],
d[row],
e[row],
f[row],
g[row]
elseif queryLength == 8 then
return entityId,
a[row],
b[row],
c[row],
d[row],
e[row],
f[row],
g[row],
h[row]
end end
local field = archetype.records local field = archetype.records
@ -935,7 +1002,9 @@ do
queryOutput[j] = columns[field[id]][row] queryOutput[j] = columns[field[id]][row]
end end
return entityId, unpack(queryOutput, 1, queryLength) return entityId, unpack(queryOutput)
end
end
end end
local function world_query_without(self, ...) local function world_query_without(self, ...)
@ -977,23 +1046,23 @@ do
local columns = archetype.columns local columns = archetype.columns
local tr = archetype.records local tr = archetype.records
for row in archetype.entities do for row in archetype.entities do
if queryLength == 1 then if not B then
local va = columns[tr[A]] local va = columns[tr[A]]
local pa = fn(va[row]) local pa = fn(va[row])
va[row] = pa va[row] = pa
elseif queryLength == 2 then elseif not C then
local va = columns[tr[A]] local va = columns[tr[A]]
local vb = columns[tr[B]] local vb = columns[tr[B]]
va[row], vb[row] = fn(va[row], vb[row]) va[row], vb[row] = fn(va[row], vb[row])
elseif queryLength == 3 then elseif not D then
local va = columns[tr[A]] local va = columns[tr[A]]
local vb = columns[tr[B]] local vb = columns[tr[B]]
local vc = columns[tr[C]] local vc = columns[tr[C]]
va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row]) va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row])
elseif queryLength == 4 then elseif not E then
local va = columns[tr[A]] local va = columns[tr[A]]
local vb = columns[tr[B]] local vb = columns[tr[B]]
local vc = columns[tr[C]] local vc = columns[tr[C]]
@ -1088,7 +1157,8 @@ do
local length = 0 local length = 0
local components = { ... } :: any local components = { ... } :: any
A, B, C, D, E, F, G, H = ... A, B, C, D, E, F, G, H, I = ...
local archetypes = world.archetypes local archetypes = world.archetypes
local firstArchetypeMap: ArchetypeMap local firstArchetypeMap: ArchetypeMap
@ -1131,6 +1201,8 @@ do
init = false init = false
ids = components ids = components
world_query_iter_create()
return it return it
end end
end end

View file

@ -516,6 +516,25 @@ TEST("world:query()", function()
CHECK(count == 2) CHECK(count == 2)
end end
do CASE "despawning while iterating"
local world = jecs.World.new()
local A = world:component()
local B = world:component()
local e1 = world:entity()
local e2 = world:entity()
world:add(e1, A)
world:add(e2, A)
world:add(e2, B)
local count = 0
for id in world:query(A) do
world:clear(id)
count += 1
end
CHECK(count == 2)
end
do CASE "iterator invalidation" do CASE "iterator invalidation"
do CASE "adding" do CASE "adding"
SKIP() SKIP()