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

improved sorted-ranges and docs

parent 1d502cbb
No related branches found
No related tags found
No related merge requests found
......@@ -65,6 +65,11 @@ export function areEqual(a: Nums, b: Nums) {
return true;
}
/**
* Returns 0 if `v` is smaller or equal the first element of `xs`
* Returns length of `xs` if `v` is bigger than the last element of `xs`
* Otherwise returns the first index where the value of `xs` is equal or bigger than `v`
*/
export function findPredecessorIndex(xs: Nums, v: number) {
const len = xs.length;
if (v <= xs[0]) return 0;
......
......@@ -41,6 +41,11 @@ namespace OrderedSet {
/** Returns elements of `a` that are not in `b`, i.e `a` - `b` */
export const subtract: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.subtract as any;
/**
* Returns 0 if `x` is smaller or equal the first element of `set`
* Returns length of `set` if `x` is bigger than the last element of `set`
* Otherwise returns the first index where the value of `set` is equal or bigger than `x`
*/
export const findPredecessorIndex: <T extends number = number>(set: OrderedSet<T>, x: number) => number = Base.findPredecessorIndex as any;
export const findPredecessorIndexInInterval: <T extends number = number>(set: OrderedSet<T>, x: T, range: Interval) => number = Base.findPredecessorIndexInInterval as any;
export const findRange: <T extends number = number>(set: OrderedSet<T>, min: T, max: T) => Interval = Base.findRange as any;
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
......@@ -23,6 +23,46 @@ namespace SortedRanges {
}
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]
}
/** 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)
......@@ -32,52 +72,27 @@ namespace SortedRanges {
private value: Segmentation.Segment<I> = { index: 0 as I, 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;
private updateInterval() {
this.interval = Interval.ofRange(this.ranges[this.curIndex], this.ranges[this.curIndex + 1])
}
private updateValue() {
this.value.index = this.curIndex / 2 as I
this.value.start = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex])
this.value.end = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex + 1])
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()
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
this.curIndex = firstIntersectionIndexFrom(this.ranges, this.set, this.curIndex + 1)
this.hasNext = this.curIndex !== -1
}
return this.value;
}
private 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>) {
const min = OrderedSet.min(set)
const max = OrderedSet.max(set)
const b = ranges.length > 0 && ranges[0] <= max && ranges[ranges.length - 1] >= min
if (b) {
this.curIndex = this.getRangeIndex(min)
this.maxIndex = Math.min(ranges.length - 2, this.getRangeIndex(max) + 2)
this.curMin = ranges[this.curIndex]
this.updateInterval()
}
this.hasNext = b && this.curIndex <= this.maxIndex
this.curIndex = firstIntersectionIndex(ranges, set)
this.hasNext = this.curIndex !== -1
}
}
}
......
......@@ -166,6 +166,7 @@ namespace StructureElement {
return Loci(structure, elements);
}
/** Create union of `xs` and `ys` */
export function union(xs: Loci, ys: Loci): Loci {
if (xs.elements.length > ys.elements.length) return union(ys, xs);
if (xs.elements.length === 0) return ys;
......@@ -191,6 +192,7 @@ namespace StructureElement {
return Loci(xs.structure, elements);
}
/** Subtract `ys` from `xs` */
export function subtract(xs: Loci, ys: Loci): Loci {
const map = new Map<number, OrderedSet<UnitIndex>>();
for (const e of ys.elements) map.set(e.unit.id, e.indices);
......
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