@mark1russell7/collections 0.9.1 → 0.9.3
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/README.md +16 -0
- package/build/functions.d.ts +161 -0
- package/build/functions.d.ts.map +1 -0
- package/build/functions.js +414 -0
- package/build/functions.js.map +1 -0
- package/build/index.d.ts +19 -64
- package/build/index.d.ts.map +1 -1
- package/build/index.js +103 -357
- package/build/index.js.map +1 -1
- package/build/summary-tree/index.d.ts +2 -0
- package/build/summary-tree/index.js +1 -0
- package/package.json +5 -1
- package/src/behaviors/readonly.ts +6 -0
- package/src/impl/hash-set.ts +30 -22
- package/src/impl/summary-tree.ts +56 -425
- package/src/impl/tree-set.ts +18 -18
- package/src/index.ts +10 -1
- package/src/summary-tree/functions.ts +581 -0
- package/src/summary-tree/index.ts +6 -0
package/build/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compose as compose$1 } from "./core/layers.js";
|
|
2
|
+
import { _ as split, a as insert, b as summaryOf, c as locate, d as remove, f as search, g as splice, h as slice, i as height, l as of, m as size, n as at, o as isEmpty, p as set, r as concat$1, s as leaves, t as append, u as prepend, v as splitAt, x as toArray$2, y as summary } from "./functions.js";
|
|
2
3
|
import { none as none$1, some as some$1, toOptional, tryCatch } from "@mark1russell7/optional";
|
|
3
4
|
// src/core/policies.ts
|
|
4
5
|
/**
|
|
@@ -3079,8 +3080,7 @@ var TreeSet = class TreeSet {
|
|
|
3079
3080
|
return modified;
|
|
3080
3081
|
}
|
|
3081
3082
|
retainAll(elements) {
|
|
3082
|
-
const toRetain =
|
|
3083
|
-
for (const element of elements) toRetain.add(element);
|
|
3083
|
+
const toRetain = this.setOf(elements);
|
|
3084
3084
|
let modified = false;
|
|
3085
3085
|
for (const element of Array.from(this)) if (!toRetain.has(element)) {
|
|
3086
3086
|
this.remove(element);
|
|
@@ -3102,8 +3102,7 @@ var TreeSet = class TreeSet {
|
|
|
3102
3102
|
compare: this._compare,
|
|
3103
3103
|
eq: this._eq
|
|
3104
3104
|
});
|
|
3105
|
-
const otherSet =
|
|
3106
|
-
for (const element of other) otherSet.add(element);
|
|
3105
|
+
const otherSet = this.setOf(other);
|
|
3107
3106
|
for (const element of this) if (otherSet.has(element)) result.add(element);
|
|
3108
3107
|
return result;
|
|
3109
3108
|
}
|
|
@@ -3112,8 +3111,7 @@ var TreeSet = class TreeSet {
|
|
|
3112
3111
|
compare: this._compare,
|
|
3113
3112
|
eq: this._eq
|
|
3114
3113
|
});
|
|
3115
|
-
const otherSet =
|
|
3116
|
-
for (const element of other) otherSet.add(element);
|
|
3114
|
+
const otherSet = this.setOf(other);
|
|
3117
3115
|
for (const element of this) if (!otherSet.has(element)) result.add(element);
|
|
3118
3116
|
return result;
|
|
3119
3117
|
}
|
|
@@ -3123,16 +3121,27 @@ var TreeSet = class TreeSet {
|
|
|
3123
3121
|
eq: this._eq
|
|
3124
3122
|
});
|
|
3125
3123
|
for (const element of this) result.add(element);
|
|
3126
|
-
for (const element of other) if (result.has(element)) result.remove(element);
|
|
3124
|
+
for (const element of this.setOf(other)) if (result.has(element)) result.remove(element);
|
|
3127
3125
|
else result.add(element);
|
|
3128
3126
|
return result;
|
|
3129
3127
|
}
|
|
3130
3128
|
isSubsetOf(other) {
|
|
3131
|
-
const otherSet =
|
|
3132
|
-
for (const element of other) otherSet.add(element);
|
|
3129
|
+
const otherSet = this.setOf(other);
|
|
3133
3130
|
for (const element of this) if (!otherSet.has(element)) return false;
|
|
3134
3131
|
return true;
|
|
3135
3132
|
}
|
|
3133
|
+
/**
|
|
3134
|
+
* This method makes a set of the elements, with the comparator and the equality of this set.
|
|
3135
|
+
* Before, the set operations used a native `Set`, which compares with `===` and ignores the comparator.
|
|
3136
|
+
*/
|
|
3137
|
+
setOf(elements) {
|
|
3138
|
+
const set = new TreeSet({
|
|
3139
|
+
compare: this._compare,
|
|
3140
|
+
eq: this._eq
|
|
3141
|
+
});
|
|
3142
|
+
for (const element of elements) set.add(element);
|
|
3143
|
+
return set;
|
|
3144
|
+
}
|
|
3136
3145
|
isSupersetOf(other) {
|
|
3137
3146
|
for (const element of other) if (!this.has(element)) return false;
|
|
3138
3147
|
return true;
|
|
@@ -3633,9 +3642,11 @@ const PRESENT = Symbol("PRESENT");
|
|
|
3633
3642
|
var HashSet = class HashSet {
|
|
3634
3643
|
_map;
|
|
3635
3644
|
_eq;
|
|
3645
|
+
_hash;
|
|
3636
3646
|
constructor(options = {}) {
|
|
3637
3647
|
const { initialCapacity = 16, loadFactor = .75, eq = defaultEq, hash = defaultHash } = options;
|
|
3638
3648
|
this._eq = eq;
|
|
3649
|
+
this._hash = hash;
|
|
3639
3650
|
this._map = new HashMap({
|
|
3640
3651
|
initialCapacity,
|
|
3641
3652
|
loadFactor,
|
|
@@ -3674,16 +3685,9 @@ var HashSet = class HashSet {
|
|
|
3674
3685
|
return modified;
|
|
3675
3686
|
}
|
|
3676
3687
|
retainAll(other) {
|
|
3677
|
-
const toRetain =
|
|
3688
|
+
const toRetain = this.setOf(other);
|
|
3678
3689
|
const toRemove = [];
|
|
3679
|
-
for (const element of this)
|
|
3680
|
-
let shouldRetain = false;
|
|
3681
|
-
for (const retainElement of toRetain) if (this._eq(element, retainElement)) {
|
|
3682
|
-
shouldRetain = true;
|
|
3683
|
-
break;
|
|
3684
|
-
}
|
|
3685
|
-
if (!shouldRetain) toRemove.push(element);
|
|
3686
|
-
}
|
|
3690
|
+
for (const element of this) if (!toRetain.contains(element)) toRemove.push(element);
|
|
3687
3691
|
let modified = false;
|
|
3688
3692
|
for (const element of toRemove) {
|
|
3689
3693
|
this.remove(element);
|
|
@@ -3712,11 +3716,9 @@ var HashSet = class HashSet {
|
|
|
3712
3716
|
* The new set contains only elements present in both sets.
|
|
3713
3717
|
*/
|
|
3714
3718
|
intersection(other) {
|
|
3715
|
-
const
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
break;
|
|
3719
|
-
}
|
|
3719
|
+
const others = this.setOf(other);
|
|
3720
|
+
const result = this.empty();
|
|
3721
|
+
for (const element of this) if (others.contains(element)) result.add(element);
|
|
3720
3722
|
return result;
|
|
3721
3723
|
}
|
|
3722
3724
|
/**
|
|
@@ -3733,8 +3735,9 @@ var HashSet = class HashSet {
|
|
|
3733
3735
|
* The new set contains elements in either set but not in both.
|
|
3734
3736
|
*/
|
|
3735
3737
|
symmetricDifference(other) {
|
|
3736
|
-
const
|
|
3737
|
-
const
|
|
3738
|
+
const others = this.setOf(other);
|
|
3739
|
+
const result = this.union(others);
|
|
3740
|
+
const inter = this.intersection(others);
|
|
3738
3741
|
result.removeAll(inter);
|
|
3739
3742
|
return result;
|
|
3740
3743
|
}
|
|
@@ -3743,8 +3746,7 @@ var HashSet = class HashSet {
|
|
|
3743
3746
|
* All elements in this set are also in the other set.
|
|
3744
3747
|
*/
|
|
3745
3748
|
isSubsetOf(other) {
|
|
3746
|
-
const otherSet =
|
|
3747
|
-
otherSet.addAll(other);
|
|
3749
|
+
const otherSet = this.setOf(other);
|
|
3748
3750
|
for (const element of this) if (!otherSet.contains(element)) return false;
|
|
3749
3751
|
return true;
|
|
3750
3752
|
}
|
|
@@ -3777,9 +3779,23 @@ var HashSet = class HashSet {
|
|
|
3777
3779
|
* This method makes a shallow copy of this set.
|
|
3778
3780
|
*/
|
|
3779
3781
|
clone() {
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3782
|
+
return this.setOf(this);
|
|
3783
|
+
}
|
|
3784
|
+
/**
|
|
3785
|
+
* This method makes an empty set with the equality and the hash function of this set.
|
|
3786
|
+
* Before, the inner sets kept only the equality, so they did not find an element with a custom hash.
|
|
3787
|
+
*/
|
|
3788
|
+
empty() {
|
|
3789
|
+
return new HashSet({
|
|
3790
|
+
eq: this._eq,
|
|
3791
|
+
hash: this._hash
|
|
3792
|
+
});
|
|
3793
|
+
}
|
|
3794
|
+
/** This method makes a set of the elements, with the equality and the hash function of this set. */
|
|
3795
|
+
setOf(elements) {
|
|
3796
|
+
const set = this.empty();
|
|
3797
|
+
set.addAll(elements);
|
|
3798
|
+
return set;
|
|
3783
3799
|
}
|
|
3784
3800
|
/**
|
|
3785
3801
|
* This method gives statistics about the underlying hash table.
|
|
@@ -4060,283 +4076,81 @@ function priorityQueue(optionsOrElementsOrComparator) {
|
|
|
4060
4076
|
return new PriorityQueue(optionsOrElementsOrComparator);
|
|
4061
4077
|
}
|
|
4062
4078
|
// src/impl/summary-tree.ts
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
if (inner === void 0) inner = left === null ? own : this.spec.monoid.combine(left.summary, own);
|
|
4081
|
-
return {
|
|
4082
|
-
left,
|
|
4083
|
-
leaf,
|
|
4084
|
-
own,
|
|
4085
|
-
inner,
|
|
4086
|
-
right,
|
|
4087
|
-
height: 1 + Math.max(heightOf(left), heightOf(right)),
|
|
4088
|
-
size: sizeOf(left) + 1 + sizeOf(right),
|
|
4089
|
-
summary: right === null ? inner : this.spec.monoid.combine(inner, right.summary)
|
|
4090
|
-
};
|
|
4091
|
-
}
|
|
4092
|
-
/** This function copies a node with a new right subtree. It keeps the summary `inner`, so it calls `combine` once at most. */
|
|
4093
|
-
withRight(n, right) {
|
|
4094
|
-
return this.node(n.left, n.leaf, n.own, right, n.inner);
|
|
4095
|
-
}
|
|
4096
|
-
rotateLeft(n) {
|
|
4097
|
-
const r = n.right;
|
|
4098
|
-
return this.node(this.withRight(n, r.left), r.leaf, r.own, r.right);
|
|
4099
|
-
}
|
|
4100
|
-
rotateRight(n) {
|
|
4101
|
-
const l = n.left;
|
|
4102
|
-
return this.withRight(l, this.node(l.right, n.leaf, n.own, n.right));
|
|
4103
|
-
}
|
|
4104
|
-
/** This function joins a tree that is higher by more than 1 with a leaf and a lower tree on its right. */
|
|
4105
|
-
joinRight(left, leaf, own, right) {
|
|
4106
|
-
const c = left.right;
|
|
4107
|
-
if (heightOf(c) <= heightOf(right) + 1) {
|
|
4108
|
-
const t = this.node(c, leaf, own, right);
|
|
4109
|
-
if (t.height <= heightOf(left.left) + 1) return this.withRight(left, t);
|
|
4110
|
-
return this.rotateLeft(this.withRight(left, this.rotateRight(t)));
|
|
4111
|
-
}
|
|
4112
|
-
const t = this.joinRight(c, leaf, own, right);
|
|
4113
|
-
const joined = this.withRight(left, t);
|
|
4114
|
-
return t.height <= heightOf(left.left) + 1 ? joined : this.rotateLeft(joined);
|
|
4115
|
-
}
|
|
4116
|
-
/** This function joins a lower tree on the left with a leaf and a tree that is higher by more than 1. */
|
|
4117
|
-
joinLeft(left, leaf, own, right, inner) {
|
|
4118
|
-
const c = right.left;
|
|
4119
|
-
if (heightOf(c) <= heightOf(left) + 1) {
|
|
4120
|
-
const t = this.node(left, leaf, own, c, inner);
|
|
4121
|
-
if (t.height <= heightOf(right.right) + 1) return this.node(t, right.leaf, right.own, right.right);
|
|
4122
|
-
return this.rotateRight(this.node(this.rotateLeft(t), right.leaf, right.own, right.right));
|
|
4123
|
-
}
|
|
4124
|
-
const t = this.joinLeft(left, leaf, own, c, inner);
|
|
4125
|
-
const joined = this.node(t, right.leaf, right.own, right.right);
|
|
4126
|
-
return t.height <= heightOf(right.right) + 1 ? joined : this.rotateRight(joined);
|
|
4127
|
-
}
|
|
4128
|
-
/**
|
|
4129
|
-
* This function gives the tree of the leaves of `left`, then `leaf`, then the leaves of `right`. Give `inner` only
|
|
4130
|
-
* when it is the summary of `left` and `own`.
|
|
4131
|
-
*/
|
|
4132
|
-
join(left, leaf, own, right, inner) {
|
|
4133
|
-
if (heightOf(left) > heightOf(right) + 1) return this.joinRight(left, leaf, own, right);
|
|
4134
|
-
if (heightOf(right) > heightOf(left) + 1) return this.joinLeft(left, leaf, own, right, inner);
|
|
4135
|
-
return this.node(left, leaf, own, right, inner);
|
|
4136
|
-
}
|
|
4137
|
-
/** This function removes the last leaf of a tree, and gives the rest and the node of that leaf. */
|
|
4138
|
-
splitLast(tree) {
|
|
4139
|
-
if (tree.right === null) return [tree.left, tree];
|
|
4140
|
-
const [rest, last] = this.splitLast(tree.right);
|
|
4141
|
-
return [this.join(tree.left, tree.leaf, tree.own, rest, tree.inner), last];
|
|
4142
|
-
}
|
|
4143
|
-
concat(left, right) {
|
|
4144
|
-
if (left === null) return right;
|
|
4145
|
-
if (right === null) return left;
|
|
4146
|
-
const [rest, last] = this.splitLast(left);
|
|
4147
|
-
return this.join(rest, last.leaf, last.own, right);
|
|
4148
|
-
}
|
|
4149
|
-
/** This function splits a tree into its first `index` leaves and the other leaves. */
|
|
4150
|
-
splitAt(tree, index) {
|
|
4151
|
-
if (tree === null) return [null, null];
|
|
4152
|
-
const before = sizeOf(tree.left);
|
|
4153
|
-
if (index <= before) {
|
|
4154
|
-
const [a, b] = this.splitAt(tree.left, index);
|
|
4155
|
-
return [a, this.join(b, tree.leaf, tree.own, tree.right)];
|
|
4156
|
-
}
|
|
4157
|
-
const [a, b] = this.splitAt(tree.right, index - before - 1);
|
|
4158
|
-
return [this.join(tree.left, tree.leaf, tree.own, a, tree.inner), b];
|
|
4159
|
-
}
|
|
4160
|
-
/** This function splits a tree before the first leaf whose prefix summary, after `acc`, satisfies the predicate. */
|
|
4161
|
-
splitBy(tree, predicate, acc) {
|
|
4162
|
-
if (tree === null) return [null, null];
|
|
4163
|
-
const { combine } = this.spec.monoid;
|
|
4164
|
-
const throughLeft = tree.left === null ? acc : combine(acc, tree.left.summary);
|
|
4165
|
-
if (tree.left !== null && predicate(throughLeft)) {
|
|
4166
|
-
const [a, b] = this.splitBy(tree.left, predicate, acc);
|
|
4167
|
-
return [a, this.join(b, tree.leaf, tree.own, tree.right)];
|
|
4168
|
-
}
|
|
4169
|
-
const throughLeaf = combine(throughLeft, tree.own);
|
|
4170
|
-
if (predicate(throughLeaf)) return [tree.left, this.join(null, tree.leaf, tree.own, tree.right)];
|
|
4171
|
-
const [a, b] = this.splitBy(tree.right, predicate, throughLeaf);
|
|
4172
|
-
return [this.join(tree.left, tree.leaf, tree.own, a, tree.inner), b];
|
|
4173
|
-
}
|
|
4174
|
-
/** This function replaces the leaf at an index in the tree. It copies only the path to the leaf. */
|
|
4175
|
-
replaceAt(tree, index, leaf, own) {
|
|
4176
|
-
const before = sizeOf(tree.left);
|
|
4177
|
-
if (index === before) return this.node(tree.left, leaf, own, tree.right);
|
|
4178
|
-
if (index < before) return this.node(this.replaceAt(tree.left, index, leaf, own), tree.leaf, tree.own, tree.right);
|
|
4179
|
-
return this.withRight(tree, this.replaceAt(tree.right, index - before - 1, leaf, own));
|
|
4180
|
-
}
|
|
4181
|
-
/** This function puts one leaf before the leaf at an index. It copies only the path, and `join` keeps the balance. */
|
|
4182
|
-
insertAt(tree, index, leaf, own) {
|
|
4183
|
-
if (tree === null) return this.node(null, leaf, own, null);
|
|
4184
|
-
const before = sizeOf(tree.left);
|
|
4185
|
-
if (index <= before) return this.join(this.insertAt(tree.left, index, leaf, own), tree.leaf, tree.own, tree.right);
|
|
4186
|
-
return this.join(tree.left, tree.leaf, tree.own, this.insertAt(tree.right, index - before - 1, leaf, own), tree.inner);
|
|
4187
|
-
}
|
|
4188
|
-
/**
|
|
4189
|
-
* This function replaces the leaf at an index with one or more leaves. It descends once.
|
|
4190
|
-
* At the node of the leaf, it puts the first new leaf in the node.
|
|
4191
|
-
* It puts the other new leaves at the start of the right subtree of that node.
|
|
4192
|
-
*/
|
|
4193
|
-
replaceSpan(tree, index, leaves) {
|
|
4194
|
-
const before = sizeOf(tree.left);
|
|
4195
|
-
if (index < before) return this.join(this.replaceSpan(tree.left, index, leaves), tree.leaf, tree.own, tree.right);
|
|
4196
|
-
if (index > before) return this.join(tree.left, tree.leaf, tree.own, this.replaceSpan(tree.right, index - before - 1, leaves), tree.inner);
|
|
4197
|
-
let right = tree.right;
|
|
4198
|
-
for (let i = 1; i < leaves.length; i++) right = this.insertAt(right, i - 1, leaves[i], this.spec.measure(leaves[i]));
|
|
4199
|
-
return this.join(tree.left, leaves[0], this.spec.measure(leaves[0]), right);
|
|
4200
|
-
}
|
|
4201
|
-
/** This function removes the leaf at an index. It copies only the path, and `join` keeps the balance. */
|
|
4202
|
-
removeAt(tree, index) {
|
|
4203
|
-
const before = sizeOf(tree.left);
|
|
4204
|
-
if (index === before) return this.concat(tree.left, tree.right);
|
|
4205
|
-
if (index < before) return this.join(this.removeAt(tree.left, index), tree.leaf, tree.own, tree.right);
|
|
4206
|
-
return this.join(tree.left, tree.leaf, tree.own, this.removeAt(tree.right, index - before - 1), tree.inner);
|
|
4207
|
-
}
|
|
4208
|
-
/** This function gives the leaf at an index of the tree. The index must be in the tree. */
|
|
4209
|
-
leafAt(tree, index) {
|
|
4210
|
-
let node = tree;
|
|
4211
|
-
for (;;) {
|
|
4212
|
-
const before = sizeOf(node.left);
|
|
4213
|
-
if (index === before) return node.leaf;
|
|
4214
|
-
if (index < before) node = node.left;
|
|
4215
|
-
else {
|
|
4216
|
-
index -= before + 1;
|
|
4217
|
-
node = node.right;
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
/** This function joins the leaves at `index` and `index + 1` when `spec.merge` gives one leaf for them. */
|
|
4222
|
-
seam(tree, index) {
|
|
4223
|
-
const { merge } = this.spec;
|
|
4224
|
-
if (merge === void 0 || tree === null || index < 0 || index + 1 >= tree.size) return tree;
|
|
4225
|
-
const merged = merge(this.leafAt(tree, index), this.leafAt(tree, index + 1));
|
|
4226
|
-
if (merged === void 0) return tree;
|
|
4227
|
-
return this.removeAt(this.replaceAt(tree, index, merged, this.spec.measure(merged)), index + 1);
|
|
4228
|
-
}
|
|
4229
|
-
/** This function makes a balanced tree of the leaves `items[lo]` to `items[hi - 1]`. */
|
|
4230
|
-
build(items, lo, hi) {
|
|
4231
|
-
if (lo >= hi) return null;
|
|
4232
|
-
const mid = lo + hi >>> 1;
|
|
4233
|
-
const leaf = items[mid];
|
|
4234
|
-
return this.node(this.build(items, lo, mid), leaf, this.spec.measure(leaf), this.build(items, mid + 1, hi));
|
|
4235
|
-
}
|
|
4236
|
-
};
|
|
4237
|
-
/** The largest number of removed and inserted leaves for which `splice` copies paths instead of splitting the tree. */
|
|
4238
|
-
const SMALL_EDIT = 8;
|
|
4239
|
-
/** The builders of each spec. Each spec has one builder, so that two trees of the same spec can be joined. */
|
|
4240
|
-
const builders = /* @__PURE__ */ new WeakMap();
|
|
4241
|
-
function builderOf(spec) {
|
|
4242
|
-
let builder = builders.get(spec);
|
|
4243
|
-
if (builder === void 0) {
|
|
4244
|
-
builder = new Builder(spec);
|
|
4245
|
-
builders.set(spec, builder);
|
|
4246
|
-
}
|
|
4247
|
-
return builder;
|
|
4248
|
-
}
|
|
4249
|
-
function* walk(tree) {
|
|
4250
|
-
const stack = [];
|
|
4251
|
-
let node = tree;
|
|
4252
|
-
while (node !== null || stack.length > 0) {
|
|
4253
|
-
while (node !== null) {
|
|
4254
|
-
stack.push(node);
|
|
4255
|
-
node = node.left;
|
|
4256
|
-
}
|
|
4257
|
-
const top = stack.pop();
|
|
4258
|
-
yield top.leaf;
|
|
4259
|
-
node = top.right;
|
|
4260
|
-
}
|
|
4261
|
-
}
|
|
4262
|
-
/** This function gives the index of a leaf, with a negative index counted from the end, or -1 when it is not in the tree. */
|
|
4263
|
-
function indexOf(index, size) {
|
|
4264
|
-
if (!Number.isInteger(index)) return -1;
|
|
4265
|
-
const at = index < 0 ? size + index : index;
|
|
4266
|
-
return at >= 0 && at < size ? at : -1;
|
|
4267
|
-
}
|
|
4268
|
-
function clamp$1(value, size) {
|
|
4269
|
-
if (Number.isNaN(value)) return 0;
|
|
4270
|
-
const whole = Math.trunc(value);
|
|
4271
|
-
return whole < 0 ? Math.max(0, size + whole) : Math.min(whole, size);
|
|
4272
|
-
}
|
|
4079
|
+
/**
|
|
4080
|
+
* SummaryTree: the class form of the summary tree, a persistent sequence of leaves with a summary of each part.
|
|
4081
|
+
*
|
|
4082
|
+
* The class wraps the plain functions of the entry `@mark1russell7/collections/summary-tree`. Its `record` is the
|
|
4083
|
+
* plain record that those functions take. A bundle that uses the class keeps each of its methods, so a program that
|
|
4084
|
+
* calls only a few operations imports the functions instead.
|
|
4085
|
+
*
|
|
4086
|
+
* @example
|
|
4087
|
+
* // The number of leaves and the total length of the strings
|
|
4088
|
+
* const spec = {
|
|
4089
|
+
* monoid: { empty: { count: 0, length: 0 }, combine: (a, b) => ({ count: a.count + b.count, length: a.length + b.length }) },
|
|
4090
|
+
* measure: (leaf: string) => ({ count: 1, length: leaf.length }),
|
|
4091
|
+
* };
|
|
4092
|
+
* const tree = summaryTree(spec, ["ab", "cde", "f"]);
|
|
4093
|
+
* tree.summary; // { count: 3, length: 6 }
|
|
4094
|
+
* const [left, right] = tree.split((prefix) => prefix.length > 2); // left: ["ab"], right: ["cde", "f"]
|
|
4095
|
+
*/
|
|
4273
4096
|
/**
|
|
4274
4097
|
* A persistent sequence of leaves with a summary of each part. Make one with `summaryTree`. Each method that changes
|
|
4275
4098
|
* the sequence gives a new tree.
|
|
4276
4099
|
*/
|
|
4277
4100
|
var SummaryTree = class SummaryTree {
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
constructor(
|
|
4281
|
-
this.
|
|
4282
|
-
this.root = root;
|
|
4101
|
+
/** The plain record of the tree: its spec and its root. The functions of the entry `./summary-tree` take it. */
|
|
4102
|
+
record;
|
|
4103
|
+
constructor(record) {
|
|
4104
|
+
this.record = record;
|
|
4283
4105
|
}
|
|
4284
4106
|
/** This function makes a tree of a spec from leaves, as `summaryTree` does. */
|
|
4285
4107
|
static of(spec, leaves = []) {
|
|
4286
|
-
|
|
4287
|
-
const items = [...leaves];
|
|
4288
|
-
return new SummaryTree(builder, builder.build(items, 0, items.length));
|
|
4108
|
+
return new SummaryTree(of(spec, leaves));
|
|
4289
4109
|
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4110
|
+
/** This function wraps a plain record of the entry `./summary-tree` in a tree. It does not copy the nodes. */
|
|
4111
|
+
static fromRecord(record) {
|
|
4112
|
+
return new SummaryTree(record);
|
|
4292
4113
|
}
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
if (leaves.builder !== this.builder) throw new TypeError("SummaryTree: the two trees have different specs");
|
|
4296
|
-
return leaves.root;
|
|
4297
|
-
}
|
|
4298
|
-
const items = [...leaves];
|
|
4299
|
-
return this.builder.build(items, 0, items.length);
|
|
4114
|
+
wrap(record) {
|
|
4115
|
+
return record === this.record ? this : new SummaryTree(record);
|
|
4300
4116
|
}
|
|
4301
4117
|
/** The spec of the tree: its monoid and its measure. */
|
|
4302
4118
|
get spec() {
|
|
4303
|
-
return this.
|
|
4119
|
+
return this.record.spec;
|
|
4304
4120
|
}
|
|
4305
4121
|
/** The number of leaves. */
|
|
4306
4122
|
get size() {
|
|
4307
|
-
return
|
|
4123
|
+
return size(this.record);
|
|
4308
4124
|
}
|
|
4309
4125
|
get isEmpty() {
|
|
4310
|
-
return this.
|
|
4126
|
+
return isEmpty(this.record);
|
|
4311
4127
|
}
|
|
4312
4128
|
/** The summary of all the leaves, in their order. An empty tree has the summary `monoid.empty`. */
|
|
4313
4129
|
get summary() {
|
|
4314
|
-
return
|
|
4130
|
+
return summary(this.record);
|
|
4315
4131
|
}
|
|
4316
4132
|
/** The height of the tree: 0 for an empty tree. The height is at most 1.45 log2(size + 2). */
|
|
4317
4133
|
get height() {
|
|
4318
|
-
return
|
|
4134
|
+
return height(this.record);
|
|
4319
4135
|
}
|
|
4320
4136
|
/**
|
|
4321
4137
|
* This function gives the leaf at an index, or `undefined` when the index is not in the tree. A negative index counts
|
|
4322
4138
|
* from the end, as `Array.prototype.at` does.
|
|
4323
4139
|
*/
|
|
4324
4140
|
at(index) {
|
|
4325
|
-
|
|
4326
|
-
return index === -1 ? void 0 : this.builder.leafAt(this.root, index);
|
|
4141
|
+
return at(this.record, index);
|
|
4327
4142
|
}
|
|
4328
4143
|
/** This function gives the summary of the leaves from `start` to `end`, with `end` not included. */
|
|
4329
4144
|
summaryOf(start = 0, end = this.size) {
|
|
4330
|
-
return this.
|
|
4145
|
+
return summaryOf(this.record, start, end);
|
|
4331
4146
|
}
|
|
4332
4147
|
/** This function gives the tree of the leaves of this tree, then the leaves of `other`. The two trees must have the same spec. */
|
|
4333
4148
|
concat(other) {
|
|
4334
|
-
|
|
4335
|
-
return this.wrap(this.builder.seam(joined, this.size - 1));
|
|
4149
|
+
return this.wrap(concat$1(this.record, recordOf(other)));
|
|
4336
4150
|
}
|
|
4337
4151
|
/** This function splits the tree into its first `index` leaves and the other leaves. */
|
|
4338
4152
|
splitAt(index) {
|
|
4339
|
-
const [left, right] =
|
|
4153
|
+
const [left, right] = splitAt(this.record, index);
|
|
4340
4154
|
return [this.wrap(left), this.wrap(right)];
|
|
4341
4155
|
}
|
|
4342
4156
|
/**
|
|
@@ -4345,7 +4159,7 @@ var SummaryTree = class SummaryTree {
|
|
|
4345
4159
|
* prefix. When no prefix satisfies it, the right tree is empty.
|
|
4346
4160
|
*/
|
|
4347
4161
|
split(predicate) {
|
|
4348
|
-
const [left, right] =
|
|
4162
|
+
const [left, right] = split(this.record, predicate);
|
|
4349
4163
|
return [this.wrap(left), this.wrap(right)];
|
|
4350
4164
|
}
|
|
4351
4165
|
/**
|
|
@@ -4353,27 +4167,7 @@ var SummaryTree = class SummaryTree {
|
|
|
4353
4167
|
* nothing. It gives `undefined` when no prefix satisfies the predicate.
|
|
4354
4168
|
*/
|
|
4355
4169
|
search(predicate) {
|
|
4356
|
-
|
|
4357
|
-
let node = this.root;
|
|
4358
|
-
let acc = this.builder.spec.monoid.empty;
|
|
4359
|
-
let index = 0;
|
|
4360
|
-
while (node !== null) {
|
|
4361
|
-
const throughLeft = node.left === null ? acc : combine(acc, node.left.summary);
|
|
4362
|
-
if (node.left !== null && predicate(throughLeft)) {
|
|
4363
|
-
node = node.left;
|
|
4364
|
-
continue;
|
|
4365
|
-
}
|
|
4366
|
-
const through = combine(throughLeft, node.own);
|
|
4367
|
-
if (predicate(through)) return {
|
|
4368
|
-
index: index + sizeOf(node.left),
|
|
4369
|
-
leaf: node.leaf,
|
|
4370
|
-
before: throughLeft,
|
|
4371
|
-
through
|
|
4372
|
-
};
|
|
4373
|
-
index += sizeOf(node.left) + 1;
|
|
4374
|
-
acc = through;
|
|
4375
|
-
node = node.right;
|
|
4376
|
-
}
|
|
4170
|
+
return search(this.record, predicate);
|
|
4377
4171
|
}
|
|
4378
4172
|
/**
|
|
4379
4173
|
* This function finds the leaf that holds a position of an additive key, and it calls no `combine`. The key must be
|
|
@@ -4386,80 +4180,26 @@ var SummaryTree = class SummaryTree {
|
|
|
4386
4180
|
* const at = rope.locate((s) => s.length, 1000);
|
|
4387
4181
|
*/
|
|
4388
4182
|
locate(key, target) {
|
|
4389
|
-
|
|
4390
|
-
let node = this.root;
|
|
4391
|
-
let index = 0;
|
|
4392
|
-
let rest = target;
|
|
4393
|
-
while (node !== null) {
|
|
4394
|
-
if (node.left !== null) {
|
|
4395
|
-
const left = key(node.left.summary);
|
|
4396
|
-
if (rest < left) {
|
|
4397
|
-
node = node.left;
|
|
4398
|
-
continue;
|
|
4399
|
-
}
|
|
4400
|
-
rest -= left;
|
|
4401
|
-
index += node.left.size;
|
|
4402
|
-
}
|
|
4403
|
-
const own = key(node.own);
|
|
4404
|
-
if (rest < own) return {
|
|
4405
|
-
index,
|
|
4406
|
-
leaf: node.leaf,
|
|
4407
|
-
offset: rest
|
|
4408
|
-
};
|
|
4409
|
-
rest -= own;
|
|
4410
|
-
index += 1;
|
|
4411
|
-
node = node.right;
|
|
4412
|
-
}
|
|
4183
|
+
return locate(this.record, key, target);
|
|
4413
4184
|
}
|
|
4414
4185
|
/** This function gives the tree of the leaves from `start` to `end`, with `end` not included. A negative index counts from the end. */
|
|
4415
4186
|
slice(start = 0, end = this.size) {
|
|
4416
|
-
|
|
4417
|
-
const to = clamp$1(end, this.size);
|
|
4418
|
-
if (to <= from) return this.wrap(null);
|
|
4419
|
-
const [, rest] = this.builder.splitAt(this.root, from);
|
|
4420
|
-
const [middle] = this.builder.splitAt(rest, to - from);
|
|
4421
|
-
return this.wrap(middle);
|
|
4187
|
+
return this.wrap(slice(this.record, start, end));
|
|
4422
4188
|
}
|
|
4423
4189
|
/**
|
|
4424
4190
|
* This function removes `deleteCount` leaves at `start` and puts the leaves of `inserted` there, as
|
|
4425
4191
|
* `Array.prototype.splice` does. It gives the new tree, not the removed leaves.
|
|
4426
4192
|
*/
|
|
4427
4193
|
splice(start, deleteCount = this.size, inserted = []) {
|
|
4428
|
-
|
|
4429
|
-
const count = Math.max(0, Math.min(Number.isNaN(deleteCount) ? 0 : Math.trunc(deleteCount), this.size - from));
|
|
4430
|
-
const builder = this.builder;
|
|
4431
|
-
const leaves = inserted instanceof SummaryTree ? void 0 : [...inserted];
|
|
4432
|
-
const added = leaves === void 0 ? inserted.size : leaves.length;
|
|
4433
|
-
if (count === 0 && added === 0) return this;
|
|
4434
|
-
let root = this.root;
|
|
4435
|
-
if (leaves !== void 0 && count + added <= SMALL_EDIT) {
|
|
4436
|
-
const replaced = Math.min(count, added);
|
|
4437
|
-
if (count > 0 && added > count) {
|
|
4438
|
-
for (let i = 0; i < count - 1; i++) root = builder.replaceAt(root, from + i, leaves[i], builder.spec.measure(leaves[i]));
|
|
4439
|
-
root = builder.replaceSpan(root, from + count - 1, leaves.slice(count - 1));
|
|
4440
|
-
} else for (let i = 0; i < added; i++) {
|
|
4441
|
-
const leaf = leaves[i];
|
|
4442
|
-
const own = builder.spec.measure(leaf);
|
|
4443
|
-
root = i < replaced ? builder.replaceAt(root, from + i, leaf, own) : builder.insertAt(root, from + i, leaf, own);
|
|
4444
|
-
}
|
|
4445
|
-
for (let i = replaced; i < count; i++) root = builder.removeAt(root, from + added);
|
|
4446
|
-
} else {
|
|
4447
|
-
const middle = leaves === void 0 ? this.treeOf(inserted) : builder.build(leaves, 0, leaves.length);
|
|
4448
|
-
const [left, rest] = builder.splitAt(root, from);
|
|
4449
|
-
const [, right] = builder.splitAt(rest, count);
|
|
4450
|
-
root = builder.concat(builder.concat(left, middle), right);
|
|
4451
|
-
}
|
|
4452
|
-
if (added > 0) root = builder.seam(root, from + added - 1);
|
|
4453
|
-
return this.wrap(builder.seam(root, from - 1));
|
|
4194
|
+
return this.wrap(splice(this.record, start, deleteCount, recordOf(inserted)));
|
|
4454
4195
|
}
|
|
4455
4196
|
/** This function puts the leaves of `inserted` before the leaf at `index`. */
|
|
4456
4197
|
insert(index, inserted) {
|
|
4457
|
-
return this.
|
|
4198
|
+
return this.wrap(insert(this.record, index, recordOf(inserted)));
|
|
4458
4199
|
}
|
|
4459
4200
|
/** This function removes the leaves from `start` to `end`, with `end` not included. */
|
|
4460
4201
|
remove(start, end = this.size) {
|
|
4461
|
-
|
|
4462
|
-
return this.splice(from, Math.max(0, clamp$1(end, this.size) - from));
|
|
4202
|
+
return this.wrap(remove(this.record, start, end));
|
|
4463
4203
|
}
|
|
4464
4204
|
/**
|
|
4465
4205
|
* This function replaces the leaf at an index. A negative index counts from the end, as `Array.prototype.with` does.
|
|
@@ -4467,27 +4207,29 @@ var SummaryTree = class SummaryTree {
|
|
|
4467
4207
|
* `spec.merge`.
|
|
4468
4208
|
*/
|
|
4469
4209
|
set(index, leaf) {
|
|
4470
|
-
|
|
4471
|
-
return at === -1 ? this : this.wrap(this.builder.replaceAt(this.root, at, leaf, this.builder.spec.measure(leaf)));
|
|
4210
|
+
return this.wrap(set(this.record, index, leaf));
|
|
4472
4211
|
}
|
|
4473
4212
|
/** This function adds leaves after the last leaf. */
|
|
4474
4213
|
append(...leaves) {
|
|
4475
|
-
return this.
|
|
4214
|
+
return this.wrap(append(this.record, ...leaves));
|
|
4476
4215
|
}
|
|
4477
4216
|
/** This function adds leaves before the first leaf. */
|
|
4478
4217
|
prepend(...leaves) {
|
|
4479
|
-
|
|
4480
|
-
return this.wrap(this.builder.seam(joined, leaves.length - 1));
|
|
4218
|
+
return this.wrap(prepend(this.record, ...leaves));
|
|
4481
4219
|
}
|
|
4482
4220
|
/** This function gives the leaves in their order. */
|
|
4483
4221
|
[Symbol.iterator]() {
|
|
4484
|
-
return
|
|
4222
|
+
return leaves(this.record);
|
|
4485
4223
|
}
|
|
4486
4224
|
/** This function gives the leaves in an array. */
|
|
4487
4225
|
toArray() {
|
|
4488
|
-
return
|
|
4226
|
+
return toArray$2(this.record);
|
|
4489
4227
|
}
|
|
4490
4228
|
};
|
|
4229
|
+
/** This function gives the record of a tree, or the leaves when they are not a tree. */
|
|
4230
|
+
function recordOf(leaves) {
|
|
4231
|
+
return leaves instanceof SummaryTree ? leaves.record : leaves;
|
|
4232
|
+
}
|
|
4491
4233
|
/**
|
|
4492
4234
|
* This function makes a persistent tree of leaves with a summary of each part. Use the same `spec` object for each
|
|
4493
4235
|
* tree that `concat` or `splice` joins.
|
|
@@ -4902,6 +4644,7 @@ const MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
4902
4644
|
"merge",
|
|
4903
4645
|
"putAll",
|
|
4904
4646
|
"pollOrUndefined",
|
|
4647
|
+
"deleteWhere",
|
|
4905
4648
|
"ensureCapacity",
|
|
4906
4649
|
"trimToSize",
|
|
4907
4650
|
"grow",
|
|
@@ -4919,7 +4662,10 @@ const MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
4919
4662
|
"fixAfterInsertion",
|
|
4920
4663
|
"fixAfterDeletion",
|
|
4921
4664
|
"rotateLeft",
|
|
4922
|
-
"rotateRight"
|
|
4665
|
+
"rotateRight",
|
|
4666
|
+
"moveToHead",
|
|
4667
|
+
"removeNode",
|
|
4668
|
+
"evictLRU"
|
|
4923
4669
|
]);
|
|
4924
4670
|
/** Methods that return a view of the collection: the view is readonly too. */
|
|
4925
4671
|
const VIEW_METHODS = /* @__PURE__ */ new Set([
|