UNPKG

closed-interval

Version:

Utilities for working with a range of items of any type

119 lines (118 loc) 3.56 kB
const makeComparator = () => (v1, v2) => { if (v1 < v2) { return -1; } else if (v1 > v2) { return 1; } else { return 0; } }; class Range { customComparator; minimum; maximum; comparator; constructor(fromInclusive, toInclusive, customComparator = null) { this.customComparator = customComparator; this.comparator = customComparator === null ? makeComparator() : customComparator; if (this.comparator(fromInclusive, toInclusive) === -1) { this.minimum = fromInclusive; this.maximum = toInclusive; } else { this.minimum = toInclusive; this.maximum = fromInclusive; } } /** * @deprecated Use Range.of instead. */ static between(fromInclusive, toInclusive, comparator = null) { return Range.of(fromInclusive, toInclusive, comparator); } static of(fromInclusive, toInclusive, comparator = null) { return new Range(fromInclusive, toInclusive, comparator); } static is(element, comparator = null) { return Range.between(element, element, comparator); } contains(element) { return (this.comparator(this.minimum, element) <= 0 && this.comparator(this.maximum, element) >= 0); } containsRange(other) { return (this.contains(other.getMinimum()) && this.contains(other.getMaximum())); } elementCompareTo(element) { if (this.comparator(this.minimum, element) === 1) { return -1; } if (this.comparator(this.maximum, element) === -1) { return 1; } return 0; } fit(element) { if (this.elementCompareTo(element) === -1) { return this.minimum; } if (this.elementCompareTo(element) === 1) { return this.maximum; } return element; } getComparator() { return this.comparator; } getMaximum() { return this.maximum; } getMinimum() { return this.minimum; } intersectionWith(other) { if (!this.isOverlappedBy(other)) { throw new Error(`Cannot calculate intersection with non-overlapping range ${other}`); } const min = this.getComparator()(this.minimum, other.getMinimum()) < 0 ? other.getMinimum() : this.minimum; const max = this.getComparator()(this.maximum, other.getMaximum()) < 0 ? this.maximum : other.getMaximum(); return Range.between(min, max, this.getComparator()); } isAfter(element) { return this.comparator(element, this.minimum) < 0; } isAfterRange(otherRange) { return this.isAfter(otherRange.getMaximum()); } isBefore(element) { return this.comparator(element, this.maximum) > 0; } isBeforeRange(otherRange) { return this.isBefore(otherRange.getMinimum()); } isEndedBy(element) { return this.comparator(element, this.maximum) === 0; } isNaturalOrdering() { return this.customComparator === null; } isOverlappedBy(otherRange) { return (otherRange.contains(this.minimum) || otherRange.contains(this.maximum) || this.contains(otherRange.getMinimum())); } isStartedBy(element) { return this.comparator(element, this.minimum) === 0; } toString() { return `[${this.minimum}..${this.maximum}]`; } } export default Range;