"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRanges = void 0;
function* mapIterable(source, transform) {
    for (const value of source) {
        yield transform(value);
    }
}
async function getNotDiscardedIntervals(disk) {
    return notDiscardedIntervalsIterator(disk.getDiscardedChunks(), await disk.getCapacity());
}
function* notDiscardedIntervalsIterator(discardedChunks, capacity) {
    let lastStart = 0;
    for (const discardedChunk of discardedChunks) {
        yield [lastStart, discardedChunk.start - 1];
        lastStart = discardedChunk.end + 1;
    }
    if (lastStart < capacity) {
        yield [lastStart, capacity - 1];
    }
}
function* mergeIntervals(intervals) {
    // Merges adjacent and overlapping intervals (helper for getRanges)
    let current;
    for (const interval of intervals) {
        if (current === undefined) {
            current = interval.slice(); // slice for copying
        }
        else if (interval[0] > current[1] + 1) {
            // There's a gap
            yield current;
            current = interval.slice(); // slice for copying
        }
        else {
            // No gap
            current[1] = interval[1];
        }
    }
    if (current !== undefined) {
        yield current;
    }
}
async function getRanges(disk, blockSize) {
    const intervals = await getNotDiscardedIntervals(disk);
    const blockSizedIntervals = mapIterable(intervals, (chunk) => [
        Math.floor(chunk[0] / blockSize),
        Math.floor(chunk[1] / blockSize),
    ]);
    const mergedBlockSizedIntervals = mergeIntervals(blockSizedIntervals);
    return mapIterable(mergedBlockSizedIntervals, (interval) => {
        const offset = interval[0] * blockSize;
        const length = (interval[1] - interval[0] + 1) * blockSize;
        return { offset, length };
    });
}
exports.getRanges = getRanges;
//# sourceMappingURL=mapped-ranges.js.map