Change casing

This commit is contained in:
Ukendio 2024-07-15 20:29:06 +02:00
parent 1b6cdd4791
commit 459e670ce9
5 changed files with 319 additions and 158 deletions

View file

@ -2,6 +2,5 @@
"aliases": { "aliases": {
"jecs": "src", "jecs": "src",
"testkit": "testkit", "testkit": "testkit",
"mirror": "mirror"
} }
} }

161
benches/cached.luau Normal file
View file

@ -0,0 +1,161 @@
local jecs = require("@jecs")
local mirror = require("../mirror/init")
type i53 = number
do
TITLE(testkit.color.white_underline("Jecs query"))
local ecs = jecs.World.new()
do
TITLE("one component in common")
local function view_bench(world: jecs.World, A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53)
BENCH("4 component", function()
for _ in world:query(D, C, B, A) do
end
end)
end
local D1 = ecs:component()
local D2 = ecs:component()
local D3 = ecs:component()
local D4 = ecs:component()
local D5 = ecs:component()
local D6 = ecs:component()
local D7 = ecs:component()
local D8 = ecs:component()
local function flip()
return math.random() >= 0.15
end
local added = 0
local archetypes = {}
for i = 1, 2 ^ 16 - 2 do
local entity = ecs:entity()
local combination = ""
if flip() then
combination ..= "B"
ecs:set(entity, D2, {value = true})
end
if flip() then
combination ..= "C"
ecs:set(entity, D3, {value = true})
end
if flip() then
combination ..= "D"
ecs:set(entity, D4, {value = true})
end
if flip() then
combination ..= "E"
ecs:set(entity, D5, {value = true})
end
if flip() then
combination ..= "F"
ecs:set(entity, D6, {value = true})
end
if flip() then
combination ..= "G"
ecs:set(entity, D7, {value = true})
end
if flip() then
combination ..= "H"
ecs:set(entity, D8, {value = true})
end
if #combination == 7 then
added += 1
ecs:set(entity, D1, {value = true})
end
archetypes[combination] = true
end
local a = 0
for _ in archetypes do
a += 1
end
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
end
end
do
TITLE(testkit.color.white_underline("Mirror query"))
local ecs = mirror.World.new()
do
TITLE("one component in common")
local function view_bench(world: jecs.World, A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53)
BENCH("4 component", function()
for _ in world:query(D, C, B, A) do
end
end)
end
local D1 = ecs:component()
local D2 = ecs:component()
local D3 = ecs:component()
local D4 = ecs:component()
local D5 = ecs:component()
local D6 = ecs:component()
local D7 = ecs:component()
local D8 = ecs:component()
local function flip()
return math.random() >= 0.15
end
local added = 0
local archetypes = {}
for i = 1, 2 ^ 16 - 2 do
local entity = ecs:entity()
local combination = ""
if flip() then
combination ..= "B"
ecs:set(entity, D2, {value = true})
end
if flip() then
combination ..= "C"
ecs:set(entity, D3, {value = true})
end
if flip() then
combination ..= "D"
ecs:set(entity, D4, {value = true})
end
if flip() then
combination ..= "E"
ecs:set(entity, D5, {value = true})
end
if flip() then
combination ..= "F"
ecs:set(entity, D6, {value = true})
end
if flip() then
combination ..= "G"
ecs:set(entity, D7, {value = true})
end
if flip() then
combination ..= "H"
ecs:set(entity, D8, {value = true})
end
if #combination == 7 then
added += 1
ecs:set(entity, D1, {value = true})
end
archetypes[combination] = true
end
local a = 0
for _ in archetypes do
a += 1
end
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
end
end

View file

