@fluidframework/merge-tree 1.2.6 → 2.0.0-dev.1.3.0.96595
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/.mocharc.js +12 -0
- package/README.md +2 -2
- package/dist/MergeTreeTextHelper.d.ts +23 -0
- package/dist/MergeTreeTextHelper.d.ts.map +1 -0
- package/dist/MergeTreeTextHelper.js +133 -0
- package/dist/MergeTreeTextHelper.js.map +1 -0
- package/dist/base.d.ts +2 -26
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js.map +1 -1
- package/dist/client.d.ts +27 -16
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +81 -101
- package/dist/client.js.map +1 -1
- package/dist/collections/heap.d.ts +28 -0
- package/dist/collections/heap.d.ts.map +1 -0
- package/dist/collections/heap.js +65 -0
- package/dist/collections/heap.js.map +1 -0
- package/dist/collections/index.d.ts +11 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +23 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/intervalTree.d.ts +60 -0
- package/dist/collections/intervalTree.d.ts.map +1 -0
- package/dist/collections/intervalTree.js +99 -0
- package/dist/collections/intervalTree.js.map +1 -0
- package/dist/collections/list.d.ts +39 -0
- package/dist/collections/list.d.ts.map +1 -0
- package/dist/collections/list.js +155 -0
- package/dist/collections/list.js.map +1 -0
- package/dist/collections/rbTree.d.ts +154 -0
- package/dist/collections/rbTree.d.ts.map +1 -0
- package/dist/{collections.js → collections/rbTree.js} +15 -478
- package/dist/collections/rbTree.js.map +1 -0
- package/dist/collections/stack.d.ts +16 -0
- package/dist/collections/stack.d.ts.map +1 -0
- package/dist/collections/stack.js +30 -0
- package/dist/collections/stack.js.map +1 -0
- package/dist/collections/tst.d.ts +55 -0
- package/dist/collections/tst.d.ts.map +1 -0
- package/dist/collections/tst.js +171 -0
- package/dist/collections/tst.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/localReference.d.ts +48 -99
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js +132 -169
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +71 -302
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +395 -642
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/dist/mergeTreeDeltaCallback.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +344 -0
- package/dist/mergeTreeNodes.d.ts.map +1 -0
- package/dist/mergeTreeNodes.js +383 -0
- package/dist/mergeTreeNodes.js.map +1 -0
- package/dist/mergeTreeTracking.d.ts +1 -1
- package/dist/mergeTreeTracking.d.ts.map +1 -1
- package/dist/mergeTreeTracking.js.map +1 -1
- package/dist/opBuilder.d.ts +1 -1
- package/dist/opBuilder.d.ts.map +1 -1
- package/dist/opBuilder.js.map +1 -1
- package/dist/partialLengths.d.ts +188 -18
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +495 -253
- package/dist/partialLengths.js.map +1 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js.map +1 -1
- package/dist/referencePositions.d.ts +6 -26
- package/dist/referencePositions.d.ts.map +1 -1
- package/dist/referencePositions.js +3 -20
- package/dist/referencePositions.js.map +1 -1
- package/dist/segmentGroupCollection.d.ts +3 -1
- package/dist/segmentGroupCollection.d.ts.map +1 -1
- package/dist/segmentGroupCollection.js +14 -1
- package/dist/segmentGroupCollection.js.map +1 -1
- package/dist/segmentPropertiesManager.d.ts +10 -1
- package/dist/segmentPropertiesManager.d.ts.map +1 -1
- package/dist/segmentPropertiesManager.js +42 -13
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/snapshotChunks.d.ts +2 -1
- package/dist/snapshotChunks.d.ts.map +1 -1
- package/dist/snapshotChunks.js.map +1 -1
- package/dist/snapshotLoader.d.ts.map +1 -1
- package/dist/snapshotLoader.js.map +1 -1
- package/dist/snapshotV1.d.ts +1 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +1 -1
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts +5 -1
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +4 -0
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +1 -1
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/textSegment.d.ts +7 -7
- package/dist/textSegment.d.ts.map +1 -1
- package/dist/textSegment.js +3 -125
- package/dist/textSegment.js.map +1 -1
- package/{DEV.md → docs/DEV.md} +2 -2
- package/docs/Obliterate.md +639 -0
- package/{REFERENCEPOSITIONS.md → docs/REFERENCEPOSITIONS.md} +2 -2
- package/lib/MergeTreeTextHelper.d.ts +23 -0
- package/lib/MergeTreeTextHelper.d.ts.map +1 -0
- package/lib/MergeTreeTextHelper.js +129 -0
- package/lib/MergeTreeTextHelper.js.map +1 -0
- package/lib/base.d.ts +2 -26
- package/lib/base.d.ts.map +1 -1
- package/lib/base.js.map +1 -1
- package/lib/client.d.ts +27 -16
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +79 -99
- package/lib/client.js.map +1 -1
- package/lib/collections/heap.d.ts +28 -0
- package/lib/collections/heap.d.ts.map +1 -0
- package/lib/collections/heap.js +61 -0
- package/lib/collections/heap.js.map +1 -0
- package/lib/collections/index.d.ts +11 -0
- package/lib/collections/index.d.ts.map +1 -0
- package/lib/collections/index.js +11 -0
- package/lib/collections/index.js.map +1 -0
- package/lib/collections/intervalTree.d.ts +60 -0
- package/lib/collections/intervalTree.d.ts.map +1 -0
- package/lib/collections/intervalTree.js +94 -0
- package/lib/collections/intervalTree.js.map +1 -0
- package/lib/collections/list.d.ts +39 -0
- package/lib/collections/list.d.ts.map +1 -0
- package/lib/collections/list.js +149 -0
- package/lib/collections/list.js.map +1 -0
- package/lib/collections/rbTree.d.ts +154 -0
- package/lib/collections/rbTree.d.ts.map +1 -0
- package/lib/{collections.js → collections/rbTree.js} +14 -469
- package/lib/collections/rbTree.js.map +1 -0
- package/lib/collections/stack.d.ts +16 -0
- package/lib/collections/stack.d.ts.map +1 -0
- package/lib/collections/stack.js +26 -0
- package/lib/collections/stack.js.map +1 -0
- package/lib/collections/tst.d.ts +55 -0
- package/lib/collections/tst.d.ts.map +1 -0
- package/lib/collections/tst.js +167 -0
- package/lib/collections/tst.js.map +1 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/localReference.d.ts +48 -99
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js +132 -170
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +71 -302
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +371 -607
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/lib/mergeTreeDeltaCallback.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +344 -0
- package/lib/mergeTreeNodes.d.ts.map +1 -0
- package/lib/mergeTreeNodes.js +369 -0
- package/lib/mergeTreeNodes.js.map +1 -0
- package/lib/mergeTreeTracking.d.ts +1 -1
- package/lib/mergeTreeTracking.d.ts.map +1 -1
- package/lib/mergeTreeTracking.js.map +1 -1
- package/lib/opBuilder.d.ts +1 -1
- package/lib/opBuilder.d.ts.map +1 -1
- package/lib/opBuilder.js.map +1 -1
- package/lib/partialLengths.d.ts +188 -18
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +491 -249
- package/lib/partialLengths.js.map +1 -1
- package/lib/properties.d.ts.map +1 -1
- package/lib/properties.js.map +1 -1
- package/lib/referencePositions.d.ts +6 -26
- package/lib/referencePositions.d.ts.map +1 -1
- package/lib/referencePositions.js +3 -20
- package/lib/referencePositions.js.map +1 -1
- package/lib/segmentGroupCollection.d.ts +3 -1
- package/lib/segmentGroupCollection.d.ts.map +1 -1
- package/lib/segmentGroupCollection.js +14 -1
- package/lib/segmentGroupCollection.js.map +1 -1
- package/lib/segmentPropertiesManager.d.ts +10 -1
- package/lib/segmentPropertiesManager.d.ts.map +1 -1
- package/lib/segmentPropertiesManager.js +42 -13
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/snapshotChunks.d.ts +2 -1
- package/lib/snapshotChunks.d.ts.map +1 -1
- package/lib/snapshotChunks.js.map +1 -1
- package/lib/snapshotLoader.d.ts.map +1 -1
- package/lib/snapshotLoader.js.map +1 -1
- package/lib/snapshotV1.d.ts +1 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +1 -1
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts +5 -1
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +4 -0
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +1 -1
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/textSegment.d.ts +7 -7
- package/lib/textSegment.d.ts.map +1 -1
- package/lib/textSegment.js +1 -122
- package/lib/textSegment.js.map +1 -1
- package/package.json +99 -20
- package/src/MergeTreeTextHelper.ts +170 -0
- package/src/base.ts +2 -35
- package/src/client.ts +91 -111
- package/src/collections/heap.ts +75 -0
- package/src/collections/index.ts +11 -0
- package/src/collections/intervalTree.ts +146 -0
- package/src/collections/list.ts +165 -0
- package/src/{collections.ts → collections/rbTree.ts} +84 -563
- package/src/collections/stack.ts +27 -0
- package/src/collections/tst.ts +212 -0
- package/src/index.ts +8 -2
- package/src/localReference.ts +152 -203
- package/src/mergeTree.ts +578 -996
- package/src/mergeTreeDeltaCallback.ts +1 -1
- package/src/mergeTreeNodes.ts +752 -0
- package/src/mergeTreeTracking.ts +1 -1
- package/src/opBuilder.ts +1 -1
- package/src/partialLengths.ts +631 -258
- package/src/properties.ts +1 -0
- package/src/referencePositions.ts +10 -44
- package/src/segmentGroupCollection.ts +17 -2
- package/src/segmentPropertiesManager.ts +46 -12
- package/src/snapshotChunks.ts +2 -1
- package/src/snapshotLoader.ts +2 -1
- package/src/snapshotV1.ts +3 -3
- package/src/snapshotlegacy.ts +6 -2
- package/src/sortedSegmentSet.ts +1 -1
- package/src/textSegment.ts +10 -157
- package/dist/collections.d.ts +0 -197
- package/dist/collections.d.ts.map +0 -1
- package/dist/collections.js.map +0 -1
- package/lib/collections.d.ts +0 -197
- package/lib/collections.d.ts.map +0 -1
- package/lib/collections.js.map +0 -1
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
7
|
+
|
|
8
|
+
/* eslint-disable @typescript-eslint/prefer-optional-chain, no-bitwise */
|
|
9
|
+
|
|
10
|
+
import { assert } from "@fluidframework/common-utils";
|
|
11
|
+
import {
|
|
12
|
+
LocalClientId,
|
|
13
|
+
UnassignedSequenceNumber,
|
|
14
|
+
UniversalSequenceNumber,
|
|
15
|
+
} from "./constants";
|
|
16
|
+
import {
|
|
17
|
+
LocalReferenceCollection,
|
|
18
|
+
LocalReferencePosition,
|
|
19
|
+
} from "./localReference";
|
|
20
|
+
import { MergeTree } from "./mergeTree";
|
|
21
|
+
import {
|
|
22
|
+
IMergeTreeDeltaOpArgs,
|
|
23
|
+
} from "./mergeTreeDeltaCallback";
|
|
24
|
+
import { TrackingGroupCollection } from "./mergeTreeTracking";
|
|
25
|
+
import {
|
|
26
|
+
ICombiningOp,
|
|
27
|
+
IJSONSegment,
|
|
28
|
+
IMarkerDef,
|
|
29
|
+
MergeTreeDeltaType,
|
|
30
|
+
ReferenceType,
|
|
31
|
+
} from "./ops";
|
|
32
|
+
import { PartialSequenceLengths } from "./partialLengths";
|
|
33
|
+
import {
|
|
34
|
+
clone,
|
|
35
|
+
createMap,
|
|
36
|
+
MapLike,
|
|
37
|
+
PropertySet,
|
|
38
|
+
} from "./properties";
|
|
39
|
+
import {
|
|
40
|
+
refTypeIncludesFlag,
|
|
41
|
+
RangeStackMap,
|
|
42
|
+
ReferencePosition,
|
|
43
|
+
refGetRangeLabels,
|
|
44
|
+
refGetTileLabels,
|
|
45
|
+
} from "./referencePositions";
|
|
46
|
+
import { SegmentGroupCollection } from "./segmentGroupCollection";
|
|
47
|
+
import { PropertiesManager, PropertiesRollback } from "./segmentPropertiesManager";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Common properties for a node in a merge tree.
|
|
51
|
+
*/
|
|
52
|
+
export interface IMergeNodeCommon {
|
|
53
|
+
parent?: IMergeBlock;
|
|
54
|
+
/**
|
|
55
|
+
* The length of the contents of the node.
|
|
56
|
+
*/
|
|
57
|
+
cachedLength: number;
|
|
58
|
+
/**
|
|
59
|
+
* The index of this node in its parent's list of children.
|
|
60
|
+
*/
|
|
61
|
+
index: number;
|
|
62
|
+
/**
|
|
63
|
+
* A string that can be used for comparing the location of this node to other `MergeNode`s in the same tree.
|
|
64
|
+
* `a.ordinal < b.ordinal` if and only if `a` comes before `b` in a pre-order traversal of the tree.
|
|
65
|
+
*/
|
|
66
|
+
ordinal: string;
|
|
67
|
+
isLeaf(): this is ISegment;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type IMergeNode = IMergeBlock | ISegment;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Internal (i.e. non-leaf) node in a merge tree.
|
|
74
|
+
*/
|
|
75
|
+
export interface IMergeBlock extends IMergeNodeCommon {
|
|
76
|
+
needsScour?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Number of direct children of this node
|
|
79
|
+
*/
|
|
80
|
+
childCount: number;
|
|
81
|
+
/**
|
|
82
|
+
* Array of child nodes.
|
|
83
|
+
*
|
|
84
|
+
* @remarks To avoid reallocation, this is always initialized to have maximum length as deemed by
|
|
85
|
+
* the merge tree's branching factor. Use `childCount` to determine how many children this node actually has.
|
|
86
|
+
*/
|
|
87
|
+
children: IMergeNode[];
|
|
88
|
+
/**
|
|
89
|
+
* Supports querying the total length of all descendants of this IMergeBlock from the perspective of any
|
|
90
|
+
* (clientId, seq) within the collab window.
|
|
91
|
+
*
|
|
92
|
+
* @remarks This is only optional for implementation reasons (internal nodes can be created/moved without
|
|
93
|
+
* immediately initializing the partial lengths). Aside from mid-update on tree operations, these lengths
|
|
94
|
+
* objects are always defined.
|
|
95
|
+
*/
|
|
96
|
+
partialLengths?: PartialSequenceLengths;
|
|
97
|
+
hierBlock(): IHierBlock | undefined;
|
|
98
|
+
assignChild(child: IMergeNode, index: number, updateOrdinal?: boolean): void;
|
|
99
|
+
setOrdinal(child: IMergeNode, index: number): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface IHierBlock extends IMergeBlock {
|
|
103
|
+
hierToString(indentCount: number): string;
|
|
104
|
+
/**
|
|
105
|
+
* @deprecated for internal use only. public export will be removed.
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
addNodeReferences(mergeTree: MergeTree, node: IMergeNode): void;
|
|
109
|
+
rightmostTiles: MapLike<ReferencePosition>;
|
|
110
|
+
leftmostTiles: MapLike<ReferencePosition>;
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated for internal use only. public export will be removed.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
rangeStacks: RangeStackMap;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Contains removal information associated to an {@link ISegment}.
|
|
120
|
+
*/
|
|
121
|
+
export interface IRemovalInfo {
|
|
122
|
+
/**
|
|
123
|
+
* Local seq at which this segment was removed, if the removal is yet-to-be acked.
|
|
124
|
+
*/
|
|
125
|
+
localRemovedSeq?: number;
|
|
126
|
+
/**
|
|
127
|
+
* Seq at which this segment was removed.
|
|
128
|
+
*/
|
|
129
|
+
removedSeq: number;
|
|
130
|
+
/**
|
|
131
|
+
* List of client IDs that have removed this segment.
|
|
132
|
+
* The client that actually removed the segment (i.e. whose removal op was sequenced first) is stored as the first
|
|
133
|
+
* client in this list. Other clients in the list have all issued concurrent ops to remove the segment.
|
|
134
|
+
* @remarks When this list has length \> 1, this is referred to as the "overlapping remove" case.
|
|
135
|
+
*/
|
|
136
|
+
removedClientIds: number[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function toRemovalInfo(maybe: Partial<IRemovalInfo> | undefined): IRemovalInfo | undefined {
|
|
140
|
+
if (maybe?.removedClientIds !== undefined && maybe?.removedSeq !== undefined) {
|
|
141
|
+
return maybe as IRemovalInfo;
|
|
142
|
+
}
|
|
143
|
+
assert(maybe?.removedClientIds === undefined && maybe?.removedSeq === undefined,
|
|
144
|
+
0x2bf /* "both removedClientIds and removedSeq should be set or not set" */);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* A segment representing a portion of the merge tree.
|
|
149
|
+
* Segments are leaf nodes of the merge tree and contain data.
|
|
150
|
+
*/
|
|
151
|
+
export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo> {
|
|
152
|
+
readonly type: string;
|
|
153
|
+
readonly segmentGroups: SegmentGroupCollection;
|
|
154
|
+
readonly trackingCollection: TrackingGroupCollection;
|
|
155
|
+
/**
|
|
156
|
+
* Manages pending local state for properties on this segment.
|
|
157
|
+
*/
|
|
158
|
+
propertyManager?: PropertiesManager;
|
|
159
|
+
/**
|
|
160
|
+
* Local seq at which this segment was inserted. If this is defined, `seq` will be UnassignedSequenceNumber.
|
|
161
|
+
* Once the segment is acked, this field is cleared.
|
|
162
|
+
*/
|
|
163
|
+
localSeq?: number;
|
|
164
|
+
/**
|
|
165
|
+
* Local seq at which this segment was removed. If this is defined, `removedSeq` will initially be set to
|
|
166
|
+
* UnassignedSequenceNumber. However, if another client concurrently removes the same segment, `removedSeq`
|
|
167
|
+
* will be updated to the seq at which that client removed this segment.
|
|
168
|
+
*
|
|
169
|
+
* Like `localSeq`, this field is cleared once the local removal of the segment is acked.
|
|
170
|
+
*/
|
|
171
|
+
localRemovedSeq?: number;
|
|
172
|
+
/**
|
|
173
|
+
* Seq at which this segment was inserted.
|
|
174
|
+
* If undefined, it is assumed the segment was inserted prior to the collab window's minimum sequence number.
|
|
175
|
+
*/
|
|
176
|
+
seq?: number;
|
|
177
|
+
/**
|
|
178
|
+
* Short clientId for the client that inserted this segment.
|
|
179
|
+
*/
|
|
180
|
+
clientId: number;
|
|
181
|
+
/**
|
|
182
|
+
* Local references added to this segment.
|
|
183
|
+
*/
|
|
184
|
+
localRefs?: LocalReferenceCollection;
|
|
185
|
+
/**
|
|
186
|
+
* Properties that have been added to this segment via annotation.
|
|
187
|
+
*/
|
|
188
|
+
properties?: PropertySet;
|
|
189
|
+
addProperties(
|
|
190
|
+
newProps: PropertySet,
|
|
191
|
+
op?: ICombiningOp,
|
|
192
|
+
seq?: number,
|
|
193
|
+
collabWindow?: CollaborationWindow,
|
|
194
|
+
rollback?: PropertiesRollback,
|
|
195
|
+
): PropertySet | undefined;
|
|
196
|
+
clone(): ISegment;
|
|
197
|
+
canAppend(segment: ISegment): boolean;
|
|
198
|
+
append(segment: ISegment): void;
|
|
199
|
+
splitAt(pos: number): ISegment | undefined;
|
|
200
|
+
toJSONObject(): any;
|
|
201
|
+
/**
|
|
202
|
+
* Acks the current segment against the segment group, op, and merge tree.
|
|
203
|
+
*
|
|
204
|
+
* Throws error if the segment state doesn't match segment group or op.
|
|
205
|
+
* E.g. Segment group not first is pending queue.
|
|
206
|
+
* Inserted segment does not have unassigned sequence number.
|
|
207
|
+
*
|
|
208
|
+
* Returns true if the op modifies the segment, otherwise false.
|
|
209
|
+
* The only current false case is overlapping remove, where a segment is removed
|
|
210
|
+
* by a previously sequenced operation before the current operation is acked.
|
|
211
|
+
*
|
|
212
|
+
* @deprecated for internal use only. public export will be removed.
|
|
213
|
+
* @internal
|
|
214
|
+
*/
|
|
215
|
+
ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface IMarkerModifiedAction {
|
|
219
|
+
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
|
220
|
+
(marker: Marker): void;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface ISegmentAction<TClientData> {
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
|
225
|
+
(segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,
|
|
226
|
+
end: number, accum: TClientData): boolean;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface ISegmentChanges {
|
|
230
|
+
next?: ISegment;
|
|
231
|
+
replaceCurrent?: ISegment;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface BlockAction<TClientData> {
|
|
235
|
+
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
|
236
|
+
(
|
|
237
|
+
block: IMergeBlock,
|
|
238
|
+
pos: number,
|
|
239
|
+
refSeq: number,
|
|
240
|
+
clientId: number,
|
|
241
|
+
start: number | undefined,
|
|
242
|
+
end: number | undefined,
|
|
243
|
+
accum: TClientData,
|
|
244
|
+
): boolean;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface NodeAction<TClientData> {
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
|
249
|
+
(
|
|
250
|
+
node: IMergeNode,
|
|
251
|
+
pos: number,
|
|
252
|
+
refSeq: number,
|
|
253
|
+
clientId: number,
|
|
254
|
+
start: number | undefined,
|
|
255
|
+
end: number | undefined,
|
|
256
|
+
clientData: TClientData,
|
|
257
|
+
): boolean;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export interface IncrementalSegmentAction<TContext> {
|
|
261
|
+
(segment: ISegment, state: IncrementalMapState<TContext>);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface IncrementalBlockAction<TContext> {
|
|
265
|
+
(state: IncrementalMapState<TContext>);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface BlockUpdateActions {
|
|
269
|
+
child: (block: IMergeBlock, index: number) => void;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface InsertContext {
|
|
273
|
+
candidateSegment?: ISegment;
|
|
274
|
+
prepareEvents?: boolean;
|
|
275
|
+
structureChange?: boolean;
|
|
276
|
+
leaf: (segment: ISegment | undefined, pos: number, ic: InsertContext) => ISegmentChanges;
|
|
277
|
+
continuePredicate?: (continueFromBlock: IMergeBlock) => boolean;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface SegmentActions<TClientData> {
|
|
281
|
+
leaf?: ISegmentAction<TClientData>;
|
|
282
|
+
shift?: NodeAction<TClientData>;
|
|
283
|
+
contains?: NodeAction<TClientData>;
|
|
284
|
+
pre?: BlockAction<TClientData>;
|
|
285
|
+
post?: BlockAction<TClientData>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface IncrementalSegmentActions<TContext> {
|
|
289
|
+
leaf: IncrementalSegmentAction<TContext>;
|
|
290
|
+
pre?: IncrementalBlockAction<TContext>;
|
|
291
|
+
post?: IncrementalBlockAction<TContext>;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface SearchResult {
|
|
295
|
+
text: string;
|
|
296
|
+
pos: number;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface MergeTreeStats {
|
|
300
|
+
maxHeight: number;
|
|
301
|
+
nodeCount: number;
|
|
302
|
+
leafCount: number;
|
|
303
|
+
removedLeafCount: number;
|
|
304
|
+
liveCount: number;
|
|
305
|
+
histo: number[];
|
|
306
|
+
windowTime?: number;
|
|
307
|
+
packTime?: number;
|
|
308
|
+
ordTime?: number;
|
|
309
|
+
maxOrdTime?: number;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface SegmentGroup {
|
|
313
|
+
segments: ISegment[];
|
|
314
|
+
previousProps?: PropertySet[];
|
|
315
|
+
removedReferences?: LocalReferencePosition[];
|
|
316
|
+
localSeq: number;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export class MergeNode implements IMergeNodeCommon {
|
|
320
|
+
index: number = 0;
|
|
321
|
+
ordinal: string = "";
|
|
322
|
+
parent?: IMergeBlock;
|
|
323
|
+
cachedLength: number = 0;
|
|
324
|
+
|
|
325
|
+
isLeaf() {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
export function ordinalToArray(ord: string) {
|
|
330
|
+
const a: number[] = [];
|
|
331
|
+
if (ord) {
|
|
332
|
+
for (let i = 0, len = ord.length; i < len; i++) {
|
|
333
|
+
a.push(ord.charCodeAt(i));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return a;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Note that the actual branching factor of the MergeTree is `MaxNodesInBlock - 1`. This is because
|
|
340
|
+
// the MergeTree always inserts first, then checks for overflow and splits if the child count equals
|
|
341
|
+
// `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
|
|
342
|
+
// facilitate splits.)
|
|
343
|
+
export const MaxNodesInBlock = 8;
|
|
344
|
+
|
|
345
|
+
export class MergeBlock extends MergeNode implements IMergeBlock {
|
|
346
|
+
public children: IMergeNode[];
|
|
347
|
+
public constructor(public childCount: number) {
|
|
348
|
+
super();
|
|
349
|
+
this.children = new Array<IMergeNode>(MaxNodesInBlock);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public hierBlock(): IHierBlock | undefined {
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
public setOrdinal(child: IMergeNode, index: number) {
|
|
357
|
+
let childCount = this.childCount;
|
|
358
|
+
if (childCount === 8) {
|
|
359
|
+
childCount = 7;
|
|
360
|
+
}
|
|
361
|
+
assert((childCount >= 1) && (childCount <= 7), 0x040 /* "Child count is not within [1,7] range!" */);
|
|
362
|
+
let localOrdinal: number;
|
|
363
|
+
const ordinalWidth = 1 << (MaxNodesInBlock - (childCount + 1));
|
|
364
|
+
if (index === 0) {
|
|
365
|
+
localOrdinal = ordinalWidth - 1;
|
|
366
|
+
} else {
|
|
367
|
+
const prevOrd = this.children[index - 1].ordinal;
|
|
368
|
+
const prevOrdCode = prevOrd.charCodeAt(prevOrd.length - 1);
|
|
369
|
+
localOrdinal = prevOrdCode + ordinalWidth;
|
|
370
|
+
}
|
|
371
|
+
child.ordinal = this.ordinal + String.fromCharCode(localOrdinal);
|
|
372
|
+
assert(child.ordinal.length === (this.ordinal.length + 1), 0x041 /* "Unexpected child ordinal length!" */);
|
|
373
|
+
if (index > 0) {
|
|
374
|
+
assert(
|
|
375
|
+
child.ordinal > this.children[index - 1].ordinal,
|
|
376
|
+
0x042, /* "Child ordinal <= previous sibling ordinal!" */
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
public assignChild(child: IMergeNode, index: number, updateOrdinal = true) {
|
|
382
|
+
child.parent = this;
|
|
383
|
+
child.index = index;
|
|
384
|
+
if (updateOrdinal) {
|
|
385
|
+
this.setOrdinal(child, index);
|
|
386
|
+
}
|
|
387
|
+
this.children[index] = child;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export abstract class BaseSegment extends MergeNode implements ISegment {
|
|
392
|
+
public clientId: number = LocalClientId;
|
|
393
|
+
public seq: number = UniversalSequenceNumber;
|
|
394
|
+
public removedSeq?: number;
|
|
395
|
+
public removedClientIds?: number[];
|
|
396
|
+
public readonly segmentGroups: SegmentGroupCollection = new SegmentGroupCollection(this);
|
|
397
|
+
public readonly trackingCollection: TrackingGroupCollection = new TrackingGroupCollection(this);
|
|
398
|
+
public propertyManager?: PropertiesManager;
|
|
399
|
+
public properties?: PropertySet;
|
|
400
|
+
public localRefs?: LocalReferenceCollection;
|
|
401
|
+
public abstract readonly type: string;
|
|
402
|
+
public localSeq?: number;
|
|
403
|
+
public localRemovedSeq?: number;
|
|
404
|
+
|
|
405
|
+
public addProperties(newProps: PropertySet, op?: ICombiningOp, seq?: number,
|
|
406
|
+
collabWindow?: CollaborationWindow, rollback: PropertiesRollback = PropertiesRollback.None) {
|
|
407
|
+
if (!this.propertyManager) {
|
|
408
|
+
this.propertyManager = new PropertiesManager();
|
|
409
|
+
}
|
|
410
|
+
if (!this.properties) {
|
|
411
|
+
this.properties = createMap<any>();
|
|
412
|
+
}
|
|
413
|
+
return this.propertyManager.addProperties(
|
|
414
|
+
this.properties,
|
|
415
|
+
newProps,
|
|
416
|
+
op,
|
|
417
|
+
seq,
|
|
418
|
+
collabWindow && collabWindow.collaborating,
|
|
419
|
+
rollback,
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
public hasProperty(key: string): boolean {
|
|
424
|
+
return !!this.properties && (this.properties[key] !== undefined);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
public isLeaf() {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
protected cloneInto(b: ISegment) {
|
|
432
|
+
b.clientId = this.clientId;
|
|
433
|
+
// TODO: deep clone properties
|
|
434
|
+
b.properties = clone(this.properties);
|
|
435
|
+
b.removedClientIds = this.removedClientIds?.slice();
|
|
436
|
+
// TODO: copy removed client overlap and branch removal info
|
|
437
|
+
b.removedSeq = this.removedSeq;
|
|
438
|
+
b.seq = this.seq;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
public canAppend(segment: ISegment): boolean {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
protected addSerializedProps(jseg: IJSONSegment) {
|
|
446
|
+
if (this.properties) {
|
|
447
|
+
jseg.props = this.properties;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public abstract toJSONObject(): any;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* @deprecated for internal use only. public export will be removed.
|
|
455
|
+
* @internal
|
|
456
|
+
*/
|
|
457
|
+
public ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean {
|
|
458
|
+
const currentSegmentGroup = this.segmentGroups.dequeue();
|
|
459
|
+
assert(currentSegmentGroup === segmentGroup, 0x043 /* "On ack, unexpected segmentGroup!" */);
|
|
460
|
+
switch (opArgs.op.type) {
|
|
461
|
+
case MergeTreeDeltaType.ANNOTATE:
|
|
462
|
+
assert(!!this.propertyManager, 0x044 /* "On annotate ack, missing segment property manager!" */);
|
|
463
|
+
this.propertyManager.ackPendingProperties(opArgs.op);
|
|
464
|
+
return true;
|
|
465
|
+
|
|
466
|
+
case MergeTreeDeltaType.INSERT:
|
|
467
|
+
assert(this.seq === UnassignedSequenceNumber, 0x045 /* "On insert, seq number already assigned!" */);
|
|
468
|
+
this.seq = opArgs.sequencedMessage!.sequenceNumber;
|
|
469
|
+
this.localSeq = undefined;
|
|
470
|
+
return true;
|
|
471
|
+
|
|
472
|
+
case MergeTreeDeltaType.REMOVE:
|
|
473
|
+
const removalInfo: IRemovalInfo | undefined = toRemovalInfo(this);
|
|
474
|
+
assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
|
|
475
|
+
this.localRemovedSeq = undefined;
|
|
476
|
+
if (removalInfo.removedSeq === UnassignedSequenceNumber) {
|
|
477
|
+
removalInfo.removedSeq = opArgs.sequencedMessage!.sequenceNumber;
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
|
|
482
|
+
default:
|
|
483
|
+
throw new Error(`${opArgs.op.type} is in unrecognized operation type`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
public splitAt(pos: number): ISegment | undefined {
|
|
488
|
+
if (pos > 0) {
|
|
489
|
+
const leafSegment = this.createSplitSegmentAt(pos);
|
|
490
|
+
if (leafSegment) {
|
|
491
|
+
this.copyPropertiesTo(leafSegment);
|
|
492
|
+
leafSegment.parent = this.parent;
|
|
493
|
+
|
|
494
|
+
// Give the leaf a temporary yet valid ordinal.
|
|
495
|
+
// when this segment is put in the tree, it will get its real ordinal,
|
|
496
|
+
// but this ordinal meets all the necessary invariants for now.
|
|
497
|
+
leafSegment.ordinal = this.ordinal + String.fromCharCode(0);
|
|
498
|
+
|
|
499
|
+
leafSegment.removedClientIds = this.removedClientIds?.slice();
|
|
500
|
+
leafSegment.removedSeq = this.removedSeq;
|
|
501
|
+
leafSegment.localRemovedSeq = this.localRemovedSeq;
|
|
502
|
+
leafSegment.seq = this.seq;
|
|
503
|
+
leafSegment.localSeq = this.localSeq;
|
|
504
|
+
leafSegment.clientId = this.clientId;
|
|
505
|
+
this.segmentGroups.copyTo(leafSegment);
|
|
506
|
+
this.trackingCollection.copyTo(leafSegment);
|
|
507
|
+
if (this.localRefs) {
|
|
508
|
+
this.localRefs.split(pos, leafSegment);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return leafSegment;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private copyPropertiesTo(other: ISegment) {
|
|
516
|
+
if (this.propertyManager) {
|
|
517
|
+
if (this.properties) {
|
|
518
|
+
other.propertyManager = new PropertiesManager();
|
|
519
|
+
other.properties = this.propertyManager.copyTo(
|
|
520
|
+
this.properties,
|
|
521
|
+
other.properties,
|
|
522
|
+
other.propertyManager,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
public abstract clone(): ISegment;
|
|
529
|
+
public abstract append(segment: ISegment): void;
|
|
530
|
+
protected abstract createSplitSegmentAt(pos: number): BaseSegment | undefined;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export const reservedMarkerIdKey = "markerId";
|
|
534
|
+
export const reservedMarkerSimpleTypeKey = "markerSimpleType";
|
|
535
|
+
|
|
536
|
+
export interface IJSONMarkerSegment extends IJSONSegment {
|
|
537
|
+
marker: IMarkerDef;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export class Marker extends BaseSegment implements ReferencePosition {
|
|
541
|
+
public static readonly type = "Marker";
|
|
542
|
+
public static is(segment: ISegment): segment is Marker {
|
|
543
|
+
return segment.type === Marker.type;
|
|
544
|
+
}
|
|
545
|
+
public readonly type = Marker.type;
|
|
546
|
+
|
|
547
|
+
public static make(
|
|
548
|
+
refType: ReferenceType, props?: PropertySet) {
|
|
549
|
+
const marker = new Marker(refType);
|
|
550
|
+
if (props) {
|
|
551
|
+
marker.addProperties(props);
|
|
552
|
+
}
|
|
553
|
+
return marker;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
constructor(public refType: ReferenceType) {
|
|
557
|
+
super();
|
|
558
|
+
this.cachedLength = 1;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
toJSONObject() {
|
|
562
|
+
const obj: IJSONMarkerSegment = { marker: { refType: this.refType } };
|
|
563
|
+
super.addSerializedProps(obj);
|
|
564
|
+
return obj;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
static fromJSONObject(spec: any) {
|
|
568
|
+
if (spec && typeof spec === "object" && "marker" in spec) {
|
|
569
|
+
return Marker.make(
|
|
570
|
+
spec.marker.refType,
|
|
571
|
+
spec.props as PropertySet);
|
|
572
|
+
}
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
clone() {
|
|
577
|
+
const b = Marker.make(this.refType, this.properties);
|
|
578
|
+
this.cloneInto(b);
|
|
579
|
+
return b;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
getSegment() {
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
getOffset() {
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
hasSimpleType(simpleTypeName: string) {
|
|
591
|
+
return !!this.properties &&
|
|
592
|
+
this.properties[reservedMarkerSimpleTypeKey] === simpleTypeName;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
getProperties() {
|
|
596
|
+
return this.properties;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
getId(): string | undefined {
|
|
600
|
+
if (this.properties && this.properties[reservedMarkerIdKey]) {
|
|
601
|
+
return this.properties[reservedMarkerIdKey] as string;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
toString() {
|
|
606
|
+
let bbuf = "";
|
|
607
|
+
if (refTypeIncludesFlag(this, ReferenceType.Tile)) {
|
|
608
|
+
bbuf += "Tile";
|
|
609
|
+
}
|
|
610
|
+
if (refTypeIncludesFlag(this, ReferenceType.NestBegin)) {
|
|
611
|
+
if (bbuf.length > 0) {
|
|
612
|
+
bbuf += "; ";
|
|
613
|
+
}
|
|
614
|
+
bbuf += "RangeBegin";
|
|
615
|
+
}
|
|
616
|
+
if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
|
|
617
|
+
if (bbuf.length > 0) {
|
|
618
|
+
bbuf += "; ";
|
|
619
|
+
}
|
|
620
|
+
bbuf += "RangeEnd";
|
|
621
|
+
}
|
|
622
|
+
let lbuf = "";
|
|
623
|
+
const id = this.getId();
|
|
624
|
+
if (id) {
|
|
625
|
+
bbuf += ` (${id}) `;
|
|
626
|
+
}
|
|
627
|
+
const tileLabels = refGetTileLabels(this);
|
|
628
|
+
if (tileLabels) {
|
|
629
|
+
lbuf += "tile -- ";
|
|
630
|
+
for (let i = 0, len = tileLabels.length; i < len; i++) {
|
|
631
|
+
const tileLabel = tileLabels[i];
|
|
632
|
+
if (i > 0) {
|
|
633
|
+
lbuf += "; ";
|
|
634
|
+
}
|
|
635
|
+
lbuf += tileLabel;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
const rangeLabels = refGetRangeLabels(this);
|
|
639
|
+
if (rangeLabels) {
|
|
640
|
+
let rangeKind = "begin";
|
|
641
|
+
if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
|
|
642
|
+
rangeKind = "end";
|
|
643
|
+
}
|
|
644
|
+
if (tileLabels) {
|
|
645
|
+
lbuf += " ";
|
|
646
|
+
}
|
|
647
|
+
lbuf += `range ${rangeKind} -- `;
|
|
648
|
+
const labels = rangeLabels;
|
|
649
|
+
for (let i = 0, len = labels.length; i < len; i++) {
|
|
650
|
+
const rangeLabel = labels[i];
|
|
651
|
+
if (i > 0) {
|
|
652
|
+
lbuf += "; ";
|
|
653
|
+
}
|
|
654
|
+
lbuf += rangeLabel;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
let pbuf = "";
|
|
658
|
+
if (this.properties) {
|
|
659
|
+
pbuf += JSON.stringify(this.properties, (key, value) => {
|
|
660
|
+
// Avoid circular reference when stringifying makers containing handles.
|
|
661
|
+
// (Substitute a debug string instead.)
|
|
662
|
+
const handle = !!value && value.IFluidHandle;
|
|
663
|
+
|
|
664
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
665
|
+
return handle
|
|
666
|
+
? `#Handle(${handle.routeContext.path}/${handle.path})`
|
|
667
|
+
: value;
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return `M ${bbuf}: ${lbuf} ${pbuf}`;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
protected createSplitSegmentAt(pos: number) {
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
canAppend(segment: ISegment): boolean {
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
append() { throw new Error("Can not append to marker"); }
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export enum IncrementalExecOp {
|
|
685
|
+
Go,
|
|
686
|
+
Stop,
|
|
687
|
+
Yield,
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export class IncrementalMapState<TContext> {
|
|
691
|
+
op = IncrementalExecOp.Go;
|
|
692
|
+
constructor(
|
|
693
|
+
public block: IMergeBlock,
|
|
694
|
+
public actions: IncrementalSegmentActions<TContext>,
|
|
695
|
+
public pos: number,
|
|
696
|
+
public refSeq: number,
|
|
697
|
+
public clientId: number,
|
|
698
|
+
public context: TContext,
|
|
699
|
+
public start: number,
|
|
700
|
+
public end: number,
|
|
701
|
+
public childIndex = 0,
|
|
702
|
+
) {
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export class CollaborationWindow {
|
|
707
|
+
clientId = LocalClientId;
|
|
708
|
+
collaborating = false;
|
|
709
|
+
// Lowest-numbered segment in window; no client can reference a state before this one
|
|
710
|
+
minSeq = 0;
|
|
711
|
+
// Highest-numbered segment in window and current
|
|
712
|
+
// reference segment for this client
|
|
713
|
+
currentSeq = 0;
|
|
714
|
+
|
|
715
|
+
localSeq = 0;
|
|
716
|
+
|
|
717
|
+
loadFrom(a: CollaborationWindow) {
|
|
718
|
+
this.clientId = a.clientId;
|
|
719
|
+
this.collaborating = a.collaborating;
|
|
720
|
+
this.minSeq = a.minSeq;
|
|
721
|
+
this.currentSeq = a.currentSeq;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export const compareNumbers = (a: number, b: number) => a - b;
|
|
726
|
+
|
|
727
|
+
export const compareStrings = (a: string, b: string) => a.localeCompare(b);
|
|
728
|
+
|
|
729
|
+
const indentStrings = ["", " ", " "];
|
|
730
|
+
export function internedSpaces(n: number) {
|
|
731
|
+
if (indentStrings[n] === undefined) {
|
|
732
|
+
indentStrings[n] = "";
|
|
733
|
+
for (let i = 0; i < n; i++) {
|
|
734
|
+
indentStrings[n] += " ";
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return indentStrings[n];
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export interface IConsensusInfo {
|
|
741
|
+
marker: Marker;
|
|
742
|
+
callback: (m: Marker) => void;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export interface SegmentAccumulator {
|
|
746
|
+
segments: ISegment[];
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export interface MinListener {
|
|
750
|
+
minRequired: number;
|
|
751
|
+
onMinGE(minSeq: number): void;
|
|
752
|
+
}
|