From 39e5c3a1e079cb1cafebce3c6395e00913075c63 Mon Sep 17 00:00:00 2001 From: Jordan Baker Date: Fri, 19 Jan 2024 13:28:37 -0700 Subject: [PATCH] add a IntervalHashSet --- src/IntervalSet.ts | 11 +++++++++-- src/IntervalTree.ts | 17 +++++++++-------- src/Node.ts | 24 +++++++++++------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/IntervalSet.ts b/src/IntervalSet.ts index f5f5360..96a1b83 100644 --- a/src/IntervalSet.ts +++ b/src/IntervalSet.ts @@ -1,6 +1,13 @@ -import { SortedSet } from '@rimbu/core' +import { HashSet, Hasher, SortedSet } from '@rimbu/core' import { Interval } from './Interval' +/** + * A HashSet of Intervals. + */ +export const IntervalHashSet = HashSet.createContext({ + hasher: Hasher.anyDeepHasher(), // deep so it should also hash the data part +}) + export const compareIntervals = (a: Interval, b: Interval) => { return ( a.start - b.start || @@ -12,7 +19,7 @@ export const compareIntervals = (a: Interval, b: Interval) => { /** * A SortedSet of Intervals. */ -export const IntervalSet = SortedSet.createContext({ +export const IntervalSortedSet = SortedSet.createContext({ comp: { compare: compareIntervals, isComparable(obj): obj is Interval { diff --git a/src/IntervalTree.ts b/src/IntervalTree.ts index 42b565c..7866ed8 100644 --- a/src/IntervalTree.ts +++ b/src/IntervalTree.ts @@ -7,8 +7,9 @@ import { debug } from './debug' import { Node } from './Node' import { Interval } from './Interval' import { SortedMap, HashSet } from '@rimbu/core' -import { IntervalSet } from './IntervalSet' +import { IntervalSortedSet } from './IntervalSet' import { IntervalTuples } from './types' +import { IntervalHashSet } from './IntervalSet' export class IntervalTree { public allIntervals: HashSet @@ -88,7 +89,7 @@ export class IntervalTree { */ public chop(start: number, end: number): void { assert(start < end, 'start must be <= end') - const insertionsBuilder = HashSet.builder() + const insertionsBuilder = IntervalHashSet.builder() const startHits = this.search(start).filter((iv) => iv.start < start) const endHits = this.search(end).filter((iv) => iv.end > end) startHits.forEach((iv) => { @@ -115,7 +116,7 @@ export class IntervalTree { chopAll(intervals: [number, number][]) { intervals.forEach(([start, end]) => { - const insertionsBuilder = HashSet.builder() + const insertionsBuilder = IntervalHashSet.builder() const startHits = this.search(start).filter((iv) => iv.start < start) const endHits = this.search(end).filter((iv) => iv.end > end) startHits.forEach((iv) => { @@ -217,7 +218,7 @@ badInterval=${iv} } public toString() { - const sortedIntervals = IntervalSet.from(this.allIntervals) + const sortedIntervals = IntervalSortedSet.from(this.allIntervals) return `IntervalTree([ ${sortedIntervals.toArray().join(', ')} ])` } @@ -236,7 +237,7 @@ badInterval=${iv} merged.push(higher) } - const sortedIntervals = IntervalSet.from(this.allIntervals) + const sortedIntervals = IntervalSortedSet.from(this.allIntervals) sortedIntervals.forEach((higher) => { if (!merged.length) { newSeries(higher) @@ -277,9 +278,9 @@ badInterval=${iv} strict = false ): HashSet { if (!this.topNode) { - return HashSet.empty() + return IntervalHashSet.empty() } - const resultBuilder = HashSet.builder() + const resultBuilder = IntervalHashSet.builder() if (end === undefined) { return this.topNode.searchPoint(start, resultBuilder).build() } @@ -402,7 +403,7 @@ badInterval=${iv} } private initialize(intervals: Interval[] = []) { - this.allIntervals = HashSet.from(intervals) + this.allIntervals = IntervalHashSet.from(intervals) this.topNode = Node.fromIntervals(intervals)! this.boundaryTable = SortedMap.empty() this.addBoundariesAll(intervals) diff --git a/src/Node.ts b/src/Node.ts index c71c208..90a77e2 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,7 +1,7 @@ import assert from 'assert' import { Interval } from './Interval' -import { compareIntervals } from './IntervalSet' +import { IntervalHashSet, compareIntervals } from './IntervalSet' import { HashSet } from '@rimbu/core' import { debug } from './debug' @@ -23,7 +23,9 @@ export class Node { balance = 0 ) { this.xCenter = xCenter - this.sCenter = Array.isArray(sCenter) ? HashSet.from(sCenter) : sCenter + this.sCenter = Array.isArray(sCenter) + ? IntervalHashSet.from(sCenter) + : sCenter this.leftNode = leftNode ?? null this.rightNode = rightNode ?? null // depth & balance are set when rotated @@ -246,15 +248,11 @@ export class Node { public searchPoint(point: number, resultBuilder: HashSet.Builder) { // Returns all intervals that contain point. - // debug('searchPoint: point=', point, this.toString()) - // debug('searchPoint: result=', resultBuilder.toString()) - this.sCenter.forEach((interval) => { - // debug('searchPoint: interval=', interval) - if (interval.start <= point && point < interval.end) { - // debug('searchPoint interval', interval) - resultBuilder.add(interval) - } - }) + resultBuilder.addAll( + this.sCenter.filter( + (interval) => interval.start <= point && point < interval.end + ) + ) if (point < this.xCenter && this.getBranch(0)) { this.getBranch(0).searchPoint(point, resultBuilder) } else if (point > this.xCenter && this.getBranch(1)) { @@ -264,7 +262,7 @@ export class Node { } public searchOverlap(pointList: number[]): HashSet { - const resultBuilder = HashSet.builder() + const resultBuilder = IntervalHashSet.builder() for (const point of pointList) { this.searchPoint(point, resultBuilder) } @@ -515,7 +513,7 @@ export class Node { } public allChildren(): HashSet { - return this.allChildrenHelper(HashSet.empty()) + return this.allChildrenHelper(IntervalHashSet.empty()) } private allChildrenHelper(result: HashSet): HashSet {