refactor: make getRelatedTo return an iterator

Convert `getRelatedTo` from returning an array to returning an
`IterableIterator`. This improves memory efficiency by yielding
entities lazily instead of allocating a new array on every call.
This commit is contained in:
2026-06-02 06:39:07 +08:00
parent 2469cdc7cb
commit 5d125167cc
3 changed files with 31 additions and 26 deletions
+12 -12
View File
@@ -52,8 +52,8 @@ function clearSubtree(world: World, entity: Entity): void {
}
}
function childrenOf(world: World, parent: Entity): Entity[] {
return world.getRelatedTo(parent, ChildOf);
function* childrenOf(world: World, parent: Entity): IterableIterator<Entity> {
yield* world.getRelatedTo(parent, ChildOf);
}
function parentOf(world: World, child: Entity): Entity | null {
@@ -230,10 +230,9 @@ export class TaskRunner {
}
private _executeRandom(entity: Entity): void {
const children = childrenOf(this._world, entity);
// Check if any child already reached a terminal
for (const child of children) {
// Single pass: check terminals and collect eligible children
const eligible: Entity[] = [];
for (const child of childrenOf(this._world, entity)) {
if (isTerminal(this._world, child)) {
const status = terminalStatus(this._world, child)!;
this._finish(
@@ -246,13 +245,14 @@ export class TaskRunner {
);
return;
}
if (
!this._world.has(child, Running) &&
!this._world.has(child, Scheduled)
) {
eligible.push(child);
}
}
// Pick a random child that isn't already running
const eligible = children.filter(
(c) => !this._world.has(c, Running) && !this._world.has(c, Scheduled),
);
if (eligible.length > 0) {
const pick = eligible[Math.floor(Math.random() * eligible.length)];
this._world.add(pick, Scheduled);
@@ -261,7 +261,7 @@ export class TaskRunner {
}
private _executeRepeat(entity: Entity): void {
const children = childrenOf(this._world, entity);
const children = [...childrenOf(this._world, entity)];
// Repeat expects exactly one child
if (children.length === 0) return;
+10 -5
View File
@@ -388,17 +388,22 @@ export class World {
/**
* Get all source entities that point to `target` via this relationship.
*/
getRelatedTo(target: Entity, rel: RelationshipDef): Entity[] {
*getRelatedTo(
target: Entity,
rel: RelationshipDef,
): IterableIterator<Entity> {
const ti = entityIndex(target);
if (!this._isAlive(ti, target)) return [];
if (!this._isAlive(ti, target)) return;
const rev = this._relReverse.get(rel._key);
if (!rev) return [];
if (!rev) return;
const sources = rev.get(ti);
if (!sources) return [];
if (!sources) return;
return [...sources].map((si) => makeEntity(si, this._generations[si]));
for (const si of sources) {
yield makeEntity(si, this._generations[si]);
}
}
/**