@fluidframework/merge-tree 1.2.1 → 2.0.0-internal.1.0.0

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.
Files changed (231) hide show
  1. package/DEV.md +2 -2
  2. package/README.md +1 -1
  3. package/REFERENCEPOSITIONS.md +2 -2
  4. package/dist/MergeTreeTextHelper.d.ts +23 -0
  5. package/dist/MergeTreeTextHelper.d.ts.map +1 -0
  6. package/dist/MergeTreeTextHelper.js +136 -0
  7. package/dist/MergeTreeTextHelper.js.map +1 -0
  8. package/dist/base.d.ts +2 -26
  9. package/dist/base.d.ts.map +1 -1
  10. package/dist/base.js.map +1 -1
  11. package/dist/client.d.ts +21 -12
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +87 -27
  14. package/dist/client.js.map +1 -1
  15. package/dist/collections/heap.d.ts +28 -0
  16. package/dist/collections/heap.d.ts.map +1 -0
  17. package/dist/collections/heap.js +65 -0
  18. package/dist/collections/heap.js.map +1 -0
  19. package/dist/collections/index.d.ts +11 -0
  20. package/dist/collections/index.d.ts.map +1 -0
  21. package/dist/collections/index.js +23 -0
  22. package/dist/collections/index.js.map +1 -0
  23. package/dist/collections/intervalTree.d.ts +60 -0
  24. package/dist/collections/intervalTree.d.ts.map +1 -0
  25. package/dist/collections/intervalTree.js +99 -0
  26. package/dist/collections/intervalTree.js.map +1 -0
  27. package/dist/collections/list.d.ts +39 -0
  28. package/dist/collections/list.d.ts.map +1 -0
  29. package/dist/collections/list.js +155 -0
  30. package/dist/collections/list.js.map +1 -0
  31. package/dist/collections/rbTree.d.ts +154 -0
  32. package/dist/collections/rbTree.d.ts.map +1 -0
  33. package/dist/{collections.js → collections/rbTree.js} +10 -448
  34. package/dist/collections/rbTree.js.map +1 -0
  35. package/dist/collections/stack.d.ts +16 -0
  36. package/dist/collections/stack.d.ts.map +1 -0
  37. package/dist/collections/stack.js +30 -0
  38. package/dist/collections/stack.js.map +1 -0
  39. package/dist/collections/tst.d.ts +55 -0
  40. package/dist/collections/tst.d.ts.map +1 -0
  41. package/dist/collections/tst.js +171 -0
  42. package/dist/collections/tst.js.map +1 -0
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/localReference.d.ts +48 -99
  48. package/dist/localReference.d.ts.map +1 -1
  49. package/dist/localReference.js +132 -169
  50. package/dist/localReference.js.map +1 -1
  51. package/dist/mergeTree.d.ts +38 -299
  52. package/dist/mergeTree.d.ts.map +1 -1
  53. package/dist/mergeTree.js +214 -598
  54. package/dist/mergeTree.js.map +1 -1
  55. package/dist/mergeTreeDeltaCallback.d.ts +1 -1
  56. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  57. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  58. package/dist/mergeTreeNodes.d.ts +269 -0
  59. package/dist/mergeTreeNodes.d.ts.map +1 -0
  60. package/dist/mergeTreeNodes.js +383 -0
  61. package/dist/mergeTreeNodes.js.map +1 -0
  62. package/dist/mergeTreeTracking.d.ts +1 -1
  63. package/dist/mergeTreeTracking.d.ts.map +1 -1
  64. package/dist/mergeTreeTracking.js.map +1 -1
  65. package/dist/opBuilder.d.ts +1 -1
  66. package/dist/opBuilder.d.ts.map +1 -1
  67. package/dist/opBuilder.js.map +1 -1
  68. package/dist/partialLengths.d.ts +130 -15
  69. package/dist/partialLengths.d.ts.map +1 -1
  70. package/dist/partialLengths.js +230 -138
  71. package/dist/partialLengths.js.map +1 -1
  72. package/dist/properties.d.ts.map +1 -1
  73. package/dist/properties.js.map +1 -1
  74. package/dist/referencePositions.d.ts +6 -26
  75. package/dist/referencePositions.d.ts.map +1 -1
  76. package/dist/referencePositions.js.map +1 -1
  77. package/dist/segmentGroupCollection.d.ts +2 -1
  78. package/dist/segmentGroupCollection.d.ts.map +1 -1
  79. package/dist/segmentGroupCollection.js +3 -0
  80. package/dist/segmentGroupCollection.js.map +1 -1
  81. package/dist/segmentPropertiesManager.d.ts +10 -1
  82. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  83. package/dist/segmentPropertiesManager.js +41 -6
  84. package/dist/segmentPropertiesManager.js.map +1 -1
  85. package/dist/snapshotLoader.d.ts.map +1 -1
  86. package/dist/snapshotLoader.js.map +1 -1
  87. package/dist/snapshotV1.d.ts +1 -1
  88. package/dist/snapshotV1.d.ts.map +1 -1
  89. package/dist/snapshotV1.js.map +1 -1
  90. package/dist/snapshotlegacy.d.ts +5 -1
  91. package/dist/snapshotlegacy.d.ts.map +1 -1
  92. package/dist/snapshotlegacy.js +4 -0
  93. package/dist/snapshotlegacy.js.map +1 -1
  94. package/dist/sortedSegmentSet.d.ts +1 -1
  95. package/dist/sortedSegmentSet.d.ts.map +1 -1
  96. package/dist/sortedSegmentSet.js.map +1 -1
  97. package/dist/textSegment.d.ts +7 -7
  98. package/dist/textSegment.d.ts.map +1 -1
  99. package/dist/textSegment.js +3 -125
  100. package/dist/textSegment.js.map +1 -1
  101. package/lib/MergeTreeTextHelper.d.ts +23 -0
  102. package/lib/MergeTreeTextHelper.d.ts.map +1 -0
  103. package/lib/MergeTreeTextHelper.js +132 -0
  104. package/lib/MergeTreeTextHelper.js.map +1 -0
  105. package/lib/base.d.ts +2 -26
  106. package/lib/base.d.ts.map +1 -1
  107. package/lib/base.js.map +1 -1
  108. package/lib/client.d.ts +21 -12
  109. package/lib/client.d.ts.map +1 -1
  110. package/lib/client.js +85 -25
  111. package/lib/client.js.map +1 -1
  112. package/lib/collections/heap.d.ts +28 -0
  113. package/lib/collections/heap.d.ts.map +1 -0
  114. package/lib/collections/heap.js +61 -0
  115. package/lib/collections/heap.js.map +1 -0
  116. package/lib/collections/index.d.ts +11 -0
  117. package/lib/collections/index.d.ts.map +1 -0
  118. package/lib/collections/index.js +11 -0
  119. package/lib/collections/index.js.map +1 -0
  120. package/lib/collections/intervalTree.d.ts +60 -0
  121. package/lib/collections/intervalTree.d.ts.map +1 -0
  122. package/lib/collections/intervalTree.js +94 -0
  123. package/lib/collections/intervalTree.js.map +1 -0
  124. package/lib/collections/list.d.ts +39 -0
  125. package/lib/collections/list.d.ts.map +1 -0
  126. package/lib/collections/list.js +149 -0
  127. package/lib/collections/list.js.map +1 -0
  128. package/lib/collections/rbTree.d.ts +154 -0
  129. package/lib/collections/rbTree.d.ts.map +1 -0
  130. package/lib/{collections.js → collections/rbTree.js} +9 -439
  131. package/lib/collections/rbTree.js.map +1 -0
  132. package/lib/collections/stack.d.ts +16 -0
  133. package/lib/collections/stack.d.ts.map +1 -0
  134. package/lib/collections/stack.js +26 -0
  135. package/lib/collections/stack.js.map +1 -0
  136. package/lib/collections/tst.d.ts +55 -0
  137. package/lib/collections/tst.d.ts.map +1 -0
  138. package/lib/collections/tst.js +167 -0
  139. package/lib/collections/tst.js.map +1 -0
  140. package/lib/index.d.ts +3 -1
  141. package/lib/index.d.ts.map +1 -1
  142. package/lib/index.js +3 -1
  143. package/lib/index.js.map +1 -1
  144. package/lib/localReference.d.ts +48 -99
  145. package/lib/localReference.d.ts.map +1 -1
  146. package/lib/localReference.js +132 -170
  147. package/lib/localReference.js.map +1 -1
  148. package/lib/mergeTree.d.ts +38 -299
  149. package/lib/mergeTree.d.ts.map +1 -1
  150. package/lib/mergeTree.js +190 -563
  151. package/lib/mergeTree.js.map +1 -1
  152. package/lib/mergeTreeDeltaCallback.d.ts +1 -1
  153. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  154. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  155. package/lib/mergeTreeNodes.d.ts +269 -0
  156. package/lib/mergeTreeNodes.d.ts.map +1 -0
  157. package/lib/mergeTreeNodes.js +369 -0
  158. package/lib/mergeTreeNodes.js.map +1 -0
  159. package/lib/mergeTreeTracking.d.ts +1 -1
  160. package/lib/mergeTreeTracking.d.ts.map +1 -1
  161. package/lib/mergeTreeTracking.js.map +1 -1
  162. package/lib/opBuilder.d.ts +1 -1
  163. package/lib/opBuilder.d.ts.map +1 -1
  164. package/lib/opBuilder.js.map +1 -1
  165. package/lib/partialLengths.d.ts +130 -15
  166. package/lib/partialLengths.d.ts.map +1 -1
  167. package/lib/partialLengths.js +227 -135
  168. package/lib/partialLengths.js.map +1 -1
  169. package/lib/properties.d.ts.map +1 -1
  170. package/lib/properties.js.map +1 -1
  171. package/lib/referencePositions.d.ts +6 -26
  172. package/lib/referencePositions.d.ts.map +1 -1
  173. package/lib/referencePositions.js.map +1 -1
  174. package/lib/segmentGroupCollection.d.ts +2 -1
  175. package/lib/segmentGroupCollection.d.ts.map +1 -1
  176. package/lib/segmentGroupCollection.js +3 -0
  177. package/lib/segmentGroupCollection.js.map +1 -1
  178. package/lib/segmentPropertiesManager.d.ts +10 -1
  179. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  180. package/lib/segmentPropertiesManager.js +41 -6
  181. package/lib/segmentPropertiesManager.js.map +1 -1
  182. package/lib/snapshotLoader.d.ts.map +1 -1
  183. package/lib/snapshotLoader.js.map +1 -1
  184. package/lib/snapshotV1.d.ts +1 -1
  185. package/lib/snapshotV1.d.ts.map +1 -1
  186. package/lib/snapshotV1.js.map +1 -1
  187. package/lib/snapshotlegacy.d.ts +5 -1
  188. package/lib/snapshotlegacy.d.ts.map +1 -1
  189. package/lib/snapshotlegacy.js +4 -0
  190. package/lib/snapshotlegacy.js.map +1 -1
  191. package/lib/sortedSegmentSet.d.ts +1 -1
  192. package/lib/sortedSegmentSet.d.ts.map +1 -1
  193. package/lib/sortedSegmentSet.js.map +1 -1
  194. package/lib/textSegment.d.ts +7 -7
  195. package/lib/textSegment.d.ts.map +1 -1
  196. package/lib/textSegment.js +1 -122
  197. package/lib/textSegment.js.map +1 -1
  198. package/package.json +93 -17
  199. package/src/MergeTreeTextHelper.ts +172 -0
  200. package/src/base.ts +2 -35
  201. package/src/client.ts +114 -30
  202. package/src/collections/heap.ts +75 -0
  203. package/src/collections/index.ts +11 -0
  204. package/src/collections/intervalTree.ts +140 -0
  205. package/src/collections/list.ts +165 -0
  206. package/src/{collections.ts → collections/rbTree.ts} +79 -538
  207. package/src/collections/stack.ts +27 -0
  208. package/src/collections/tst.ts +212 -0
  209. package/src/index.ts +8 -2
  210. package/src/localReference.ts +152 -203
  211. package/src/mergeTree.ts +265 -868
  212. package/src/mergeTreeDeltaCallback.ts +1 -1
  213. package/src/mergeTreeNodes.ts +676 -0
  214. package/src/mergeTreeTracking.ts +1 -1
  215. package/src/opBuilder.ts +1 -1
  216. package/src/partialLengths.ts +295 -150
  217. package/src/properties.ts +1 -0
  218. package/src/referencePositions.ts +7 -27
  219. package/src/segmentGroupCollection.ts +5 -1
  220. package/src/segmentPropertiesManager.ts +45 -6
  221. package/src/snapshotLoader.ts +2 -1
  222. package/src/snapshotV1.ts +2 -2
  223. package/src/snapshotlegacy.ts +6 -2
  224. package/src/sortedSegmentSet.ts +1 -1
  225. package/src/textSegment.ts +10 -157
  226. package/dist/collections.d.ts +0 -197
  227. package/dist/collections.d.ts.map +0 -1
  228. package/dist/collections.js.map +0 -1
  229. package/lib/collections.d.ts +0 -197
  230. package/lib/collections.d.ts.map +0 -1
  231. package/lib/collections.js.map +0 -1
