articulated 0.1.0 → 0.3.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 (38) hide show
  1. package/README.md +53 -26
  2. package/build/commonjs/id.d.ts +3 -6
  3. package/build/commonjs/id.js.map +1 -1
  4. package/build/commonjs/id_list.d.ts +152 -52
  5. package/build/commonjs/id_list.js +845 -186
  6. package/build/commonjs/id_list.js.map +1 -1
  7. package/build/commonjs/index.d.ts +1 -1
  8. package/build/commonjs/index.js +4 -1
  9. package/build/commonjs/index.js.map +1 -1
  10. package/build/commonjs/internal/leaf_map.d.ts +25 -0
  11. package/build/commonjs/internal/leaf_map.js +56 -0
  12. package/build/commonjs/internal/leaf_map.js.map +1 -0
  13. package/build/commonjs/internal/seq_map.d.ts +20 -0
  14. package/build/commonjs/internal/seq_map.js +42 -0
  15. package/build/commonjs/internal/seq_map.js.map +1 -0
  16. package/build/commonjs/saved_id_list.d.ts +5 -5
  17. package/build/esm/id.d.ts +3 -6
  18. package/build/esm/id.js.map +1 -1
  19. package/build/esm/id_list.d.ts +152 -52
  20. package/build/esm/id_list.js +842 -185
  21. package/build/esm/id_list.js.map +1 -1
  22. package/build/esm/index.d.ts +1 -1
  23. package/build/esm/index.js +1 -1
  24. package/build/esm/index.js.map +1 -1
  25. package/build/esm/internal/leaf_map.d.ts +25 -0
  26. package/build/esm/internal/leaf_map.js +49 -0
  27. package/build/esm/internal/leaf_map.js.map +1 -0
  28. package/build/esm/internal/seq_map.d.ts +20 -0
  29. package/build/esm/internal/seq_map.js +34 -0
  30. package/build/esm/internal/seq_map.js.map +1 -0
  31. package/build/esm/saved_id_list.d.ts +5 -5
  32. package/package.json +13 -2
  33. package/src/id.ts +3 -6
  34. package/src/id_list.ts +1066 -191
  35. package/src/index.ts +1 -1
  36. package/src/internal/leaf_map.ts +59 -0
  37. package/src/internal/seq_map.ts +50 -0
  38. package/src/saved_id_list.ts +5 -5
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "./id";
2
- export * from "./id_list";
2
+ export { IdList, KnownIdView } from "./id_list";
3
3
  export * from "./saved_id_list";
@@ -0,0 +1,59 @@
1
+ import createRBTree, { Tree } from "functional-red-black-tree";
2
+ import type { LeafNode } from "../id_list";
3
+
4
+ /**
5
+ * A persistent sorted map from each LeafNode to its parent's seq.
6
+ *
7
+ * Leaves are sorted by their first ElementId.
8
+ * This lets you quickly look up the LeafNode containing an ElementId,
9
+ * even though the LeafNode might start at a lower counter.
10
+ */
11
+ export class LeafMap {
12
+ private constructor(private readonly tree: Tree<LeafNode, number>) {}
13
+
14
+ static new() {
15
+ return new this(createRBTree(compareLeaves));
16
+ }
17
+
18
+ /**
19
+ * Returns the greatest leaf whose first id is <= the given id,
20
+ * or undefined if none exists. Also returns the associated seq (or -1 if not found).
21
+ *
22
+ * The returned leaf might not actually contain the given id.
23
+ */
24
+ getLeaf(
25
+ bunchId: string,
26
+ counter: number
27
+ ): [leaf: LeafNode | undefined, seq: number] {
28
+ const iter = this.tree.le({ bunchId, startCounter: counter } as LeafNode);
29
+ return [iter.key, iter.value ?? -1];
30
+ }
31
+
32
+ set(leaf: LeafNode, seq: number): LeafMap {
33
+ // TODO: Vendor functional-red-black-tree and add our own set method
34
+ // so we can avoid this 2x penalty.
35
+ return new LeafMap(this.tree.remove(leaf).insert(leaf, seq));
36
+ }
37
+
38
+ delete(leaf: LeafNode): LeafMap {
39
+ return new LeafMap(this.tree.remove(leaf));
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Sort function for LeafNodes in LeafMap.
45
+ *
46
+ * Sorting by startCounters lets us quickly look up the LeafNode containing an ElementId,
47
+ * even though the LeafNode might start at a lower counter.
48
+ */
49
+ function compareLeaves(a: LeafNode, b: LeafNode) {
50
+ if (a.bunchId === b.bunchId) {
51
+ return a.startCounter - b.startCounter;
52
+ } else {
53
+ return a.bunchId > b.bunchId ? 1 : -1;
54
+ }
55
+ }
56
+
57
+ export interface MutableLeafMap {
58
+ value: LeafMap;
59
+ }
@@ -0,0 +1,50 @@
1
+ import createRBTree, { Tree } from "functional-red-black-tree";
2
+
3
+ /**
4
+ * A persistent map from an InnerNode's seq to its parent's seq
5
+ * (or 0 for the root).
6
+ *
7
+ * Sequence numbers start at 1 and increment each time you call set(nextSeq, ...).
8
+ */
9
+ export class SeqMap {
10
+ constructor(
11
+ private readonly tree: Tree<number, number>,
12
+ private readonly nextSeq: number
13
+ ) {}
14
+
15
+ static new(): SeqMap {
16
+ return new this(
17
+ createRBTree((a, b) => a - b),
18
+ 1
19
+ );
20
+ }
21
+
22
+ bumpNextSeq(): SeqMap {
23
+ return new SeqMap(this.tree, this.nextSeq + 1);
24
+ }
25
+
26
+ get(seq: number): number {
27
+ return this.tree.get(seq)!;
28
+ }
29
+
30
+ set(seq: number, value: number): SeqMap {
31
+ // TODO: Vendor functional-red-black-tree and add our own set method
32
+ // so we can avoid this 2x penalty.
33
+ return new SeqMap(this.tree.remove(seq).insert(seq, value), this.nextSeq);
34
+ }
35
+
36
+ // delete(seq: number): SeqMap {
37
+ // return new SeqMap(this.tree.remove(seq), this.nextSeq);
38
+ // }
39
+ }
40
+
41
+ export interface MutableSeqMap {
42
+ value: SeqMap;
43
+ }
44
+
45
+ export function getAndBumpNextSeq(seqsMut: MutableSeqMap): number {
46
+ // @ts-expect-error Ignore private
47
+ const nextSeq = seqsMut.value.nextSeq;
48
+ seqsMut.value = seqsMut.value.bumpNextSeq();
49
+ return nextSeq;
50
+ }
@@ -1,13 +1,13 @@
1
1
  /**
2
- * Saved state for an IdList.
2
+ * JSON saved state for an IdList.
3
3
  *
4
4
  * It describes all of the list's known ElementIds in list order, with basic compression:
5
5
  * if sequential ElementIds have the same bunchId, the same isDeleted status,
6
6
  * and sequential counters, then they are combined into a single object.
7
7
  */
8
8
  export type SavedIdList = Array<{
9
- bunchId: string;
10
- startCounter: number;
11
- count: number;
12
- isDeleted: boolean;
9
+ readonly bunchId: string;
10
+ readonly startCounter: number;
11
+ readonly count: number;
12
+ readonly isDeleted: boolean;
13
13
  }>;