dubc-ds-tmap 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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # dubc-ds-tmap
2
+
3
+ Observable sorted map based on a weighted binary search tree.
@@ -0,0 +1,88 @@
1
+ import { Base } from "dubc-ds-base";
2
+ import { Pair, Pairs } from "dubc-ds-pairs";
3
+ export interface Include {
4
+ start: boolean;
5
+ end: boolean;
6
+ }
7
+ export declare const IN_IN: {
8
+ start: boolean;
9
+ end: boolean;
10
+ };
11
+ export declare const IN_EX: {
12
+ start: boolean;
13
+ end: boolean;
14
+ };
15
+ export declare const EX_IN: {
16
+ start: boolean;
17
+ end: boolean;
18
+ };
19
+ export declare const EX_EX: {
20
+ start: boolean;
21
+ end: boolean;
22
+ };
23
+ type N<K extends {}, V> = Node<K, V> | undefined;
24
+ declare class Node<K extends {}, V> {
25
+ readonly key: K;
26
+ value: V;
27
+ weight: number;
28
+ parent: N<K, V>;
29
+ left: N<K, V>;
30
+ right: N<K, V>;
31
+ constructor(key: K, value: V);
32
+ private weigh;
33
+ index(): number;
34
+ next(): N<K, V>;
35
+ prev(): N<K, V>;
36
+ rotateLeft(): N<K, V>;
37
+ rotateRight(): N<K, V>;
38
+ }
39
+ export interface Conf<K extends {}, V> {
40
+ readonly unique: boolean;
41
+ readonly compare: (a: K, b: K) => number;
42
+ readonly valueEq: (a: V, b: V) => boolean;
43
+ }
44
+ export declare class TMap<K extends {}, V> extends Base<Pair<K, V>> {
45
+ private root;
46
+ private _compare;
47
+ protected conf: Conf<K, V>;
48
+ constructor(input: Pairs<K, V>, c: Conf<K, V>);
49
+ static of<K extends {}, V>(compare: (a: K, b: K) => number, ...pairs: Pair<K, V>[] | [K, V][]): TMap<K, V>;
50
+ toEmpty(): TMap<K, V>;
51
+ get size(): number;
52
+ clear(): void;
53
+ replace(i: Pairs<K, V>): void;
54
+ drop(f: (pair: Pair<K, V>) => boolean): void;
55
+ get compare(): (a: K, b: K) => number;
56
+ set compare(cmp: (a: K, b: K) => number);
57
+ get keyEq(): (a: K, b: K) => boolean;
58
+ get unique(): boolean;
59
+ at(i: number): Pair<K, V>;
60
+ get only(): Pair<K, V>;
61
+ get first(): Pair<K, V> | undefined;
62
+ get last(): Pair<K, V> | undefined;
63
+ [Symbol.iterator](): Generator<Node<K, V>, void, unknown>;
64
+ private keys2;
65
+ get keys(): Iterable<K>;
66
+ private values2;
67
+ get values(): Iterable<V>;
68
+ reversed(): Generator<Pair<K, V>, void, unknown>;
69
+ range(startKey: K, endKey: K, inc?: Include): Generator<Pair<K, V>, void, unknown>;
70
+ private find;
71
+ get(key: K): V | undefined;
72
+ has(key: K): boolean;
73
+ from(key: K): Pair<K, V> | undefined;
74
+ to(key: K): Pair<K, V> | undefined;
75
+ after(key: K): Pair<K, V> | undefined;
76
+ before(key: K): Pair<K, V> | undefined;
77
+ rank(key: K): number | undefined;
78
+ protected rawPut(key: K, value: V): {
79
+ node: Node<K, V>;
80
+ old?: V;
81
+ };
82
+ set(key: K, value: V): V | undefined;
83
+ setAll(entries: Pairs<K, V>): number;
84
+ delete(key: K): V | undefined;
85
+ private remove;
86
+ private weigh;
87
+ }
88
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,433 @@
1
+ import { Base } from "dubc-ds-base";
2
+ import { forEach } from "dubc-ds-pairs";
3
+ export const IN_IN = { start: true, end: true };
4
+ export const IN_EX = { start: true, end: false };
5
+ export const EX_IN = { start: false, end: true };
6
+ export const EX_EX = { start: false, end: false };
7
+ class Node {
8
+ constructor(key, value) {
9
+ this.key = key;
10
+ this.value = value;
11
+ this.weight = 1;
12
+ }
13
+ weigh() {
14
+ var _a, _b, _c, _d;
15
+ this.weight = 1 + ((_b = (_a = this.left) === null || _a === void 0 ? void 0 : _a.weight) !== null && _b !== void 0 ? _b : 0) + ((_d = (_c = this.right) === null || _c === void 0 ? void 0 : _c.weight) !== null && _d !== void 0 ? _d : 0);
16
+ }
17
+ index() {
18
+ let i = -1;
19
+ let node = this;
20
+ let prev = node.right;
21
+ while (node) {
22
+ if (node.right === prev) {
23
+ i += node.left ? node.left.weight + 1 : 1;
24
+ }
25
+ prev = node;
26
+ node = node.parent;
27
+ }
28
+ return i;
29
+ }
30
+ next() {
31
+ let node = this;
32
+ let child = node.right;
33
+ if (child !== undefined)
34
+ while (child !== undefined) {
35
+ node = child;
36
+ child = child.left;
37
+ }
38
+ else
39
+ while (node !== undefined && node.right === child) {
40
+ child = node;
41
+ node = node.parent;
42
+ }
43
+ return node;
44
+ }
45
+ prev() {
46
+ let node = this;
47
+ let child = node.left;
48
+ if (child !== undefined)
49
+ while (child !== undefined) {
50
+ node = child;
51
+ child = child.right;
52
+ }
53
+ else
54
+ while (node !== undefined && node.left === child) {
55
+ child = node;
56
+ node = node.parent;
57
+ }
58
+ return node;
59
+ }
60
+ rotateLeft() {
61
+ let a = this;
62
+ let b = a.right;
63
+ let r = b === null || b === void 0 ? void 0 : b.left;
64
+ b.parent = a.parent;
65
+ b.left = a;
66
+ a.parent = b;
67
+ a.right = r;
68
+ if (r)
69
+ r.parent = a;
70
+ a.weigh();
71
+ b === null || b === void 0 ? void 0 : b.weigh();
72
+ return b;
73
+ }
74
+ rotateRight() {
75
+ let a = this;
76
+ let b = a.left;
77
+ let l = b === null || b === void 0 ? void 0 : b.right;
78
+ b.parent = a.parent;
79
+ b.right = a;
80
+ a.parent = b;
81
+ a.left = l;
82
+ if (l)
83
+ l.parent = a;
84
+ a.weigh();
85
+ b === null || b === void 0 ? void 0 : b.weigh();
86
+ return b;
87
+ }
88
+ }
89
+ const EQ = { lset: false, rset: false, eset: true, eright: false };
90
+ //const EG:Op = { lset:false, rset:false, eset:true, eright:true }
91
+ const LT = { lset: true, rset: false, eset: false, eright: false };
92
+ const LE = { lset: true, rset: false, eset: true, eright: true };
93
+ const GT = { lset: false, rset: true, eset: false, eright: true };
94
+ const GE = { lset: false, rset: true, eset: true, eright: false };
95
+ export class TMap extends Base {
96
+ constructor(input, c) {
97
+ super();
98
+ this._compare = c.compare;
99
+ this.conf = c;
100
+ this.setAll(input);
101
+ }
102
+ static of(compare, ...pairs) {
103
+ const conf = { compare, valueEq: Object.is, unique: true };
104
+ return new TMap(pairs, conf);
105
+ }
106
+ toEmpty() {
107
+ const conf2 = {
108
+ unique: this.conf.unique,
109
+ valueEq: this.conf.valueEq,
110
+ compare: this._compare,
111
+ };
112
+ const r = new TMap(this, conf2);
113
+ return r;
114
+ }
115
+ get size() { var _a, _b; return (_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a.weight) !== null && _b !== void 0 ? _b : 0; }
116
+ clear() {
117
+ const sz = this.size;
118
+ this.root = undefined;
119
+ if (sz > 0)
120
+ this.fire({ cleared: sz });
121
+ }
122
+ replace(i) {
123
+ const sz = this.size;
124
+ this.root = undefined;
125
+ forEach(i, (k, v) => { this.rawPut(k, v); });
126
+ if (sz > 0) {
127
+ if (this.root === undefined)
128
+ this.fire({ cleared: sz });
129
+ else
130
+ this.fire({ cleared: sz, added: { items: this, at: 0 } });
131
+ }
132
+ else if (this.root !== undefined)
133
+ this.fire({ added: { items: this, at: 0 } });
134
+ }
135
+ drop(f) {
136
+ let n = this.first;
137
+ let at = 0;
138
+ while (n !== undefined) {
139
+ const x = n;
140
+ n = n.next();
141
+ if (f(x)) {
142
+ this.remove(x);
143
+ this.fire({ deleted: { items: [x], at: at } });
144
+ }
145
+ else
146
+ at++;
147
+ }
148
+ }
149
+ get compare() { return this._compare; }
150
+ set compare(cmp) {
151
+ this._compare = cmp;
152
+ let n = this.first;
153
+ if (n === undefined)
154
+ return;
155
+ this.root = undefined;
156
+ while (n !== undefined) {
157
+ this.rawPut(n.key, n.value);
158
+ n = n.next();
159
+ }
160
+ this.fire({ cleared: this.size, added: { items: this, at: 0 } });
161
+ }
162
+ get keyEq() { return (a, b) => this._compare(a, b) === 0; }
163
+ get unique() { return this.conf.unique; }
164
+ at(i) {
165
+ var _a;
166
+ let node = this.root;
167
+ let weight = this.size;
168
+ // if (i < 0) i += weight // TODO
169
+ if (i < 0 || i >= weight)
170
+ throw new TypeError("bounds");
171
+ while (true) {
172
+ const left = node === null || node === void 0 ? void 0 : node.left;
173
+ const lw = (_a = left === null || left === void 0 ? void 0 : left.weight) !== null && _a !== void 0 ? _a : 0;
174
+ if (i > lw) {
175
+ i -= lw + 1;
176
+ node = node === null || node === void 0 ? void 0 : node.right;
177
+ }
178
+ else if (i < lw) {
179
+ node = left;
180
+ }
181
+ else
182
+ break;
183
+ }
184
+ return node;
185
+ }
186
+ get only() {
187
+ if (this.size !== 1)
188
+ throw new Error("size isn't 1");
189
+ return this.root;
190
+ }
191
+ get first() {
192
+ let current = this.root;
193
+ let previous;
194
+ while (current) {
195
+ previous = current;
196
+ current = current.left;
197
+ }
198
+ return previous;
199
+ }
200
+ get last() {
201
+ let current = this.root;
202
+ let previous;
203
+ while (current) {
204
+ previous = current;
205
+ current = current.right;
206
+ }
207
+ return previous;
208
+ }
209
+ *[Symbol.iterator]() {
210
+ let n = this.first;
211
+ while (n) {
212
+ yield n;
213
+ n = n.next();
214
+ }
215
+ }
216
+ *keys2() {
217
+ for (const x of this)
218
+ yield x.key;
219
+ }
220
+ get keys() {
221
+ return this.keys2();
222
+ }
223
+ *values2() {
224
+ for (const x of this)
225
+ yield x.value;
226
+ }
227
+ get values() {
228
+ return this.values2();
229
+ }
230
+ *reversed() {
231
+ let n = this.last;
232
+ while (n) {
233
+ yield n;
234
+ n = n.prev();
235
+ }
236
+ }
237
+ *range(startKey, endKey, inc = IN_EX) {
238
+ const start = this.find(startKey, inc.start ? GE : GT);
239
+ const cmp = this.compare;
240
+ if (inc.end)
241
+ for (let n = start; n !== undefined && cmp(n.key, endKey) <= 0; n = n.next()) {
242
+ yield n;
243
+ }
244
+ else
245
+ for (let n = start; n !== undefined && cmp(n.key, endKey) < 0; n = n.next()) {
246
+ yield n;
247
+ }
248
+ }
249
+ find(key, op = EQ) {
250
+ let node = this.root;
251
+ let ret;
252
+ const unique = this.unique;
253
+ const cmp = this.compare;
254
+ while (node) {
255
+ const c = cmp(node.key, key);
256
+ if (c < 0) {
257
+ if (op.lset)
258
+ ret = node;
259
+ node = node.right;
260
+ }
261
+ else if (c > 0) {
262
+ if (op.rset)
263
+ ret = node;
264
+ node = node.left;
265
+ }
266
+ else {
267
+ if (op.eset) {
268
+ if (unique)
269
+ return node;
270
+ else
271
+ ret = node;
272
+ }
273
+ node = op.eright ? node.right : node.left;
274
+ }
275
+ }
276
+ return ret;
277
+ }
278
+ get(key) { var _a; return (_a = this.find(key, EQ)) === null || _a === void 0 ? void 0 : _a.value; }
279
+ has(key) { return this.find(key, EQ) !== undefined; }
280
+ from(key) { return this.find(key, GE); }
281
+ to(key) { return this.find(key, LE); }
282
+ after(key) { return this.find(key, GT); }
283
+ before(key) { return this.find(key, LT); }
284
+ rank(key) {
285
+ var _a;
286
+ return (_a = this.find(key, EQ)) === null || _a === void 0 ? void 0 : _a.index();
287
+ }
288
+ rawPut(key, value) {
289
+ let previous = undefined, node = this.root;
290
+ let unique = this.unique ? 0 : undefined;
291
+ let c = 0, cmp = this.compare;
292
+ while (node) {
293
+ c = cmp(node.key, key);
294
+ if (c === unique) {
295
+ const old = node.value;
296
+ node.value = value;
297
+ return { node, old };
298
+ }
299
+ previous = node;
300
+ if (c <= 0)
301
+ node = node.right;
302
+ else
303
+ node = node.left;
304
+ }
305
+ node = new Node(key, value);
306
+ node.parent = previous;
307
+ if (previous === undefined)
308
+ this.root = node;
309
+ else {
310
+ if (c <= 0)
311
+ previous.right = node;
312
+ else
313
+ previous.left = node;
314
+ this.weigh(previous);
315
+ }
316
+ return { node, old: undefined };
317
+ }
318
+ set(key, value) {
319
+ const r = this.rawPut(key, value);
320
+ if (r.old === undefined) {
321
+ const at = r.node.index();
322
+ this.fire({ added: { items: [{ key, value }], at } });
323
+ return;
324
+ }
325
+ if (this.conf.valueEq(r.old, value))
326
+ return r.old;
327
+ const at = r.node.index();
328
+ this.fire({
329
+ deleted: { items: [{ key, value: r.old }], at },
330
+ added: { items: [{ key, value }], at }
331
+ });
332
+ return r.old;
333
+ }
334
+ setAll(entries) {
335
+ let sz = this.size;
336
+ if (sz > 0) {
337
+ forEach(entries, (k, v) => { this.set(k, v); });
338
+ return this.size - sz;
339
+ }
340
+ forEach(entries, (k, v) => { this.rawPut(k, v); });
341
+ const changed = this.size - sz;
342
+ if (changed > 0)
343
+ this.fire({ added: { items: this, at: 0 } });
344
+ return changed;
345
+ }
346
+ delete(key) {
347
+ const node = this.find(key);
348
+ if (node === undefined)
349
+ return undefined;
350
+ const at = node.index();
351
+ this.remove(node);
352
+ this.fire({ deleted: { items: [node], at } });
353
+ return node.value;
354
+ }
355
+ remove(node) {
356
+ const p = node.parent;
357
+ let left = node.left, right = node.right;
358
+ let bal;
359
+ let next;
360
+ if (right === undefined) {
361
+ bal = p;
362
+ next = left;
363
+ left = undefined;
364
+ }
365
+ else if (right.left) {
366
+ next = right;
367
+ while (next.left) {
368
+ bal = next;
369
+ next = next.left;
370
+ }
371
+ const c = next.right;
372
+ bal.left = c;
373
+ if (c)
374
+ c.parent = bal;
375
+ }
376
+ else {
377
+ bal = right;
378
+ next = right;
379
+ right = undefined;
380
+ }
381
+ if (p === undefined)
382
+ this.root = next;
383
+ else if (p.left === node)
384
+ p.left = next;
385
+ else
386
+ p.right = next;
387
+ if (next) {
388
+ next.parent = p;
389
+ if (left) {
390
+ next.left = left, left.parent = next;
391
+ }
392
+ if (right) {
393
+ next.right = right, right.parent = next;
394
+ }
395
+ }
396
+ this.weigh(bal);
397
+ }
398
+ weigh(n) {
399
+ let next = n;
400
+ while (next) {
401
+ let node = next, orig = next;
402
+ next = node.parent;
403
+ let left = node.left, right = node.right;
404
+ let lw = weight(left);
405
+ let rw = weight(right);
406
+ if (rw * 5 + 2 < lw * 2) {
407
+ if (weight(left === null || left === void 0 ? void 0 : left.left) * 5 < lw * 2)
408
+ node.left = left === null || left === void 0 ? void 0 : left.rotateLeft();
409
+ node = node.rotateRight();
410
+ }
411
+ else if (lw * 5 + 2 < rw * 2) {
412
+ if (weight(right === null || right === void 0 ? void 0 : right.right) * 5 < rw * 2)
413
+ node.right = right === null || right === void 0 ? void 0 : right.rotateRight();
414
+ node = node.rotateLeft();
415
+ }
416
+ else {
417
+ node.weight = lw + rw + 1;
418
+ continue;
419
+ }
420
+ if (next === undefined)
421
+ this.root = node;
422
+ else if (next.left === orig)
423
+ next.left = node;
424
+ else
425
+ next.right = node;
426
+ }
427
+ }
428
+ }
429
+ function weight(n) {
430
+ var _a;
431
+ return (_a = n === null || n === void 0 ? void 0 : n.weight) !== null && _a !== void 0 ? _a : 0;
432
+ }
433
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "dubc-ds-tmap",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "description": "Observable map based on a weighted binary search tree.",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "README.md",
10
+ "dist/index.js",
11
+ "dist/index.d.ts"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepare": "tsc",
16
+ "test": "vitest --coverage"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/p-jack/dubc.git"
21
+ },
22
+ "author": "Paul Jack",
23
+ "license": "BSD-3-Clause",
24
+ "bugs": {
25
+ "url": "https://github.com/p-jack/dubc/issues"
26
+ },
27
+ "homepage": "https://github.com/p-jack/dubc#readme",
28
+ "dependencies": {
29
+ "dubc-ds-base": "^1.0.2",
30
+ "dubc-ds-pairs": "^1.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@vitest/coverage-v8": "^3.2.4",
34
+ "dubc-ds-test": "^1.0.1",
35
+ "jsdom": "^27.0.1",
36
+ "typescript": "^5.9.3",
37
+ "vitest": "^3.2.4"
38
+ }
39
+ }