sorted-ranges.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Segmentation, OrderedSet, SortedArray, Interval } from '../int';
  7. import _Iterator from '../iterator';
  8. /** Pairs of min and max indices of sorted, non-overlapping ranges */
  9. type SortedRanges<T extends number = number> = SortedArray<T>
  10. namespace SortedRanges {
  11. export function ofSortedRanges<T extends number = number>(array: ArrayLike<T>) { return SortedArray.ofSortedArray<T>(array); }
  12. export function start<T extends number = number>(ranges: SortedRanges<T>) { return ranges[0]; }
  13. export function end<T extends number = number>(ranges: SortedRanges<T>) { return ranges[ranges.length - 1] + 1; }
  14. export function min<T extends number = number>(ranges: SortedRanges<T>) { return ranges[0]; }
  15. export function max<T extends number = number>(ranges: SortedRanges<T>) { return ranges[ranges.length - 1]; }
  16. export function size<T extends number = number>(ranges: SortedRanges<T>) {
  17. let size = 0;
  18. for (let i = 0, il = ranges.length; i < il; i += 2) {
  19. size += ranges[i + 1] - ranges[i] + 1;
  20. }
  21. return size;
  22. }
  23. export function count<T extends number = number>(ranges: SortedRanges<T>) { return ranges.length / 2; }
  24. export function startAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
  25. return ranges[index * 2];
  26. }
  27. export function endAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
  28. return ranges[index * 2 + 1] + 1;
  29. }
  30. export function minAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
  31. return ranges[index * 2];
  32. }
  33. export function maxAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
  34. return ranges[index * 2 + 1];
  35. }
  36. export function areEqual<T extends number = number>(a: SortedRanges<T>, b: SortedRanges<T>) {
  37. if (a.length !== b.length) return false;
  38. for (let i = 0, il = a.length; i < il; ++i) {
  39. if (a[i] !== b[i]) return false;
  40. }
  41. return true;
  42. }
  43. export function forEach<T extends number = number>(ranges: SortedRanges<T>, f: (value: T, i: number) => void) {
  44. let k = 0;
  45. for (let i = 0, il = ranges.length; i < il; i += 2) {
  46. for (let j = ranges[i], jl = ranges[i + 1]; j <= jl; ++j) {
  47. f(j, k);
  48. ++k;
  49. }
  50. }
  51. }
  52. /** Returns if a value of `set` is included in `ranges` */
  53. export function has<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
  54. return firstIntersectionIndex(ranges, set) !== -1;
  55. }
  56. /** Returns if a value of `set` is included in `ranges` from given index */
  57. export function hasFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number) {
  58. return firstIntersectionIndexFrom(ranges, set, from) !== -1;
  59. }
  60. export function firstIntersectionIndex<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>): number {
  61. return firstIntersectionIndexFrom(ranges, set, 0);
  62. }
  63. export function firstIntersectionIndexFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number): number {
  64. if (minAt(ranges, from) > OrderedSet.max(set) || max(ranges) < OrderedSet.min(set)) return -1;
  65. for (let i = from, il = count(ranges); i < il; ++i) {
  66. const interval = Interval.ofRange(minAt(ranges, i), maxAt(ranges, i));
  67. if (OrderedSet.areIntersecting(interval, set)) return i;
  68. }
  69. return -1;
  70. }
  71. export function transientSegments<T extends number = number, I extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
  72. return new Iterator<T, I>(ranges, set);
  73. }
  74. export class Iterator<T extends number = number, I extends number = number> implements _Iterator<Segmentation.Segment<I>> {
  75. private value: Segmentation.Segment<I> = { index: 0 as I, start: 0 as T, end: 0 as T }
  76. private curIndex = 0
  77. hasNext: boolean = false;
  78. private updateValue() {
  79. this.value.index = this.curIndex as I;
  80. this.value.start = OrderedSet.findPredecessorIndex(this.set, startAt(this.ranges, this.curIndex));
  81. this.value.end = OrderedSet.findPredecessorIndex(this.set, endAt(this.ranges, this.curIndex));
  82. }
  83. move() {
  84. if (this.hasNext) {
  85. this.updateValue();
  86. this.curIndex = firstIntersectionIndexFrom(this.ranges, this.set, this.curIndex + 1);
  87. this.hasNext = this.curIndex !== -1;
  88. }
  89. return this.value;
  90. }
  91. constructor(private ranges: SortedRanges<T>, private set: OrderedSet<T>) {
  92. this.curIndex = firstIntersectionIndex(ranges, set);
  93. this.hasNext = this.curIndex !== -1;
  94. }
  95. }
  96. }
  97. export default SortedRanges;