UNPKG

range-ts

Version:

RangeMap implementation based on Guava

332 lines 17.3 kB
import { __read, __spreadArray } from "tslib"; import { BoundType } from "../core/bound-type"; import { NumberRange } from "../number-range/number-range"; import { RangeMap } from "./range-map"; import { isEqual } from "lodash-es"; describe("RangeMap", function () { describe("put", function () { it("should handle non-overlapping ranges and values", function () { var rangeMap = new RangeMap(); rangeMap.put(NumberRange.closedOpen(1, 3), "a"); rangeMap.put(NumberRange.closedOpen(4, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[1..3)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[4..6)"); expect(result[1][1]).toBe("b"); }); it("should handle overlapping ranges and values", function () { var rangeMap = new RangeMap(); rangeMap.put(NumberRange.closedOpen(1, 3), "a"); rangeMap.put(NumberRange.closedOpen(2, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[1..2)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[2..6)"); expect(result[1][1]).toBe("b"); }); it("should handle enclosed ranges", function () { var rangeMap = new RangeMap(); rangeMap.put(NumberRange.closedOpen(1, 10), "a"); rangeMap.put(NumberRange.closedOpen(3, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(3); expect(result[0][0].toString()).toBe("[1..3)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[3..6)"); expect(result[1][1]).toBe("b"); expect(result[2][0].toString()).toBe("[6..10)"); expect(result[2][1]).toBe("a"); }); it("should handle complex behavior", function () { var rangeMap = new RangeMap(); rangeMap.put(NumberRange.upTo(8, BoundType.CLOSED), "a"); rangeMap.put(NumberRange.closedOpen(3, 6), "b"); rangeMap.put(NumberRange.closedOpen(8, 12), "c"); rangeMap.put(NumberRange.atLeast(18), "e"); expect(rangeMap.get(2)).toBe("a"); expect(rangeMap.get(3)).toBe("b"); expect(rangeMap.get(5)).toBe("b"); expect(rangeMap.get(6)).toBe("a"); expect(rangeMap.get(8)).toBe("c"); expect(rangeMap.get(13)).toBe(null); expect(rangeMap.get(18)).toBe("e"); }); }); describe("put coalescing", function () { describe("with different values", function () { it("should handle non-overlapping ranges and values", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 3), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(4, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[1..3)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[4..6)"); expect(result[1][1]).toBe("b"); }); it("should handle overlapping ranges and values", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 3), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(2, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[1..2)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[2..6)"); expect(result[1][1]).toBe("b"); }); it("should handle enclosed ranges", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 10), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(3, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(3); expect(result[0][0].toString()).toBe("[1..3)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[3..6)"); expect(result[1][1]).toBe("b"); expect(result[2][0].toString()).toBe("[6..10)"); expect(result[2][1]).toBe("a"); }); it("should handle enclosing ranges", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(3, 6), "b"); rangeMap.putCoalescing(NumberRange.closedOpen(1, 10), "a"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(1); expect(result[0][0].toString()).toBe("[1..10)"); expect(result[0][1]).toBe("a"); }); it("should handle complex behavior", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.upTo(8, BoundType.CLOSED), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(3, 6), "b"); rangeMap.putCoalescing(NumberRange.closedOpen(8, 12), "c"); rangeMap.putCoalescing(NumberRange.atLeast(18), "e"); expect(rangeMap.get(2)).toBe("a"); expect(rangeMap.get(3)).toBe("b"); expect(rangeMap.get(5)).toBe("b"); expect(rangeMap.get(6)).toBe("a"); expect(rangeMap.get(8)).toBe("c"); expect(rangeMap.get(13)).toBe(null); expect(rangeMap.get(18)).toBe("e"); }); }); describe("with same values", function () { it("should not combine non-connecting ranges", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 3), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(4, 6), "a"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[1..3)"); expect(result[0][1]).toBe("a"); expect(result[1][0].toString()).toBe("[4..6)"); expect(result[1][1]).toBe("a"); }); it("should combine overlapping ranges and values", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 3), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(2, 6), "a"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(1); expect(result[0][0].toString()).toBe("[1..6)"); expect(result[0][1]).toBe("a"); }); it("should handle enclosed ranges", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(1, 10), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(3, 6), "a"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(1); expect(result[0][0].toString()).toBe("[1..10)"); expect(result[0][1]).toBe("a"); }); it("should filter out empty ranges", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(0, 24), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(0, 6), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(2); expect(result[0][0].toString()).toBe("[0..6)"); expect(result[0][1]).toBe("b"); expect(result[1][0].toString()).toBe("[6..24)"); expect(result[1][1]).toBe("a"); }); it('should replace existing values', function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(0, 24), "a"); rangeMap.putCoalescing(NumberRange.closedOpen(0, 24), "b"); var result = Array.from(rangeMap.asMapOfRanges().entries()); expect(result.length).toBe(1); expect(result[0][0].toString()).toBe("[0..24)"); expect(result[0][1]).toBe("b"); }); }); }); describe("asMapOfValues", function () { it("should work", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(2, 10), 4); rangeMap.putCoalescing(NumberRange.closedOpen(13, 16), 4); rangeMap.putCoalescing(NumberRange.closedOpen(3, 12), 3); var result = rangeMap.asMapOfValues(); var result3 = result.get(3); var result4 = result.get(4); expect(result4.length).toBe(2); expect(result4[0].toString()).toBe("[2..3)"); expect(result4[1].toString()).toBe("[13..16)"); expect(result3.length).toBe(1); expect(result3[0].toString()).toBe("[3..12)"); }); }); describe("subRangeMap", function () { it("should work", function () { var rangeMap = new RangeMap(); rangeMap.putCoalescing(NumberRange.closedOpen(2, 10), 4); rangeMap.putCoalescing(NumberRange.closedOpen(13, 16), 4); rangeMap.putCoalescing(NumberRange.closedOpen(3, 12), 3); var subRangeMap = rangeMap.subRangeMap(NumberRange.closedOpen(2.5, 11)); var result = subRangeMap.asMapOfValues(); var result3 = result.get(3); var result4 = result.get(4); expect(result4.length).toBe(1); expect(result4[0].toString()).toBe("[2.5..3)"); expect(result3.length).toBe(1); expect(result3[0].toString()).toBe("[3..11)"); }); }); describe("remove", function () { it('should remove an identical range', function () { var rangeMap = new RangeMap(); var range = NumberRange.closedOpen(2, 10); rangeMap.putCoalescing(range, 4); rangeMap.remove(range); expect(rangeMap.asMapOfRanges().size).toBe(0); }); it('should remove encosed range', function () { var rangeMap = new RangeMap(); var itemRange = NumberRange.closedOpen(3, 9); var removeRange = NumberRange.closedOpen(2, 10); rangeMap.putCoalescing(itemRange, 4); rangeMap.remove(removeRange); expect(rangeMap.asMapOfRanges().size).toBe(0); }); it('should truncate range when partial overlapped', function () { var rangeMap = new RangeMap(); var itemRange = NumberRange.closedOpen(1, 5); var removeRange = NumberRange.closedOpen(3, 10); rangeMap.putCoalescing(itemRange, 4); rangeMap.remove(removeRange); var result = rangeMap.asMapOfRanges(); expect(result.size).toBe(1); expect(__spreadArray([], __read(result.entries()), false)[0]).toEqual([NumberRange.closedOpen(1, 3), 4]); }); it('should truncate range when contained', function () { var rangeMap = new RangeMap(); var itemRange = NumberRange.closedOpen(1, 10); var removeRange = NumberRange.closedOpen(3, 5); rangeMap.putCoalescing(itemRange, 4); rangeMap.remove(removeRange); var result = rangeMap.asMapOfRanges(); expect(result.size).toBe(2); expect(__spreadArray([], __read(result.entries()), false)[0]).toEqual([NumberRange.closedOpen(1, 3), 4]); expect(__spreadArray([], __read(result.entries()), false)[1]).toEqual([NumberRange.closedOpen(5, 10), 4]); }); it('should not touch connected but not overlapping ranges', function () { var rangeMap = new RangeMap(); var itemRange = NumberRange.closedOpen(1, 5); var removeRange = NumberRange.closedOpen(5, 10); rangeMap.putCoalescing(itemRange, 4); rangeMap.remove(removeRange); var result = rangeMap.asMapOfRanges(); expect(result.size).toBe(1); expect(__spreadArray([], __read(result.entries()), false)[0]).toEqual([NumberRange.closedOpen(1, 5), 4]); }); it('should not touch non-overlapping ranges', function () { var rangeMap = new RangeMap(); var itemRange = NumberRange.closedOpen(1, 3); var removeRange = NumberRange.closedOpen(5, 10); rangeMap.putCoalescing(itemRange, 4); rangeMap.remove(removeRange); var result = rangeMap.asMapOfRanges(); expect(result.size).toBe(1); expect(__spreadArray([], __read(result.entries()), false)[0]).toEqual([NumberRange.closedOpen(1, 3), 4]); }); }); describe('issues', function () { it('should correctly preserve positive and negative infinity range endpoints wwith putCoalescing', function () { var rangeMap = new RangeMap(isEqual); rangeMap.put(NumberRange.all(), []); rangeMap.putCoalescing(NumberRange.closedOpen(1834354800000, 1834441200000), 'ab934de2-99be-4d01-8086-9b21082665c9'); check(); rangeMap.putCoalescing(NumberRange.closedOpen(1751320800000, 1751493600000), 'e4fe9b11-b33b-4a9d-8f82-893fa543d8ed'); check(); rangeMap.putCoalescing(NumberRange.closedOpen(1751320800000, 1752098400000), 'a546e6f6-796c-45c9-9ea1-91610d23ef04'); check(); function check() { var resultEntries = __spreadArray([], __read(rangeMap.asMapOfRanges().entries()), false); expect(resultEntries.some(function (_a) { var _b = __read(_a, 2), range = _b[0], value = _b[1]; return range.lowerEndpoint === Number.NEGATIVE_INFINITY; })).toBeTrue(); expect(resultEntries.some(function (_a) { var _b = __read(_a, 2), range = _b[0], value = _b[1]; return range.upperEndpoint === Number.POSITIVE_INFINITY; })).toBeTrue(); } }); it('should return the correct span if the same range is added multiple times with put', function () { var rangeMap = new RangeMap(isEqual); rangeMap.put(NumberRange.closedOpen(1590962400000, 1622498400000), 1); rangeMap.put(NumberRange.closedOpen(1590962400000, 1622498400000), 2); rangeMap.put(NumberRange.closedOpen(1590962400000, 1622498400000), 3); rangeMap.put(NumberRange.closedOpen(1616281200000, 1648076400000), 4); expect(rangeMap.span()).toEqual(NumberRange.closedOpen(1590962400000, 1648076400000)); }); }); }); describe("README example", function () { it("should work", function () { var festivalAttendanceRangeMap = new RangeMap(isEqual); var attendance = [ { name: "Bob", days: [1, 2, 3, 4], }, { name: "Lisa", days: [1, 2, 3], }, { name: "Eve", days: [4, 1], }, ]; festivalAttendanceRangeMap.putCoalescing(NumberRange.closedOpen(1, 5), []); attendance.forEach(function (_a) { var name = _a.name, days = _a.days; days.forEach(function (day) { var dayRange = NumberRange.closedOpen(day, day + 1); var subRangeMap = festivalAttendanceRangeMap .subRangeMap(dayRange) .asMapOfRanges(); __spreadArray([], __read(subRangeMap.entries()), false).forEach(function (_a) { var _b = __read(_a, 2), key = _b[0], value = _b[1]; festivalAttendanceRangeMap.putCoalescing(key, __spreadArray(__spreadArray([], __read(value), false), [name], false)); }); }); }); var result = festivalAttendanceRangeMap.asMapOfRanges(); expect(__spreadArray([], __read(result.entries()), false)).toEqual([ [NumberRange.closedOpen(1, 2), ["Bob", "Lisa", "Eve"]], [NumberRange.closedOpen(2, 4), ["Bob", "Lisa"]], [NumberRange.closedOpen(4, 5), ["Bob", "Eve"]], ]); }); }); //# sourceMappingURL=range-map.spec.js.map