Skip to content
Snippets Groups Projects
Commit fa4d8a20 authored by Alexander Rose's avatar Alexander Rose
Browse files

added SortedRanges transient segments iterator

parent 076497bb
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import SortedRanges from '../sorted-ranges'
import OrderedSet from '../ordered-set';
import SortedArray from '../sorted-array';
describe('rangesArray', () => {
function test(name: string, a: any, b: any) {
it(name, () => expect(a).toEqual(b));
}
function testIterator(name: string, ranges: SortedRanges, set: OrderedSet, expectedValues: { index: number[], start: number[], end: number[]}) {
it(`iterator, ${name}`, () => {
const rangesIt = SortedRanges.transientSegments(ranges, set)
const { index, start, end } = expectedValues
let i = 0
while (rangesIt.hasNext) {
const segment = rangesIt.move()
expect(segment.index).toBe(index[i])
expect(segment.start).toBe(start[i])
expect(segment.end).toBe(end[i])
++i
}
expect(i).toBe(index.length)
})
}
const a1234 = SortedRanges.ofSortedRanges([1, 2, 3, 4]);
const a1134 = SortedRanges.ofSortedRanges([1, 1, 3, 4]);
test('size', SortedRanges.size(a1234), 4);
test('size', SortedRanges.size(a1134), 3);
test('min/max', [SortedRanges.min(a1234), SortedRanges.max(a1234)], [1, 4]);
test('start/end', [SortedRanges.start(a1234), SortedRanges.end(a1234)], [1, 5]);
testIterator('two ranges',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
OrderedSet.ofBounds(1, 4),
{ index: [0, 1], start: [0, 2], end: [2, 4] }
)
testIterator('first range',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
SortedArray.ofSortedArray([2]),
{ index: [0], start: [0], end: [1] }
)
testIterator('second range',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
SortedArray.ofSortedArray([4]),
{ index: [1], start: [0], end: [1] }
)
testIterator('set not in ranges',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
SortedArray.ofSortedArray([10]),
{ index: [], start: [], end: [] }
)
testIterator('set in second range and beyond',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
SortedArray.ofSortedArray([3, 10]),
{ index: [1], start: [0], end: [2] }
)
testIterator('length 1 range',
SortedRanges.ofSortedRanges([1, 1, 3, 4]),
SortedArray.ofSortedArray([0, 1, 10]),
{ index: [0], start: [1], end: [2] }
)
});
\ No newline at end of file
/**
* Copyright (c) 2018 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 transientSegments<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
return new Iterator<T>(ranges, set)
}
export class Iterator<T extends number = number> implements _Iterator<Segmentation.Segment<T>> {
private value: Segmentation.Segment<T> = { index: 0, start: 0 as T, end: 0 as T }
private curIndex = 0
private maxIndex = 0
private interval: Interval<T>
private curMin: T = 0 as T
hasNext: boolean = false;
updateInterval() {
this.interval = Interval.ofRange(this.ranges[this.curIndex], this.ranges[this.curIndex + 1])
}
updateValue() {
this.value.index = this.curIndex / 2
this.value.start = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex]) as T
this.value.end = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex + 1]) + 1 as T
}
move() {
if (this.hasNext) {
this.updateValue()
while (this.curIndex <= this.maxIndex) {
this.curIndex += 2
this.curMin = Interval.end(this.interval)
this.updateInterval()
if (Interval.min(this.interval) >= this.curMin && OrderedSet.areIntersecting(this.interval, this.set)) break
}
this.hasNext = this.curIndex <= this.maxIndex
}
return this.value;
}
getRangeIndex(value: number) {
const index = SortedArray.findPredecessorIndex(this.ranges, value)
return (index % 2 === 1) ? index - 1 : index
}
constructor(private ranges: SortedRanges<T>, private set: OrderedSet<T>) {
if (ranges.length) {
this.curIndex = this.getRangeIndex(OrderedSet.min(set))
this.maxIndex = Math.min(ranges.length - 2, this.getRangeIndex(OrderedSet.max(set)))
this.curMin = this.ranges[this.curIndex]
this.updateInterval()
}
this.hasNext = ranges.length > 0 && this.curIndex <= this.maxIndex
}
}
}
export default SortedRanges
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment