Skip to content

Commit da6da71

Browse files
IntervalCollection: Use SequenceIntervalClass in implementations (#24203)
Use SequenceIntervalClass in implementations to avoid casting. Primarily removes a number of instance of checks where they are no longer necessary. Also cleaned up some missed generics.
1 parent 18dd811 commit da6da71

File tree

9 files changed

+101
-149
lines changed

9 files changed

+101
-149
lines changed

packages/dds/sequence/src/index.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,16 @@ export {
3232
IIntervalCollection,
3333
ISequenceIntervalCollection,
3434
ISequenceIntervalCollectionEvents,
35-
IntervalLocator,
36-
intervalLocatorFromEndpoint,
3735
} from "./intervalCollection.js";
3836
export {
3937
IntervalIndex,
4038
SequenceIntervalIndex,
4139
SequenceIntervalIndexes,
4240
IOverlappingIntervalsIndex,
4341
ISequenceOverlappingIntervalsIndex,
42+
IEndpointIndex,
4443
createOverlappingIntervalsIndex,
4544
createOverlappingSequenceIntervalsIndex,
46-
IEndpointInRangeIndex,
47-
IStartpointInRangeIndex,
48-
createEndpointInRangeIndex,
49-
createStartpointInRangeIndex,
50-
IIdIntervalIndex,
51-
createIdIntervalIndex,
52-
IEndpointIndex,
5345
createEndpointIndex,
5446
} from "./intervalIndex/index.js";
5547
export {

packages/dds/sequence/src/intervalCollection.ts

Lines changed: 70 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ export class LocalIntervalCollection {
177177
private readonly options: Partial<SequenceOptions>,
178178
/** Callback invoked each time one of the endpoints of an interval slides. */
179179
private readonly onPositionChange?: (
180-
interval: SequenceInterval,
181-
previousInterval: SequenceInterval,
180+
interval: SequenceIntervalClass,
181+
previousInterval: SequenceIntervalClass,
182182
) => void,
183183
) {
184184
this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client);
@@ -229,7 +229,7 @@ export class LocalIntervalCollection {
229229
return id;
230230
}
231231

232-
private removeIntervalFromIndexes(interval: SequenceInterval) {
232+
private removeIntervalFromIndexes(interval: SequenceIntervalClass) {
233233
for (const index of this.indexes) {
234234
index.remove(interval);
235235
}
@@ -243,7 +243,7 @@ export class LocalIntervalCollection {
243243
return this.indexes.delete(index);
244244
}
245245

246-
public removeExistingInterval(interval: SequenceInterval) {
246+
public removeExistingInterval(interval: SequenceIntervalClass) {
247247
this.removeIntervalFromIndexes(interval);
248248
this.removeIntervalListeners(interval);
249249
}
@@ -253,7 +253,7 @@ export class LocalIntervalCollection {
253253
end: SequencePlace,
254254
intervalType: IntervalType,
255255
op?: ISequencedDocumentMessage,
256-
): SequenceInterval {
256+
): SequenceIntervalClass {
257257
return createSequenceInterval(
258258
this.label,
259259
start,
@@ -273,7 +273,7 @@ export class LocalIntervalCollection {
273273
props?: PropertySet,
274274
op?: ISequencedDocumentMessage,
275275
) {
276-
const interval: SequenceInterval = this.createInterval(start, end, intervalType, op);
276+
const interval: SequenceIntervalClass = this.createInterval(start, end, intervalType, op);
277277
if (interval) {
278278
if (!interval.properties) {
279279
interval.properties = createMap<any>();
@@ -299,27 +299,25 @@ export class LocalIntervalCollection {
299299
return interval;
300300
}
301301

302-
private linkEndpointsToInterval(interval: SequenceInterval): void {
303-
if (interval instanceof SequenceIntervalClass) {
304-
interval.start.addProperties({ interval });
305-
interval.end.addProperties({ interval });
306-
}
302+
private linkEndpointsToInterval(interval: SequenceIntervalClass): void {
303+
interval.start.addProperties({ interval });
304+
interval.end.addProperties({ interval });
307305
}
308306

309-
private addIntervalToIndexes(interval: SequenceInterval) {
307+
private addIntervalToIndexes(interval: SequenceIntervalClass) {
310308
for (const index of this.indexes) {
311309
index.add(interval);
312310
}
313311
}
314312

315-
public add(interval: SequenceInterval): void {
313+
public add(interval: SequenceIntervalClass): void {
316314
this.linkEndpointsToInterval(interval);
317315
this.addIntervalToIndexes(interval);
318316
this.addIntervalListeners(interval);
319317
}
320318

321319
public changeInterval(
322-
interval: SequenceInterval,
320+
interval: SequenceIntervalClass,
323321
start: SequencePlace | undefined,
324322
end: SequencePlace | undefined,
325323
op?: ISequencedDocumentMessage,
@@ -355,7 +353,7 @@ export class LocalIntervalCollection {
355353
};
356354
}
357355

358-
private addIntervalListeners(interval: SequenceInterval) {
356+
private addIntervalListeners(interval: SequenceIntervalClass) {
359357
const cloneRef = (ref: LocalReferencePosition) => {
360358
const segment = ref.getSegment();
361359
if (segment === undefined) {
@@ -374,40 +372,36 @@ export class LocalIntervalCollection {
374372
ref.canSlideToEndpoint,
375373
);
376374
};
377-
if (interval instanceof SequenceIntervalClass) {
378-
let previousInterval: (SequenceInterval & SequenceIntervalClass) | undefined;
379-
let pendingChanges = 0;
380-
interval.addPositionChangeListeners(
381-
() => {
382-
pendingChanges++;
383-
// Note: both start and end can change and invoke beforeSlide on each endpoint before afterSlide.
384-
if (!previousInterval) {
385-
previousInterval = interval.clone() as SequenceInterval & SequenceIntervalClass;
386-
previousInterval.start = cloneRef(previousInterval.start);
387-
previousInterval.end = cloneRef(previousInterval.end);
388-
this.removeIntervalFromIndexes(interval);
389-
}
390-
},
391-
() => {
392-
assert(
393-
previousInterval !== undefined,
394-
0x3fa /* Invalid interleaving of before/after slide */,
395-
);
396-
pendingChanges--;
397-
if (pendingChanges === 0) {
398-
this.addIntervalToIndexes(interval);
399-
this.onPositionChange?.(interval, previousInterval);
400-
previousInterval = undefined;
401-
}
402-
},
403-
);
404-
}
375+
let previousInterval: SequenceIntervalClass | undefined;
376+
let pendingChanges = 0;
377+
interval.addPositionChangeListeners(
378+
() => {
379+
pendingChanges++;
380+
// Note: both start and end can change and invoke beforeSlide on each endpoint before afterSlide.
381+
if (!previousInterval) {
382+
previousInterval = interval.clone();
383+
previousInterval.start = cloneRef(previousInterval.start);
384+
previousInterval.end = cloneRef(previousInterval.end);
385+
this.removeIntervalFromIndexes(interval);
386+
}
387+
},
388+
() => {
389+
assert(
390+
previousInterval !== undefined,
391+
0x3fa /* Invalid interleaving of before/after slide */,
392+
);
393+
pendingChanges--;
394+
if (pendingChanges === 0) {
395+
this.addIntervalToIndexes(interval);
396+
this.onPositionChange?.(interval, previousInterval);
397+
previousInterval = undefined;
398+
}
399+
},
400+
);
405401
}
406402

407-
private removeIntervalListeners(interval: SequenceInterval) {
408-
if (interval instanceof SequenceIntervalClass) {
409-
interval.removePositionChangeListeners();
410-
}
403+
private removeIntervalListeners(interval: SequenceIntervalClass) {
404+
interval.removePositionChangeListeners();
411405
}
412406
}
413407

@@ -466,8 +460,8 @@ export const opsMap: Record<IntervalDeltaOpType, IIntervalCollectionOperation> =
466460
*/
467461
export type DeserializeCallback = (properties: PropertySet) => void;
468462

469-
class IntervalCollectionIterator implements Iterator<SequenceInterval> {
470-
private readonly results: SequenceInterval[];
463+
class IntervalCollectionIterator implements Iterator<SequenceIntervalClass> {
464+
private readonly results: SequenceIntervalClass[];
471465
private index: number;
472466

473467
constructor(
@@ -482,7 +476,7 @@ class IntervalCollectionIterator implements Iterator<SequenceInterval> {
482476
collection.gatherIterationResults(this.results, iteratesForward, start, end);
483477
}
484478

485-
public next(): IteratorResult<SequenceInterval> {
479+
public next(): IteratorResult<SequenceIntervalClass> {
486480
if (this.index < this.results.length) {
487481
return {
488482
value: this.results[this.index++],
@@ -1328,30 +1322,24 @@ export class IntervalCollection
13281322
}
13291323

13301324
private emitChange(
1331-
interval: SequenceInterval,
1332-
previousInterval: SequenceInterval,
1325+
interval: SequenceIntervalClass,
1326+
previousInterval: SequenceIntervalClass,
13331327
local: boolean,
13341328
slide: boolean,
13351329
op?: ISequencedDocumentMessage,
13361330
): void {
13371331
// Temporarily make references transient so that positional queries work (non-transient refs
13381332
// on resolve to DetachedPosition on any segments that don't contain them). The original refType
13391333
// is restored as single-endpoint changes re-use previous references.
1340-
let startRefType: ReferenceType;
1341-
let endRefType: ReferenceType;
1342-
if (previousInterval instanceof SequenceIntervalClass) {
1343-
startRefType = previousInterval.start.refType;
1344-
endRefType = previousInterval.end.refType;
1345-
previousInterval.start.refType = ReferenceType.Transient;
1346-
previousInterval.end.refType = ReferenceType.Transient;
1347-
this.emit("changeInterval", interval, previousInterval, local, op, slide);
1348-
this.emit("changed", interval, undefined, previousInterval ?? undefined, local, slide);
1349-
previousInterval.start.refType = startRefType;
1350-
previousInterval.end.refType = endRefType;
1351-
} else {
1352-
this.emit("changeInterval", interval, previousInterval, local, op, slide);
1353-
this.emit("changed", interval, undefined, previousInterval ?? undefined, local, slide);
1354-
}
1334+
1335+
const startRefType = previousInterval.start.refType;
1336+
const endRefType = previousInterval.end.refType;
1337+
previousInterval.start.refType = ReferenceType.Transient;
1338+
previousInterval.end.refType = ReferenceType.Transient;
1339+
this.emit("changeInterval", interval, previousInterval, local, op, slide);
1340+
this.emit("changed", interval, undefined, previousInterval ?? undefined, local, slide);
1341+
previousInterval.start.refType = startRefType;
1342+
previousInterval.end.refType = endRefType;
13551343
}
13561344

13571345
/**
@@ -1386,7 +1374,7 @@ export class IntervalCollection
13861374
start: SequencePlace;
13871375
end: SequencePlace;
13881376
props?: PropertySet;
1389-
}): SequenceInterval {
1377+
}): SequenceIntervalClass {
13901378
if (!this.localCollection) {
13911379
throw new LoggingError("attach must be called prior to adding intervals");
13921380
}
@@ -1405,15 +1393,15 @@ export class IntervalCollection
14051393

14061394
this.assertStickinessEnabled(start, end);
14071395

1408-
const interval: SequenceInterval = this.localCollection.addInterval(
1396+
const interval: SequenceIntervalClass = this.localCollection.addInterval(
14091397
toSequencePlace(startPos, startSide),
14101398
toSequencePlace(endPos, endSide),
14111399
IntervalType.SlideOnRemove,
14121400
props,
14131401
);
14141402

14151403
if (interval) {
1416-
if (!this.isCollaborating && interval instanceof SequenceIntervalClass) {
1404+
if (!this.isCollaborating) {
14171405
setSlideOnRemove(interval.start);
14181406
setSlideOnRemove(interval.end);
14191407
}
@@ -1449,7 +1437,7 @@ export class IntervalCollection
14491437
}
14501438

14511439
private deleteExistingInterval(
1452-
interval: SequenceInterval,
1440+
interval: SequenceIntervalClass,
14531441
local: boolean,
14541442
op?: ISequencedDocumentMessage,
14551443
) {
@@ -1484,7 +1472,7 @@ export class IntervalCollection
14841472
/**
14851473
* {@inheritdoc IIntervalCollection.removeIntervalById}
14861474
*/
1487-
public removeIntervalById(id: string): SequenceInterval | undefined {
1475+
public removeIntervalById(id: string): SequenceIntervalClass | undefined {
14881476
if (!this.localCollection) {
14891477
throw new LoggingError("Attach must be called before accessing intervals");
14901478
}
@@ -1500,7 +1488,7 @@ export class IntervalCollection
15001488
public change(
15011489
id: string,
15021490
{ start, end, props }: { start?: SequencePlace; end?: SequencePlace; props?: PropertySet },
1503-
): SequenceInterval | undefined {
1491+
): SequenceIntervalClass | undefined {
15041492
if (!this.localCollection) {
15051493
throw new LoggingError("Attach must be called before accessing intervals");
15061494
}
@@ -1528,7 +1516,7 @@ export class IntervalCollection
15281516
const interval = this.getIntervalById(id);
15291517
if (interval) {
15301518
let deltaProps: PropertySet | undefined;
1531-
let newInterval: SequenceInterval | undefined;
1519+
let newInterval: SequenceIntervalClass | undefined;
15321520
if (props !== undefined) {
15331521
interval.propertyManager ??= new PropertiesManager();
15341522
deltaProps = interval.propertyManager.handleProperties(
@@ -1541,7 +1529,7 @@ export class IntervalCollection
15411529
}
15421530
if (start !== undefined && end !== undefined) {
15431531
newInterval = this.localCollection.changeInterval(interval, start, end);
1544-
if (!this.isCollaborating && newInterval instanceof SequenceIntervalClass) {
1532+
if (!this.isCollaborating && newInterval !== undefined) {
15451533
setSlideOnRemove(newInterval.start);
15461534
setSlideOnRemove(newInterval.end);
15471535
}
@@ -1587,10 +1575,8 @@ export class IntervalCollection
15871575
if (newInterval) {
15881576
this.addPendingChange(id, serializedInterval);
15891577
this.emitChange(newInterval, interval, true, false);
1590-
if (interval instanceof SequenceIntervalClass) {
1591-
this.client?.removeLocalReferencePosition(interval.start);
1592-
this.client?.removeLocalReferencePosition(interval.end);
1593-
}
1578+
this.client?.removeLocalReferencePosition(interval.start);
1579+
this.client?.removeLocalReferencePosition(interval.end);
15941580
}
15951581
return newInterval;
15961582
}
@@ -1833,11 +1819,6 @@ export class IntervalCollection
18331819
}
18341820

18351821
if (localInterval !== undefined) {
1836-
// we know we must be using `SequenceInterval` because `this.client` exists
1837-
assert(
1838-
localInterval instanceof SequenceIntervalClass,
1839-
0x3a0 /* localInterval must be `SequenceInterval` when used with client */,
1840-
);
18411822
// The rebased op may place this interval's endpoints on different segments. Calling `changeInterval` here
18421823
// updates the local client's state to be consistent with the emitted op.
18431824
this.localCollection?.changeInterval(
@@ -1878,12 +1859,7 @@ export class IntervalCollection
18781859
return value;
18791860
}
18801861

1881-
private ackInterval(interval: SequenceInterval, op: ISequencedDocumentMessage): void {
1882-
// Only SequenceIntervals need potential sliding
1883-
if (!(interval instanceof SequenceIntervalClass)) {
1884-
return;
1885-
}
1886-
1862+
private ackInterval(interval: SequenceIntervalClass, op: ISequencedDocumentMessage): void {
18871863
if (
18881864
!refTypeIncludesFlag(interval.start, ReferenceType.StayOnRemove) &&
18891865
!refTypeIncludesFlag(interval.end, ReferenceType.StayOnRemove)
@@ -2004,7 +1980,7 @@ export class IntervalCollection
20041980

20051981
this.localCollection.ensureSerializedId(serializedInterval);
20061982

2007-
const interval: SequenceInterval = this.localCollection.addInterval(
1983+
const interval: SequenceIntervalClass = this.localCollection.addInterval(
20081984
toSequencePlace(serializedInterval.start, serializedInterval.startSide ?? Side.Before),
20091985
toSequencePlace(serializedInterval.end, serializedInterval.endSide ?? Side.Before),
20101986
serializedInterval.intervalType,
@@ -2108,7 +2084,7 @@ export class IntervalCollection
21082084
* {@inheritdoc IIntervalCollection.gatherIterationResults}
21092085
*/
21102086
public gatherIterationResults(
2111-
results: SequenceInterval[],
2087+
results: SequenceIntervalClass[],
21122088
iteratesForward: boolean,
21132089
start?: number,
21142090
end?: number,
@@ -2145,7 +2121,7 @@ export class IntervalCollection
21452121
/**
21462122
* {@inheritdoc IIntervalCollection.map}
21472123
*/
2148-
public map(fn: (interval: SequenceInterval) => void) {
2124+
public map(fn: (interval: SequenceIntervalClass) => void) {
21492125
if (!this.localCollection) {
21502126
throw new LoggingError("attachSequence must be called");
21512127
}
@@ -2197,7 +2173,7 @@ export interface IntervalLocator {
21972173
/**
21982174
* Interval within that collection
21992175
*/
2200-
interval: SequenceInterval;
2176+
interval: SequenceIntervalClass;
22012177
}
22022178

22032179
/**

0 commit comments

Comments
 (0)