@ -52,7 +52,7 @@ local E8 = mcs:entity()
local registry2 = ecr.registry() local registry2 = ecr.registry()
local function flip() local function flip()
return math.random() >= 0.15 return math.random() >= 0.15
end end
@ -61,80 +61,80 @@ local N = 2^16-2
local archetypes = {} local archetypes = {}
local hm = 0 local hm = 0
for i = 1, N do for i = 1, N do
local id = registry2.create() local id = registry2.create()
local combination = "" local combination = ""
local n = newWorld:spawn() local n = newWorld:spawn()
local entity = ecs:entity() local entity = ecs:entity()
local m = mcs:entity() local m = mcs:entity()
if flip() then if flip() then
combination ..= "B" combination ..= "B"
registry2:set(id, B2, {value = true}) registry2:set(id, B2, {value = true})
ecs:set(entity, D2, { value = true}) ecs:set(entity, D2, { value = true})
mcs:set(m, E2, { value = 2}) mcs:set(m, E2, { value = 2})
newWorld:insert(n, A2({value = true})) newWorld:insert(n, A2({value = true}))
end end
if flip() then if flip() then
combination ..= "C" combination ..= "C"
registry2:set(id, B3, {value = true}) registry2:set(id, B3, {value = true})
ecs:set(entity, D3, { value = true}) ecs:set(entity, D3, { value = true})
mcs:set(m, E3, { value = 2}) mcs:set(m, E3, { value = 2})
newWorld:insert(n, A3({value = true})) newWorld:insert(n, A3({value = true}))
end end
if flip() then if flip() then
combination ..= "D" combination ..= "D"
registry2:set(id, B4, {value = true}) registry2:set(id, B4, {value = true})
ecs:set(entity, D4, { value = true}) ecs:set(entity, D4, { value = true})
mcs:set(m, E4, { value = 2}) mcs:set(m, E4, { value = 2})
newWorld:insert(n, A4({value = true})) newWorld:insert(n, A4({value = true}))
end end
if flip() then if flip() then
combination ..= "E" combination ..= "E"
registry2:set(id, B5, {value = true}) registry2:set(id, B5, {value = true})
ecs:set(entity, D5, { value = true}) ecs:set(entity, D5, { value = true})
mcs:set(m, E5, { value = 2}) mcs:set(m, E5, { value = 2})
newWorld:insert(n, A5({value = true})) newWorld:insert(n, A5({value = true}))
end end
if flip() then if flip() then
combination ..= "F" combination ..= "F"
registry2:set(id, B6, {value = true}) registry2:set(id, B6, {value = true})
ecs:set(entity, D6, { value = true}) ecs:set(entity, D6, { value = true})
mcs:set(m, E6, { value = 2}) mcs:set(m, E6, { value = 2})
newWorld:insert(n, A6({value = true})) newWorld:insert(n, A6({value = true}))
end end
if flip() then if flip() then
combination ..= "G" combination ..= "G"
registry2:set(id, B7, {value = true}) registry2:set(id, B7, {value = true})
ecs:set(entity, D7, { value = true}) ecs:set(entity, D7, { value = true})
mcs:set(m, E7, { value = 2}) mcs:set(m, E7, { value = 2})
newWorld:insert(n, A7({value = true})) newWorld:insert(n, A7({value = true}))
end end
if flip() then if flip() then
combination ..= "H" combination ..= "H"
registry2:set(id, B8, {value = true}) registry2:set(id, B8, {value = true})
newWorld:insert(n, A8({value = true})) newWorld:insert(n, A8({value = true}))
ecs:set(entity, D8, { value = true}) ecs:set(entity, D8, { value = true})
mcs:set(m, E8, { value = 2}) mcs:set(m, E8, { value = 2})
end end
if #combination == 7 then if #combination == 7 then
combination = "A" .. combination combination = "A" .. combination
common += 1 common += 1
registry2:set(id, B1, {value = true}) registry2:set(id, B1, {value = true})
ecs:set(entity, D1, { value = true}) ecs:set(entity, D1, { value = true})
newWorld:insert(n, A1({value = true})) newWorld:insert(n, A1({value = true}))
mcs:set(m, E1, { value = 2}) mcs:set(m, E1, { value = 2})
end end
if combination:find("BCDF") then if combination:find("BCDF") then
if not archetypes[combination] then if not archetypes[combination] then
print(combination) print(combination)
end end
hm += 1 hm += 1
end end
archetypes[combination] = true archetypes[combination] = true
@ -149,7 +149,7 @@ local green = rgb.green
local WALL = gray(" │ ") local WALL = gray(" │ ")
local numberOfArchetypes = 0 local numberOfArchetypes = 0
for _ in archetypes do for _ in archetypes do
numberOfArchetypes += 1 numberOfArchetypes += 1
end end
print(common) print(common)
@ -167,36 +167,22 @@ print(
return { return {
ParameterGenerator = function() ParameterGenerator = function()
return return
end, end,
Functions = { Functions = {
Mirror = function() ECR = function()
local matched = 0 local matched = 0
for entityId, firstComponent in mcs:query(E1, E4, E6, E8) do for entityId, firstComponent in registry2:view(B1, B4) do
matched += 1 matched += 1
end end
end, end,
Matter = function() Jecs = function()
local matched = 0 local matched = 0
for entityId, firstComponent in newWorld:query(A1, A4, A6, A8) do for entityId, firstComponent in ecs:query(D1, D4) do
matched += 1 matched += 1
end end
end,
ECR = function()
local matched = 0
for entityId, firstComponent in registry2:view(B1, B4, B6, B8) do
matched += 1
end
end,
Jecs = function()
local matched = 0
for entityId, firstComponent in ecs:query(D1, D4, D6, D8) do
matched += 1
end
end, end,
}, },

View file

@ -142,7 +142,7 @@ end
local ERROR_ENTITY_NOT_ALIVE = "Entity is not alive" local ERROR_ENTITY_NOT_ALIVE = "Entity is not alive"
local ERROR_GENERATION_INVALID = "INVALID GENERATION" local ERROR_GENERATION_INVALID = "INVALID GENERATION"
local function getAlive(index: EntityIndex, e: i24): i53 local function entity_index_get_alive(index: EntityIndex, e: i24): i53
local denseArray = index.dense local denseArray = index.dense
local id = denseArray[ECS_ENTITY_T_LO(e)] local id = denseArray[ECS_ENTITY_T_LO(e)]
@ -159,18 +159,18 @@ local function getAlive(index: EntityIndex, e: i24): i53
error(ERROR_ENTITY_NOT_ALIVE) error(ERROR_ENTITY_NOT_ALIVE)
end end
local function sparseGet(entityIndex, id) local function entity_index_sparse_get(entityIndex, id)
return entityIndex.sparse[getAlive(entityIndex, id)] return entityIndex.sparse[entity_index_get_alive(entityIndex, id)]
end end
-- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits -- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits
local function ECS_PAIR_RELATION(entityIndex, e) local function ecs_pair_relation(entityIndex, e)
return getAlive(entityIndex, ECS_ENTITY_T_HI(e)) return entity_index_get_alive(entityIndex, ECS_ENTITY_T_HI(e))
end end
-- ECS_PAIR_SECOND gets the relationship / pred / LOW bits -- ECS_PAIR_SECOND gets the relationship / pred / LOW bits
local function ECS_PAIR_OBJECT(entityIndex, e) local function ecs_pair_object(entityIndex, e)
return getAlive(entityIndex, ECS_ENTITY_T_LO(e)) return entity_index_get_alive(entityIndex, ECS_ENTITY_T_LO(e))
end end
local function entity_index_new_id(entityIndex: EntityIndex, index: i24): i53 local function entity_index_new_id(entityIndex: EntityIndex, index: i24): i53
@ -300,8 +300,8 @@ local function archetype_of(world: any, types: { i24 }, prev: Archetype?): Arche
idr.size += 1 idr.size += 1
records[componentId] = i records[componentId] = i
if ECS_IS_PAIR(componentId) then if ECS_IS_PAIR(componentId) then
local relation = ECS_PAIR_RELATION(world.entityIndex, componentId) local relation = ecs_pair_relation(world.entityIndex, componentId)
local object = ECS_PAIR_OBJECT(world.entityIndex, componentId) local object = ecs_pair_object(world.entityIndex, componentId)
local r = ECS_PAIR(relation, EcsWildcard) local r = ECS_PAIR(relation, EcsWildcard)
local idr_r = id_record_ensure(componentIndex, r) local idr_r = id_record_ensure(componentIndex, r)
@ -375,7 +375,7 @@ local function world_target(world: World, entity: i53, relation: i24--[[, nth: n
return nil return nil
end end
return ECS_PAIR_OBJECT(entityIndex, archetype.types[archetypeRecord]) return ecs_pair_object(entityIndex, archetype.types[archetypeRecord])
end end
local function world_parent(world: World, entity: i53) local function world_parent(world: World, entity: i53)
@ -408,22 +408,22 @@ local function find_insert(types: { i53 }, toAdd: i53): number
return #types + 1 return #types + 1
end end
local function find_archetype_with(world: World, node: Archetype, componentId: i53): Archetype local function find_archetype_with(world: World, node: Archetype, id: i53): Archetype
local types = node.types local types = node.types
-- Component IDs are added incrementally, so inserting and sorting -- Component IDs are added incrementally, so inserting and sorting
-- them each time would be expensive. Instead this insertion sort can find the insertion -- them each time would be expensive. Instead this insertion sort can find the insertion
-- point in the types array. -- point in the types array.
local destinationType = table.clone(node.types) :: { i53 } local dst_type = table.clone(node.types) :: { i53 }
local at = find_insert(types, componentId) local at = find_insert(types, id)
if at == -1 then if at == -1 then
-- If it finds a duplicate, it just means it is the same archetype so it can return it -- If it finds a duplicate, it just means it is the same archetype so it can return it
-- directly instead of needing to hash types for a lookup to the archetype. -- directly instead of needing to hash types for a lookup to the archetype.
return node return node
end end
table.insert(destinationType, at, componentId) table.insert(dst_type, at, id)
return archetype_ensure(world, destinationType, node) return archetype_ensure(world, dst_type, node)
end end
local function edge_ensure(archetype: Archetype, componentId: i53): ArchetypeEdge local function edge_ensure(archetype: Archetype, componentId: i53): ArchetypeEdge
@ -624,42 +624,49 @@ local function world_clear(world: World, entityId: i53)
entity_move(world.entityIndex, entityId, record, ROOT_ARCHETYPE) entity_move(world.entityIndex, entityId, record, ROOT_ARCHETYPE)
end end
-- Keeping the function as small as possible to enable inlining local world_get: (world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?) -> (...any)
local function fetch(record: Record, componentId: i24): any do
local archetype = record.archetype -- Keeping the function as small as possible to enable inlining
if not archetype then local function fetch(id: i24, records, columns, row): any
return nil local tr = records[id]
end
local archetypeRecord = archetype.records[componentId] if not tr then
return nil
end
if not archetypeRecord then return columns[tr][row]
return nil end
end
return archetype.columns[archetypeRecord][record.row] function world_get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
end local id = entityId
local record = world.entityIndex.sparse[id]
if not record then
return nil
end
local function world_get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any local archetype = record.archetype
local id = entityId if not archetype then
local record = world.entityIndex.sparse[id] return nil
if not record then end
return nil
end
local va = fetch(record, a) local records = archetype.records
local columns = archetype.records
local row = record.row
if b == nil then local va = fetch(a, tr, columns, row)
return va
elseif c == nil then if b == nil then
return va, fetch(record, b) return va
elseif d == nil then elseif c == nil then
return va, fetch(record, b), fetch(record, c) return va, fetch(b, tr, columns, row)
elseif e == nil then elseif d == nil then
return va, fetch(record, b), fetch(record, c), fetch(record, d) return va, fetch(b, tr, columns, row), fetch(c, tr, columns, row)
else elseif e == nil then
error("args exceeded") return va, fetch(b, tr, columns, row), fetch(c, tr, columns, row), fetch(d, tr, columns, row)
end else
error("args exceeded")
end
end
end end
type Item = () -> (number, ...any) type Item = () -> (number, ...any)
@ -848,58 +855,66 @@ do
end end
end end
local cache
function world_query(world: World, ...: number): Query function world_query(world: World, ...: number): Query
-- breaking? -- breaking?
if (...) == nil then if (...) == nil then
error("Missing components") error("Missing components")
end end
indices = {} indices = {}
compatibleArchetypes = {}
length = 0 length = 0
components = { ... } components = { ... }
local archetypes: { Archetype } = world.archetypes :: any if cache then
local firstArchetypeMap: ArchetypeMap compatibleArchetypes = cache
local componentIndex = world.componentIndex else
compatibleArchetypes = {}
local archetypes: { Archetype } = world.archetypes :: any
local firstArchetypeMap: ArchetypeMap
local componentIndex = world.componentIndex
for _, componentId in components do for _, componentId in components do
local map: ArchetypeMap = componentIndex[componentId] :: any local map: ArchetypeMap = componentIndex[componentId] :: any
if not map then if not map then
return EmptyQuery return EmptyQuery
end end
if (firstArchetypeMap :: any) == nil or firstArchetypeMap.size > map.size then if (firstArchetypeMap :: any) == nil or firstArchetypeMap.size > map.size then
firstArchetypeMap = map firstArchetypeMap = map
end end
end end
for id in firstArchetypeMap.cache do for id in firstArchetypeMap.cache do
local compatibleArchetype = archetypes[id] local compatibleArchetype = archetypes[id]
local archetypeRecords = compatibleArchetype.records local archetypeRecords = compatibleArchetype.records
local records: { number } = {} local records: { number } = {}
local skip = false local skip = false
for i, componentId in components do for i, componentId in components do
local index = archetypeRecords[componentId] local index = archetypeRecords[componentId]
if not index then if not index then
skip = true skip = true
break break
end end
-- index should be index.offset -- index should be index.offset
records[i] = index records[i] = index
end end
if skip then if skip then
continue continue
end end
length += 1 length += 1
compatibleArchetypes[length] = compatibleArchetype compatibleArchetypes[length] = compatibleArchetype
indices[length] = records indices[length] = records
end end
cache = compatibleArchetypes
end
lastArchetype = 1 lastArchetype = 1
archetype = compatibleArchetypes[lastArchetype] archetype = compatibleArchetypes[lastArchetype]
@ -1113,14 +1128,15 @@ return {
Rest = EcsRest, Rest = EcsRest,
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
-- Inwards facing API for testing
IS_PAIR = ECS_IS_PAIR, IS_PAIR = ECS_IS_PAIR,
ECS_ID = ECS_ENTITY_T_LO, ECS_ID = ECS_ENTITY_T_LO,
ECS_PAIR = ECS_PAIR,
ECS_GENERATION_INC = ECS_GENERATION_INC, ECS_GENERATION_INC = ECS_GENERATION_INC,
ECS_GENERATION = ECS_GENERATION, ECS_GENERATION = ECS_GENERATION,
ECS_PAIR_RELATION = ECS_PAIR_RELATION,
ECS_PAIR_OBJECT = ECS_PAIR_OBJECT,
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number, ecs_pair_relation = ecs_pair_relation,
getAlive = getAlive, ecs_pair_object = ecs_pair_object,
entity_index_get_alive = entity_index_get_alive,
} }

View file

@ -4,10 +4,10 @@ local __ = jecs.Wildcard
local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION
local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC
local IS_PAIR = jecs.IS_PAIR local IS_PAIR = jecs.IS_PAIR
local ECS_PAIR = jecs.ECS_PAIR local pair = jecs.pair
local getAlive = jecs.getAlive local getAlive = jecs.entity_index_get_alive
local ECS_PAIR_RELATION = jecs.ECS_PAIR_RELATION local ecs_pair_relation = jecs.ecs_pair_relation
local ECS_PAIR_OBJECT = jecs.ECS_PAIR_OBJECT local ecs_pair_object = jecs.ecs_pair_object
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test() local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
local function CHECK_NO_ERR<T...>(s: string, fn: (T...) -> (), ...: T...) local function CHECK_NO_ERR<T...>(s: string, fn: (T...) -> (), ...: T...)
@ -256,11 +256,11 @@ TEST("world", function()
CHECK(IS_PAIR(world:entity()) == false) CHECK(IS_PAIR(world:entity()) == false)
local pair = ECS_PAIR(e2, e3) local pair = pair(e2, e3)
CHECK(IS_PAIR(pair) == true) CHECK(IS_PAIR(pair) == true)
CHECK(ECS_PAIR_RELATION(world.entityIndex, pair) == e2) CHECK(ecs_pair_relation(world.entityIndex, pair) == e2)
CHECK(ECS_PAIR_OBJECT(world.entityIndex, pair) == e3) CHECK(ecs_pair_object(world.entityIndex, pair) == e3)
end end
do CASE("should allow querying for relations") do CASE("should allow querying for relations")
@ -269,8 +269,8 @@ TEST("world", function()
local Apples = world:entity() local Apples = world:entity()
local bob = world:entity() local bob = world:entity()
world:set(bob, ECS_PAIR(Eats, Apples), true) world:set(bob, pair(Eats, Apples), true)
for e, bool in world:query(ECS_PAIR(Eats, Apples)) do for e, bool in world:query(pair(Eats, Apples)) do
CHECK(e == bob) CHECK(e == bob)
CHECK(bool) CHECK(bool)
end end
@ -282,14 +282,14 @@ TEST("world", function()
local Apples = world:entity() local Apples = world:entity()
local bob = world:entity() local bob = world:entity()
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") world:set(bob, pair(Eats, Apples), "bob eats apples")
local w = jecs.Wildcard local w = jecs.Wildcard
for e, data in world:query(ECS_PAIR(Eats, w)) do for e, data in world:query(pair(Eats, w)) do
CHECK(e == bob) CHECK(e == bob)
CHECK(data == "bob eats apples") CHECK(data == "bob eats apples")
end end
for e, data in world:query(ECS_PAIR(w, Apples)) do for e, data in world:query(pair(w, Apples)) do
CHECK(e == bob) CHECK(e == bob)
CHECK(data == "bob eats apples") CHECK(data == "bob eats apples")
end end
@ -303,12 +303,12 @@ TEST("world", function()
local bob = world:entity() local bob = world:entity()
local alice = world:entity() local alice = world:entity()
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") world:set(bob, pair(Eats, Apples), "bob eats apples")
world:set(alice, ECS_PAIR(Eats, Oranges), "alice eats oranges") world:set(alice, pair(Eats, Oranges), "alice eats oranges")
local w = jecs.Wildcard local w = jecs.Wildcard
local count = 0 local count = 0
for e, data in world:query(ECS_PAIR(Eats, w)) do for e, data in world:query(pair(Eats, w)) do
count += 1 count += 1
if e == bob then if e == bob then
CHECK(data == "bob eats apples") CHECK(data == "bob eats apples")
@ -320,7 +320,7 @@ TEST("world", function()
CHECK(count == 2) CHECK(count == 2)
count = 0 count = 0
for e, data in world:query(ECS_PAIR(w, Apples)) do for e, data in world:query(pair(w, Apples)) do
count += 1 count += 1
CHECK(data == "bob eats apples") CHECK(data == "bob eats apples")
end end
@ -337,21 +337,21 @@ TEST("world", function()
local alice = world:entity() local alice = world:entity()
world:set(bob, Apples, "apples") world:set(bob, Apples, "apples")
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") world:set(bob, pair(Eats, Apples), "bob eats apples")
world:set(alice, ECS_PAIR(Eats, Oranges), "alice eats oranges") world:set(alice, pair(Eats, Oranges), "alice eats oranges")
world:delete(Apples) world:delete(Apples)
local Wildcard = jecs.Wildcard local Wildcard = jecs.Wildcard
local count = 0 local count = 0
for _, data in world:query(ECS_PAIR(Wildcard, Apples)) do for _, data in world:query(pair(Wildcard, Apples)) do
count += 1 count += 1
end end
world:delete(ECS_PAIR(Eats, Apples)) world:delete(pair(Eats, Apples))
CHECK(count == 0) CHECK(count == 0)
CHECK(world:get(bob, ECS_PAIR(Eats, Apples)) == nil) CHECK(world:get(bob, pair(Eats, Apples)) == nil)
end end
do CASE("should error when setting invalid pair") do CASE("should error when setting invalid pair")
@ -362,13 +362,12 @@ TEST("world", function()
world:delete(Apples) world:delete(Apples)
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") world:set(bob, pair(Eats, Apples), "bob eats apples")
end end
do CASE("should find target for ChildOf") do CASE("should find target for ChildOf")
local world = jecs.World.new() local world = jecs.World.new()
local ChildOf = jecs.ChildOf local ChildOf = jecs.ChildOf
local pair = ECS_PAIR
local Name = world:component() local Name = world:component()
@ -383,7 +382,7 @@ TEST("world", function()
CHECK(world:parent(bob) == alice) -- O(1) CHECK(world:parent(bob) == alice) -- O(1)
local count = 0 local count = 0
for _, name in world:query(Name, ECS_PAIR(ChildOf, alice)) do for _, name in world:query(Name, pair(ChildOf, alice)) do
count += 1 count += 1
end end
CHECK(count == 2) CHECK(count == 2)
@ -521,11 +520,11 @@ TEST("world", function()
local Bob = world:component() local Bob = world:component()
local helloBob = world:entity() local helloBob = world:entity()
world:add(helloBob, ECS_PAIR(Hello, Bob)) world:add(helloBob, pair(Hello, Bob))
world:add(helloBob, Bob) world:add(helloBob, Bob)
local withoutCount = 0 local withoutCount = 0
for _ in world:query(ECS_PAIR(Hello, Bob)):without(Bob) do for _ in world:query(pair(Hello, Bob)):without(Bob) do
withoutCount += 1 withoutCount += 1
end end