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
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/** Options for configuring link property names. */
|
|
2
|
+
export interface DllOptions {
|
|
3
|
+
/** Name of the "next" link property. */
|
|
4
|
+
nextName?: string;
|
|
5
|
+
/** Name of the "prev" link property. */
|
|
6
|
+
prevName?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** A range defined by two nodes. */
|
|
10
|
+
export interface DllRange<T extends object = object> {
|
|
11
|
+
/** Start node of the range. */
|
|
12
|
+
from?: T;
|
|
13
|
+
/** End node of the range. */
|
|
14
|
+
to?: T;
|
|
15
|
+
/** List that owns the range. */
|
|
16
|
+
list?: HeadNode | ExtListBase<T>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A range defined by a pointer and a node. */
|
|
20
|
+
export interface DllPtrRange<T extends object = object> {
|
|
21
|
+
/** Start pointer of the range. */
|
|
22
|
+
from?: PtrBase<T>;
|
|
23
|
+
/** End node of the range. */
|
|
24
|
+
to?: T;
|
|
25
|
+
/** List that owns the range. */
|
|
26
|
+
list?: HeadNode | ExtListBase<T>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check whether a node has both link properties set.
|
|
31
|
+
* @param options - Link property names.
|
|
32
|
+
* @param node - Object to test.
|
|
33
|
+
* @returns `true` if the node has both next and prev links.
|
|
34
|
+
*/
|
|
35
|
+
export function isNodeLike<T extends object>(options: DllOptions, node: T | null | undefined): boolean;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check whether a node links to itself on both sides.
|
|
39
|
+
* @param options - Link property names.
|
|
40
|
+
* @param node - Object to test.
|
|
41
|
+
* @returns `true` if the node is stand-alone (self-linked).
|
|
42
|
+
*/
|
|
43
|
+
export function isStandAlone<T extends object>(options: DllOptions, node: T | null | undefined): boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check whether two option sets share the same link property names.
|
|
47
|
+
* @param options1 - First set of options.
|
|
48
|
+
* @param options2 - Second set of options.
|
|
49
|
+
* @returns `true` if nextName and prevName match.
|
|
50
|
+
*/
|
|
51
|
+
export function isCompatible(options1: DllOptions, options2: DllOptions): boolean;
|
|
52
|
+
|
|
53
|
+
/** A self-linked circular DLL node. */
|
|
54
|
+
export class Node {
|
|
55
|
+
/** Name of the "next" link property. */
|
|
56
|
+
readonly nextName: string;
|
|
57
|
+
/** Name of the "prev" link property. */
|
|
58
|
+
readonly prevName: string;
|
|
59
|
+
|
|
60
|
+
/** @param options - Link property names. */
|
|
61
|
+
constructor(options?: DllOptions);
|
|
62
|
+
|
|
63
|
+
/** Whether this node links to itself. */
|
|
64
|
+
get isStandAlone(): boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Sentinel node used as the head of a hosted DLL. */
|
|
68
|
+
export class HeadNode extends Node {
|
|
69
|
+
/**
|
|
70
|
+
* Test whether a value looks like a compatible node.
|
|
71
|
+
* @param node - Object to test.
|
|
72
|
+
* @returns `true` if the object has valid next and prev links.
|
|
73
|
+
*/
|
|
74
|
+
isNodeLike<T extends object>(node: T | null | undefined): boolean;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Test whether an options object shares the same link names.
|
|
78
|
+
* @param options - Options to compare.
|
|
79
|
+
* @returns `true` if names match.
|
|
80
|
+
*/
|
|
81
|
+
isCompatibleNames(options: DllOptions): boolean;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Test whether another list is compatible.
|
|
85
|
+
* @param list - List or head node to compare.
|
|
86
|
+
* @returns `true` if compatible.
|
|
87
|
+
*/
|
|
88
|
+
isCompatible(list: HeadNode | ExtListBase): boolean;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Test whether a pointer belongs to a compatible list.
|
|
92
|
+
* @param ptr - Pointer to test.
|
|
93
|
+
* @returns `true` if compatible.
|
|
94
|
+
*/
|
|
95
|
+
isCompatiblePtr(ptr: PtrBase): boolean;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Test whether a range is compatible with this list.
|
|
99
|
+
* @param range - Range to test.
|
|
100
|
+
* @returns `true` if compatible.
|
|
101
|
+
*/
|
|
102
|
+
isCompatibleRange(range: DllRange | null): boolean;
|
|
103
|
+
|
|
104
|
+
/** Whether the list is empty (head links to itself). */
|
|
105
|
+
get isEmpty(): boolean;
|
|
106
|
+
|
|
107
|
+
/** Whether the list contains exactly one node. */
|
|
108
|
+
get isOne(): boolean;
|
|
109
|
+
|
|
110
|
+
/** Whether the list contains zero or one nodes. */
|
|
111
|
+
get isOneOrEmpty(): boolean;
|
|
112
|
+
|
|
113
|
+
/** The sentinel head node. */
|
|
114
|
+
get head(): this;
|
|
115
|
+
|
|
116
|
+
/** The first node after the head. */
|
|
117
|
+
get front(): object;
|
|
118
|
+
|
|
119
|
+
/** The last node before the head. */
|
|
120
|
+
get back(): object;
|
|
121
|
+
|
|
122
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
123
|
+
get range(): DllRange | null;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Count the number of nodes in the list.
|
|
127
|
+
* @returns Node count.
|
|
128
|
+
*/
|
|
129
|
+
getLength(): number;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Adopt a node or pointer into this list, making it stand-alone if needed.
|
|
133
|
+
* @param nodeOrPtr - Node or pointer to adopt.
|
|
134
|
+
* @returns The adopted node.
|
|
135
|
+
* @throws If the node is already part of another list.
|
|
136
|
+
*/
|
|
137
|
+
adoptNode<T extends object>(nodeOrPtr: T | PtrBase<T>): T;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Adopt a value into this list. Overridden by value-list subclasses.
|
|
141
|
+
* @param nodeOrPtr - Node, pointer, or value to adopt.
|
|
142
|
+
* @returns The adopted node.
|
|
143
|
+
*/
|
|
144
|
+
adoptValue(nodeOrPtr: any): any;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Normalize a node or pointer to a plain node.
|
|
148
|
+
* @param nodeOrPtr - Node or pointer.
|
|
149
|
+
* @returns The underlying node, or `null`.
|
|
150
|
+
*/
|
|
151
|
+
normalizeNode<T extends object>(nodeOrPtr: T | PtrBase<T> | null): T | null;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Normalize a range, resolving any pointers to nodes.
|
|
155
|
+
* @param range - Range to normalize.
|
|
156
|
+
* @returns Normalized range with plain node references.
|
|
157
|
+
*/
|
|
158
|
+
normalizeRange<T extends object>(range: DllRange<T>): DllRange<T>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** A node that wraps an arbitrary value. */
|
|
162
|
+
export class ValueNode<V = unknown> extends Node {
|
|
163
|
+
/** The wrapped value. */
|
|
164
|
+
value: V;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param value - Value to wrap.
|
|
168
|
+
* @param options - Link property names.
|
|
169
|
+
*/
|
|
170
|
+
constructor(value: V, options?: DllOptions);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Base class for DLL pointers. */
|
|
174
|
+
export class PtrBase<T extends object = object> {
|
|
175
|
+
/** The list this pointer belongs to. */
|
|
176
|
+
list: HeadNode | ExtListBase<T>;
|
|
177
|
+
/** The node this pointer references. */
|
|
178
|
+
node: T;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @param list - Owning list, or another pointer to copy.
|
|
182
|
+
* @param node - Target node or pointer.
|
|
183
|
+
* @param ListClass - Expected list constructor for validation.
|
|
184
|
+
*/
|
|
185
|
+
constructor(list: HeadNode | ExtListBase<T> | PtrBase<T>, node?: T | PtrBase<T>, ListClass?: Function);
|
|
186
|
+
|
|
187
|
+
/** The node after the current node. */
|
|
188
|
+
get nextNode(): T;
|
|
189
|
+
|
|
190
|
+
/** The node before the current node. */
|
|
191
|
+
get prevNode(): T;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Whether the previous node is valid for iteration.
|
|
195
|
+
* @returns Always `true` for DLL pointers.
|
|
196
|
+
*/
|
|
197
|
+
isPrevNodeValid(): boolean;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Advance the pointer to the next node.
|
|
201
|
+
* @returns `this` for chaining.
|
|
202
|
+
*/
|
|
203
|
+
next(): this;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Move the pointer to the previous node.
|
|
207
|
+
* @returns `this` for chaining.
|
|
208
|
+
*/
|
|
209
|
+
prev(): this;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Base class for external (headless) DLL wrappers. */
|
|
213
|
+
export class ExtListBase<T extends object = object> {
|
|
214
|
+
/** Name of the "next" link property. */
|
|
215
|
+
readonly nextName: string;
|
|
216
|
+
/** Name of the "prev" link property. */
|
|
217
|
+
readonly prevName: string;
|
|
218
|
+
/** Current head node, or `null` if empty. */
|
|
219
|
+
head: T | null;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param head - Initial head node, pointer, or another ExtListBase to copy.
|
|
223
|
+
* @param options - Link property names.
|
|
224
|
+
*/
|
|
225
|
+
constructor(head?: T | PtrBase<T> | ExtListBase<T> | null, options?: DllOptions);
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Test whether another list is compatible.
|
|
229
|
+
* @param list - List to compare.
|
|
230
|
+
* @returns `true` if compatible.
|
|
231
|
+
*/
|
|
232
|
+
isCompatible(list: HeadNode | ExtListBase): boolean;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Test whether a pointer belongs to a compatible list.
|
|
236
|
+
* @param ptr - Pointer to test.
|
|
237
|
+
* @returns `true` if compatible.
|
|
238
|
+
*/
|
|
239
|
+
isCompatiblePtr(ptr: PtrBase): boolean;
|
|
240
|
+
|
|
241
|
+
// Copied from HeadNode via copyDescriptors:
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Test whether a value looks like a compatible node.
|
|
245
|
+
* @param node - Object to test.
|
|
246
|
+
* @returns `true` if the object has valid next and prev links.
|
|
247
|
+
*/
|
|
248
|
+
isNodeLike(node: object | null | undefined): boolean;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Test whether an options object shares the same link names.
|
|
252
|
+
* @param options - Options to compare.
|
|
253
|
+
* @returns `true` if names match.
|
|
254
|
+
*/
|
|
255
|
+
isCompatibleNames(options: DllOptions): boolean;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Test whether a range is compatible with this list.
|
|
259
|
+
* @param range - Range to test.
|
|
260
|
+
* @returns `true` if compatible.
|
|
261
|
+
*/
|
|
262
|
+
isCompatibleRange(range: DllRange<T> | null): boolean;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Normalize a node or pointer to a plain node.
|
|
266
|
+
* @param nodeOrPtr - Node or pointer.
|
|
267
|
+
* @returns The underlying node, or `null`.
|
|
268
|
+
*/
|
|
269
|
+
normalizeNode(nodeOrPtr: T | PtrBase<T> | null): T | null;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Normalize a range, resolving any pointers to nodes.
|
|
273
|
+
* @param range - Range to normalize.
|
|
274
|
+
* @returns Normalized range with plain node references.
|
|
275
|
+
*/
|
|
276
|
+
normalizeRange(range: DllRange<T>): DllRange<T>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Adopt a node or pointer into this list.
|
|
280
|
+
* @param nodeOrPtr - Node or pointer to adopt.
|
|
281
|
+
* @returns The adopted node.
|
|
282
|
+
*/
|
|
283
|
+
adoptNode(nodeOrPtr: T | PtrBase<T>): T;
|
|
284
|
+
|
|
285
|
+
/** Alias for {@link adoptNode}. */
|
|
286
|
+
adoptValue(nodeOrPtr: T | PtrBase<T>): T;
|
|
287
|
+
|
|
288
|
+
/** Whether the list is empty. */
|
|
289
|
+
get isEmpty(): boolean;
|
|
290
|
+
|
|
291
|
+
/** Whether the list contains exactly one node. */
|
|
292
|
+
get isOne(): boolean;
|
|
293
|
+
|
|
294
|
+
/** Whether the list contains zero or one nodes. */
|
|
295
|
+
get isOneOrEmpty(): boolean;
|
|
296
|
+
|
|
297
|
+
/** The head node, or `undefined` if empty. */
|
|
298
|
+
get front(): T | undefined;
|
|
299
|
+
|
|
300
|
+
/** The node before the head, or `undefined` if empty. */
|
|
301
|
+
get back(): T | undefined;
|
|
302
|
+
|
|
303
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
304
|
+
get range(): DllRange<T> | null;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Count the number of nodes.
|
|
308
|
+
* @returns Node count.
|
|
309
|
+
*/
|
|
310
|
+
getLength(): number;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Set a new head node.
|
|
314
|
+
* @param head - New head node or pointer, or `null` to detach.
|
|
315
|
+
* @returns The previous head node, or `null`.
|
|
316
|
+
*/
|
|
317
|
+
attach(head?: T | PtrBase<T> | null): T | null;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Detach the head, leaving the list empty.
|
|
321
|
+
* @returns The previous head node, or `null`.
|
|
322
|
+
*/
|
|
323
|
+
detach(): T | null;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Advance the head to the next node.
|
|
327
|
+
* @returns `this` for chaining.
|
|
328
|
+
*/
|
|
329
|
+
next(): this;
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Move the head to the previous node.
|
|
333
|
+
* @returns `this` for chaining.
|
|
334
|
+
*/
|
|
335
|
+
prev(): this;
|
|
336
|
+
}
|
package/src/list/nodes.js
CHANGED
|
@@ -1,24 +1,49 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
import {isRangeLike, normalizeNode, normalizeRange} from '../list-helpers.js';
|
|
4
2
|
import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Check whether a node has valid next and prev links.
|
|
6
|
+
* @param {object} options - Link property names.
|
|
7
|
+
* @param {object} node - Node to check.
|
|
8
|
+
* @returns {boolean} `true` if the node has truthy next and prev links.
|
|
9
|
+
*/
|
|
6
10
|
export const isNodeLike = ({nextName, prevName}, node) => node && node[prevName] && node[nextName];
|
|
11
|
+
/**
|
|
12
|
+
* Check whether a node points to itself (stand-alone).
|
|
13
|
+
* @param {object} options - Link property names.
|
|
14
|
+
* @param {object} node - Node to check.
|
|
15
|
+
* @returns {boolean} `true` if the node's next and prev links point to itself.
|
|
16
|
+
*/
|
|
7
17
|
export const isStandAlone = ({nextName, prevName}, node) => node && node[prevName] === node && node[nextName] === node;
|
|
18
|
+
/**
|
|
19
|
+
* Check whether two option sets share the same link property names.
|
|
20
|
+
* @param {object} options1 - First options.
|
|
21
|
+
* @param {object} options2 - Second options.
|
|
22
|
+
* @returns {boolean} `true` if `nextName` and `prevName` match.
|
|
23
|
+
*/
|
|
8
24
|
export const isCompatible = (options1, options2) => options1.nextName === options2.nextName && options1.prevName === options2.prevName;
|
|
9
25
|
|
|
26
|
+
/** Doubly linked list node with circular self-links. */
|
|
10
27
|
export class Node {
|
|
28
|
+
/** @param {object} [options] - Link property names. */
|
|
11
29
|
constructor({nextName = 'next', prevName = 'prev'} = {}) {
|
|
12
30
|
this.nextName = nextName;
|
|
13
31
|
this.prevName = prevName;
|
|
14
32
|
this[nextName] = this[prevName] = this;
|
|
15
33
|
}
|
|
34
|
+
/** Whether this node's next link points to itself. */
|
|
16
35
|
get isStandAlone() {
|
|
17
36
|
return this[this.nextName] === this;
|
|
18
37
|
}
|
|
19
38
|
}
|
|
20
39
|
|
|
40
|
+
/** Sentinel head node for hosted doubly linked lists. */
|
|
21
41
|
export class HeadNode extends Node {
|
|
42
|
+
/**
|
|
43
|
+
* Check whether a value looks like a compatible node.
|
|
44
|
+
* @param {*} node - Value to check.
|
|
45
|
+
* @returns {boolean} `true` if the value has valid next and prev links.
|
|
46
|
+
*/
|
|
22
47
|
isNodeLike(node) {
|
|
23
48
|
if (!node) return false;
|
|
24
49
|
const next = node[this.nextName];
|
|
@@ -27,14 +52,29 @@ export class HeadNode extends Node {
|
|
|
27
52
|
return prev && canHaveProps[typeof prev] === 1;
|
|
28
53
|
}
|
|
29
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Check whether another options object shares the same link names.
|
|
57
|
+
* @param {object} options - Options to compare.
|
|
58
|
+
* @returns {boolean} `true` if `nextName` and `prevName` match.
|
|
59
|
+
*/
|
|
30
60
|
isCompatibleNames({nextName, prevName}) {
|
|
31
61
|
return this.nextName === nextName && this.prevName === prevName;
|
|
32
62
|
}
|
|
33
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Check whether another list is compatible with this one.
|
|
66
|
+
* @param {object} list - List to compare.
|
|
67
|
+
* @returns {boolean} `true` if compatible.
|
|
68
|
+
*/
|
|
34
69
|
isCompatible(list) {
|
|
35
70
|
return list === this || (list instanceof HeadNode && this.nextName === list.nextName && this.prevName === list.prevName);
|
|
36
71
|
}
|
|
37
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Check whether a pointer belongs to a compatible list.
|
|
75
|
+
* @param {PtrBase} ptr - Pointer to check.
|
|
76
|
+
* @returns {boolean} `true` if compatible.
|
|
77
|
+
*/
|
|
38
78
|
isCompatiblePtr(ptr) {
|
|
39
79
|
return (
|
|
40
80
|
ptr instanceof PtrBase &&
|
|
@@ -42,38 +82,54 @@ export class HeadNode extends Node {
|
|
|
42
82
|
);
|
|
43
83
|
}
|
|
44
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Check whether a range is compatible with this list.
|
|
87
|
+
* @param {object} [range] - Range to validate.
|
|
88
|
+
* @returns {boolean} `true` if compatible.
|
|
89
|
+
*/
|
|
45
90
|
isCompatibleRange(range) {
|
|
46
|
-
return isRangeLike(this, range);
|
|
91
|
+
return isRangeLike(this, range, PtrBase);
|
|
47
92
|
}
|
|
48
93
|
|
|
94
|
+
/** Whether the list has no nodes. */
|
|
49
95
|
get isEmpty() {
|
|
50
96
|
return this[this.nextName] === this;
|
|
51
97
|
}
|
|
52
98
|
|
|
99
|
+
/** Whether the list has exactly one node. */
|
|
53
100
|
get isOne() {
|
|
54
101
|
return this[this.nextName] !== this && this[this.nextName][this.nextName] === this;
|
|
55
102
|
}
|
|
56
103
|
|
|
104
|
+
/** Whether the list has zero or one node. */
|
|
57
105
|
get isOneOrEmpty() {
|
|
58
106
|
return this[this.nextName][this.nextName] === this;
|
|
59
107
|
}
|
|
60
108
|
|
|
109
|
+
/** The head sentinel itself. */
|
|
61
110
|
get head() {
|
|
62
111
|
return this;
|
|
63
112
|
}
|
|
64
113
|
|
|
114
|
+
/** The first node after the head. */
|
|
65
115
|
get front() {
|
|
66
116
|
return this[this.nextName];
|
|
67
117
|
}
|
|
68
118
|
|
|
119
|
+
/** The last node before the head. */
|
|
69
120
|
get back() {
|
|
70
121
|
return this[this.prevName];
|
|
71
122
|
}
|
|
72
123
|
|
|
124
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
73
125
|
get range() {
|
|
74
126
|
return this[this.nextName] === this ? null : {from: this[this.nextName], to: this[this.prevName], list: this};
|
|
75
127
|
}
|
|
76
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Count the number of nodes.
|
|
131
|
+
* @returns {number} The node count.
|
|
132
|
+
*/
|
|
77
133
|
getLength() {
|
|
78
134
|
let n = 0;
|
|
79
135
|
const nextName = this.nextName;
|
|
@@ -81,6 +137,11 @@ export class HeadNode extends Node {
|
|
|
81
137
|
return n;
|
|
82
138
|
}
|
|
83
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Adopt a node or pointer, making it stand-alone if needed.
|
|
142
|
+
* @param {object} nodeOrPtr - Node or pointer to adopt.
|
|
143
|
+
* @returns {object} The adopted node.
|
|
144
|
+
*/
|
|
84
145
|
adoptNode(nodeOrPtr) {
|
|
85
146
|
const node = nodeOrPtr instanceof PtrBase ? nodeOrPtr.node : nodeOrPtr;
|
|
86
147
|
if (node[this.nextName] || node[this.prevName]) {
|
|
@@ -92,12 +153,22 @@ export class HeadNode extends Node {
|
|
|
92
153
|
return node;
|
|
93
154
|
}
|
|
94
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Normalize a node or pointer to a plain node.
|
|
158
|
+
* @param {object|null} nodeOrPtr - Node or pointer.
|
|
159
|
+
* @returns {object|null} The underlying node, or `null`.
|
|
160
|
+
*/
|
|
95
161
|
normalizeNode(nodeOrPtr) {
|
|
96
162
|
const node = normalizeNode(this, nodeOrPtr, PtrBase);
|
|
97
163
|
if (nodeOrPtr instanceof PtrBase) nodeOrPtr.list = this;
|
|
98
164
|
return node;
|
|
99
165
|
}
|
|
100
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Normalize a range, resolving any pointers to nodes.
|
|
169
|
+
* @param {object} [range] - Range to normalize.
|
|
170
|
+
* @returns {object|null} The normalized range, or `null`.
|
|
171
|
+
*/
|
|
101
172
|
normalizeRange(range) {
|
|
102
173
|
return normalizeRange(this, range, PtrBase);
|
|
103
174
|
}
|
|
@@ -105,14 +176,25 @@ export class HeadNode extends Node {
|
|
|
105
176
|
|
|
106
177
|
addAlias(HeadNode.prototype, 'adoptNode', 'adoptValue');
|
|
107
178
|
|
|
179
|
+
/** Value wrapper node for doubly linked lists. */
|
|
108
180
|
export class ValueNode extends Node {
|
|
181
|
+
/**
|
|
182
|
+
* @param {*} value - Value to wrap.
|
|
183
|
+
* @param {object} [options] - Link property names.
|
|
184
|
+
*/
|
|
109
185
|
constructor(value, options) {
|
|
110
186
|
super(options);
|
|
111
187
|
this.value = value;
|
|
112
188
|
}
|
|
113
189
|
}
|
|
114
190
|
|
|
191
|
+
/** Base class for DLL pointers providing navigation. */
|
|
115
192
|
export class PtrBase {
|
|
193
|
+
/**
|
|
194
|
+
* @param {PtrBase|HeadNode|ExtListBase} list - Owning list or another PtrBase to copy.
|
|
195
|
+
* @param {object} [node] - Target node.
|
|
196
|
+
* @param {Function} [ListClass] - Expected list constructor for validation.
|
|
197
|
+
*/
|
|
116
198
|
constructor(list, node, ListClass) {
|
|
117
199
|
if (list instanceof PtrBase) {
|
|
118
200
|
this.list = list.list;
|
|
@@ -132,30 +214,49 @@ export class PtrBase {
|
|
|
132
214
|
if (!this.node) this.node = this.list.front;
|
|
133
215
|
}
|
|
134
216
|
|
|
217
|
+
/** The node after the current node. */
|
|
135
218
|
get nextNode() {
|
|
136
219
|
return this.node[this.list.nextName];
|
|
137
220
|
}
|
|
138
221
|
|
|
222
|
+
/** The node before the current node. */
|
|
139
223
|
get prevNode() {
|
|
140
224
|
return this.node[this.list.prevName];
|
|
141
225
|
}
|
|
142
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Check whether the prevNode link is valid. Always `true` for DLL pointers.
|
|
229
|
+
* @returns {boolean} `true`.
|
|
230
|
+
*/
|
|
143
231
|
isPrevNodeValid() {
|
|
144
232
|
return true;
|
|
145
233
|
}
|
|
146
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Advance to the next node.
|
|
237
|
+
* @returns {PtrBase} `this` for chaining.
|
|
238
|
+
*/
|
|
147
239
|
next() {
|
|
148
240
|
this.node = this.node[this.list.nextName];
|
|
149
241
|
return this;
|
|
150
242
|
}
|
|
151
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Move to the previous node.
|
|
246
|
+
* @returns {PtrBase} `this` for chaining.
|
|
247
|
+
*/
|
|
152
248
|
prev() {
|
|
153
249
|
this.node = this.node[this.list.prevName];
|
|
154
250
|
return this;
|
|
155
251
|
}
|
|
156
252
|
}
|
|
157
253
|
|
|
254
|
+
/** Base class for external (headless) doubly linked lists. */
|
|
158
255
|
export class ExtListBase {
|
|
256
|
+
/**
|
|
257
|
+
* @param {object|ExtListBase|PtrBase|null} [head=null] - Initial head node, ExtListBase, or PtrBase.
|
|
258
|
+
* @param {object} [options] - Link property names.
|
|
259
|
+
*/
|
|
159
260
|
constructor(head = null, {nextName = 'next', prevName = 'prev'} = {}) {
|
|
160
261
|
if (head instanceof ExtListBase) {
|
|
161
262
|
this.nextName = head.nextName;
|
|
@@ -174,10 +275,20 @@ export class ExtListBase {
|
|
|
174
275
|
this.attach(head);
|
|
175
276
|
}
|
|
176
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Check whether another list is compatible.
|
|
280
|
+
* @param {object} list - List to compare.
|
|
281
|
+
* @returns {boolean} `true` if compatible.
|
|
282
|
+
*/
|
|
177
283
|
isCompatible(list) {
|
|
178
284
|
return list === this || (list instanceof ExtListBase && this.nextName === list.nextName && this.prevName === list.prevName);
|
|
179
285
|
}
|
|
180
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Check whether a pointer belongs to a compatible list.
|
|
289
|
+
* @param {PtrBase} ptr - Pointer to check.
|
|
290
|
+
* @returns {boolean} `true` if compatible.
|
|
291
|
+
*/
|
|
181
292
|
isCompatiblePtr(ptr) {
|
|
182
293
|
return (
|
|
183
294
|
ptr instanceof PtrBase &&
|
|
@@ -185,30 +296,40 @@ export class ExtListBase {
|
|
|
185
296
|
);
|
|
186
297
|
}
|
|
187
298
|
|
|
299
|
+
/** Whether the list has no nodes. */
|
|
188
300
|
get isEmpty() {
|
|
189
301
|
return !this.head;
|
|
190
302
|
}
|
|
191
303
|
|
|
304
|
+
/** Whether the list has exactly one node. */
|
|
192
305
|
get isOne() {
|
|
193
306
|
return this.head && this.head[this.nextName] === this.head;
|
|
194
307
|
}
|
|
195
308
|
|
|
309
|
+
/** Whether the list has zero or one node. */
|
|
196
310
|
get isOneOrEmpty() {
|
|
197
311
|
return !this.head || this.head[this.nextName] === this.head;
|
|
198
312
|
}
|
|
199
313
|
|
|
314
|
+
/** The head node, or `null` if empty. */
|
|
200
315
|
get front() {
|
|
201
316
|
return this.head;
|
|
202
317
|
}
|
|
203
318
|
|
|
319
|
+
/** The last node, or `undefined` if empty. */
|
|
204
320
|
get back() {
|
|
205
321
|
return this.head?.[this.prevName];
|
|
206
322
|
}
|
|
207
323
|
|
|
324
|
+
/** A range spanning all nodes, or `null` if empty. */
|
|
208
325
|
get range() {
|
|
209
326
|
return this.head ? {from: this.head, to: this.head[this.prevName], list: this.head} : null;
|
|
210
327
|
}
|
|
211
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Count the number of nodes.
|
|
331
|
+
* @returns {number} The node count.
|
|
332
|
+
*/
|
|
212
333
|
getLength() {
|
|
213
334
|
if (!this.head) return 0;
|
|
214
335
|
|
|
@@ -222,6 +343,11 @@ export class ExtListBase {
|
|
|
222
343
|
return n;
|
|
223
344
|
}
|
|
224
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Set a new head node.
|
|
348
|
+
* @param {object|PtrBase|null} [head=null] - New head node, pointer, or `null`.
|
|
349
|
+
* @returns {object|null} The previous head node.
|
|
350
|
+
*/
|
|
225
351
|
attach(head = null) {
|
|
226
352
|
const oldHead = this.head;
|
|
227
353
|
if (head instanceof PtrBase) {
|
|
@@ -234,17 +360,29 @@ export class ExtListBase {
|
|
|
234
360
|
return oldHead;
|
|
235
361
|
}
|
|
236
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Remove the head reference without modifying nodes.
|
|
365
|
+
* @returns {object|null} The previous head node.
|
|
366
|
+
*/
|
|
237
367
|
detach() {
|
|
238
368
|
const oldHead = this.head;
|
|
239
369
|
this.head = null;
|
|
240
370
|
return oldHead;
|
|
241
371
|
}
|
|
242
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Advance the head to the next node.
|
|
375
|
+
* @returns {ExtListBase} `this` for chaining.
|
|
376
|
+
*/
|
|
243
377
|
next() {
|
|
244
378
|
if (this.head) this.head = this.head[this.nextName];
|
|
245
379
|
return this;
|
|
246
380
|
}
|
|
247
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Move the head to the previous node.
|
|
384
|
+
* @returns {ExtListBase} `this` for chaining.
|
|
385
|
+
*/
|
|
248
386
|
prev() {
|
|
249
387
|
if (this.head) this.head = this.head[this.prevName];
|
|
250
388
|
return this;
|