UNPKG

range-ts

Version:

RangeMap implementation based on Guava

135 lines 5.26 kB
import { NumberRange } from "../number-range/number-range"; import { BoundType } from "../core/bound-type"; export class RangeMap { static fromRangeValues(values, eq) { const rangeMap = new RangeMap(eq); rangeMap.rangeValues = values; return rangeMap; } constructor(eq = (a, b) => a === b) { this.eq = eq; this.rangeValues = []; } put(range, value) { this.combinedPut(range, value, false); } putCoalescing(range, value) { this.combinedPut(range, value, true); } get(value) { const foundRangeValue = this.rangeValues.find((currentRangeValue) => currentRangeValue.range.contains(value)); if (foundRangeValue) { return foundRangeValue.value; } return null; } asMapOfRanges() { const newMap = new Map(); this.rangeValues .filter((range) => !range.range.isEmpty()) .sort((a, b) => a.range.lowerEndpoint.valueOf() - b.range.lowerEndpoint.valueOf()) .forEach((currentRangeValue) => { newMap.set(currentRangeValue.range, currentRangeValue.value); }); return newMap; } asMapOfValues() { const newMap = new Map(); this.rangeValues .filter((range) => !range.range.isEmpty()) .sort((a, b) => a.range.lowerEndpoint.valueOf() - b.range.lowerEndpoint.valueOf()) .forEach((currentRangeValue) => { if (newMap.has(currentRangeValue.value)) { newMap.get(currentRangeValue.value).push(currentRangeValue.range); } else { newMap.set(currentRangeValue.value, [currentRangeValue.range]); } }); return newMap; } subRangeMap(range) { const rangeValues = this.rangeValues.flatMap((rangeValue) => { const intersection = rangeValue.range.intersection(range); if (!intersection) { return []; } return [ { range: intersection, value: rangeValue.value, }, ]; }); return RangeMap.fromRangeValues(rangeValues); } getEntry(key) { const foundRangeValue = this.rangeValues.find((currentRangeValue) => currentRangeValue.range.contains(key)); if (foundRangeValue) { return [foundRangeValue.range, foundRangeValue.value]; } return null; } span() { if (this.rangeValues.length === 0) { return null; } const sortedRangeValues = this.rangeValues.sort((a, b) => a.range.lowerEndpoint.valueOf() - b.range.lowerEndpoint.valueOf()); return new NumberRange(sortedRangeValues[0].range.lowerEndpoint, sortedRangeValues[0].range.lowerBoundType, sortedRangeValues[sortedRangeValues.length - 1].range.upperEndpoint, sortedRangeValues[sortedRangeValues.length - 1].range.upperBoundType); } remove(range) { if (range.isEmpty()) { return; } const toDelete = { toDeleteId: Math.random() }; this.put(range, toDelete); this.rangeValues = this.rangeValues.filter(rangeValue => rangeValue.value !== toDelete); } combinedPut(range, value, shouldPutCoalescing = false) { let newRange = range; let affectedRangeValues = []; const unaffectedRangeValues = []; this.rangeValues.forEach((currentRangeValue) => { if (currentRangeValue.range.isConnected(newRange)) { affectedRangeValues.push(currentRangeValue); } else { unaffectedRangeValues.push(currentRangeValue); } }); affectedRangeValues = affectedRangeValues.flatMap((currentRangeValue) => { var _a; if (shouldPutCoalescing && this.eq(value, currentRangeValue.value)) { newRange = newRange.span(currentRangeValue.range); return []; } if ((_a = currentRangeValue.range.intersection(newRange)) === null || _a === void 0 ? void 0 : _a.isEmpty()) { return [currentRangeValue]; } const rangeBefore = currentRangeValue.range.intersection(NumberRange.upTo(newRange.lowerEndpoint, newRange.lowerBoundType === BoundType.OPEN ? BoundType.CLOSED : BoundType.OPEN)); const rangeAfter = currentRangeValue.range.intersection(new NumberRange(newRange.upperEndpoint, newRange.upperBoundType === BoundType.OPEN ? BoundType.CLOSED : BoundType.OPEN, Number.POSITIVE_INFINITY, BoundType.OPEN)); return [rangeBefore, rangeAfter] .filter((a) => !!a) .filter(a => !a.isEmpty()) .map((currentRange) => ({ range: currentRange, value: currentRangeValue.value, })); }); this.rangeValues = [ ...unaffectedRangeValues, ...affectedRangeValues, { range: newRange, value, }, ]; } } //# sourceMappingURL=range-map.js.map