1
1
import { printTree } from 'tree-dump/lib/printTree' ;
2
2
import { printBinary } from 'tree-dump/lib/printBinary' ;
3
3
import { first , insertLeft , insertRight , last , next , prev , remove } from 'sonic-forest/lib/util' ;
4
+ import { first2 , insert2 , next2 , remove2 } from 'sonic-forest/lib/util2' ;
4
5
import { splay } from 'sonic-forest/lib/splay/util' ;
5
6
import { Anchor } from '../rga/constants' ;
6
7
import { Point } from '../rga/Point' ;
@@ -19,6 +20,9 @@ import type {Printable} from 'tree-dump/lib/types';
19
20
import type { MutableSlice , Slice } from '../slice/types' ;
20
21
import type { Slices } from '../slice/Slices' ;
21
22
import 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 ) ;
22
26
23
27
/**
24
28
* Overlay is a tree structure that represents all the intersections of slices
@@ -29,6 +33,7 @@ import type {OverlayPair, OverlayTuple} from './types';
29
33
*/
30
34
export class Overlay < T = string > implements Printable , Stateful {
31
35
public root : OverlayPoint < T > | undefined = undefined ;
36
+ public root2 : MarkerOverlayPoint < T > | undefined = undefined ;
32
37
33
38
/** A virtual absolute start point, used when the absolute start is missing. */
34
39
public readonly START : OverlayPoint < T > ;
@@ -110,15 +115,7 @@ export class Overlay<T = string> implements Printable, Stateful {
110
115
return result ;
111
116
}
112
117
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()`. */
122
119
public chunkSlices0 (
123
120
chunk : Chunk < T > | undefined ,
124
121
p1 : Point < T > ,
@@ -179,20 +176,17 @@ export class Overlay<T = string> implements Printable, Stateful {
179
176
return new UndefEndIter ( this . points0 ( after ) ) ;
180
177
}
181
178
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 ) ;
184
181
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 ;
191
185
} ;
192
186
}
193
187
194
188
public markers ( ) : IterableIterator < MarkerOverlayPoint < T > > {
195
- return new UndefEndIter ( this . markers0 ( ) ) ;
189
+ return new UndefEndIter ( this . markers0 ( undefined ) ) ;
196
190
}
197
191
198
192
public pairs0 ( after : undefined | OverlayPoint < T > ) : UndefIterator < OverlayPair < T > > {
@@ -245,6 +239,31 @@ export class Overlay<T = string> implements Printable, Stateful {
245
239
return new UndefEndIter ( this . tuples0 ( after ) ) ;
246
240
}
247
241
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
+ */
248
267
public findContained ( range : Range < T > ) : Set < Slice < T > > {
249
268
const result = new Set < Slice < T > > ( ) ;
250
269
let point = this . getOrNextLower ( range . start ) ;
@@ -265,6 +284,14 @@ export class Overlay<T = string> implements Printable, Stateful {
265
284
return result ;
266
285
}
267
286
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
+ */
268
295
public findOverlapping ( range : Range < T > ) : Set < Slice < T > > {
269
296
const result = new Set < Slice < T > > ( ) ;
270
297
let point = this . getOrNextLower ( range . start ) ;
@@ -281,12 +308,16 @@ export class Overlay<T = string> implements Printable, Stateful {
281
308
return result ;
282
309
}
283
310
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 ;
290
321
}
291
322
292
323
// ----------------------------------------------------------------- Stateful
@@ -299,7 +330,12 @@ export class Overlay<T = string> implements Printable, Stateful {
299
330
hash = this . refreshSlices ( hash , txt . savedSlices ) ;
300
331
hash = this . refreshSlices ( hash , txt . extraSlices ) ;
301
332
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
+ }
303
339
return ( this . hash = hash ) ;
304
340
}
305
341
@@ -339,7 +375,6 @@ export class Overlay<T = string> implements Printable, Stateful {
339
375
}
340
376
341
377
private insSlice ( slice : Slice < T > ) : [ start : OverlayPoint < T > , end : OverlayPoint < T > ] {
342
- // TODO: Test cases where the inserted slice is collapsed to one point.
343
378
const x0 = slice . start ;
344
379
const x1 = slice . end ;
345
380
const [ start , isStartNew ] = this . upsertPoint ( x0 ) ;
@@ -359,10 +394,7 @@ export class Overlay<T = string> implements Printable, Stateful {
359
394
let curr : OverlayPoint < T > | undefined = start ;
360
395
do curr . addLayer ( slice ) ;
361
396
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 ) ;
366
398
return [ start , end ] ;
367
399
}
368
400
@@ -408,6 +440,10 @@ export class Overlay<T = string> implements Printable, Stateful {
408
440
* @returns Returns the existing point if it was already in the tree.
409
441
*/
410
442
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
+ }
411
447
let pivot = this . getOrNextLower ( point ) ;
412
448
if ( ! pivot ) pivot = first ( this . root ) ;
413
449
if ( ! pivot ) {
@@ -424,23 +460,23 @@ export class Overlay<T = string> implements Printable, Stateful {
424
460
}
425
461
426
462
private delPoint ( point : OverlayPoint < T > ) : void {
463
+ if ( point instanceof MarkerOverlayPoint ) this . root2 = remove2 ( this . root2 , point ) ;
427
464
this . root = remove ( this . root , point ) ;
428
465
}
429
466
430
467
public leadingTextHash : number = 0 ;
431
468
432
- protected computeSplitTextHashes ( ) : void {
469
+ protected refreshTextSlices ( stateTotal : number ) : number {
433
470
const txt = this . txt ;
434
471
const str = txt . str ;
435
472
const firstChunk = str . first ( ) ;
436
- if ( ! firstChunk ) return ;
473
+ if ( ! firstChunk ) return stateTotal ;
437
474
let chunk : Chunk < T > | undefined = firstChunk ;
438
475
let marker : MarkerOverlayPoint < T > | undefined = undefined ;
439
- let state : number = CONST . START_STATE ;
440
476
const i = this . tuples0 ( undefined ) ;
477
+ let state : number = CONST . START_STATE ;
441
478
for ( let pair = i ( ) ; pair ; pair = i ( ) ) {
442
479
const [ p1 , p2 ] = pair ;
443
- // TODO: need to incorporate slice attribute hash here?
444
480
const id1 = p1 . id ;
445
481
state = ( state << 5 ) + state + ( id1 . sid >>> 0 ) + id1 . time ;
446
482
let overlayPointHash = CONST . START_STATE ;
@@ -450,15 +486,15 @@ export class Overlay<T = string> implements Printable, Stateful {
450
486
( overlayPointHash << 5 ) + overlayPointHash + ( ( ( ( id . sid >>> 0 ) + id . time ) << 8 ) + ( off << 4 ) + len ) ;
451
487
} ) ;
452
488
state = updateNum ( state , overlayPointHash ) ;
453
- if ( p1 ) {
454
- p1 . hash = overlayPointHash ;
455
- }
489
+ p1 . hash = overlayPointHash ;
490
+ stateTotal = updateNum ( stateTotal , overlayPointHash ) ;
456
491
if ( p2 instanceof MarkerOverlayPoint ) {
457
492
if ( marker ) {
458
493
marker . textHash = state ;
459
494
} else {
460
495
this . leadingTextHash = state ;
461
496
}
497
+ stateTotal = updateNum ( stateTotal , state ) ;
462
498
state = CONST . START_STATE ;
463
499
marker = p2 ;
464
500
}
@@ -468,6 +504,7 @@ export class Overlay<T = string> implements Printable, Stateful {
468
504
} else {
469
505
this . leadingTextHash = state ;
470
506
}
507
+ return stateTotal ;
471
508
}
472
509
473
510
// ---------------------------------------------------------------- Printable
@@ -482,9 +519,21 @@ export class Overlay<T = string> implements Printable, Stateful {
482
519
] )
483
520
) ;
484
521
} ;
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
+ } ;
485
531
return (
486
532
`${ 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
+ ] )
488
537
) ;
489
538
}
490
539
}
0 commit comments