node-apparatus
Version:
A mix of common components needed for awesome node experience
59 lines • 2.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.kWayMergeAsync = kWayMergeAsync;
/**
* Merges multiple sorted iterators into a single sorted iterator using a custom frame processing function.
*
* @template T - The type of elements in the iterators.
* @param {AsyncIterableIterator<T>[]} iterators - An array of sorted iterators to be merged.
* @param {(elements: (T | null)[]) => { yieldIndex: number | null, purgeIndexes: number[] }} frameProcessFunction -
* A function that processes the current frame of elements from each iterator and determines which element to yield next
* and which iterators to purge.
* @returns {AsyncIterableIterator<T>} - An iterator that yields elements in sorted order from the merged iterators.
* @throws {Error} - Throws an error if the frame processing function is indecisive, which could lead to an infinite loop.
*/
async function* kWayMergeAsync(iterators, frameProcessFunction) {
const compareFrame = new Array();
for (const cursor of iterators) {
const result = await cursor.next();
compareFrame.push(result.value);
}
let doneCounter = compareFrame.length;
const endReachedIndexes = new Set();
while (doneCounter > 0) {
const result = frameProcessFunction(compareFrame);
const yieldIndex = result.yieldIndex;
const purgeIndexes = result.purgeIndexes || [];
let exitLoop = false;
if (yieldIndex !== null && !Number.isNaN(yieldIndex) && yieldIndex >= 0 && yieldIndex < compareFrame.length && !endReachedIndexes.has(yieldIndex)) {
yield compareFrame[yieldIndex];
const nextCursor = await iterators[yieldIndex].next();
compareFrame[yieldIndex] = nextCursor.value;
if (nextCursor.done === true) {
doneCounter--;
endReachedIndexes.add(yieldIndex);
}
}
else {
exitLoop = true;
}
if (purgeIndexes.length > 0) {
for (const purgeIndex of purgeIndexes) {
if (purgeIndex !== -1 && !Number.isNaN(purgeIndex) && purgeIndex >= 0 && purgeIndex < compareFrame.length && !endReachedIndexes.has(purgeIndex)) {
const nextCursor = await iterators[purgeIndex].next();
compareFrame[purgeIndex] = nextCursor.value;
if (nextCursor.done === true) {
doneCounter--;
endReachedIndexes.add(purgeIndex);
}
}
}
}
else if (exitLoop === true) {
//This means the iteration was in-decisive, so we exit the loop, to prevent infinite loop.
throw new Error("Frame processing was in-decisive, either it is pointing to empty iterator or incorrect value.");
break;
}
}
}
//# sourceMappingURL=k-way-merge-async.js.map