11import { printTree } from 'tree-dump/lib/printTree' ;
22import { printBinary } from 'tree-dump/lib/printBinary' ;
33import { first , insertLeft , insertRight , last , next , prev , remove } from 'sonic-forest/lib/util' ;
4+ import { first2 , insert2 , next2 , remove2 } from 'sonic-forest/lib/util2' ;
45import { splay } from 'sonic-forest/lib/splay/util' ;
56import { Anchor } from '../rga/constants' ;
67import { Point } from '../rga/Point' ;
@@ -19,6 +20,9 @@ import type {Printable} from 'tree-dump/lib/types';
1920import type { MutableSlice , Slice } from '../slice/types' ;
2021import type { Slices } from '../slice/Slices' ;
2122import type { OverlayPair , OverlayTuple } from './types' ;
23+ import type { Comparator } from 'sonic-forest/lib/types' ;
24+
25+ const spatialComparator : Comparator < OverlayPoint > = ( a : OverlayPoint , b : OverlayPoint ) => a . cmpSpatial ( b ) ;
2226
2327/**
2428 * Overlay is a tree structure that represents all the intersections of slices
@@ -29,6 +33,7 @@ import type {OverlayPair, OverlayTuple} from './types';
2933 */
3034export class Overlay < T = string > implements Printable , Stateful {
3135 public root : OverlayPoint < T > | undefined = undefined ;
36+ public root2 : MarkerOverlayPoint < T > | undefined = undefined ;
3237
3338 /** A virtual absolute start point, used when the absolute start is missing. */
3439 public readonly START : OverlayPoint < T > ;
@@ -110,15 +115,7 @@ export class Overlay<T = string> implements Printable, Stateful {
110115 return result ;
111116 }
112117
113- public find ( predicate : ( point : OverlayPoint < T > ) => boolean ) : OverlayPoint < T > | undefined {
114- let point = this . first ( ) ;
115- while ( point ) {
116- if ( predicate ( point ) ) return point ;
117- point = next ( point ) ;
118- }
119- return ;
120- }
121-
118+ /** @todo Rename to `chunks()`. */
122119 public chunkSlices0 (
123120 chunk : Chunk < T > | undefined ,
124121 p1 : Point < T > ,
@@ -179,20 +176,17 @@ export class Overlay<T = string> implements Printable, Stateful {
179176 return new UndefEndIter ( this . points0 ( after ) ) ;
180177 }
181178
182- public markers0 ( ) : UndefIterator < MarkerOverlayPoint < T > > {
183- let curr = this . first ( ) ;
179+ public markers0 ( after : undefined | MarkerOverlayPoint < T > ) : UndefIterator < MarkerOverlayPoint < T > > {
180+ let curr = after ? next2 ( after ) : first2 ( this . root2 ) ;
184181 return ( ) => {
185- while ( curr ) {
186- const ret = curr ;
187- if ( curr ) curr = next ( curr ) ;
188- if ( ret instanceof MarkerOverlayPoint ) return ret ;
189- }
190- return ;
182+ const ret = curr ;
183+ if ( curr ) curr = next2 ( curr ) ;
184+ return ret ;
191185 } ;
192186 }
193187
194188 public markers ( ) : IterableIterator < MarkerOverlayPoint < T > > {
195- return new UndefEndIter ( this . markers0 ( ) ) ;
189+ return new UndefEndIter ( this . markers0 ( undefined ) ) ;
196190 }
197191
198192 public pairs0 ( after : undefined | OverlayPoint < T > ) : UndefIterator < OverlayPair < T > > {
@@ -245,6 +239,31 @@ export class Overlay<T = string> implements Printable, Stateful {
245239 return new UndefEndIter ( this . tuples0 ( after ) ) ;
246240 }
247241
242+ /**
243+ * Finds the first point that satisfies the given predicate function.
244+ *
245+ * @param predicate Predicate function to find the point, returns true if the
246+ * point is found.
247+ * @returns The first point that satisfies the predicate, or undefined if no
248+ * point is found.
249+ */
250+ public find ( predicate : ( point : OverlayPoint < T > ) => boolean ) : OverlayPoint < T > | undefined {
251+ let point = this . first ( ) ;
252+ while ( point ) {
253+ if ( predicate ( point ) ) return point ;
254+ point = next ( point ) ;
255+ }
256+ return ;
257+ }
258+
259+ /**
260+ * Finds all slices that are contained within the given range. A slice is
261+ * considered contained if its start and end points are within the range,
262+ * inclusive (uses {@link Range#contains} method to check containment).
263+ *
264+ * @param range The range to search for contained slices.
265+ * @returns A set of slices that are contained within the given range.
266+ */
248267 public findContained ( range : Range < T > ) : Set < Slice < T > > {
249268 const result = new Set < Slice < T > > ( ) ;
250269 let point = this . getOrNextLower ( range . start ) ;
@@ -265,6 +284,14 @@ export class Overlay<T = string> implements Printable, Stateful {
265284 return result ;
266285 }
267286
287+ /**
288+ * Finds all slices that overlap with the given range. A slice is considered
289+ * overlapping if its start or end point is within the range, inclusive
290+ * (uses {@link Range#containsPoint} method to check overlap).
291+ *
292+ * @param range The range to search for overlapping slices.
293+ * @returns A set of slices that overlap with the given range.
294+ */
268295 public findOverlapping ( range : Range < T > ) : Set < Slice < T > > {
269296 const result = new Set < Slice < T > > ( ) ;
270297 let point = this . getOrNextLower ( range . start ) ;
@@ -281,12 +308,16 @@ export class Overlay<T = string> implements Printable, Stateful {
281308 return result ;
282309 }
283310
284- public isBlockSplit ( id : ITimestampStruct ) : boolean {
285- const point = this . txt . point ( id , Anchor . Before ) ;
286- const overlayPoint = this . getOrNextLower ( point ) ;
287- return (
288- overlayPoint instanceof MarkerOverlayPoint && overlayPoint . id . time === id . time && overlayPoint . id . sid === id . sid
289- ) ;
311+ /**
312+ * Returns `true` if the current character is a marker sentinel.
313+ *
314+ * @param id ID of the point to check.
315+ * @returns Whether the point is a marker point.
316+ */
317+ public isMarker ( id : ITimestampStruct ) : boolean {
318+ const p = this . txt . point ( id , Anchor . Before ) ;
319+ const op = this . getOrNextLower ( p ) ;
320+ return op instanceof MarkerOverlayPoint && op . id . time === id . time && op . id . sid === id . sid ;
290321 }
291322
292323 // ----------------------------------------------------------------- Stateful
@@ -299,7 +330,12 @@ export class Overlay<T = string> implements Printable, Stateful {
299330 hash = this . refreshSlices ( hash , txt . savedSlices ) ;
300331 hash = this . refreshSlices ( hash , txt . extraSlices ) ;
301332 hash = this . refreshSlices ( hash , txt . localSlices ) ;
302- if ( ! slicesOnly ) this . computeSplitTextHashes ( ) ;
333+
334+ // TODO: Move test hash calculation out of the overlay.
335+ if ( ! slicesOnly ) {
336+ // hash = updateRga(hash, txt.str);
337+ hash = this . refreshTextSlices ( hash ) ;
338+ }
303339 return ( this . hash = hash ) ;
304340 }
305341
@@ -339,7 +375,6 @@ export class Overlay<T = string> implements Printable, Stateful {
339375 }
340376
341377 private insSlice ( slice : Slice < T > ) : [ start : OverlayPoint < T > , end : OverlayPoint < T > ] {
342- // TODO: Test cases where the inserted slice is collapsed to one point.
343378 const x0 = slice . start ;
344379 const x1 = slice . end ;
345380 const [ start , isStartNew ] = this . upsertPoint ( x0 ) ;
@@ -359,10 +394,7 @@ export class Overlay<T = string> implements Printable, Stateful {
359394 let curr : OverlayPoint < T > | undefined = start ;
360395 do curr . addLayer ( slice ) ;
361396 while ( ( curr = next ( curr ) ) && curr !== end ) ;
362- } else {
363- // TODO: review if this is needed:
364- start . addMarker ( slice ) ;
365- }
397+ } else start . addMarker ( slice ) ;
366398 return [ start , end ] ;
367399 }
368400
@@ -408,6 +440,10 @@ export class Overlay<T = string> implements Printable, Stateful {
408440 * @returns Returns the existing point if it was already in the tree.
409441 */
410442 private insPoint ( point : OverlayPoint < T > ) : OverlayPoint < T > | undefined {
443+ if ( point instanceof MarkerOverlayPoint ) {
444+ this . root2 = insert2 ( this . root2 , point , spatialComparator ) ;
445+ // if (this.root2 !== point) this.root2 = splay2(this.root2!, point, 10);
446+ }
411447 let pivot = this . getOrNextLower ( point ) ;
412448 if ( ! pivot ) pivot = first ( this . root ) ;
413449 if ( ! pivot ) {
@@ -424,23 +460,23 @@ export class Overlay<T = string> implements Printable, Stateful {
424460 }
425461
426462 private delPoint ( point : OverlayPoint < T > ) : void {
463+ if ( point instanceof MarkerOverlayPoint ) this . root2 = remove2 ( this . root2 , point ) ;
427464 this . root = remove ( this . root , point ) ;
428465 }
429466
430467 public leadingTextHash : number = 0 ;
431468
432- protected computeSplitTextHashes ( ) : void {
469+ protected refreshTextSlices ( stateTotal : number ) : number {
433470 const txt = this . txt ;
434471 const str = txt . str ;
435472 const firstChunk = str . first ( ) ;
436- if ( ! firstChunk ) return ;
473+ if ( ! firstChunk ) return stateTotal ;
437474 let chunk : Chunk < T > | undefined = firstChunk ;
438475 let marker : MarkerOverlayPoint < T > | undefined = undefined ;
439- let state : number = CONST . START_STATE ;
440476 const i = this . tuples0 ( undefined ) ;
477+ let state : number = CONST . START_STATE ;
441478 for ( let pair = i ( ) ; pair ; pair = i ( ) ) {
442479 const [ p1 , p2 ] = pair ;
443- // TODO: need to incorporate slice attribute hash here?
444480 const id1 = p1 . id ;
445481 state = ( state << 5 ) + state + ( id1 . sid >>> 0 ) + id1 . time ;
446482 let overlayPointHash = CONST . START_STATE ;
@@ -450,15 +486,15 @@ export class Overlay<T = string> implements Printable, Stateful {
450486 ( overlayPointHash << 5 ) + overlayPointHash + ( ( ( ( id . sid >>> 0 ) + id . time ) << 8 ) + ( off << 4 ) + len ) ;
451487 } ) ;
452488 state = updateNum ( state , overlayPointHash ) ;
453- if ( p1 ) {
454- p1 . hash = overlayPointHash ;
455- }
489+ p1 . hash = overlayPointHash ;
490+ stateTotal = updateNum ( stateTotal , overlayPointHash ) ;
456491 if ( p2 instanceof MarkerOverlayPoint ) {
457492 if ( marker ) {
458493 marker . textHash = state ;
459494 } else {
460495 this . leadingTextHash = state ;
461496 }
497+ stateTotal = updateNum ( stateTotal , state ) ;
462498 state = CONST . START_STATE ;
463499 marker = p2 ;
464500 }
@@ -468,6 +504,7 @@ export class Overlay<T = string> implements Printable, Stateful {
468504 } else {
469505 this . leadingTextHash = state ;
470506 }
507+ return stateTotal ;
471508 }
472509
473510 // ---------------------------------------------------------------- Printable
@@ -482,9 +519,21 @@ export class Overlay<T = string> implements Printable, Stateful {
482519 ] )
483520 ) ;
484521 } ;
522+ const printMarkerPoint = ( tab : string , point : MarkerOverlayPoint < T > ) : string => {
523+ return (
524+ point . toString ( tab ) +
525+ printBinary ( tab , [
526+ ! point . l2 ? null : ( tab ) => printMarkerPoint ( tab , point . l2 ! ) ,
527+ ! point . r2 ? null : ( tab ) => printMarkerPoint ( tab , point . r2 ! ) ,
528+ ] )
529+ ) ;
530+ } ;
485531 return (
486532 `${ this . constructor . name } #${ this . hash . toString ( 36 ) } ` +
487- printTree ( tab , [ ! this . root ? null : ( tab ) => printPoint ( tab , this . root ! ) ] )
533+ printTree ( tab , [
534+ ! this . root ? null : ( tab ) => printPoint ( tab , this . root ! ) ,
535+ ! this . root2 ? null : ( tab ) => printMarkerPoint ( tab , this . root2 ! ) ,
536+ ] )
488537 ) ;
489538 }
490539}
0 commit comments