123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { Segmentation, OrderedSet, SortedArray, Interval } from '../int';
- import _Iterator from '../iterator';
- /** Pairs of min and max indices of sorted, non-overlapping ranges */
- type SortedRanges<T extends number = number> = SortedArray<T>
- namespace SortedRanges {
- export function ofSortedRanges<T extends number = number>(array: ArrayLike<T>) { return SortedArray.ofSortedArray<T>(array); }
- export function start<T extends number = number>(ranges: SortedRanges<T>) { return ranges[0]; }
- export function end<T extends number = number>(ranges: SortedRanges<T>) { return ranges[ranges.length - 1] + 1; }
- export function min<T extends number = number>(ranges: SortedRanges<T>) { return ranges[0]; }
- export function max<T extends number = number>(ranges: SortedRanges<T>) { return ranges[ranges.length - 1]; }
- export function size<T extends number = number>(ranges: SortedRanges<T>) {
- let size = 0;
- for (let i = 0, il = ranges.length; i < il; i += 2) {
- size += ranges[i + 1] - ranges[i] + 1;
- }
- return size;
- }
- export function count<T extends number = number>(ranges: SortedRanges<T>) { return ranges.length / 2; }
- export function startAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
- return ranges[index * 2];
- }
- export function endAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
- return ranges[index * 2 + 1] + 1;
- }
- export function minAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
- return ranges[index * 2];
- }
- export function maxAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
- return ranges[index * 2 + 1];
- }
- export function areEqual<T extends number = number>(a: SortedRanges<T>, b: SortedRanges<T>) {
- if (a.length !== b.length) return false;
- for (let i = 0, il = a.length; i < il; ++i) {
- if (a[i] !== b[i]) return false;
- }
- return true;
- }
- export function forEach<T extends number = number>(ranges: SortedRanges<T>, f: (value: T, i: number) => void) {
- let k = 0;
- for (let i = 0, il = ranges.length; i < il; i += 2) {
- for (let j = ranges[i], jl = ranges[i + 1]; j <= jl; ++j) {
- f(j, k);
- ++k;
- }
- }
- }
- /** Returns if a value of `set` is included in `ranges` */
- export function has<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
- return firstIntersectionIndex(ranges, set) !== -1;
- }
- /** Returns if a value of `set` is included in `ranges` from given index */
- export function hasFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number) {
- return firstIntersectionIndexFrom(ranges, set, from) !== -1;
- }
- export function firstIntersectionIndex<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>): number {
- return firstIntersectionIndexFrom(ranges, set, 0);
- }
- export function firstIntersectionIndexFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number): number {
- if (minAt(ranges, from) > OrderedSet.max(set) || max(ranges) < OrderedSet.min(set)) return -1;
- for (let i = from, il = count(ranges); i < il; ++i) {
- const interval = Interval.ofRange(minAt(ranges, i), maxAt(ranges, i));
- if (OrderedSet.areIntersecting(interval, set)) return i;
- }
- return -1;
- }
- export function transientSegments<T extends number = number, I extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
- return new Iterator<T, I>(ranges, set);
- }
- export class Iterator<T extends number = number, I extends number = number> implements _Iterator<Segmentation.Segment<I>> {
- private value: Segmentation.Segment<I> = { index: 0 as I, start: 0 as T, end: 0 as T }
- private curIndex = 0
- hasNext: boolean = false;
- private updateValue() {
- this.value.index = this.curIndex as I;
- this.value.start = OrderedSet.findPredecessorIndex(this.set, startAt(this.ranges, this.curIndex));
- this.value.end = OrderedSet.findPredecessorIndex(this.set, endAt(this.ranges, this.curIndex));
- }
- move() {
- if (this.hasNext) {
- this.updateValue();
- this.curIndex = firstIntersectionIndexFrom(this.ranges, this.set, this.curIndex + 1);
- this.hasNext = this.curIndex !== -1;
- }
- return this.value;
- }
- constructor(private ranges: SortedRanges<T>, private set: OrderedSet<T>) {
- this.curIndex = firstIntersectionIndex(ranges, set);
- this.hasNext = this.curIndex !== -1;
- }
- }
- }
- export default SortedRanges;
|