@fluidframework/tree 2.13.0 → 2.20.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 (303) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/api-report/tree.alpha.api.md +22 -12
  3. package/api-report/tree.beta.api.md +9 -5
  4. package/api-report/tree.legacy.alpha.api.md +9 -5
  5. package/api-report/tree.legacy.public.api.md +9 -5
  6. package/api-report/tree.public.api.md +9 -5
  7. package/assertTagging.config.mjs +14 -0
  8. package/dist/alpha.d.ts +3 -0
  9. package/dist/core/index.d.ts +2 -2
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/core/index.js +6 -4
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/core/rebase/index.d.ts +2 -2
  14. package/dist/core/rebase/index.d.ts.map +1 -1
  15. package/dist/core/rebase/index.js +5 -1
  16. package/dist/core/rebase/index.js.map +1 -1
  17. package/dist/core/rebase/types.d.ts +5 -4
  18. package/dist/core/rebase/types.d.ts.map +1 -1
  19. package/dist/core/rebase/types.js +29 -1
  20. package/dist/core/rebase/types.js.map +1 -1
  21. package/dist/core/rebase/utils.d.ts +10 -0
  22. package/dist/core/rebase/utils.d.ts.map +1 -1
  23. package/dist/core/rebase/utils.js +22 -1
  24. package/dist/core/rebase/utils.js.map +1 -1
  25. package/dist/core/tree/delta.d.ts +21 -26
  26. package/dist/core/tree/delta.d.ts.map +1 -1
  27. package/dist/core/tree/delta.js.map +1 -1
  28. package/dist/core/tree/deltaUtil.d.ts +1 -3
  29. package/dist/core/tree/deltaUtil.d.ts.map +1 -1
  30. package/dist/core/tree/deltaUtil.js +2 -14
  31. package/dist/core/tree/deltaUtil.js.map +1 -1
  32. package/dist/core/tree/index.d.ts +1 -1
  33. package/dist/core/tree/index.d.ts.map +1 -1
  34. package/dist/core/tree/index.js +1 -3
  35. package/dist/core/tree/index.js.map +1 -1
  36. package/dist/core/tree/visitDelta.d.ts.map +1 -1
  37. package/dist/core/tree/visitDelta.js +82 -80
  38. package/dist/core/tree/visitDelta.js.map +1 -1
  39. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  40. package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  41. package/dist/feature-libraries/deltaUtils.d.ts.map +1 -1
  42. package/dist/feature-libraries/deltaUtils.js +13 -0
  43. package/dist/feature-libraries/deltaUtils.js.map +1 -1
  44. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  45. package/dist/feature-libraries/forest-summary/forestSummarizer.js +1 -6
  46. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  47. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +5 -5
  48. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  49. package/dist/feature-libraries/modular-schema/crossFieldQueries.js +2 -9
  50. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  51. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +19 -2
  52. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  53. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  54. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  55. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  56. package/dist/feature-libraries/modular-schema/index.d.ts +2 -2
  57. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  58. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  59. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  60. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  61. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +8 -8
  62. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  63. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +4 -4
  64. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  65. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +105 -199
  66. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  67. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +11 -20
  68. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  69. package/dist/feature-libraries/modular-schema/modularChangeTypes.js +20 -0
  70. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  71. package/dist/feature-libraries/optional-field/optionalField.d.ts +3 -3
  72. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  73. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  74. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts +1 -1
  75. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  76. package/dist/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  77. package/dist/feature-libraries/sequence-field/rebase.js +4 -4
  78. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  79. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.js +1 -1
  80. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  81. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js +1 -1
  82. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  83. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +2 -3
  84. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  85. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  86. package/dist/feature-libraries/sequence-field/utils.js +36 -4
  87. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  88. package/dist/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  89. package/dist/feature-libraries/treeCursorUtils.js +4 -1
  90. package/dist/feature-libraries/treeCursorUtils.js.map +1 -1
  91. package/dist/index.d.ts +26 -2
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +4 -2
  94. package/dist/index.js.map +1 -1
  95. package/dist/package.json +2 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/shared-tree/index.d.ts +1 -1
  100. package/dist/shared-tree/index.d.ts.map +1 -1
  101. package/dist/shared-tree/index.js +4 -2
  102. package/dist/shared-tree/index.js.map +1 -1
  103. package/dist/shared-tree/sharedTree.d.ts +38 -18
  104. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  105. package/dist/shared-tree/sharedTree.js +38 -34
  106. package/dist/shared-tree/sharedTree.js.map +1 -1
  107. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  108. package/dist/shared-tree/treeCheckout.js +12 -8
  109. package/dist/shared-tree/treeCheckout.js.map +1 -1
  110. package/dist/simple-tree/api/treeNodeApi.js +1 -1
  111. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  112. package/dist/simple-tree/arrayNode.js +1 -1
  113. package/dist/simple-tree/arrayNode.js.map +1 -1
  114. package/dist/simple-tree/toMapTree.js +1 -1
  115. package/dist/simple-tree/toMapTree.js.map +1 -1
  116. package/dist/util/bTreeUtils.d.ts +10 -0
  117. package/dist/util/bTreeUtils.d.ts.map +1 -0
  118. package/dist/util/bTreeUtils.js +52 -0
  119. package/dist/util/bTreeUtils.js.map +1 -0
  120. package/dist/util/idAllocator.d.ts +0 -2
  121. package/dist/util/idAllocator.d.ts.map +1 -1
  122. package/dist/util/idAllocator.js +0 -2
  123. package/dist/util/idAllocator.js.map +1 -1
  124. package/dist/util/index.d.ts +2 -1
  125. package/dist/util/index.d.ts.map +1 -1
  126. package/dist/util/index.js +5 -1
  127. package/dist/util/index.js.map +1 -1
  128. package/dist/util/rangeMap.d.ts +52 -30
  129. package/dist/util/rangeMap.d.ts.map +1 -1
  130. package/dist/util/rangeMap.js +161 -117
  131. package/dist/util/rangeMap.js.map +1 -1
  132. package/dist/util/utils.d.ts +4 -1
  133. package/dist/util/utils.d.ts.map +1 -1
  134. package/dist/util/utils.js +7 -1
  135. package/dist/util/utils.js.map +1 -1
  136. package/lib/alpha.d.ts +3 -0
  137. package/lib/core/index.d.ts +2 -2
  138. package/lib/core/index.d.ts.map +1 -1
  139. package/lib/core/index.js +2 -2
  140. package/lib/core/index.js.map +1 -1
  141. package/lib/core/rebase/index.d.ts +2 -2
  142. package/lib/core/rebase/index.d.ts.map +1 -1
  143. package/lib/core/rebase/index.js +2 -2
  144. package/lib/core/rebase/index.js.map +1 -1
  145. package/lib/core/rebase/types.d.ts +5 -4
  146. package/lib/core/rebase/types.d.ts.map +1 -1
  147. package/lib/core/rebase/types.js +26 -1
  148. package/lib/core/rebase/types.js.map +1 -1
  149. package/lib/core/rebase/utils.d.ts +10 -0
  150. package/lib/core/rebase/utils.d.ts.map +1 -1
  151. package/lib/core/rebase/utils.js +20 -0
  152. package/lib/core/rebase/utils.js.map +1 -1
  153. package/lib/core/tree/delta.d.ts +21 -26
  154. package/lib/core/tree/delta.d.ts.map +1 -1
  155. package/lib/core/tree/delta.js.map +1 -1
  156. package/lib/core/tree/deltaUtil.d.ts +1 -3
  157. package/lib/core/tree/deltaUtil.d.ts.map +1 -1
  158. package/lib/core/tree/deltaUtil.js +1 -12
  159. package/lib/core/tree/deltaUtil.js.map +1 -1
  160. package/lib/core/tree/index.d.ts +1 -1
  161. package/lib/core/tree/index.d.ts.map +1 -1
  162. package/lib/core/tree/index.js +1 -1
  163. package/lib/core/tree/index.js.map +1 -1
  164. package/lib/core/tree/visitDelta.d.ts.map +1 -1
  165. package/lib/core/tree/visitDelta.js +82 -80
  166. package/lib/core/tree/visitDelta.js.map +1 -1
  167. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  168. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  169. package/lib/feature-libraries/deltaUtils.d.ts.map +1 -1
  170. package/lib/feature-libraries/deltaUtils.js +13 -0
  171. package/lib/feature-libraries/deltaUtils.js.map +1 -1
  172. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  173. package/lib/feature-libraries/forest-summary/forestSummarizer.js +1 -6
  174. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  175. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +5 -5
  176. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  177. package/lib/feature-libraries/modular-schema/crossFieldQueries.js +2 -9
  178. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  179. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +19 -2
  180. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  181. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  182. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  183. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  184. package/lib/feature-libraries/modular-schema/index.d.ts +2 -2
  185. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  186. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  187. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  188. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  189. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +4 -4
  190. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  191. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +4 -4
  192. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  193. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +74 -166
  194. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  195. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +11 -20
  196. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  197. package/lib/feature-libraries/modular-schema/modularChangeTypes.js +18 -1
  198. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  199. package/lib/feature-libraries/optional-field/optionalField.d.ts +3 -3
  200. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  201. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  202. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts +1 -1
  203. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  204. package/lib/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  205. package/lib/feature-libraries/sequence-field/rebase.js +4 -4
  206. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  207. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js +1 -1
  208. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  209. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +1 -1
  210. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  211. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +2 -3
  212. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  213. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  214. package/lib/feature-libraries/sequence-field/utils.js +36 -4
  215. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  216. package/lib/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  217. package/lib/feature-libraries/treeCursorUtils.js +4 -1
  218. package/lib/feature-libraries/treeCursorUtils.js.map +1 -1
  219. package/lib/index.d.ts +26 -2
  220. package/lib/index.d.ts.map +1 -1
  221. package/lib/index.js +1 -1
  222. package/lib/index.js.map +1 -1
  223. package/lib/packageVersion.d.ts +1 -1
  224. package/lib/packageVersion.js +1 -1
  225. package/lib/packageVersion.js.map +1 -1
  226. package/lib/shared-tree/index.d.ts +1 -1
  227. package/lib/shared-tree/index.d.ts.map +1 -1
  228. package/lib/shared-tree/index.js +1 -1
  229. package/lib/shared-tree/index.js.map +1 -1
  230. package/lib/shared-tree/sharedTree.d.ts +38 -18
  231. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  232. package/lib/shared-tree/sharedTree.js +37 -33
  233. package/lib/shared-tree/sharedTree.js.map +1 -1
  234. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  235. package/lib/shared-tree/treeCheckout.js +13 -9
  236. package/lib/shared-tree/treeCheckout.js.map +1 -1
  237. package/lib/simple-tree/api/treeNodeApi.js +1 -1
  238. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  239. package/lib/simple-tree/arrayNode.js +1 -1
  240. package/lib/simple-tree/arrayNode.js.map +1 -1
  241. package/lib/simple-tree/toMapTree.js +1 -1
  242. package/lib/simple-tree/toMapTree.js.map +1 -1
  243. package/lib/util/bTreeUtils.d.ts +10 -0
  244. package/lib/util/bTreeUtils.d.ts.map +1 -0
  245. package/lib/util/bTreeUtils.js +47 -0
  246. package/lib/util/bTreeUtils.js.map +1 -0
  247. package/lib/util/idAllocator.d.ts +0 -2
  248. package/lib/util/idAllocator.d.ts.map +1 -1
  249. package/lib/util/idAllocator.js +0 -2
  250. package/lib/util/idAllocator.js.map +1 -1
  251. package/lib/util/index.d.ts +2 -1
  252. package/lib/util/index.d.ts.map +1 -1
  253. package/lib/util/index.js +2 -1
  254. package/lib/util/index.js.map +1 -1
  255. package/lib/util/rangeMap.d.ts +52 -30
  256. package/lib/util/rangeMap.d.ts.map +1 -1
  257. package/lib/util/rangeMap.js +160 -117
  258. package/lib/util/rangeMap.js.map +1 -1
  259. package/lib/util/utils.d.ts +4 -1
  260. package/lib/util/utils.d.ts.map +1 -1
  261. package/lib/util/utils.js +7 -1
  262. package/lib/util/utils.js.map +1 -1
  263. package/package.json +23 -23
  264. package/src/core/index.ts +5 -2
  265. package/src/core/rebase/index.ts +5 -0
  266. package/src/core/rebase/types.ts +33 -5
  267. package/src/core/rebase/utils.ts +27 -0
  268. package/src/core/tree/delta.ts +21 -26
  269. package/src/core/tree/deltaUtil.ts +1 -16
  270. package/src/core/tree/index.ts +0 -2
  271. package/src/core/tree/visitDelta.ts +108 -97
  272. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +2 -2
  273. package/src/feature-libraries/deltaUtils.ts +13 -0
  274. package/src/feature-libraries/forest-summary/forestSummarizer.ts +1 -6
  275. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +12 -13
  276. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +21 -1
  277. package/src/feature-libraries/modular-schema/genericFieldKind.ts +2 -2
  278. package/src/feature-libraries/modular-schema/index.ts +2 -0
  279. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +12 -11
  280. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +138 -225
  281. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +40 -27
  282. package/src/feature-libraries/optional-field/optionalField.ts +3 -3
  283. package/src/feature-libraries/sequence-field/moveEffectTable.ts +1 -1
  284. package/src/feature-libraries/sequence-field/rebase.ts +9 -3
  285. package/src/feature-libraries/sequence-field/sequenceFieldCodecV1.ts +1 -1
  286. package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +1 -1
  287. package/src/feature-libraries/sequence-field/sequenceFieldToDelta.ts +3 -4
  288. package/src/feature-libraries/sequence-field/utils.ts +36 -4
  289. package/src/feature-libraries/treeCursorUtils.ts +6 -1
  290. package/src/index.ts +34 -6
  291. package/src/packageVersion.ts +1 -1
  292. package/src/shared-tree/index.ts +4 -1
  293. package/src/shared-tree/sharedTree.ts +60 -40
  294. package/src/shared-tree/treeCheckout.ts +19 -12
  295. package/src/simple-tree/api/treeNodeApi.ts +1 -1
  296. package/src/simple-tree/arrayNode.ts +1 -1
  297. package/src/simple-tree/toMapTree.ts +1 -1
  298. package/src/util/bTreeUtils.ts +60 -0
  299. package/src/util/idAllocator.ts +0 -2
  300. package/src/util/index.ts +3 -0
  301. package/src/util/rangeMap.ts +208 -143
  302. package/src/util/utils.ts +10 -3
  303. package/lib/package.json +0 -3
