list-toolkit 2.2.6 → 2.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.
- package/README.md +40 -37
- package/llms-full.txt +743 -0
- package/llms.txt +100 -0
- package/package.json +34 -29
- package/src/cache/cache-fifo.d.ts +6 -0
- package/src/cache/cache-fifo.js +7 -4
- package/src/cache/cache-lfu.d.ts +18 -0
- package/src/cache/cache-lfu.js +18 -6
- package/src/cache/cache-lru.d.ts +74 -0
- package/src/cache/cache-lru.js +60 -5
- package/src/cache/cache-random.d.ts +20 -0
- package/src/cache/cache-random.js +17 -6
- package/src/cache/decorator.d.ts +46 -0
- package/src/cache/decorator.js +26 -2
- package/src/cache.d.ts +13 -0
- package/src/cache.js +7 -2
- package/src/ext-list.d.ts +3 -0
- package/src/ext-list.js +0 -2
- package/src/ext-slist.d.ts +3 -0
- package/src/ext-slist.js +0 -2
- package/src/ext-value-list.d.ts +3 -0
- package/src/ext-value-list.js +0 -2
- package/src/ext-value-slist.d.ts +3 -0
- package/src/ext-value-slist.js +0 -2
- package/src/heap/basics.d.ts +89 -0
- package/src/heap/basics.js +42 -5
- package/src/heap/leftist-heap.d.ts +107 -0
- package/src/heap/leftist-heap.js +54 -2
- package/src/heap/min-heap.d.ts +270 -0
- package/src/heap/min-heap.js +186 -2
- package/src/heap/skew-heap.d.ts +105 -0
- package/src/heap/skew-heap.js +54 -2
- package/src/heap.d.ts +3 -0
- package/src/heap.js +0 -2
- package/src/list/basics.d.ts +43 -0
- package/src/list/basics.js +26 -8
- package/src/list/core.d.ts +271 -0
- package/src/list/core.js +162 -7
- package/src/list/ext-value.d.ts +253 -0
- package/src/list/ext-value.js +40 -6
- package/src/list/ext.d.ts +242 -0
- package/src/list/ext.js +148 -10
- package/src/list/nodes.d.ts +336 -0
- package/src/list/nodes.js +141 -3
- package/src/list/ptr.d.ts +72 -0
- package/src/list/ptr.js +44 -2
- package/src/list/value.d.ts +292 -0
- package/src/list/value.js +47 -6
- package/src/list-helpers.d.ts +44 -0
- package/src/list-helpers.js +36 -3
- package/src/list-utils.d.ts +141 -0
- package/src/list-utils.js +89 -3
- package/src/list.d.ts +3 -0
- package/src/list.js +0 -2
- package/src/meta-utils.d.ts +212 -0
- package/src/meta-utils.js +152 -1
- package/src/nt-utils.d.ts +91 -0
- package/src/nt-utils.js +65 -4
- package/src/queue.d.ts +74 -0
- package/src/queue.js +28 -2
- package/src/slist/basics.d.ts +47 -0
- package/src/slist/basics.js +23 -8
- package/src/slist/core.d.ts +251 -0
- package/src/slist/core.js +151 -6
- package/src/slist/ext-value.d.ts +188 -0
- package/src/slist/ext-value.js +35 -6
- package/src/slist/ext.d.ts +182 -0
- package/src/slist/ext.js +114 -12
- package/src/slist/nodes.d.ts +361 -0
- package/src/slist/nodes.js +156 -3
- package/src/slist/ptr.d.ts +73 -0
- package/src/slist/ptr.js +45 -2
- package/src/slist/value.d.ts +246 -0
- package/src/slist/value.js +38 -6
- package/src/slist.d.ts +3 -0
- package/src/slist.js +0 -2
- package/src/stack.d.ts +59 -0
- package/src/stack.js +29 -3
- package/src/tree/splay-tree.d.ts +151 -0
- package/src/tree/splay-tree.js +94 -3
- package/src/value-list.d.ts +3 -0
- package/src/value-list.js +0 -2
- package/src/value-slist.d.ts +3 -0
- package/src/value-slist.js +0 -2
- package/cjs/cache/cache-fifo.js +0 -37
- package/cjs/cache/cache-lfu.js +0 -76
- package/cjs/cache/cache-lru.js +0 -100
- package/cjs/cache/cache-random.js +0 -77
- package/cjs/cache/decorator.js +0 -47
- package/cjs/cache.js +0 -27
- package/cjs/ext-list.js +0 -21
- package/cjs/ext-slist.js +0 -21
- package/cjs/ext-value-list.js +0 -21
- package/cjs/ext-value-slist.js +0 -21
- package/cjs/heap/basics.js +0 -63
- package/cjs/heap/leftist-heap.js +0 -124
- package/cjs/heap/min-heap.js +0 -294
- package/cjs/heap/skew-heap.js +0 -114
- package/cjs/heap.js +0 -21
- package/cjs/list/basics.js +0 -88
- package/cjs/list/core.js +0 -305
- package/cjs/list/ext-value.js +0 -88
- package/cjs/list/ext.js +0 -356
- package/cjs/list/nodes.js +0 -240
- package/cjs/list/ptr.js +0 -61
- package/cjs/list/value.js +0 -99
- package/cjs/list-helpers.js +0 -91
- package/cjs/list-utils.js +0 -141
- package/cjs/list.js +0 -21
- package/cjs/meta-utils.js +0 -171
- package/cjs/nt-utils.js +0 -132
- package/cjs/package.json +0 -1
- package/cjs/queue.js +0 -58
- package/cjs/slist/basics.js +0 -71
- package/cjs/slist/core.js +0 -362
- package/cjs/slist/ext-value.js +0 -82
- package/cjs/slist/ext.js +0 -336
- package/cjs/slist/nodes.js +0 -276
- package/cjs/slist/ptr.js +0 -87
- package/cjs/slist/value.js +0 -90
- package/cjs/slist.js +0 -21
- package/cjs/stack.js +0 -55
- package/cjs/tree/splay-tree.js +0 -362
- package/cjs/value-list.js +0 -21
- package/cjs/value-slist.js +0 -21
package/src/slist/nodes.js
CHANGED
|
@@ -1,79 +1,143 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
import {isRangeLike, normalizeNode, normalizeRange, normalizePtrRange} from '../list-helpers.js';
|
|
4
2
|
import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Check whether a node has a valid next link.
|
|
6
|
+
* @param {object} options - Link property names.
|
|
7
|
+
* @param {object} node - Node to check.
|
|
8
|
+
* @returns {boolean} `true` if the node has a truthy next link.
|
|
9
|
+
*/
|
|
6
10
|
export const isNodeLike = ({nextName}, node) => node && node[nextName];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check whether a node points to itself (stand-alone).
|
|
14
|
+
* @param {object} options - Link property names.
|
|
15
|
+
* @param {object} node - Node to check.
|
|
16
|
+
* @returns {boolean} `true` if the node's next link points to itself.
|
|
17
|
+
*/
|
|
7
18
|
export const isStandAlone = ({nextName}, node) => node && node[nextName] === node;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check whether two option sets share the same next link property name.
|
|
22
|
+
* @param {object} options1 - First options.
|
|
23
|
+
* @param {object} options2 - Second options.
|
|
24
|
+
* @returns {boolean} `true` if `nextName` matches.
|
|
25
|
+
*/
|
|
8
26
|
export const isCompatible = (options1, options2) => options1.nextName === options2.nextName;
|
|
9
27
|
|
|
28
|
+
/** Singly linked list node with a circular self-link. */
|
|
10
29
|
export class Node {
|
|
30
|
+
/** @param {object} [options] - Link property names. */
|
|
11
31
|
constructor({nextName = 'next'} = {}) {
|
|
12
32
|
this.nextName = nextName;
|
|
13
33
|
this[nextName] = this;
|
|
14
34
|
}
|
|
35
|
+
/** Whether this node's next link points to itself. */
|
|
15
36
|
get isStandAlone() {
|
|
16
37
|
return this[this.nextName] === this;
|
|
17
38
|
}
|
|
18
39
|
}
|
|
19
40
|
|
|
41
|
+
/** Sentinel head node for hosted singly linked lists. */
|
|
20
42
|
export class HeadNode extends Node {
|
|
43
|
+
/** @param {object} [options] - Link property names. */
|
|
21
44
|
constructor(options) {
|
|
22
45
|
super(options);
|
|
23
46
|
this.last = this;
|
|
24
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Check whether a value looks like a compatible node.
|
|
50
|
+
* @param {*} node - Value to check.
|
|
51
|
+
* @returns {boolean} `true` if the value has a valid next link.
|
|
52
|
+
*/
|
|
25
53
|
isNodeLike(node) {
|
|
26
54
|
if (!node) return false;
|
|
27
55
|
const next = node[this.nextName];
|
|
28
56
|
return next && canHaveProps[typeof next] === 1;
|
|
29
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Check whether another options object shares the same link name.
|
|
60
|
+
* @param {object} options - Options to compare.
|
|
61
|
+
* @returns {boolean} `true` if `nextName` matches.
|
|
62
|
+
*/
|
|
30
63
|
isCompatibleNames({nextName}) {
|
|
31
64
|
return this.nextName === nextName;
|
|
32
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Check whether another list is compatible with this one.
|
|
68
|
+
* @param {object} list - List to compare.
|
|
69
|
+
* @returns {boolean} `true` if compatible.
|
|
70
|
+
*/
|
|
33
71
|
isCompatible(list) {
|
|
34
72
|
return list === this || (list instanceof HeadNode && this.nextName === list.nextName);
|
|
35
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Check whether a pointer belongs to a compatible list.
|
|
76
|
+
* @param {PtrBase} ptr - Pointer to check.
|
|
77
|
+
* @returns {boolean} `true` if compatible.
|
|
78
|
+
*/
|
|
36
79
|
isCompatiblePtr(ptr) {
|
|
37
80
|
return ptr instanceof PtrBase && (ptr.list === this || (ptr.list instanceof HeadNode && this.nextName === ptr.list.nextName));
|
|
38
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Check whether a range is compatible with this list.
|
|
84
|
+
* @param {object} [range] - Range to validate.
|
|
85
|
+
* @returns {boolean} `true` if compatible.
|
|
86
|
+
*/
|
|
39
87
|
isCompatibleRange(range) {
|
|
40
|
-
return isRangeLike(this, range);
|
|
88
|
+
return isRangeLike(this, range, PtrBase);
|
|
41
89
|
}
|
|
42
90
|
|
|
91
|
+
/** Whether the list has no nodes. */
|
|
43
92
|
get isEmpty() {
|
|
44
93
|
return this[this.nextName] === this;
|
|
45
94
|
}
|
|
46
95
|
|
|
96
|
+
/** Whether the list has exactly one node. */
|
|
47
97
|
get isOne() {
|
|
48
98
|
return this[this.nextName] !== this && this[this.nextName][this.nextName] === this;
|
|
49
99
|
}
|
|
50
100
|
|
|
101
|
+
/** Whether the list has zero or one node. */
|
|
51
102
|
get isOneOrEmpty() {
|
|
52
103
|
return this[this.nextName][this.nextName] === this;
|
|
53
104
|
}
|
|
54
105
|
|
|
106
|
+
/** The head sentinel itself. */
|
|
55
107
|
get head() {
|
|
56
108
|
return this;
|
|
57
109
|
}
|
|
58
110
|
|
|
111
|
+
/** The first node after the head. */
|
|
59
112
|
get front() {
|
|
60
113
|
return this[this.nextName];
|
|
61
114
|
}
|
|
62
115
|
|
|
116
|
+
/** The last node in the list. */
|
|
63
117
|
get back() {
|
|
64
118
|
return this.last;
|
|
65
119
|
}
|
|
66
120
|
|
|
121
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
67
122
|
get range() {
|
|
68
123
|
return this[this.nextName] === this ? null : {from: this[this.nextName], to: this.last, list: this};
|
|
69
124
|
}
|
|
70
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Count the number of nodes.
|
|
128
|
+
* @returns {number} The node count.
|
|
129
|
+
*/
|
|
71
130
|
getLength() {
|
|
72
131
|
let n = 0;
|
|
73
132
|
for (let p = this[this.nextName]; p !== this; ++n, p = p[this.nextName]);
|
|
74
133
|
return n;
|
|
75
134
|
}
|
|
76
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Adopt a node or pointer, making it stand-alone if needed.
|
|
138
|
+
* @param {object} nodeOrPtr - Node or pointer to adopt.
|
|
139
|
+
* @returns {object} The adopted node.
|
|
140
|
+
*/
|
|
77
141
|
adoptNode(nodeOrPtr) {
|
|
78
142
|
const isPtr = nodeOrPtr instanceof PtrBase;
|
|
79
143
|
if (isPtr && !this.isCompatiblePtr(nodeOrPtr)) throw new Error('Incompatible pointer');
|
|
@@ -90,20 +154,39 @@ export class HeadNode extends Node {
|
|
|
90
154
|
return node;
|
|
91
155
|
}
|
|
92
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Normalize a node or pointer to a plain node.
|
|
159
|
+
* @param {object|null} nodeOrPtr - Node or pointer.
|
|
160
|
+
* @returns {object|null} The underlying node, or `null`.
|
|
161
|
+
*/
|
|
93
162
|
normalizeNode(nodeOrPtr) {
|
|
94
163
|
const node = normalizeNode(this, nodeOrPtr, PtrBase);
|
|
95
164
|
if (nodeOrPtr instanceof PtrBase) nodeOrPtr.list = this;
|
|
96
165
|
return node;
|
|
97
166
|
}
|
|
98
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Normalize a range, resolving any pointers to nodes.
|
|
170
|
+
* @param {object} [range] - Range to normalize.
|
|
171
|
+
* @returns {object|null} The normalized range, or `null`.
|
|
172
|
+
*/
|
|
99
173
|
normalizeRange(range) {
|
|
100
174
|
return normalizeRange(this, range, PtrBase);
|
|
101
175
|
}
|
|
102
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Normalize a pointer-based range.
|
|
179
|
+
* @param {object} [range] - Pointer range to normalize.
|
|
180
|
+
* @returns {object|null} The normalized pointer range, or `null`.
|
|
181
|
+
*/
|
|
103
182
|
normalizePtrRange(range) {
|
|
104
183
|
return normalizePtrRange(this, range, PtrBase);
|
|
105
184
|
}
|
|
106
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Recalculate the `last` pointer by traversing the list.
|
|
188
|
+
* @returns {HeadNode} `this` for chaining.
|
|
189
|
+
*/
|
|
107
190
|
syncLast() {
|
|
108
191
|
this.last = this;
|
|
109
192
|
while (this.last[this.nextName] !== this) this.last = this.last[this.nextName];
|
|
@@ -113,14 +196,26 @@ export class HeadNode extends Node {
|
|
|
113
196
|
|
|
114
197
|
addAlias(HeadNode.prototype, 'adoptNode', 'adoptValue');
|
|
115
198
|
|
|
199
|
+
/** Value wrapper node for singly linked lists. */
|
|
116
200
|
export class ValueNode extends Node {
|
|
201
|
+
/**
|
|
202
|
+
* @param {*} value - Value to wrap.
|
|
203
|
+
* @param {object} [options] - Link property names.
|
|
204
|
+
*/
|
|
117
205
|
constructor(value, options) {
|
|
118
206
|
super(options);
|
|
119
207
|
this.value = value;
|
|
120
208
|
}
|
|
121
209
|
}
|
|
122
210
|
|
|
211
|
+
/** Base class for SLL pointers providing navigation. */
|
|
123
212
|
export class PtrBase {
|
|
213
|
+
/**
|
|
214
|
+
* @param {PtrBase|HeadNode|ExtListBase} list - Owning list or another PtrBase to copy.
|
|
215
|
+
* @param {object} [node] - Target node.
|
|
216
|
+
* @param {object} [prev] - Node preceding the target.
|
|
217
|
+
* @param {Function} [ListClass] - Expected list constructor for validation.
|
|
218
|
+
*/
|
|
124
219
|
constructor(list, node, prev, ListClass) {
|
|
125
220
|
if (list instanceof PtrBase) {
|
|
126
221
|
this.list = list.list;
|
|
@@ -150,9 +245,14 @@ export class PtrBase {
|
|
|
150
245
|
if (this.prevNode) this.node = this.prevNode[this.list.nextName];
|
|
151
246
|
}
|
|
152
247
|
}
|
|
248
|
+
/** The node after the current node. */
|
|
153
249
|
get nextNode() {
|
|
154
250
|
return this.node[this.list.nextName];
|
|
155
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Check whether the prevNode link is valid.
|
|
254
|
+
* @returns {boolean} `true` if prevNode's next points to the current node.
|
|
255
|
+
*/
|
|
156
256
|
isPrevNodeValid() {
|
|
157
257
|
if (!this.prevNode) this.prevNode = this.node;
|
|
158
258
|
if (this.prevNode[this.list.nextName] === this.node) return true;
|
|
@@ -165,16 +265,28 @@ export class PtrBase {
|
|
|
165
265
|
this.prevNode = this.node;
|
|
166
266
|
return false;
|
|
167
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Advance to the next node.
|
|
270
|
+
* @returns {PtrBase} `this` for chaining.
|
|
271
|
+
*/
|
|
168
272
|
next() {
|
|
169
273
|
this.prevNode = this.node;
|
|
170
274
|
this.node = this.node[this.list.nextName];
|
|
171
275
|
return this;
|
|
172
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Move to the previous node (requires valid prevNode).
|
|
279
|
+
* @returns {PtrBase} `this` for chaining.
|
|
280
|
+
*/
|
|
173
281
|
prev() {
|
|
174
282
|
if (!this.isPrevNodeValid()) throw new Error('Cannot get previous node: "prevNode" is invalid');
|
|
175
283
|
this.node = this.prevNode;
|
|
176
284
|
return this;
|
|
177
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Synchronize prevNode by traversing the list if needed.
|
|
288
|
+
* @returns {PtrBase} `this` for chaining.
|
|
289
|
+
*/
|
|
178
290
|
syncPrev() {
|
|
179
291
|
if (this.isPrevNodeValid()) return this;
|
|
180
292
|
this.prevNode = this.node;
|
|
@@ -187,7 +299,12 @@ export class PtrBase {
|
|
|
187
299
|
}
|
|
188
300
|
}
|
|
189
301
|
|
|
302
|
+
/** Base class for external (headless) singly linked lists. */
|
|
190
303
|
export class ExtListBase {
|
|
304
|
+
/**
|
|
305
|
+
* @param {object|ExtListBase|PtrBase|null} [head=null] - Initial head node, ExtListBase, or PtrBase.
|
|
306
|
+
* @param {object} [options] - Link property names.
|
|
307
|
+
*/
|
|
191
308
|
constructor(head = null, {nextName = 'next'} = {}) {
|
|
192
309
|
if (head instanceof ExtListBase) {
|
|
193
310
|
this.nextName = head.nextName;
|
|
@@ -203,34 +320,53 @@ export class ExtListBase {
|
|
|
203
320
|
this.attach(head);
|
|
204
321
|
}
|
|
205
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Check whether another list is compatible.
|
|
325
|
+
* @param {object} list - List to compare.
|
|
326
|
+
* @returns {boolean} `true` if compatible.
|
|
327
|
+
*/
|
|
206
328
|
isCompatible(list) {
|
|
207
329
|
return list === this || (list instanceof ExtListBase && this.nextName === list.nextName);
|
|
208
330
|
}
|
|
209
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Check whether a pointer belongs to a compatible list.
|
|
334
|
+
* @param {PtrBase} ptr - Pointer to check.
|
|
335
|
+
* @returns {boolean} `true` if compatible.
|
|
336
|
+
*/
|
|
210
337
|
isCompatiblePtr(ptr) {
|
|
211
338
|
return ptr instanceof PtrBase && (ptr.list === this || (ptr.list instanceof ExtListBase && this.nextName === ptr.list.nextName));
|
|
212
339
|
}
|
|
213
340
|
|
|
341
|
+
/** Whether the list has no nodes. */
|
|
214
342
|
get isEmpty() {
|
|
215
343
|
return !this.head;
|
|
216
344
|
}
|
|
217
345
|
|
|
346
|
+
/** Whether the list has exactly one node. */
|
|
218
347
|
get isOne() {
|
|
219
348
|
return this.head && this.head[this.nextName] === this.head;
|
|
220
349
|
}
|
|
221
350
|
|
|
351
|
+
/** Whether the list has zero or one node. */
|
|
222
352
|
get isOneOrEmpty() {
|
|
223
353
|
return !this.head || this.head[this.nextName] === this.head;
|
|
224
354
|
}
|
|
225
355
|
|
|
356
|
+
/** The head node, or `null` if empty. */
|
|
226
357
|
get front() {
|
|
227
358
|
return this.head;
|
|
228
359
|
}
|
|
229
360
|
|
|
361
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
230
362
|
get range() {
|
|
231
363
|
return this.head ? {from: this.head[this.nextName], to: this.head, list: this.head} : null;
|
|
232
364
|
}
|
|
233
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Count the number of nodes.
|
|
368
|
+
* @returns {number} The node count.
|
|
369
|
+
*/
|
|
234
370
|
getLength() {
|
|
235
371
|
if (!this.head) return 0;
|
|
236
372
|
|
|
@@ -244,6 +380,10 @@ export class ExtListBase {
|
|
|
244
380
|
return n;
|
|
245
381
|
}
|
|
246
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Find the last node by traversing the list.
|
|
385
|
+
* @returns {object|null} The last node, or `null` if empty.
|
|
386
|
+
*/
|
|
247
387
|
getBack() {
|
|
248
388
|
if (!this.head) return null;
|
|
249
389
|
for (let current = this.head; ; ) {
|
|
@@ -254,6 +394,11 @@ export class ExtListBase {
|
|
|
254
394
|
// unreachable
|
|
255
395
|
}
|
|
256
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Set a new head node.
|
|
399
|
+
* @param {object|PtrBase|null} [head=null] - New head node, pointer, or `null`.
|
|
400
|
+
* @returns {object|null} The previous head node.
|
|
401
|
+
*/
|
|
257
402
|
attach(head = null) {
|
|
258
403
|
const oldHead = this.head;
|
|
259
404
|
if (head instanceof PtrBase) {
|
|
@@ -266,12 +411,20 @@ export class ExtListBase {
|
|
|
266
411
|
return oldHead;
|
|
267
412
|
}
|
|
268
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Remove the head reference without modifying nodes.
|
|
416
|
+
* @returns {object|null} The previous head node.
|
|
417
|
+
*/
|
|
269
418
|
detach() {
|
|
270
419
|
const oldHead = this.head;
|
|
271
420
|
this.head = null;
|
|
272
421
|
return oldHead;
|
|
273
422
|
}
|
|
274
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Advance the head to the next node.
|
|
426
|
+
* @returns {ExtListBase} `this` for chaining.
|
|
427
|
+
*/
|
|
275
428
|
next() {
|
|
276
429
|
if (this.head) this.head = this.head[this.nextName];
|
|
277
430
|
return this;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {HeadNode, PtrBase} from './nodes.js';
|
|
2
|
+
|
|
3
|
+
/** Pointer for navigating and mutating a hosted singly linked list. */
|
|
4
|
+
export class Ptr<T extends object = object> extends PtrBase<T> {
|
|
5
|
+
/** The hosted list this pointer belongs to. */
|
|
6
|
+
list: HeadNode;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param list - Owning list or another Ptr to copy.
|
|
10
|
+
* @param node - Target node.
|
|
11
|
+
* @param prev - Preceding node.
|
|
12
|
+
*/
|
|
13
|
+
constructor(list: HeadNode | Ptr<T>, node?: T | PtrBase<T>, prev?: T);
|
|
14
|
+
|
|
15
|
+
/** Whether the pointer is at the head sentinel. */
|
|
16
|
+
get isHead(): boolean;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a copy of this pointer.
|
|
20
|
+
* @returns A new Ptr referencing the same list and node.
|
|
21
|
+
*/
|
|
22
|
+
clone(): Ptr<T>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Remove the current node and advance to the next.
|
|
26
|
+
* @returns The removed node, or `null` if at head or single node.
|
|
27
|
+
*/
|
|
28
|
+
removeCurrent(): T | null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Insert a value before the current node.
|
|
32
|
+
* @param value - Value or node to insert.
|
|
33
|
+
* @returns A Ptr to the inserted node.
|
|
34
|
+
*/
|
|
35
|
+
addBefore(value: any): Ptr<T>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Insert an existing node before the current node.
|
|
39
|
+
* @param node - Node to insert.
|
|
40
|
+
* @returns A Ptr to the inserted node.
|
|
41
|
+
*/
|
|
42
|
+
addNodeBefore(node: T | PtrBase<T>): Ptr<T>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Insert a value after the current node.
|
|
46
|
+
* @param value - Value or node to insert.
|
|
47
|
+
* @returns A Ptr to the inserted node.
|
|
48
|
+
*/
|
|
49
|
+
addAfter(value: any): Ptr<T>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Insert an existing node after the current node.
|
|
53
|
+
* @param node - Node to insert.
|
|
54
|
+
* @returns A Ptr to the inserted node.
|
|
55
|
+
*/
|
|
56
|
+
addNodeAfter(node: T | PtrBase<T>): Ptr<T>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Splice another list's nodes before the current node.
|
|
60
|
+
* @param list - Compatible list to consume.
|
|
61
|
+
* @returns A Ptr to the first inserted node.
|
|
62
|
+
*/
|
|
63
|
+
insertBefore(list: HeadNode): Ptr<T>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Splice another list's nodes after the current node.
|
|
67
|
+
* @param list - Compatible list to consume.
|
|
68
|
+
* @returns A Ptr to the first inserted node.
|
|
69
|
+
*/
|
|
70
|
+
insertAfter(list: HeadNode): Ptr<T>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default Ptr;
|
package/src/slist/ptr.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
import {HeadNode, PtrBase} from './nodes.js';
|
|
4
2
|
import {pop, splice} from './basics.js';
|
|
5
3
|
|
|
4
|
+
/** Pointer for navigating and mutating a hosted singly linked list. */
|
|
6
5
|
export class Ptr extends PtrBase {
|
|
6
|
+
/**
|
|
7
|
+
* @param {HeadNode|Ptr} list - Owning list or another Ptr to copy.
|
|
8
|
+
* @param {object} [node] - Target node.
|
|
9
|
+
* @param {object} [prev] - Node preceding the target.
|
|
10
|
+
*/
|
|
7
11
|
constructor(list, node, prev) {
|
|
8
12
|
super(list, node, prev, HeadNode);
|
|
9
13
|
}
|
|
10
14
|
|
|
15
|
+
/** Whether the pointer is at the head sentinel. */
|
|
11
16
|
get isHead() {
|
|
12
17
|
return this.node === this.list;
|
|
13
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a copy of this pointer.
|
|
21
|
+
* @returns {Ptr} A new Ptr referencing the same list and node.
|
|
22
|
+
*/
|
|
14
23
|
clone() {
|
|
15
24
|
return new Ptr(this);
|
|
16
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Remove the current node and advance to the next.
|
|
28
|
+
* @returns {object|null} The removed node, or `null` if at head.
|
|
29
|
+
*/
|
|
17
30
|
removeCurrent() {
|
|
18
31
|
if (!this.isPrevNodeValid()) throw new Error('Current node cannot be removed: "prevNode" is invalid');
|
|
19
32
|
if (this.node === this.list || this.node === this.prevNode) return null;
|
|
@@ -22,6 +35,11 @@ export class Ptr extends PtrBase {
|
|
|
22
35
|
this.node = this.prevNode[this.list.nextName];
|
|
23
36
|
return node;
|
|
24
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Insert a value before the current node.
|
|
40
|
+
* @param {*} value - Value or node to insert.
|
|
41
|
+
* @returns {Ptr} A Ptr to the inserted node.
|
|
42
|
+
*/
|
|
25
43
|
addBefore(value) {
|
|
26
44
|
if (!this.isPrevNodeValid()) throw new Error('Cannot be added before: "prevNode" is invalid');
|
|
27
45
|
const node = this.list.adoptValue(value),
|
|
@@ -30,6 +48,11 @@ export class Ptr extends PtrBase {
|
|
|
30
48
|
if (this.list.last === this.list) this.list.last = node;
|
|
31
49
|
return this.list.makePtr(prev);
|
|
32
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Insert an existing node before the current node.
|
|
53
|
+
* @param {object} node - Node to insert.
|
|
54
|
+
* @returns {Ptr} A Ptr to the inserted node.
|
|
55
|
+
*/
|
|
33
56
|
addNodeBefore(node) {
|
|
34
57
|
if (!this.isPrevNodeValid()) throw new Error('Cannot be added before: "prevNode" is invalid');
|
|
35
58
|
node = this.list.adoptNode(node);
|
|
@@ -38,16 +61,31 @@ export class Ptr extends PtrBase {
|
|
|
38
61
|
if (this.list.last === this.list) this.list.last = node;
|
|
39
62
|
return this.list.makePtr(prev);
|
|
40
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Insert a value after the current node.
|
|
66
|
+
* @param {*} value - Value or node to insert.
|
|
67
|
+
* @returns {Ptr} A Ptr to the inserted node.
|
|
68
|
+
*/
|
|
41
69
|
addAfter(value) {
|
|
42
70
|
const node = this.list.adoptValue(value),
|
|
43
71
|
prev = splice(this.list, this.node, {prevFrom: node});
|
|
44
72
|
return this.list.makePtr(prev);
|
|
45
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Insert an existing node after the current node.
|
|
76
|
+
* @param {object} node - Node to insert.
|
|
77
|
+
* @returns {Ptr} A Ptr to the inserted node.
|
|
78
|
+
*/
|
|
46
79
|
addNodeAfter(node) {
|
|
47
80
|
node = this.list.adoptNode(node);
|
|
48
81
|
const prev = splice(this.list, this.node, {prevFrom: node});
|
|
49
82
|
return this.list.makePtr(prev);
|
|
50
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Splice another list's nodes before the current node.
|
|
86
|
+
* @param {HeadNode} list - Compatible list to consume.
|
|
87
|
+
* @returns {Ptr} A Ptr to the first inserted node, or `this` if empty.
|
|
88
|
+
*/
|
|
51
89
|
insertBefore(list) {
|
|
52
90
|
if (!this.isPrevNodeValid()) throw new Error('Cannot be inserted before: "prevNode" is invalid');
|
|
53
91
|
if (!this.list.isCompatible(list)) throw new Error('Incompatible lists');
|
|
@@ -61,6 +99,11 @@ export class Ptr extends PtrBase {
|
|
|
61
99
|
|
|
62
100
|
return this.list.makePtr(prev);
|
|
63
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Splice another list's nodes after the current node.
|
|
104
|
+
* @param {HeadNode} list - Compatible list to consume.
|
|
105
|
+
* @returns {Ptr} A Ptr to the first inserted node, or `this` if empty.
|
|
106
|
+
*/
|
|
64
107
|
insertAfter(list) {
|
|
65
108
|
if (!this.list.isCompatible(list)) throw new Error('Incompatible lists');
|
|
66
109
|
if (list.isEmpty) return this;
|