/*
ecsjs is an entity component system library for JavaScript
Copyright (C) 2014 Peter Flannery
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import type { ComponentMap } from './component-map.js';
import type { ComponentQuery } from './query.js';
/**
* An iterator for yielding entity ids and their associated component data
* @category Iterators
* @example
* // construct an instance
* const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))
*
* // iterate component data that is related to the Player
* for(const [entityId, player, position] of iterator) { }
*
* // you can also reset the iterator back to the start
* // without having to create a new ComponentIterator instance
* iterator.reset()
* for(const [entityId, player, position] of iterator) { }
*/
export class ComponentIterator {
private keyMap: ComponentMap;
private componentMaps: ComponentMap[] = [];
// iteration state
private entries: Iterator<[number, TKey]>;
/**
* Creates a new component iterator
* @param query - The {@link ComponentQuery} to iterate over
*/
constructor(query: ComponentQuery) {
// @ts-ignore internal private var accessor
this.keyMap = query.keyMap
// @ts-ignore internal private var accessor
this.componentMaps = query.componentMaps
this.entries = this.keyMap.entries();
}
/**
* Gets the next iterator value
* @returns An {@link IteratorResult} containing the next [entityId, keyComponentData, ...relatedComponentData] tuple
*/
next(): IteratorResult<[number, TKey, ...TRelated]> {
const entry = this.entries.next();
const { value, done } = entry;
if (done) return { value, done };
const entityId = value[0];
// append the related components
for (let i = 0; i < this.componentMaps.length; i++) {
const map = this.componentMaps[i];
value.push(map.get(entityId));
}
return { value: value as any, done: false };
}
/**
* Resets the iterator back to the first entry
*/
reset() {
this.entries = this.keyMap.entries();
}
/**
* Returns this iterator instance
*/
[Symbol.iterator]() { return this; }
}