@@ -5,24 +5,16 @@
5
5
 
6
6
  import { assert } from "@fluidframework/common-utils";
7
7
  import { UsageError } from "@fluidframework/container-utils";
8
- import { Client } from "./client";
9
8
  import { List, ListMakeHead, ListRemoveEntry } from "./collections";
10
9
  import {
11
10
  ISegment,
12
- } from "./mergeTree";
11
+ } from "./mergeTreeNodes";
13
12
  import { ICombiningOp, ReferenceType } from "./ops";
14
13
  import { addProperties, PropertySet } from "./properties";
15
14
  import {
16
- minReferencePosition,
17
- maxReferencePosition,
18
- compareReferencePositions,
19
15
  refHasTileLabels,
20
16
  refHasRangeLabels,
21
17
  ReferencePosition,
22
- refGetRangeLabels,
23
- refGetTileLabels,
24
- refHasRangeLabel,
25
- refHasTileLabel,
26
18
  refTypeIncludesFlag,
27
19
  } from "./referencePositions";
28
20
 
@@ -51,105 +43,34 @@ export interface LocalReferencePosition extends ReferencePosition {
51
43
  }
52
44
 
53
45
  /**
54
- * @deprecated - Use LocalReferencePosition
46
+ * @privateRemarks This should not be exported outside merge tree.
47
+ * @internal
55
48
  */
