@@ -15,42 +15,75 @@ export default class IntervalSet {
1515 return this . #intervals[ Symbol . iterator ] ( ) ;
1616 }
1717
18- has ( interval : Interval ) {
19- return this . #intervals. some ( ( existing ) => existing . contains ( interval ) ) ;
18+ #findFirstWhere( predicate : ( interval : Interval ) => boolean ) {
19+ let left = 0 , right = this . #intervals. length ;
20+ while ( left < right ) {
21+ const middle = Math . floor ( ( left + right ) / 2 ) ;
22+ if ( predicate ( this . #intervals[ middle ] ) ) {
23+ right = middle ;
24+ } else {
25+ left = middle + 1 ;
26+ }
27+ }
28+ return left ;
2029 }
2130
22- #compareIntervalsTo( other : Interval ) {
23- const { [ - 1 ] : lower = [ ] , [ 0 ] : contiguous = [ ] , [ 1 ] : upper = [ ] } = Object
24- . groupBy ( this . #intervals, ( interval ) => Math . sign ( other . gapTo ( interval ) ) ) ;
25- return { lower, contiguous, upper } ;
31+ has ( interval : Interval ) {
32+ let left = 0 , right = this . #intervals. length - 1 ;
33+ while ( left <= right ) {
34+ const middle = Math . floor ( ( left + right ) / 2 ) ;
35+ const existing = this . #intervals[ middle ] ;
36+ if ( existing . upper < interval . lower ) {
37+ left = middle + 1 ;
38+ } else if ( existing . lower > interval . upper ) {
39+ right = middle - 1 ;
40+ } else if ( existing . contains ( interval ) ) {
41+ return true ;
42+ } else if ( existing . upper < interval . upper ) {
43+ left = middle + 1 ;
44+ } else {
45+ right = middle - 1 ;
46+ }
47+ }
48+ return false ;
2649 }
2750
2851 add ( interval : Interval ) {
29- const { lower, contiguous, upper } = this . #compareIntervalsTo( interval ) ;
30- if ( contiguous . length === 0 ) {
31- this . #intervals = [ ...lower , interval , ...upper ] ;
52+ const start = this . #findFirstWhere( ( i ) => i . upper >= interval . lower - 1 ) ;
53+ let end = start ;
54+ while (
55+ end < this . #intervals. length &&
56+ this . #intervals[ end ] . lower <= interval . upper + 1
57+ ) end ++ ;
58+ if ( start === end ) {
59+ this . #intervals. splice ( start , 0 , interval ) ;
3260 return ;
3361 }
3462 const mergedInterval = new Interval (
35- Math . min ( interval . lower , contiguous [ 0 ] . lower ) ,
36- Math . max ( interval . upper , contiguous [ contiguous . length - 1 ] . upper ) ,
63+ Math . min ( interval . lower , this . #intervals [ start ] . lower ) ,
64+ Math . max ( interval . upper , this . #intervals [ end - 1 ] . upper ) ,
3765 ) ;
38- this . #intervals = [ ... lower , mergedInterval , ... upper ] ;
66+ this . #intervals. splice ( start , end - start , mergedInterval ) ;
3967 }
4068
4169 delete ( interval : Interval ) {
42- const { lower, contiguous, upper } = this . #compareIntervalsTo( interval ) ;
43- if ( contiguous . length === 0 ) return ;
70+ const start = this . #findFirstWhere( ( i ) => i . upper >= interval . lower ) ;
71+ let end = start ;
72+ while (
73+ end < this . #intervals. length &&
74+ this . #intervals[ end ] . lower <= interval . upper
75+ ) end ++ ;
76+ if ( start === end ) return ;
4477 const newIntervals : Interval [ ] = [ ] ;
45- const first = contiguous [ 0 ] ;
78+ const first = this . #intervals [ start ] ;
4679 if ( first . lower < interval . lower ) {
4780 newIntervals . push ( new Interval ( first . lower , interval . lower - 1 ) ) ;
4881 }
49- const last = contiguous [ contiguous . length - 1 ] ;
82+ const last = this . #intervals [ end - 1 ] ;
5083 if ( last . upper > interval . upper ) {
5184 newIntervals . push ( new Interval ( interval . upper + 1 , last . upper ) ) ;
5285 }
53- this . #intervals = [ ... lower , ... newIntervals , ...upper ] ;
86+ this . #intervals. splice ( start , end - start , ...newIntervals ) ;
5487 }
5588
5689 difference ( other : IntervalSet ) {
0 commit comments