@@ -3,25 +3,80 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { oob } from "@fluidframework/core-utils/internal";
6
+ import { assert, oob } from "@fluidframework/core-utils/internal";
7
+ import { BTree } from "@tylerbu/sorted-btree-es6";
7
8
 
8
9
  /**
9
- * RangeMap represents a mapping from integers to values of type T or undefined.
10
+ * RangeMap represents a mapping from keys of type K to values of type V or undefined.
11
+ * The set of all possible keys is assumed to be fully ordered,
12
+ * and for each key there should be a single next higher key.
10
13
  * The values for a range of consecutive keys can be changed or queried in a single operation.
14
+ * The structure of the keys is described by the `offsetKey` and `subtractKeys` functions provided in the constructor.
11
15
  */
12
- export class RangeMap<T> {
13
- private readonly entries: RangeEntry<T>[];
16
+ export class RangeMap<K, V> {
17
+ private tree: BTree<K, RangeEntry<V>>;
14
18
 
15
- public constructor(initialEntries?: RangeEntry<T>[]) {
16
- this.entries = initialEntries ? [...initialEntries] : [];
19
+ /**
20
+ * @param offsetKey - Function which returns a new key which is `offset` keys after `key`.
21
+ * When `offset` is negative, the returned key should come before `key`.
22
+ *
23
+ * @param subtractKeys - Function which returns the difference between `b` and `a`.
24
+ * Offsetting `b` by this difference should return `a`.
25
+ * The difference can be infinite if `a` cannot be reached from `b` by offsetting,
26
+ * but the difference should still be positive if `a` is larger than `b` and negative if smaller.
27
+ */
28
+ public constructor(
29
+ private readonly offsetKey: (key: K, offset: number) => K,
30
+ private readonly subtractKeys: (a: K, b: K) => number,
31
+ ) {
32
+ this.tree = new BTree(undefined, subtractKeys);
17
33
  }
18
34
 
19
35
  /**
20
- * Retrieves all entries from the rangeMap.
21
- * @returns An array of RangeEntryResult objects, each containing the start index, length, and value of a contiguous range.
36
+ * Retrieves all entries from the RangeMap.
22
37
  */
23
- public getAllEntries(): readonly RangeQueryResult<T>[] {
24
- return this.entries;
38
+ public entries(): RangeQueryEntry<K, V>[] {
39
+ const entries: RangeQueryEntry<K, V>[] = [];
40
+ for (const [start, entry] of this.tree.entries()) {
41
+ entries.push({ start, length: entry.length, value: entry.value });
42
+ }
43
+
44
+ return entries;
45
+ }
46
+
47
+ public clear(): void {
48
+ this.tree.clear();
49
+ }
50
+
51
+ /**
52
+ * Retrieves the values for all keys in the query range.
53
+ *
54
+ * @param start - The first key in the range being queried
55
+ * @param length - The length of the query range
56
+ * @returns A list of entries, each describing the value for some subrange of the query.
57
+ * The entries are in the same order as the keys, and there is an entry for every key with a non `undefined` value.
58
+ */
59
+ public getAll(start: K, length: number): RangeQueryEntry<K, V>[] {
60
+ const entries = this.getIntersectingEntries(start, length);
61
+ if (entries.length === 0) {
62
+ return entries;
63
+ }
64
+
65
+ const firstEntry = entries[0] ?? oob();
66
+ const lengthBefore = this.subtractKeys(start, firstEntry.start);
67
+ if (lengthBefore > 0) {
68
+ entries[0] = { ...firstEntry, start, length: firstEntry.length - lengthBefore };
69
+ }
70
+
71
+ const lastEntry = entries[entries.length - 1] ?? oob();
72
+ const lastEntryKey = this.offsetKey(lastEntry.start, lastEntry.length - 1);
73
+ const lastQueryKey = this.offsetKey(start, length - 1);
74
+ const lengthAfter = this.subtractKeys(lastEntryKey, lastQueryKey);
75
+ if (lengthAfter > 0) {
76
+ entries[entries.length - 1] = { ...lastEntry, length: lastEntry.length - lengthAfter };
77
+ }
78
+
79
+ return entries;
25
80
  }
26
81
 
27
82
  /**
@@ -30,23 +85,39 @@ export class RangeMap<T> {
30
85
  * @param start - The first key in the query range.
31
86
  * @param length - The length of the query range.
32
87
  * @returns A RangeQueryResult containing the value associated with `start`,
33
- * and the number of consecutive keys with that same value.
88
+ * and the number of consecutive keys with that same value (at least 1, at most `length`).
34
89
  */
35
- public get(start: number, length: number): RangeQueryResult<T> {
36
- for (const entry of this.entries) {
37
- if (entry.start > start) {
38
- return { value: undefined, length: Math.min(entry.start - start, length) };
39
- }
90
+ public getFirst(start: K, length: number): RangeQueryResult<K, V> {
91
+ {
92
+ // We first check for an entry with a key less than or equal to `start`.
93
+ const entry = this.tree.getPairOrNextLower(start);
94
+ if (entry !== undefined) {
95
+ const entryKey = entry[0];
96
+ const { value, length: entryLength } = entry[1];
40
97
 
41
- const lastRangeKey = entry.start + entry.length - 1;
42
- if (lastRangeKey >= start) {
43
- const overlapLength = lastRangeKey - start + 1;
44
- return { value: entry.value, length: Math.min(overlapLength, length) };
98
+ const entryLastKey = this.offsetKey(entryKey, entryLength - 1);
99
+ const overlappingLength = Math.min(this.subtractKeys(entryLastKey, start) + 1, length);
100
+ if (overlappingLength > 0) {
101
+ return { value, start, length: overlappingLength };
102
+ }
45
103
  }
46
104
  }
47
105
 
48
- // There were no entries intersecting the query range, so the entire query range has undefined value.
49
- return { value: undefined, length };
106
+ {
107
+ // There is no value associated with `start`.
108
+ // Now we need to determine how many of the following keys are also undefined.
109
+ const key = this.tree.nextHigherKey(start);
110
+ if (key !== undefined) {
111
+ const entryKey = key;
112
+
113
+ const lastQueryKey = this.offsetKey(start, length - 1);
114
+ if (this.le(entryKey, lastQueryKey)) {
115
+ return { value: undefined, start, length: this.subtractKeys(entryKey, start) };
116
+ }
117
+ }
118
+
119
+ return { value: undefined, start, length };
120
+ }
50
121
  }
51
122
 
52
123
  /**
@@ -56,74 +127,11 @@ export class RangeMap<T> {
56
127
  * @param length - The length of the range.
57
128
  * @param value - The value to associate with the range.
58
129
  */
59
- public set(start: number, length: number, value: T | undefined): void {
60
- if (value === undefined) {
61
- this.delete(start, length);
62
- return;
130
+ public set(start: K, length: number, value: V | undefined): void {
131
+ this.delete(start, length);
132
+ if (value !== undefined) {
133
+ this.tree.set(start, { value, length });
63
134
  }
64
-
65
- const end = start + length - 1;
66
- const newEntry: RangeEntry<T> = { start, length, value };
67
-
68
- let iBefore = -1;
69
- let iAfter = this.entries.length;
70
- for (const [i, entry] of this.entries.entries()) {
71
- const entryLastKey = entry.start + entry.length - 1;
72
- if (entryLastKey < start) {
73
- iBefore = i;
74
- } else if (entry.start > end) {
75
- iAfter = i;
76
- break;
77
- }
78
- }
79
-
80
- const numOverlappingEntries = iAfter - iBefore - 1;
81
- if (numOverlappingEntries === 0) {
82
- this.entries.splice(iAfter, 0, newEntry);
83
- return;
84
- }
85
-
86
- const iFirst = iBefore + 1;
87
- const firstEntry = this.entries[iFirst] ?? oob();
88
- const iLast = iAfter - 1;
89
- const lastEntry = this.entries[iLast] ?? oob();
90
- const lengthBeforeFirst = start - firstEntry.start;
91
- const lastEntryKey = lastEntry.start + lastEntry.length - 1;
92
- const lengthAfterLast = lastEntryKey - end;
93
-
94
- if (lengthBeforeFirst > 0 && lengthAfterLast > 0 && iFirst === iLast) {
95
- // The new entry fits in the middle of an existing entry.
96
- // We replace the existing entry with:
97
- // 1) the portion which comes before `newEntry`
98
- // 2) `newEntry`
99
- // 3) the portion which comes after `newEntry`
100
- this.entries.splice(iFirst, 1, { ...firstEntry, length: lengthBeforeFirst }, newEntry, {
101
- ...lastEntry,
102
- start: end + 1,
103
- length: lengthAfterLast,
104
- });
105
- return;
106
- }
107
-
108
- if (lengthBeforeFirst > 0) {
109
- this.entries[iFirst] = { ...firstEntry, length: lengthBeforeFirst };
110
- // The entry at `iFirst` is no longer overlapping with `newEntry`.
111
- iBefore = iFirst;
112
- }
113
-
114
- if (lengthAfterLast > 0) {
115
- this.entries[iLast] = {
116
- ...lastEntry,
117
- start: end + 1,
118
- length: lengthAfterLast,
119
- };
120
-
121
- // The entry at `iLast` is no longer overlapping with `newEntry`.
122
- iAfter = iLast;
123
- }
124
-
125
- const numContainedEntries = iAfter - iBefore - 1;
126
- this.entries.splice(iBefore + 1, numContainedEntries, newEntry);
127
135
  }
128
136
 
129
137
  /**
@@ -146,74 +154,110 @@ export class RangeMap<T> {
146
154
  * @param start - The start of the range to delete (inclusive).
147
155
  * @param length - The length of the range to delete.
148
156
  */
149
- public delete(start: number, length: number): void {
150
- const end = start + length - 1;
151
-
152
- let iBefore = -1;
153
- let iAfter = this.entries.length;
154
-
155
- for (const [i, entry] of this.entries.entries()) {
156
- const entryLastKey = entry.start + entry.length - 1;
157
- if (entryLastKey < start) {
158
- iBefore = i;
159
- } else if (entry.start > end) {
160
- iAfter = i;
161
- break;
157
+ public delete(start: K, length: number): void {
158
+ const lastDeleteKey = this.offsetKey(start, length - 1);
159
+ for (const { start: key, length: entryLength, value } of this.getIntersectingEntries(
160
+ start,
161
+ length,
162
+ )) {
163
+ this.tree.delete(key);
164
+ const lengthBefore = this.subtractKeys(start, key);
165
+ if (lengthBefore > 0) {
166
+ // A portion of this entry comes before the deletion range, so we reinsert that portion.
167
+ this.tree.set(key, { length: lengthBefore, value });
168
+ }
169
+
170
+ const lastEntryKey = this.offsetKey(key, entryLength - 1);
171
+ const lengthAfter = this.subtractKeys(lastEntryKey, lastDeleteKey);
172
+ if (lengthAfter > 0) {
173
+ // A portion of this entry comes after the deletion range, so we reinsert that portion.
174
+ this.tree.set(this.offsetKey(lastDeleteKey, 1), { length: lengthAfter, value });
162
175
  }
163
176
  }
177
+ }
178
+
179
+ public clone(): RangeMap<K, V> {
180
+ const cloned = new RangeMap<K, V>(this.offsetKey, this.subtractKeys);
181
+ cloned.tree = this.tree.clone();
182
+ return cloned;
183
+ }
164
184
 
165
- const numOverlappingEntries = iAfter - iBefore - 1;
185
+ /**
186
+ * Returns a new map which contains the entries from both input maps.
187
+ */
188
+ public static union<K, V>(a: RangeMap<K, V>, b: RangeMap<K, V>): RangeMap<K, V> {
189
+ assert(
190
+ a.offsetKey === b.offsetKey && a.subtractKeys === b.subtractKeys,
191
+ 0xaae /* Maps should have the same behavior */,
192
+ );
193
+
194
+ const merged = new RangeMap<K, V>(a.offsetKey, a.subtractKeys);
166
195
 
167
- if (numOverlappingEntries === 0) {
168
- // No entry will be removed
169
- return;
196
+ // TODO: Is there a good pattern that lets us make `tree` readonly?
197
+ merged.tree = a.tree.clone();
198
+ for (const [key, value] of b.tree.entries()) {
199
+ // TODO: Handle key collisions
200
+ merged.tree.set(key, value);
170
201
  }
171
202
 
172
- const iFirst = iBefore + 1;
173
- const iLast = iAfter - 1;
174
-
175
- for (let i = iFirst; i <= iLast; ++i) {
176
- const entry = this.entries[i] ?? oob();
177
- const entryLastKey = entry.start + entry.length - 1;
178
- let isDirty = false;
179
-
180
- if (entry.start >= start && entryLastKey <= end) {
181
- // If the entry lies within the range to be deleted, remove it
182
- this.entries.splice(i, 1);
183
- } else {
184
- // If the entry partially or completely overlaps with the range to be deleted
185
- if (entry.start < start) {
186
- // Update the endpoint and length of the portion before the range to be deleted
187
- const lengthBefore = start - entry.start;
188
- this.entries[i] = { ...entry, length: lengthBefore };
189
- isDirty = true;
203
+ return merged;
204
+ }
205
+
206
+ private getIntersectingEntries(start: K, length: number): RangeQueryEntry<K, V>[] {
207
+ const entries: RangeQueryEntry<K, V>[] = [];
208
+ const lastQueryKey = this.offsetKey(start, length - 1);
209
+ {
210
+ const entry = this.tree.getPairOrNextLower(start);
211
+ if (entry !== undefined) {
212
+ const key = entry[0];
213
+ const { length: entryLength, value } = entry[1];
214
+ const lastEntryKey = this.offsetKey(key, entryLength - 1);
215
+ if (this.ge(lastEntryKey, start)) {
216
+ entries.push({ start: key, length: entryLength, value });
190
217
  }
218
+ }
219
+ }
191
220
 
192
- if (entryLastKey > end) {
193
- // Update the startpoint and length of the portion after the range to be deleted
194
- const newStart = end + 1;
195
- const newLength = entryLastKey - end;
196
- this.entries.splice(isDirty ? i + 1 : i, isDirty ? 0 : 1, {
197
- start: newStart,
198
- length: newLength,
199
- value: entry.value,
200
- });
221
+ {
222
+ let entry = this.tree.nextHigherPair(start);
223
+ while (entry !== undefined) {
224
+ const key = entry[0];
225
+ if (this.gt(key, lastQueryKey)) {
226
+ break;
201
227
  }
228
+
229
+ const { length: entryLength, value } = entry[1];
230
+ const lastEntryKey = this.offsetKey(key, entryLength - 1);
231
+
232
+ entries.push({ start: key, length: entryLength, value });
233
+ entry = this.tree.nextHigherPair(lastEntryKey);
202
234
  }
203
235
  }
236
+
237
+ return entries;
238
+ }
239
+
240
+ private gt(a: K, b: K): boolean {
241
+ return this.subtractKeys(a, b) > 0;
242
+ }
243
+
244
+ private ge(a: K, b: K): boolean {
245
+ return this.subtractKeys(a, b) >= 0;
246
+ }
247
+
248
+ private lt(a: K, b: K): boolean {
249
+ return this.subtractKeys(a, b) < 0;
250
+ }
251
+
252
+ private le(a: K, b: K): boolean {
253
+ return this.subtractKeys(a, b) <= 0;
204
254
  }
205
255
  }
206
256
 
207
257
  /**
208
258
  * Represents a contiguous range of values in the RangeMap.
209
- * This interface is used internally and should not be exposed to consumers.
210
259
  */
211
- interface RangeEntry<T> {
212
- /**
213
- * The starting index of the range (inclusive).
214
- */
215
- readonly start: number;
216
-
260
+ interface RangeEntry<V> {
217
261
  /**
218
262
  * The length of the range.
219
263
  */
@@ -222,18 +266,23 @@ interface RangeEntry<T> {
222
266
  /**
223
267
  * The value associated with this range.
224
268
  */
225
- readonly value: T;
269
+ readonly value: V;
226
270
  }
227
271
 
228
272
  /**
229
273
  * Describes the result of a range query, including the value and length of the matching prefix.
230
274
  */
231
- export interface RangeQueryResult<T> {
275
+ export interface RangeQueryResult<K, V> {
276
+ /**
277
+ * The key for the first element in the range.
278
+ */
279
+ readonly start: K;
280
+
232
281
  /**
233
282
  * The value of the first key in the query range.
234
283
  * If no matching range is found, this will be undefined.
235
284
  */
236
- readonly value: T | undefined;
285
+ readonly value: V | undefined;
237
286
 
238
287
  /**
239
288
  * The length of the prefix of the query range which has the same value.
@@ -242,3 +291,19 @@ export interface RangeQueryResult<T> {
242
291
  */
243
292
  readonly length: number;
244
293
  }
294
+
295
+ export interface RangeQueryEntry<K, V> extends RangeQueryResult<K, V> {
296
+ readonly value: V;
297
+ }
298
+
299
+ export function newIntegerRangeMap<V>(): RangeMap<number, V> {
300
+ return new RangeMap(offsetInteger, subtractIntegers);
301
+ }
302
+
303
+ function offsetInteger(key: number, offset: number): number {
304
+ return key + offset;
305
+ }
306
+
307
+ function subtractIntegers(a: number, b: number): number {
308
+ return a - b;
309
+ }
package/src/util/utils.ts CHANGED
@@ -48,9 +48,16 @@ export function asMutable<T>(readonly: T): Mutable<T> {
48
48
  export const clone = structuredClone;
49
49
 
50
50
  /**
51
- */
52
- export function fail(message: string): never {
53
- throw new Error(message);
51
+ * Throw an error with a constant message.
52
+ * @remarks
53
+ * Works like {@link @fluidframework/core-utils/internal#assert}.
54
+ */
55
+ export function fail(message: string | number): never {
56
+ // Declaring this here aliased to a different name avoids the assert tagging objecting to the usages of `assert` below.
57
+ // Since users of `fail` do the assert message tagging instead, suppressing tagging errors here makes sense.
58
+ const assertNoTag: (condition: boolean, message: string | number) => asserts condition =
59
+ assert;
60
+ assertNoTag(false, message);
54
61
  }
55
62
 
56
63
  /**
package/lib/package.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }