diff --git a/src/mol-data/util/_spec/interval-iterator.spec.ts b/src/mol-data/util/_spec/interval-iterator.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..078d63a3cb3545132093493cb88414d9ae045038 --- /dev/null +++ b/src/mol-data/util/_spec/interval-iterator.spec.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Interval, OrderedSet, SortedArray } from '../../int'; +import { IntervalIterator } from '../interval-iterator'; + + describe('interval', () => { + function testIterator(name: string, interval: Interval, set: OrderedSet, expectedValues: { index: number[], start: number[], end: number[]}) { + it(`iterator, ${name}`, () => { + const intervalIt = new IntervalIterator(interval, set) + const { index, start, end } = expectedValues + + let i = 0 + while (intervalIt.hasNext) { + const segment = intervalIt.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) + }) + } + + testIterator('basic', + Interval.ofRange(0, 5), + SortedArray.ofSortedArray([1, 3, 7, 8]), + { index: [1, 3], start: [0, 1], end: [1, 2] } + ) +}); \ No newline at end of file diff --git a/src/mol-data/util/interval-iterator.ts b/src/mol-data/util/interval-iterator.ts new file mode 100644 index 0000000000000000000000000000000000000000..8174a23f9b77f47941b0ab8f46ea2a8ea30d5830 --- /dev/null +++ b/src/mol-data/util/interval-iterator.ts @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + + import Iterator from '../iterator' +import { OrderedSet, Interval, Segmentation } from '../int'; + +/** Emits a segment of length one for each element in the interval that is also in the set */ +export class IntervalIterator<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 + + hasNext: boolean = false; + + updateValue() { + this.value.index = this.curIndex + this.value.start = OrderedSet.findPredecessorIndex(this.set, Interval.getAt(this.interval, this.curIndex)) as T + this.value.end = this.value.start + 1 as T + } + + move() { + if (this.hasNext) { + this.updateValue() + while (this.curIndex <= this.maxIndex) { + ++this.curIndex + if (OrderedSet.has(this.set, this.curIndex)) break + } + this.hasNext = this.curIndex <= this.maxIndex + } + return this.value; + } + + constructor(private interval: Interval<T>, private set: OrderedSet<T>) { + if (Interval.size(interval)) { + this.curIndex = Interval.findPredecessorIndex(interval, OrderedSet.min(set)) + this.maxIndex = Interval.findPredecessorIndex(interval, OrderedSet.max(set)) + } + + this.hasNext = OrderedSet.areIntersecting(this.interval, this.set) + } +} \ No newline at end of file