@fluidframework/sequence 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191457
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +114 -0
- package/README.md +4 -3
- package/dist/defaultMap.d.ts +1 -1
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +9 -10
- package/dist/defaultMap.js.map +1 -1
- package/dist/defaultMapInterfaces.d.ts +1 -1
- package/dist/defaultMapInterfaces.d.ts.map +1 -1
- package/dist/defaultMapInterfaces.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +11 -424
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +74 -815
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointInRangeIndex.js +60 -0
- package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/dist/intervalIndex/endpointIndex.d.ts +21 -0
- package/dist/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointIndex.js +42 -0
- package/dist/intervalIndex/endpointIndex.js.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.js +41 -0
- package/dist/intervalIndex/idIntervalIndex.js.map +1 -0
- package/dist/intervalIndex/index.d.ts +5 -0
- package/dist/intervalIndex/index.d.ts.map +1 -1
- package/dist/intervalIndex/index.js +9 -1
- package/dist/intervalIndex/index.js.map +1 -1
- package/dist/intervalIndex/intervalIndex.d.ts +29 -0
- package/dist/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndex.js +7 -0
- package/dist/intervalIndex/intervalIndex.js.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.js +22 -0
- package/dist/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js +3 -3
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +5 -5
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.d.ts +20 -0
- package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/startpointInRangeIndex.js +62 -0
- package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/dist/intervalTree.d.ts +2 -56
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js +2 -11
- package/dist/intervalTree.js.map +1 -1
- package/dist/intervals/index.d.ts +8 -0
- package/dist/intervals/index.d.ts.map +1 -0
- package/dist/intervals/index.js +23 -0
- package/dist/intervals/index.js.map +1 -0
- package/dist/intervals/interval.d.ts +88 -0
- package/dist/intervals/interval.d.ts.map +1 -0
- package/dist/intervals/interval.js +180 -0
- package/dist/intervals/interval.js.map +1 -0
- package/dist/intervals/intervalUtils.d.ts +200 -0
- package/dist/intervals/intervalUtils.d.ts.map +1 -0
- package/dist/intervals/intervalUtils.js +79 -0
- package/dist/intervals/intervalUtils.js.map +1 -0
- package/dist/intervals/sequenceInterval.d.ts +132 -0
- package/dist/intervals/sequenceInterval.d.ts.map +1 -0
- package/dist/intervals/sequenceInterval.js +313 -0
- package/dist/intervals/sequenceInterval.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/revertibles.d.ts +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +45 -52
- package/dist/revertibles.js.map +1 -1
- package/dist/sequence.d.ts +33 -4
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +91 -47
- package/dist/sequence.js.map +1 -1
- package/dist/sequenceDeltaEvent.d.ts +8 -3
- package/dist/sequenceDeltaEvent.d.ts.map +1 -1
- package/dist/sequenceDeltaEvent.js +3 -4
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts +2 -1
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js +2 -2
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.d.ts +9 -0
- package/dist/sharedSequence.d.ts.map +1 -1
- package/dist/sharedSequence.js +9 -6
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +9 -29
- package/dist/sharedString.js.map +1 -1
- package/lib/defaultMap.d.ts +1 -1
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +5 -6
- package/lib/defaultMap.js.map +1 -1
- package/lib/defaultMapInterfaces.d.ts +1 -1
- package/lib/defaultMapInterfaces.d.ts.map +1 -1
- package/lib/defaultMapInterfaces.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +11 -424
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +43 -776
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointInRangeIndex.js +56 -0
- package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/lib/intervalIndex/endpointIndex.d.ts +21 -0
- package/lib/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointIndex.js +38 -0
- package/lib/intervalIndex/endpointIndex.js.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.js +37 -0
- package/lib/intervalIndex/idIntervalIndex.js.map +1 -0
- package/lib/intervalIndex/index.d.ts +5 -0
- package/lib/intervalIndex/index.d.ts.map +1 -1
- package/lib/intervalIndex/index.js +4 -0
- package/lib/intervalIndex/index.js.map +1 -1
- package/lib/intervalIndex/intervalIndex.d.ts +29 -0
- package/lib/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndex.js +6 -0
- package/lib/intervalIndex/intervalIndex.js.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.js +18 -0
- package/lib/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.d.ts +20 -0
- package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/startpointInRangeIndex.js +58 -0
- package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/lib/intervalTree.d.ts +2 -56
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js +2 -11
- package/lib/intervalTree.js.map +1 -1
- package/lib/intervals/index.d.ts +8 -0
- package/lib/intervals/index.d.ts.map +1 -0
- package/lib/intervals/index.js +8 -0
- package/lib/intervals/index.js.map +1 -0
- package/lib/intervals/interval.d.ts +88 -0
- package/lib/intervals/interval.d.ts.map +1 -0
- package/lib/intervals/interval.js +175 -0
- package/lib/intervals/interval.js.map +1 -0
- package/lib/intervals/intervalUtils.d.ts +200 -0
- package/lib/intervals/intervalUtils.d.ts.map +1 -0
- package/lib/intervals/intervalUtils.js +74 -0
- package/lib/intervals/intervalUtils.js.map +1 -0
- package/lib/intervals/sequenceInterval.d.ts +132 -0
- package/lib/intervals/sequenceInterval.d.ts.map +1 -0
- package/lib/intervals/sequenceInterval.js +305 -0
- package/lib/intervals/sequenceInterval.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/revertibles.d.ts +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +28 -35
- package/lib/revertibles.js.map +1 -1
- package/lib/sequence.d.ts +33 -4
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +86 -41
- package/lib/sequence.js.map +1 -1
- package/lib/sequenceDeltaEvent.d.ts +8 -3
- package/lib/sequenceDeltaEvent.d.ts.map +1 -1
- package/lib/sequenceDeltaEvent.js +2 -3
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts +2 -1
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.d.ts +9 -0
- package/lib/sharedSequence.d.ts.map +1 -1
- package/lib/sharedSequence.js +8 -5
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +9 -29
- package/lib/sharedString.js.map +1 -1
- package/package.json +29 -32
- package/src/defaultMap.ts +2 -1
- package/src/defaultMapInterfaces.ts +1 -1
- package/src/index.ts +18 -12
- package/src/intervalCollection.ts +42 -1225
- package/src/intervalIndex/endpointInRangeIndex.ts +104 -0
- package/src/intervalIndex/endpointIndex.ts +78 -0
- package/src/intervalIndex/idIntervalIndex.ts +58 -0
- package/src/intervalIndex/index.ts +5 -0
- package/src/intervalIndex/intervalIndex.ts +31 -0
- package/src/intervalIndex/intervalIndexUtils.ts +27 -0
- package/src/intervalIndex/overlappingIntervalsIndex.ts +2 -6
- package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +1 -1
- package/src/intervalIndex/sequenceIntervalIndexes.ts +1 -1
- package/src/intervalIndex/startpointInRangeIndex.ts +109 -0
- package/src/intervalTree.ts +3 -75
- package/src/intervals/index.ts +25 -0
- package/src/intervals/interval.ts +230 -0
- package/src/intervals/intervalUtils.ts +256 -0
- package/src/intervals/sequenceInterval.ts +494 -0
- package/src/packageVersion.ts +1 -1
- package/src/revertibles.ts +24 -13
- package/src/sequence.ts +100 -35
- package/src/sequenceDeltaEvent.ts +12 -4
- package/src/sharedIntervalCollection.ts +2 -3
- package/src/sharedSequence.ts +11 -5
- package/src/sharedString.ts +8 -25
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Client, PropertyAction, RedBlackTree } from "@fluidframework/merge-tree";
|
|
7
|
+
import { IIntervalHelpers, ISerializableInterval, IntervalType } from "../intervals";
|
|
8
|
+
import { IntervalIndex } from "./intervalIndex";
|
|
9
|
+
import { HasComparisonOverride, compareOverrideables, forceCompare } from "./intervalIndexUtils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Collection of intervals.
|
|
13
|
+
*
|
|
14
|
+
* Provide additional APIs to support efficiently querying a collection of intervals whose endpoints fall within a specified range.
|
|
15
|
+
*/
|
|
16
|
+
export interface IEndpointInRangeIndex<TInterval extends ISerializableInterval>
|
|
17
|
+
extends IntervalIndex<TInterval> {
|
|
18
|
+
/**
|
|
19
|
+
* @returns an array of all intervals contained in this collection whose endpoints locate in the range [start, end] (includes both ends)
|
|
20
|
+
*/
|
|
21
|
+
findIntervalsWithEndpointInRange(start: number, end: number);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class EndpointInRangeIndex<TInterval extends ISerializableInterval>
|
|
25
|
+
implements IEndpointInRangeIndex<TInterval>
|
|
26
|
+
{
|
|
27
|
+
private readonly intervalTree;
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
31
|
+
private readonly client: Client,
|
|
32
|
+
) {
|
|
33
|
+
this.intervalTree = new RedBlackTree<TInterval, TInterval>((a: TInterval, b: TInterval) => {
|
|
34
|
+
const compareEndsResult = helpers.compareEnds(a, b);
|
|
35
|
+
if (compareEndsResult !== 0) {
|
|
36
|
+
return compareEndsResult;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const overrideablesComparison = compareOverrideables(
|
|
40
|
+
a as Partial<HasComparisonOverride>,
|
|
41
|
+
b as Partial<HasComparisonOverride>,
|
|
42
|
+
);
|
|
43
|
+
if (overrideablesComparison !== 0) {
|
|
44
|
+
return overrideablesComparison;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const aId = a.getIntervalId();
|
|
48
|
+
const bId = b.getIntervalId();
|
|
49
|
+
if (aId !== undefined && bId !== undefined) {
|
|
50
|
+
return aId.localeCompare(bId);
|
|
51
|
+
}
|
|
52
|
+
return 0;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public add(interval: TInterval): void {
|
|
57
|
+
this.intervalTree.put(interval, interval);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public remove(interval: TInterval): void {
|
|
61
|
+
this.intervalTree.remove(interval);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public findIntervalsWithEndpointInRange(start: number, end: number) {
|
|
65
|
+
if (start <= 0 || start > end || this.intervalTree.isEmpty()) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
const results: TInterval[] = [];
|
|
69
|
+
const action: PropertyAction<TInterval, TInterval> = (node) => {
|
|
70
|
+
results.push(node.data);
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const transientStartInterval = this.helpers.create(
|
|
75
|
+
"transient",
|
|
76
|
+
start,
|
|
77
|
+
start,
|
|
78
|
+
this.client,
|
|
79
|
+
IntervalType.Transient,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const transientEndInterval = this.helpers.create(
|
|
83
|
+
"transient",
|
|
84
|
+
end,
|
|
85
|
+
end,
|
|
86
|
+
this.client,
|
|
87
|
+
IntervalType.Transient,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Add comparison overrides to the transient intervals
|
|
91
|
+
(transientStartInterval as Partial<HasComparisonOverride>)[forceCompare] = -1;
|
|
92
|
+
(transientEndInterval as Partial<HasComparisonOverride>)[forceCompare] = 1;
|
|
93
|
+
|
|
94
|
+
this.intervalTree.mapRange(action, results, transientStartInterval, transientEndInterval);
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function createEndpointInRangeIndex<TInterval extends ISerializableInterval>(
|
|
100
|
+
helpers: IIntervalHelpers<TInterval>,
|
|
101
|
+
client: Client,
|
|
102
|
+
): IEndpointInRangeIndex<TInterval> {
|
|
103
|
+
return new EndpointInRangeIndex<TInterval>(helpers, client);
|
|
104
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Client, RedBlackTree } from "@fluidframework/merge-tree";
|
|
7
|
+
import { IIntervalHelpers, ISerializableInterval, IntervalType } from "../intervals";
|
|
8
|
+
import { IntervalIndex } from "./intervalIndex";
|
|
9
|
+
|
|
10
|
+
export interface IEndpointIndex<TInterval extends ISerializableInterval>
|
|
11
|
+
extends IntervalIndex<TInterval> {
|
|
12
|
+
/**
|
|
13
|
+
* @returns the previous interval based on the given position number.
|
|
14
|
+
* If no such interval exists in this index, returns `undefined`
|
|
15
|
+
*/
|
|
16
|
+
previousInterval(pos: number): TInterval | undefined;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @returns the next interval based on the given position number.
|
|
20
|
+
* If no such interval exists in this index, returns `undefined`
|
|
21
|
+
*/
|
|
22
|
+
nextInterval(pos: number): TInterval | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class EndpointIndex<TInterval extends ISerializableInterval> implements IEndpointIndex<TInterval> {
|
|
26
|
+
private readonly endIntervalTree: RedBlackTree<TInterval, TInterval>;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly client: Client,
|
|
30
|
+
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
31
|
+
) {
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
33
|
+
this.endIntervalTree = new RedBlackTree<TInterval, TInterval>(helpers.compareEnds);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public previousInterval(pos: number): TInterval | undefined {
|
|
37
|
+
const transientInterval = this.helpers.create(
|
|
38
|
+
"transient",
|
|
39
|
+
pos,
|
|
40
|
+
pos,
|
|
41
|
+
this.client,
|
|
42
|
+
IntervalType.Transient,
|
|
43
|
+
);
|
|
44
|
+
const rbNode = this.endIntervalTree.floor(transientInterval);
|
|
45
|
+
if (rbNode) {
|
|
46
|
+
return rbNode.data;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public nextInterval(pos: number): TInterval | undefined {
|
|
51
|
+
const transientInterval = this.helpers.create(
|
|
52
|
+
"transient",
|
|
53
|
+
pos,
|
|
54
|
+
pos,
|
|
55
|
+
this.client,
|
|
56
|
+
IntervalType.Transient,
|
|
57
|
+
);
|
|
58
|
+
const rbNode = this.endIntervalTree.ceil(transientInterval);
|
|
59
|
+
if (rbNode) {
|
|
60
|
+
return rbNode.data;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public add(interval: TInterval): void {
|
|
65
|
+
this.endIntervalTree.put(interval, interval);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public remove(interval: TInterval): void {
|
|
69
|
+
this.endIntervalTree.remove(interval);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createEndpointIndex<TInterval extends ISerializableInterval>(
|
|
74
|
+
client: Client,
|
|
75
|
+
helpers: IIntervalHelpers<TInterval>,
|
|
76
|
+
): IEndpointIndex<TInterval> {
|
|
77
|
+
return new EndpointIndex<TInterval>(client, helpers);
|
|
78
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
|
+
import { ISerializableInterval } from "../intervals";
|
|
8
|
+
import { IntervalIndex } from "./intervalIndex";
|
|
9
|
+
|
|
10
|
+
const reservedIntervalIdKey = "intervalId";
|
|
11
|
+
|
|
12
|
+
export interface IIdIntervalIndex<TInterval extends ISerializableInterval>
|
|
13
|
+
extends IntervalIndex<TInterval>,
|
|
14
|
+
Iterable<TInterval> {
|
|
15
|
+
getIntervalById(id: string): TInterval | undefined;
|
|
16
|
+
|
|
17
|
+
[Symbol.iterator](): Iterator<TInterval>;
|
|
18
|
+
}
|
|
19
|
+
class IdIntervalIndex<TInterval extends ISerializableInterval>
|
|
20
|
+
implements IIdIntervalIndex<TInterval>, Iterable<TInterval>
|
|
21
|
+
{
|
|
22
|
+
private readonly intervalIdMap: Map<string, TInterval> = new Map();
|
|
23
|
+
|
|
24
|
+
public add(interval: TInterval) {
|
|
25
|
+
const id = interval.getIntervalId();
|
|
26
|
+
assert(
|
|
27
|
+
id !== undefined,
|
|
28
|
+
0x2c0 /* "ID must be created before adding interval to collection" */,
|
|
29
|
+
);
|
|
30
|
+
// Make the ID immutable.
|
|
31
|
+
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
32
|
+
configurable: false,
|
|
33
|
+
enumerable: true,
|
|
34
|
+
writable: false,
|
|
35
|
+
});
|
|
36
|
+
this.intervalIdMap.set(id, interval);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public remove(interval: TInterval) {
|
|
40
|
+
const id = interval.getIntervalId();
|
|
41
|
+
assert(id !== undefined, 0x311 /* expected id to exist on interval */);
|
|
42
|
+
this.intervalIdMap.delete(id);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public getIntervalById(id: string): TInterval | undefined {
|
|
46
|
+
return this.intervalIdMap.get(id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public [Symbol.iterator](): IterableIterator<TInterval> {
|
|
50
|
+
return this.intervalIdMap.values();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createIdIntervalIndex<
|
|
55
|
+
TInterval extends ISerializableInterval,
|
|
56
|
+
>(): IIdIntervalIndex<TInterval> {
|
|
57
|
+
return new IdIntervalIndex<TInterval>();
|
|
58
|
+
}
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
export { IntervalIndex } from "./intervalIndex";
|
|
7
|
+
export { IIdIntervalIndex, createIdIntervalIndex } from "./idIntervalIndex";
|
|
8
|
+
export { IEndpointIndex, createEndpointIndex } from "./endpointIndex";
|
|
9
|
+
export { IEndpointInRangeIndex, createEndpointInRangeIndex } from "./endpointInRangeIndex";
|
|
10
|
+
export { IStartpointInRangeIndex, createStartpointInRangeIndex } from "./startpointInRangeIndex";
|
|
6
11
|
export { SequenceIntervalIndexes } from "./sequenceIntervalIndexes";
|
|
7
12
|
export {
|
|
8
13
|
IOverlappingIntervalsIndex,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ISerializableInterval } from "../intervals";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Collection of intervals.
|
|
10
|
+
*
|
|
11
|
+
* Implementers of this interface will typically implement additional APIs to support efficiently querying a collection
|
|
12
|
+
* of intervals in some manner, for example:
|
|
13
|
+
* - "find all intervals with start endpoint between these two points"
|
|
14
|
+
* - "find all intervals which overlap this range"
|
|
15
|
+
* etc.
|
|
16
|
+
*/
|
|
17
|
+
export interface IntervalIndex<TInterval extends ISerializableInterval> {
|
|
18
|
+
/**
|
|
19
|
+
* Adds an interval to the index.
|
|
20
|
+
* @remarks Application code should never need to invoke this method on their index for production scenarios:
|
|
21
|
+
* Fluid handles adding and removing intervals from an index in response to sequence or interval changes.
|
|
22
|
+
*/
|
|
23
|
+
add(interval: TInterval): void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Removes an interval from the index.
|
|
27
|
+
* @remarks Application code should never need to invoke this method on their index for production scenarios:
|
|
28
|
+
* Fluid handles adding and removing intervals from an index in response to sequence or interval changes.
|
|
29
|
+
*/
|
|
30
|
+
remove(interval: TInterval): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Interface for intervals that have comparison override properties.
|
|
8
|
+
*/
|
|
9
|
+
export const forceCompare = Symbol();
|
|
10
|
+
|
|
11
|
+
export interface HasComparisonOverride {
|
|
12
|
+
[forceCompare]: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Compares two objects based on their comparison override properties.
|
|
17
|
+
* @returns A number indicating the order of the intervals (negative for a is lower than b, 0 for tie, positive for a is greater than b).
|
|
18
|
+
*/
|
|
19
|
+
export function compareOverrideables(
|
|
20
|
+
a: Partial<HasComparisonOverride>,
|
|
21
|
+
b: Partial<HasComparisonOverride>,
|
|
22
|
+
): number {
|
|
23
|
+
const forceCompareA = a[forceCompare] ?? 0;
|
|
24
|
+
const forceCompareB = b[forceCompare] ?? 0;
|
|
25
|
+
|
|
26
|
+
return forceCompareA - forceCompareB;
|
|
27
|
+
}
|
|
@@ -4,13 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Client } from "@fluidframework/merge-tree";
|
|
7
|
-
import {
|
|
8
|
-
IntervalType,
|
|
9
|
-
IIntervalHelpers,
|
|
10
|
-
IntervalIndex,
|
|
11
|
-
ISerializableInterval,
|
|
12
|
-
} from "../intervalCollection";
|
|
7
|
+
import { IntervalType, IIntervalHelpers, ISerializableInterval } from "../intervals";
|
|
13
8
|
import { IntervalNode, IntervalTree } from "../intervalTree";
|
|
9
|
+
import { IntervalIndex } from "./intervalIndex";
|
|
14
10
|
|
|
15
11
|
export interface IOverlappingIntervalsIndex<TInterval extends ISerializableInterval>
|
|
16
12
|
extends IntervalIndex<TInterval> {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
IntervalType,
|
|
16
16
|
SequenceInterval,
|
|
17
17
|
createPositionReferenceFromSegoff,
|
|
18
|
-
} from "../
|
|
18
|
+
} from "../intervals";
|
|
19
19
|
import { SequenceIntervalIndexes } from "./sequenceIntervalIndexes";
|
|
20
20
|
import { OverlappingIntervalsIndex } from "./overlappingIntervalsIndex";
|
|
21
21
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Client, PropertyAction, RedBlackTree } from "@fluidframework/merge-tree";
|
|
7
|
+
import { assert } from "@fluidframework/core-utils";
|
|
8
|
+
import { IIntervalHelpers, ISerializableInterval, IntervalType } from "../intervals";
|
|
9
|
+
import { IntervalIndex } from "./intervalIndex";
|
|
10
|
+
import { HasComparisonOverride, compareOverrideables, forceCompare } from "./intervalIndexUtils";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Collection of intervals.
|
|
14
|
+
*
|
|
15
|
+
* Provide additional APIs to support efficiently querying a collection of intervals whose startpoints fall within a specified range.
|
|
16
|
+
*/
|
|
17
|
+
export interface IStartpointInRangeIndex<TInterval extends ISerializableInterval>
|
|
18
|
+
extends IntervalIndex<TInterval> {
|
|
19
|
+
/**
|
|
20
|
+
* @returns an array of all intervals contained in this collection whose startpoints locate in the range [start, end] (includes both ends)
|
|
21
|
+
*/
|
|
22
|
+
findIntervalsWithStartpointInRange(start: number, end: number);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class StartpointInRangeIndex<TInterval extends ISerializableInterval>
|
|
26
|
+
implements IStartpointInRangeIndex<TInterval>
|
|
27
|
+
{
|
|
28
|
+
private readonly intervalTree;
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
32
|
+
private readonly client: Client,
|
|
33
|
+
) {
|
|
34
|
+
this.intervalTree = new RedBlackTree<TInterval, TInterval>((a: TInterval, b: TInterval) => {
|
|
35
|
+
assert(
|
|
36
|
+
typeof helpers.compareStarts === "function",
|
|
37
|
+
0x6d1 /* compareStarts does not exist in the helpers */,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const compareStartsResult = helpers.compareStarts(a, b);
|
|
41
|
+
if (compareStartsResult !== 0) {
|
|
42
|
+
return compareStartsResult;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const overrideablesComparison = compareOverrideables(
|
|
46
|
+
a as Partial<HasComparisonOverride>,
|
|
47
|
+
b as Partial<HasComparisonOverride>,
|
|
48
|
+
);
|
|
49
|
+
if (overrideablesComparison !== 0) {
|
|
50
|
+
return overrideablesComparison;
|
|
51
|
+
}
|
|
52
|
+
const aId = a.getIntervalId();
|
|
53
|
+
const bId = b.getIntervalId();
|
|
54
|
+
if (aId !== undefined && bId !== undefined) {
|
|
55
|
+
return aId.localeCompare(bId);
|
|
56
|
+
}
|
|
57
|
+
return 0;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public add(interval: TInterval): void {
|
|
62
|
+
this.intervalTree.put(interval, interval);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public remove(interval: TInterval): void {
|
|
66
|
+
this.intervalTree.remove(interval);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public findIntervalsWithStartpointInRange(start: number, end: number) {
|
|
70
|
+
if (start <= 0 || start > end || this.intervalTree.isEmpty()) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const results: TInterval[] = [];
|
|
74
|
+
const action: PropertyAction<TInterval, TInterval> = (node) => {
|
|
75
|
+
results.push(node.data);
|
|
76
|
+
return true;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const transientStartInterval = this.helpers.create(
|
|
80
|
+
"transient",
|
|
81
|
+
start,
|
|
82
|
+
start,
|
|
83
|
+
this.client,
|
|
84
|
+
IntervalType.Transient,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const transientEndInterval = this.helpers.create(
|
|
88
|
+
"transient",
|
|
89
|
+
end,
|
|
90
|
+
end,
|
|
91
|
+
this.client,
|
|
92
|
+
IntervalType.Transient,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Add comparison overrides to the transient intervals
|
|
96
|
+
(transientStartInterval as Partial<HasComparisonOverride>)[forceCompare] = -1;
|
|
97
|
+
(transientEndInterval as Partial<HasComparisonOverride>)[forceCompare] = 1;
|
|
98
|
+
|
|
99
|
+
this.intervalTree.mapRange(action, results, transientStartInterval, transientEndInterval);
|
|
100
|
+
return results;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function createStartpointInRangeIndex<TInterval extends ISerializableInterval>(
|
|
105
|
+
helpers: IIntervalHelpers<TInterval>,
|
|
106
|
+
client: Client,
|
|
107
|
+
): IStartpointInRangeIndex<TInterval> {
|
|
108
|
+
return new StartpointInRangeIndex<TInterval>(helpers, client);
|
|
109
|
+
}
|
package/src/intervalTree.ts
CHANGED
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
IRBAugmentation,
|
|
10
10
|
IRBMatcher,
|
|
11
11
|
RedBlackTree,
|
|
12
|
-
ConflictAction,
|
|
13
12
|
RBNodeActions,
|
|
14
13
|
} from "@fluidframework/merge-tree";
|
|
15
|
-
import {
|
|
14
|
+
import { IInterval } from "./intervals";
|
|
16
15
|
|
|
17
16
|
export interface AugmentedIntervalNode {
|
|
18
17
|
minmax: IInterval;
|
|
@@ -20,72 +19,10 @@ export interface AugmentedIntervalNode {
|
|
|
20
19
|
|
|
21
20
|
export const integerRangeToString = (range: IIntegerRange) => `[${range.start},${range.end})`;
|
|
22
21
|
|
|
23
|
-
/**
|
|
24
|
-
* Basic interval abstraction
|
|
25
|
-
*/
|
|
26
|
-
export interface IInterval {
|
|
27
|
-
/**
|
|
28
|
-
* @returns a new interval object with identical semantics.
|
|
29
|
-
*/
|
|
30
|
-
clone(): IInterval;
|
|
31
|
-
/**
|
|
32
|
-
* Compares this interval to `b` with standard comparator semantics:
|
|
33
|
-
* - returns -1 if this is less than `b`
|
|
34
|
-
* - returns 1 if this is greater than `b`
|
|
35
|
-
* - returns 0 if this is equivalent to `b`
|
|
36
|
-
* @param b - Interval to compare against
|
|
37
|
-
*/
|
|
38
|
-
compare(b: IInterval): number;
|
|
39
|
-
/**
|
|
40
|
-
* Compares the start endpoint of this interval to `b`'s start endpoint.
|
|
41
|
-
* Standard comparator semantics apply.
|
|
42
|
-
* @param b - Interval to compare against
|
|
43
|
-
*/
|
|
44
|
-
compareStart(b: IInterval): number;
|
|
45
|
-
/**
|
|
46
|
-
* Compares the end endpoint of this interval to `b`'s end endpoint.
|
|
47
|
-
* Standard comparator semantics apply.
|
|
48
|
-
* @param b - Interval to compare against
|
|
49
|
-
*/
|
|
50
|
-
compareEnd(b: IInterval): number;
|
|
51
|
-
/**
|
|
52
|
-
* Modifies one or more of the endpoints of this interval, returning a new interval representing the result.
|
|
53
|
-
* @internal
|
|
54
|
-
*/
|
|
55
|
-
modify(
|
|
56
|
-
label: string,
|
|
57
|
-
start: number | undefined,
|
|
58
|
-
end: number | undefined,
|
|
59
|
-
op?: ISequencedDocumentMessage,
|
|
60
|
-
localSeq?: number,
|
|
61
|
-
): IInterval | undefined;
|
|
62
|
-
/**
|
|
63
|
-
* @returns whether this interval overlaps with `b`.
|
|
64
|
-
* Intervals are considered to overlap if their intersection is non-empty.
|
|
65
|
-
*/
|
|
66
|
-
overlaps(b: IInterval): boolean;
|
|
67
|
-
/**
|
|
68
|
-
* Unions this interval with `b`, returning a new interval.
|
|
69
|
-
* The union operates as a convex hull, i.e. if the two intervals are disjoint, the return value includes
|
|
70
|
-
* intermediate values between the two intervals.
|
|
71
|
-
* @internal
|
|
72
|
-
*/
|
|
73
|
-
union(b: IInterval): IInterval;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
22
|
const intervalComparer = (a: IInterval, b: IInterval) => a.compare(b);
|
|
77
23
|
|
|
78
24
|
export type IntervalNode<T extends IInterval> = RBNode<T, AugmentedIntervalNode>;
|
|
79
25
|
|
|
80
|
-
/**
|
|
81
|
-
* @deprecated - This functionality was useful when adding two intervals at the same start/end positions resulted
|
|
82
|
-
* in a conflict. This is no longer the case (as of PR#6407), as interval collections support multiple intervals
|
|
83
|
-
* at the same location and gives each interval a unique id.
|
|
84
|
-
*
|
|
85
|
-
* As such, conflict resolvers are never invoked and unnecessary. They will be removed in an upcoming release.
|
|
86
|
-
*/
|
|
87
|
-
export type IntervalConflictResolver<TInterval> = (a: TInterval, b: TInterval) => TInterval;
|
|
88
|
-
|
|
89
26
|
export class IntervalTree<T extends IInterval>
|
|
90
27
|
implements IRBAugmentation<T, AugmentedIntervalNode>, IRBMatcher<T, AugmentedIntervalNode>
|
|
91
28
|
{
|
|
@@ -99,17 +36,8 @@ export class IntervalTree<T extends IInterval>
|
|
|
99
36
|
this.intervals.removeExisting(x);
|
|
100
37
|
}
|
|
101
38
|
|
|
102
|
-
public put(x: T
|
|
103
|
-
|
|
104
|
-
if (conflict) {
|
|
105
|
-
rbConflict = (key: T, currentKey: T) => {
|
|
106
|
-
const ival = conflict(key, currentKey);
|
|
107
|
-
return {
|
|
108
|
-
key: ival,
|
|
109
|
-
};
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
this.intervals.put(x, { minmax: x.clone() }, rbConflict);
|
|
39
|
+
public put(x: T) {
|
|
40
|
+
this.intervals.put(x, { minmax: x.clone() });
|
|
113
41
|
}
|
|
114
42
|
|
|
115
43
|
public map(fn: (x: T) => void) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
IInterval,
|
|
8
|
+
ISerializedInterval,
|
|
9
|
+
ISerializableInterval,
|
|
10
|
+
IntervalOpType,
|
|
11
|
+
IntervalType,
|
|
12
|
+
IIntervalHelpers,
|
|
13
|
+
IntervalStickiness,
|
|
14
|
+
SerializedIntervalDelta,
|
|
15
|
+
CompressedSerializedInterval,
|
|
16
|
+
endReferenceSlidingPreference,
|
|
17
|
+
startReferenceSlidingPreference,
|
|
18
|
+
} from "./intervalUtils";
|
|
19
|
+
export { Interval, createInterval, intervalHelpers } from "./interval";
|
|
20
|
+
export {
|
|
21
|
+
SequenceInterval,
|
|
22
|
+
createSequenceInterval,
|
|
23
|
+
createPositionReferenceFromSegoff,
|
|
24
|
+
sequenceIntervalHelpers,
|
|
25
|
+
} from "./sequenceInterval";
|