56
- export class LocalReference implements LocalReferencePosition {
57
- /**
58
- * @deprecated - use DetachedReferencePosition
59
- */
60
- public static readonly DetachedPosition: number = -1;
61
-
49
+ class LocalReference implements LocalReferencePosition {
62
50
  public properties: PropertySet | undefined;
63
- /**
64
- * @deprecated - use properties to store pair
65
- */
66
- public pairedRef?: LocalReference;
67
- /**
68
- * @deprecated - use getSegment
69
- */
70
- public segment: ISegment | undefined;
51
+
52
+ private segment: ISegment | undefined;
53
+ private offset: number = 0;
54
+ private listNode: List<LocalReference> | undefined;
71
55
 
72
56
  public callbacks?: Partial<Record<"beforeSlide" | "afterSlide", () => void>> | undefined;
73
57
 
74
- /**
75
- * @deprecated - use createReferencePosition
76
- */
77
58
  constructor(
78
- private readonly client: Client,
79
- initSegment: ISegment,
80
- /**
81
- * @deprecated - use getOffset
82
- */
83
- public offset: number = 0,
84
59
  public refType = ReferenceType.Simple,
85
60
  properties?: PropertySet,
86
61
  ) {
87
62
  _validateReferenceType(refType);
88
- this.segment = initSegment;
89
63
  this.properties = properties;
90
64
  }
91
65
 
92
- /**
93
- * @deprecated - use minReferencePosition
94
- */
95
- public min(b: LocalReference) {
96
- return minReferencePosition(this, b);
97
- }
98
- /**
99
- * @deprecated - use maxReferencePosition
100
- */
101
- public max(b: LocalReference) {
102
- return maxReferencePosition(this, b);
103
- }
104
- /**
105
- * @deprecated - use compareReferencePositions
106
- */
107
- public compare(b: LocalReference) {
108
- return compareReferencePositions(this, b);
109
- }
110
-
111
- /**
112
- * @deprecated - use getLocalReferencePosition
113
- */
114
- public toPosition() {
115
- return this.getClient().localReferencePositionToPosition(this);
116
- }
117
-
118
- /**
119
- * @deprecated - use refHasTileLabels
120
- */
121
- public hasTileLabels(): boolean {
122
- return refHasTileLabels(this);
123
- }
124
- /**
125
- * @deprecated - use refHasRangeLabels
126
- */
127
- public hasRangeLabels(): boolean {
128
- return refHasRangeLabels(this);
129
- }
130
- /**
131
- * @deprecated - use refHasTileLabel
132
- */
133
- public hasTileLabel(label: string): boolean {
134
- return refHasTileLabel(this, label);
135
- }
136
- /**
137
- * @deprecated - use refHasRangeLabel
138
- */
139
- public hasRangeLabel(label: string): boolean {
140
- return refHasRangeLabel(this, label);
141
- }
142
- /**
143
- * @deprecated - use refGetTileLabels
144
- */
145
- public getTileLabels(): string[] | undefined {
146
- return refGetTileLabels(this);
147
- }
148
- /**
149
- * @deprecated - use refGetRangeLabels
150
- */
151
- public getRangeLabels(): string[] | undefined {
152
- return refGetRangeLabels(this);
66
+ public link(segment: ISegment | undefined, offset: number, listNode: List<LocalReference> | undefined) {
67
+ if (listNode !== this.listNode
68
+ && this.listNode !== undefined) {
69
+ this.segment?.localRefs?.removeLocalRef(this);
70
+ }
71
+ this.segment = segment;
72
+ this.offset = offset;
73
+ this.listNode = listNode;
153
74
  }
154
75
 
155
76
  public isLeaf() {
@@ -160,13 +81,6 @@ export class LocalReference implements LocalReferencePosition {
160
81
  this.properties = addProperties(this.properties, newProps, op);
161
82
  }
162
83
 
163
- /**
164
- * @deprecated - no longer supported
165
- */
166
- public getClient() {
167
- return this.client;
168
- }
169
-
170
84
  public getSegment() {
171
85
  return this.segment;
172
86
  }
@@ -175,23 +89,33 @@ export class LocalReference implements LocalReferencePosition {
175
89
  return this.offset;
176
90
  }
177
91
 
92
+ public getListNode() {
93
+ return this.listNode;
94
+ }
95
+
178
96
  public getProperties() {
179
97
  return this.properties;
180
98
  }
181
99
  }
182
100
 
101
+ export function createDetachedLocalReferencePosition(refType?: ReferenceType): LocalReferencePosition {
102
+ return new LocalReference(refType, undefined);
103
+ }
104
+
183
105
  interface IRefsAtOffset {
184
106
  before?: List<LocalReference>;
185
107
  at?: List<LocalReference>;
186
108
  after?: List<LocalReference>;
187
109
  }
188
110
 
189
- function assertLocalReferences(lref: ReferencePosition | LocalReference): asserts lref is LocalReference {
111
+ export function assertLocalReferences(
112
+ lref: any,
113
+ ): asserts lref is LocalReference {
190
114
  assert(lref instanceof LocalReference, 0x2e0 /* "lref not a Local Reference" */);
191
115
  }
192
116
 
193
117
  /**
194
- * Represents a collection of {@link ReferencePosition}s associated with one segment in a merge-tree.
118
+ * Represents a collection of {@link LocalReferencePosition}s associated with one segment in a merge-tree.
195
119
  */
196
120
  export class LocalReferenceCollection {
197
121
  public static append(seg1: ISegment, seg2: ISegment) {
@@ -210,8 +134,8 @@ export class LocalReferenceCollection {
210
134
  }
211
135
 
212
136
  /**
213
- *
214
- * @internal - this method should only be called by mergeTree
137
+ * @remarks This method should only be called by mergeTree.
138
+ * @internal
215
139
  */
216
140
  public hierRefCount: number = 0;
217
141
  private readonly refsByOffset: (IRefsAtOffset | undefined)[];
@@ -219,7 +143,7 @@ export class LocalReferenceCollection {
219
143
 
220
144
  /**
221
145
  *
222
- * @internal - this method should only be called by mergeTree
146
+ * @internal
223
147
  */
224
148
  constructor(
225
149
  /** Segment this `LocalReferenceCollection` is associated to. */
@@ -232,11 +156,11 @@ export class LocalReferenceCollection {
232
156
  }
233
157
 
234
158
  /**
235
- *
236
- * @internal - this method should only be called by mergeTree
159
+ * @remarks This method should only be called by mergeTree.
160
+ * @internal
237
161
  */
238
162
  public [Symbol.iterator]() {
239
- const subiterators: IterableIterator<LocalReference>[] = [];
163
+ const subiterators: IterableIterator<LocalReferencePosition>[] = [];
240
164
  for (const refs of this.refsByOffset) {
241
165
  if (refs) {
242
166
  if (refs.before) {
@@ -252,7 +176,7 @@ export class LocalReferenceCollection {
252
176
  }
253
177
 
254
178
  const iterator = {
255
- next(): IteratorResult<LocalReference> {
179
+ next(): IteratorResult<LocalReferencePosition> {
256
180
  while (subiterators.length > 0) {
257
181
  const next = subiterators[0].next();
258
182
  if (next.done === true) {
@@ -272,8 +196,8 @@ export class LocalReferenceCollection {
272
196
  }
273
197
 
274
198
  /**
275
- *
276
- * @internal - this method should only be called by mergeTree
199
+ * @remarks This method should only be called by mergeTree.
200
+ * @internal
277
201
  */
278
202
  public clear() {
279
203
  this.refCount = 0;
@@ -281,9 +205,7 @@ export class LocalReferenceCollection {
281
205
  const detachSegments = (refs: List<LocalReference> | undefined) => {
282
206
  if (refs) {
283
207
  for (const r of refs) {
284
- if (r.segment === this.segment) {
285
- r.segment = undefined;
286
- }
208
+ this.removeLocalRef(r);
287
209
  }
288
210
  }
289
211
  };
@@ -292,59 +214,57 @@ export class LocalReferenceCollection {
292
214
  if (refsAtOffset) {
293
215
  detachSegments(refsAtOffset.before);
294
216
  detachSegments(refsAtOffset.at);
295
- detachSegments(refsAtOffset.before);
217
+ detachSegments(refsAtOffset.after);
296
218
  this.refsByOffset[i] = undefined;
297
219
  }
298
220
  }
299
221
  }
300
222
 
301
223
  /**
302
- *
303
- * @internal - this method should only be called by mergeTree
224
+ * @remarks This method should only be called by mergeTree.
225
+ * @internal
304
226
  */
305
227
  public get empty() {
306
228
  return this.refCount === 0;
307
229
  }
308
230
 
309
231
  /**
310
- *
311
- * @internal - this method should only be called by mergeTree
232
+ * @remarks This method should only be called by mergeTree.
233
+ * @internal
312
234
  */
313
235
  public createLocalRef(
314
- offset: number | undefined,
236
+ offset: number,
315
237
  refType: ReferenceType,
316
- properties: PropertySet | undefined,
317
- client: Client): ReferencePosition {
238
+ properties: PropertySet | undefined): LocalReferencePosition {
318
239
  const ref = new LocalReference(
319
- client,
320
- this.segment,
321
- offset,
322
240
  refType,
323
241
  properties,
324
242
  );
243
+ ref.link(this.segment, offset, undefined);
325
244
  if (!refTypeIncludesFlag(ref, ReferenceType.Transient)) {
326
- this.addLocalRef(ref);
245
+ this.addLocalRef(ref, offset);
327
246
  }
328
247
  return ref;
329
248
  }
330
249
 
331
250
  /**
332
- *
333
- * @internal - this method should only be called by mergeTree
251
+ * @remarks This method should only be called by mergeTree.
252
+ * @internal
334
253
  */
335
- public addLocalRef(lref: LocalReference | ReferencePosition) {
254
+ public addLocalRef(lref: LocalReferencePosition, offset: number) {
336
255
  assert(
337
256
  !refTypeIncludesFlag(lref, ReferenceType.Transient),
338
257
  0x2df /* "transient references cannot be bound to segments" */);
339
258
  assertLocalReferences(lref);
340
- const refsAtOffset = this.refsByOffset[lref.offset] =
341
- this.refsByOffset[lref.offset]
259
+ assert(offset < this.segment.cachedLength, 0x348 /* offset cannot be beyond segment length */);
260
+ const refsAtOffset = this.refsByOffset[offset] =
261
+ this.refsByOffset[offset]
342
262
  ?? { at: ListMakeHead() };
343
263
  const atRefs = refsAtOffset.at =
344
264
  refsAtOffset.at
345
265
  ?? ListMakeHead();
346
266
 
347
- atRefs.enqueue(lref);
267
+ lref.link(this.segment, offset, atRefs.enqueue(lref));
348
268
 
349
269
  if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
350
270
  this.hierRefCount++;
@@ -353,55 +273,37 @@ export class LocalReferenceCollection {
353
273
  }
354
274
 
355
275
  /**
356
- *
357
- * @internal - this method should only be called by mergeTree
276
+ * @remarks This method should only be called by mergeTree.
277
+ * @internal
358
278
  */
359
- public removeLocalRef(lref: LocalReference | ReferencePosition) {
360
- assertLocalReferences(lref);
361
- const tryRemoveRef = (refs: List<LocalReference> | undefined) => {
362
- if (refs) {
363
- let node = refs;
364
- do {
365
- node = node.next;
366
- if (node.data === lref) {
367
- ListRemoveEntry(node);
368
- if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
369
- this.hierRefCount--;
370
- }
371
- this.refCount--;
372
- return lref;
373
- }
374
- } while (!node.isHead);
375
- }
376
- };
377
- const refAtOffset = this.refsByOffset[lref.offset];
378
- if (refAtOffset !== undefined) {
379
- let ref = tryRemoveRef(refAtOffset.before);
380
- if (ref) {
381
- return ref;
382
- }
383
-
384
- ref = tryRemoveRef(refAtOffset.at);
385
- if (ref) {
386
- return ref;
387
- }
388
-
389
- ref = tryRemoveRef(refAtOffset.after);
390
- if (ref) {
391
- return ref;
279
+ public removeLocalRef(lref: LocalReferencePosition): LocalReferencePosition | undefined {
280
+ if (this.has(lref)) {
281
+ assertLocalReferences(lref);
282
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
283
+ ListRemoveEntry(lref.getListNode()!);
284
+ lref.link(
285
+ lref.getSegment(),
286
+ lref.getOffset(),
287
+ undefined);
288
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
289
+ this.hierRefCount--;
392
290
  }
291
+ this.refCount--;
292
+ return lref;
393
293
  }
394
294
  }
395
295
 
396
296
  /**
397
- * @internal - this method should only be called by mergeTree
398
297
  *
399
298
  * Called by 'append()' implementations to append local refs from the given 'other' segment to the
400
299
  * end of 'this' segment.
401
300
  *
402
301
  * Note: This method should be invoked after the caller has ensured that segments can be merged,
403
- * but before 'this' segment's cachedLength has changed, or the adjustment to the local refs
404
- * will be incorrect.
302
+ * but before 'this' segment's cachedLength has changed, or the adjustment to the local refs
303
+ * will be incorrect.
304
+ *
305
+ * @remarks This method should only be called by mergeTree.
306
+ * @internal
405
307
  */
406
308
  public append(other: LocalReferenceCollection) {
407
309
  if (!other || other.empty) {
@@ -411,16 +313,58 @@ export class LocalReferenceCollection {
411
313
  this.refCount += other.refCount;
412
314
  other.hierRefCount = 0;
413
315
  for (const lref of other) {
414
- lref.segment = this.segment;
415
- lref.offset += this.refsByOffset.length;
316
+ assertLocalReferences(lref);
317
+ lref.link(
318
+ this.segment,
319
+ lref.getOffset() + this.refsByOffset.length,
320
+ lref.getListNode());
416
321
  }
417
322
 
418
323
  this.refsByOffset.push(...other.refsByOffset);
419
324
  }
420
-
421
325
  /**
422
- * @internal - this method should only be called by mergeTree
326
+ * Returns true of the local reference is in the collection, otherwise false.
423
327
  *
328
+ * @remarks This method should only be called by mergeTree.
329
+ * @internal
330
+ */
331
+ public has(lref: ReferencePosition): boolean {
332
+ if (!(lref instanceof LocalReference)
333
+ || refTypeIncludesFlag(lref, ReferenceType.Transient)) {
334
+ return false;
335
+ }
336
+ const seg = lref.getSegment();
337
+ if (seg !== this.segment) {
338
+ return false;
339
+ }
340
+ // we should be able to optimize finding the
341
+ // list head
342
+ const listNode = lref.getListNode();
343
+ if (listNode === undefined) {
344
+ return false;
345
+ }
346
+ let prev = listNode;
347
+ let next = listNode;
348
+ while (prev?.isHead !== true && next?.isHead !== true) {
349
+ prev = prev?.prev;
350
+ next = next?.next;
351
+ }
352
+
353
+ const headNode = prev?.isHead === true ? prev : next;
354
+ if (headNode?.isHead !== true || headNode.empty()) {
355
+ return false;
356
+ }
357
+ const offset = lref.getOffset();
358
+ const refsAtOffset = this.refsByOffset[offset];
359
+ if (refsAtOffset?.before === headNode
360
+ || refsAtOffset?.at === headNode
361
+ || refsAtOffset?.after === headNode) {
362
+ return true;
363
+ }
364
+ return false;
365
+ }
366
+
367
+ /**
424
368
  * Splits this `LocalReferenceCollection` into the intervals [0, offset) and [offset, originalLength).
425
369
  * Local references in the former half of this split will remain associated with the segment used on construction.
426
370
  * Local references in the latter half of this split will be transferred to `splitSeg`,
@@ -428,6 +372,9 @@ export class LocalReferenceCollection {
428
372
  * @param offset - Offset into the original segment at which the collection should be split
429
373
  * @param splitSeg - Split segment which originally corresponded to the indices [offset, originalLength)
430
374
  * before splitting.
375
+ *
376
+ * @remarks This method should only be called by mergeTree.
377
+ * @internal
431
378
  */
432
379
  public split(offset: number, splitSeg: ISegment) {
433
380
  if (!this.empty) {
@@ -438,8 +385,11 @@ export class LocalReferenceCollection {
438
385
 
439
386
  splitSeg.localRefs = localRefs;
440
387
  for (const lref of localRefs) {
441
- lref.segment = splitSeg;
442
- lref.offset -= offset;
388
+ assertLocalReferences(lref);
389
+ lref.link(
390
+ splitSeg,
391
+ lref.getOffset() - offset,
392
+ lref.getListNode());
443
393
  if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
444
394
  this.hierRefCount--;
445
395
  localRefs.hierRefCount++;
@@ -453,59 +403,58 @@ export class LocalReferenceCollection {
453
403
  }
454
404
  }
455
405
 
456
- public addBeforeTombstones(...refs: Iterable<LocalReference | ReferencePosition>[]) {
406
+ public addBeforeTombstones(...refs: Iterable<LocalReferencePosition>[]) {
457
407
  const beforeRefs = this.refsByOffset[0]?.before ?? ListMakeHead();
458
408
 
409
+ if (this.refsByOffset[0]?.before === undefined) {
410
+ const refsAtOffset = this.refsByOffset[0] ??= { before: beforeRefs };
411
+ refsAtOffset.before ??= beforeRefs;
412
+ }
413
+
459
414
  for (const iterable of refs) {
460
415
  for (const lref of iterable) {
461
416
  assertLocalReferences(lref);
462
417
  if (refTypeIncludesFlag(lref, ReferenceType.SlideOnRemove)) {
463
- beforeRefs.push(lref);
464
- lref.segment = this.segment;
465
- lref.offset = 0;
418
+ lref.callbacks?.beforeSlide?.();
419
+ beforeRefs.unshift(lref);
420
+ lref.link(this.segment, 0, beforeRefs.next);
466
421
  if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
467
422
  this.hierRefCount++;
468
423
  }
469
424
  this.refCount++;
425
+ lref.callbacks?.afterSlide?.();
470
426
  } else {
471
- lref.segment = undefined;
427
+ lref.link(undefined, 0, undefined);
472
428
  }
473
429
  }
474
430
  }
475
- if (!beforeRefs.empty() && this.refsByOffset[0]?.before === undefined) {
476
- const refsAtOffset = this.refsByOffset[0] =
477
- this.refsByOffset[0]
478
- ?? { before: beforeRefs };
479
- refsAtOffset.before = refsAtOffset.before ?? beforeRefs;
480
- }
481
431
  }
482
432
 
483
- public addAfterTombstones(...refs: Iterable<LocalReference | ReferencePosition>[]) {
484
- const lastOffset = this.refsByOffset.length - 1;
485
- const afterRefs =
486
- this.refsByOffset[lastOffset]?.after ?? ListMakeHead();
433
+ public addAfterTombstones(...refs: Iterable<LocalReferencePosition>[]) {
434
+ const lastOffset = this.segment.cachedLength - 1;
435
+ const afterRefs = this.refsByOffset[lastOffset]?.after ?? ListMakeHead();
436
+
437
+ if (this.refsByOffset[lastOffset]?.after === undefined) {
438
+ const refsAtOffset = this.refsByOffset[lastOffset] ??= { after: afterRefs };
439
+ refsAtOffset.after ??= afterRefs;
440
+ }
487
441
 
488
442
  for (const iterable of refs) {
489
443
  for (const lref of iterable) {
490
444
  assertLocalReferences(lref);
491
445
  if (refTypeIncludesFlag(lref, ReferenceType.SlideOnRemove)) {
492
- afterRefs.push(lref);
493
- lref.segment = this.segment;
494
- lref.offset = this.segment.cachedLength - 1;
446
+ lref.callbacks?.beforeSlide?.();
447
+ afterRefs.enqueue(lref);
448
+ lref.link(this.segment, lastOffset, afterRefs.prev);
495
449
  if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
496
450
  this.hierRefCount++;
497
451
  }
498
452
  this.refCount++;
453
+ lref.callbacks?.afterSlide?.();
499
454
  } else {
500
- lref.segment = undefined;
455
+ lref.link(undefined, 0, undefined);
501
456
  }
502
457
  }
503
458
  }
504
- if (!afterRefs.empty() && this.refsByOffset[lastOffset]?.after === undefined) {
505
- const refsAtOffset = this.refsByOffset[lastOffset] =
506
- this.refsByOffset[lastOffset]
507
- ?? { after: afterRefs };
508
- refsAtOffset.after = refsAtOffset.after ?? afterRefs;
509
- }
510
459
  }
511
460
  }