list-toolkit 1.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +89 -419
  2. package/cjs/cache/cache-fifo.js +37 -0
  3. package/cjs/cache/cache-lfu.js +76 -0
  4. package/cjs/cache/cache-lru.js +100 -0
  5. package/cjs/cache/cache-random.js +77 -0
  6. package/cjs/cache/decorator.js +47 -0
  7. package/cjs/cache.js +28 -0
  8. package/cjs/ext-list.js +22 -0
  9. package/cjs/ext-slist.js +22 -0
  10. package/cjs/ext-value-list.js +22 -0
  11. package/cjs/ext-value-slist.js +22 -0
  12. package/cjs/{MinHeap.js → heap/min-heap.js} +68 -82
  13. package/cjs/heap.js +22 -0
  14. package/cjs/list/basics.js +88 -0
  15. package/cjs/list/core.js +305 -0
  16. package/cjs/list/ext-value.js +89 -0
  17. package/cjs/list/ext.js +356 -0
  18. package/cjs/list/nodes.js +240 -0
  19. package/cjs/list/ptr.js +61 -0
  20. package/cjs/list/value.js +100 -0
  21. package/cjs/list-helpers.js +91 -0
  22. package/cjs/list-utils.js +141 -0
  23. package/cjs/list.js +22 -0
  24. package/cjs/meta-utils.js +167 -0
  25. package/cjs/nt-utils.js +132 -0
  26. package/cjs/queue.js +58 -0
  27. package/cjs/slist/basics.js +71 -0
  28. package/cjs/slist/core.js +362 -0
  29. package/cjs/slist/ext-value.js +83 -0
  30. package/cjs/slist/ext.js +336 -0
  31. package/cjs/slist/nodes.js +276 -0
  32. package/cjs/slist/ptr.js +87 -0
  33. package/cjs/slist/value.js +91 -0
  34. package/cjs/slist.js +22 -0
  35. package/cjs/stack.js +55 -0
  36. package/cjs/tree/splay-tree.js +362 -0
  37. package/cjs/value-list.js +22 -0
  38. package/cjs/value-slist.js +22 -0
  39. package/package.json +7 -7
  40. package/src/cache/cache-fifo.js +27 -0
  41. package/src/cache/cache-lfu.js +63 -0
  42. package/src/cache/cache-lru.js +87 -0
  43. package/src/cache/cache-random.js +73 -0
  44. package/src/cache/decorator.js +45 -0
  45. package/src/cache.js +9 -0
  46. package/src/ext-list.js +6 -0
  47. package/src/ext-slist.js +6 -0
  48. package/src/ext-value-list.js +6 -0
  49. package/src/ext-value-slist.js +6 -0
  50. package/src/{MinHeap.js → heap/min-heap.js} +73 -85
  51. package/src/heap.js +6 -0
  52. package/src/list/basics.js +64 -0
  53. package/src/list/core.js +314 -0
  54. package/src/list/ext-value.js +81 -0
  55. package/src/list/ext.js +370 -0
  56. package/src/list/nodes.js +262 -0
  57. package/src/list/ptr.js +58 -0
  58. package/src/list/value.js +88 -0
  59. package/src/list-helpers.js +80 -0
  60. package/src/list-utils.js +140 -0
  61. package/src/list.js +6 -0
  62. package/src/meta-utils.js +147 -0
  63. package/src/nt-utils.js +85 -0
  64. package/src/queue.js +52 -0
  65. package/src/slist/basics.js +47 -0
  66. package/src/slist/core.js +364 -0
  67. package/src/slist/ext-value.js +74 -0
  68. package/src/slist/ext.js +331 -0
  69. package/src/slist/nodes.js +290 -0
  70. package/src/slist/ptr.js +77 -0
  71. package/src/slist/value.js +75 -0
  72. package/src/slist.js +6 -0
  73. package/src/stack.js +52 -0
  74. package/src/tree/splay-tree.js +378 -0
  75. package/src/value-list.js +6 -0
  76. package/src/value-slist.js +6 -0
  77. package/cjs/Cache.js +0 -71
  78. package/cjs/List.js +0 -294
  79. package/cjs/ListHead.js +0 -309
  80. package/cjs/SList.js +0 -342
  81. package/cjs/SListHead.js +0 -367
  82. package/cjs/utils.js +0 -43
  83. package/src/Cache.js +0 -61
  84. package/src/List.js +0 -303
  85. package/src/ListHead.js +0 -304
  86. package/src/SList.js +0 -330
  87. package/src/SListHead.js +0 -354
  88. package/src/utils.js +0 -35
@@ -0,0 +1,370 @@
1
+ 'use strict';
2
+
3
+ import {ExtListBase, PtrBase} from './nodes.js';
4
+ import {pop, extract, splice, append} from './basics.js';
5
+ import {addAliases, normalizeIterator} from '../meta-utils.js';
6
+
7
+ export class Ptr extends PtrBase {
8
+ constructor(list, node) {
9
+ super(list, node, ExtList);
10
+ this.node ||= this.list.head;
11
+ }
12
+ clone() {
13
+ return new Ptr(this);
14
+ }
15
+ }
16
+
17
+ export class ExtList extends ExtListBase {
18
+ makePtr(node) {
19
+ if (node && !this.isNodeLike(node)) throw new Error('"node" is not a compatible node');
20
+ node ||= this.head;
21
+ return node ? new Ptr(this, node) : null;
22
+ }
23
+
24
+ makePtrFromPrev(prev) {
25
+ if (prev && !this.isNodeLike(prev)) throw new Error('"prev" is not a compatible node');
26
+ return new Ptr(this, prev ? prev[this.nextName] : this.front);
27
+ }
28
+
29
+ // Ptr API
30
+
31
+ removeCurrent() {
32
+ if (!this.head) return null;
33
+ if (this.head[this.nextName] === this.head) {
34
+ const node = this.head;
35
+ this.head = null;
36
+ return node;
37
+ }
38
+ const result = pop(this, this.head);
39
+ this.head = result.rest;
40
+ return result.extracted;
41
+ }
42
+
43
+ removeNodeBefore() {
44
+ return this.head ? this.removeNode(this.head[this.prevName]) : null;
45
+ }
46
+
47
+ removeNodeAfter() {
48
+ return this.head ? this.removeNode(this.head[this.nextName]) : null;
49
+ }
50
+
51
+ addBefore(value) {
52
+ const node = this.adoptValue(value);
53
+ if (this.head) {
54
+ splice(this, this.head[this.prevName], node);
55
+ } else {
56
+ this.head = node;
57
+ }
58
+ return this.makePtr(node);
59
+ }
60
+
61
+ addAfter(value) {
62
+ const node = this.adoptValue(value);
63
+ if (this.head) {
64
+ splice(this, this.head, node);
65
+ } else {
66
+ this.head = node;
67
+ }
68
+ return this.makePtr(node);
69
+ }
70
+
71
+ addNodeBefore(nodeOrPtr) {
72
+ const node = this.adoptNode(nodeOrPtr);
73
+ if (this.head) {
74
+ splice(this, this.head[this.prevName], node);
75
+ } else {
76
+ this.head = node;
77
+ }
78
+ return this.makePtr(node);
79
+ }
80
+
81
+ addNodeAfter(nodeOrPtr) {
82
+ const node = this.adoptNode(nodeOrPtr);
83
+ if (this.head) {
84
+ splice(this, this.head, node);
85
+ } else {
86
+ this.head = node;
87
+ }
88
+ return this.makePtr(node);
89
+ }
90
+
91
+ insertBefore(extList) {
92
+ if (!this.isCompatible(extList)) throw new Error('Incompatible lists');
93
+
94
+ const head = extList.head;
95
+ if (head) {
96
+ splice(this, this.head[this.prevName], head);
97
+ extList.head = null;
98
+ }
99
+
100
+ return this.makePtr(head);
101
+ }
102
+
103
+ insertAfter(extList) {
104
+ if (!this.isCompatible(extList)) throw new Error('Incompatible lists');
105
+
106
+ const head = extList.head;
107
+ if (head) {
108
+ splice(this, this.head, head);
109
+ extList.head = null;
110
+ }
111
+
112
+ return this.makePtr(head);
113
+ }
114
+
115
+ moveBefore(nodeOrPtr) {
116
+ const node = this.normalizeNode(nodeOrPtr);
117
+
118
+ if (this.head === node) {
119
+ this.head = this.head[this.nextName];
120
+ return this;
121
+ }
122
+
123
+ if (this.head) {
124
+ append(this, this.head[this.prevName], {from: node});
125
+ } else {
126
+ pop(this, node);
127
+ this.head = node;
128
+ }
129
+
130
+ return this.makePtr(node);
131
+ }
132
+
133
+ moveAfter(nodeOrPtr) {
134
+ const node = this.normalizeNode(nodeOrPtr);
135
+
136
+ if (this.head === node) {
137
+ this.head = this.head[this.prevName];
138
+ return this;
139
+ }
140
+
141
+ if (this.head) {
142
+ append(this, this.head, {from: node});
143
+ } else {
144
+ pop(this, node);
145
+ this.head = node;
146
+ }
147
+
148
+ return this.makePtr(node);
149
+ }
150
+
151
+ // List API
152
+
153
+ clear(drop) {
154
+ if (drop) {
155
+ for (const current of this.getNodeIterator()) {
156
+ current[this.nextName] = current[this.prevName] = current; // make stand-alone
157
+ }
158
+ }
159
+ this.head = null;
160
+ return this;
161
+ }
162
+
163
+ removeNode(nodeOrPtr) {
164
+ if (!this.head) return null;
165
+
166
+ const node = this.normalizeNode(nodeOrPtr);
167
+
168
+ if (this.head === node) {
169
+ // remove head
170
+ if (this.head[this.nextName] === this.head) {
171
+ // single node
172
+ this.head = null;
173
+ return node;
174
+ }
175
+ this.head = this.head[this.nextName];
176
+ }
177
+
178
+ return pop(this, node).extracted;
179
+ }
180
+
181
+ removeRange(range, drop) {
182
+ return this.extractRange(range).clear(drop);
183
+ }
184
+
185
+ extractRange(range = {}) {
186
+ range = this.normalizeRange(range);
187
+ const {from = this.head, to = from} = range;
188
+
189
+ const extracted = this.make();
190
+ if (!this.head) return extracted;
191
+ if (this.head === from || this.head === to) this.head = to[this.nextName];
192
+ if (this.head === from) this.head = null;
193
+ extracted.head = extract(this, {from, to}).extracted;
194
+
195
+ return extracted;
196
+ }
197
+
198
+ extractBy(condition) {
199
+ const extracted = this.make();
200
+ if (this.isEmpty) return extracted;
201
+
202
+ const rest = this.make();
203
+ for (const current of this.getNodeIterator()) {
204
+ current[this.nextName] = current[this.prevName] = current; // make stand-alone
205
+ (condition(current) ? extracted : rest).addBefore(current);
206
+ }
207
+ this.head = rest.head;
208
+
209
+ return extracted;
210
+ }
211
+
212
+ reverse() {
213
+ if (this.isOneOrEmpty) return this;
214
+ let current = this.head;
215
+ do {
216
+ const next = current[this.nextName];
217
+ current[this.nextName] = current[this.prevName];
218
+ current[this.prevName] = next;
219
+ current = next;
220
+ } while (current !== this.head);
221
+ this.head = this.head[this.nextName];
222
+ return this;
223
+ }
224
+
225
+ sort(lessFn) {
226
+ if (this.isOneOrEmpty) return this;
227
+
228
+ const left = this.make(),
229
+ right = this.make();
230
+
231
+ // split into two sublists
232
+ let isLeft = true;
233
+ for (const current of this.getNodeIterator()) {
234
+ current[this.nextName] = current[this.prevName] = current; // make stand-alone
235
+ if (isLeft) {
236
+ left.addNodeAfter(current);
237
+ left.next();
238
+ } else {
239
+ right.addNodeAfter(current);
240
+ right.next();
241
+ }
242
+ isLeft = !isLeft;
243
+ }
244
+ this.clear();
245
+ // the list is empty now
246
+
247
+ // sort sublists
248
+ left.next().sort(lessFn);
249
+ right.next().sort(lessFn);
250
+
251
+ // merge sublists
252
+ while (!left.isEmpty && !right.isEmpty) {
253
+ this.addNodeAfter((lessFn(left.head, right.head) ? left : right).removeCurrent());
254
+ this.next();
255
+ }
256
+ if (!left.isEmpty) {
257
+ const last = left.head[left.prevName];
258
+ this.insertAfter(left);
259
+ this.head = last;
260
+ }
261
+ if (!right.isEmpty) {
262
+ const last = right.head[right.prevName];
263
+ this.insertAfter(right);
264
+ this.head = last;
265
+ }
266
+
267
+ return this.next();
268
+ }
269
+
270
+ // iterators
271
+
272
+ [Symbol.iterator]() {
273
+ let current = this.head,
274
+ readyToStop = this.isEmpty;
275
+ return normalizeIterator({
276
+ next: () => {
277
+ if (readyToStop && current === this.head) return {done: true};
278
+ readyToStop = true;
279
+ const value = current;
280
+ current = current[this.nextName];
281
+ return {value};
282
+ }
283
+ });
284
+ }
285
+
286
+ getNodeIterator(range = {}) {
287
+ range = this.normalizeRange(range);
288
+ const {from, to} = range;
289
+ return {
290
+ [Symbol.iterator]: () => {
291
+ let readyToStop = this.isEmpty,
292
+ current = readyToStop ? null : from || this.head;
293
+ const stop = readyToStop ? null : to ? to[this.nextName] : this.head;
294
+ return normalizeIterator({
295
+ next: () => {
296
+ if (readyToStop && current === stop) return {done: true};
297
+ readyToStop = true;
298
+ const value = current;
299
+ current = current[this.nextName];
300
+ return {value};
301
+ }
302
+ });
303
+ }
304
+ };
305
+ }
306
+
307
+ getPtrIterator(range) {
308
+ return mapIterator(this.getNodeIterator(range), node => new Ptr(this, node));
309
+ }
310
+
311
+ getReverseNodeIterator(range = {}) {
312
+ range = this.normalizeRange(range);
313
+ const {from, to} = range;
314
+ return {
315
+ [Symbol.iterator]: () => {
316
+ let readyToStop = this.isEmpty,
317
+ current = readyToStop ? null : to || this.head[this.prevName];
318
+ const stop = readyToStop ? null : from ? from[this.prevName] : this.head[this.prevName];
319
+ return normalizeIterator({
320
+ next: () => {
321
+ if (readyToStop && current === stop) return {done: true};
322
+ readyToStop = true;
323
+ const value = current;
324
+ current = current[this.prevName];
325
+ return {value};
326
+ }
327
+ });
328
+ }
329
+ };
330
+ }
331
+
332
+ getReversePtrIterator(range) {
333
+ return mapIterator(this.getReverseNodeIterator(range), node => new Ptr(this, node));
334
+ }
335
+
336
+ // meta helpers
337
+
338
+ clone() {
339
+ return new ExtList(this);
340
+ }
341
+
342
+ make(head = null) {
343
+ return new ExtList(head, this);
344
+ }
345
+
346
+ makeFrom(values) {
347
+ return ExtList.from(values, this);
348
+ }
349
+
350
+ static from(values, options) {
351
+ const list = new ExtList(null, options);
352
+ for (const value of values) {
353
+ list.addNodeAfter(value);
354
+ list.next();
355
+ }
356
+ return list.next();
357
+ }
358
+ }
359
+
360
+ ExtList.Ptr = Ptr;
361
+
362
+ addAliases(ExtList.prototype, {
363
+ addAfter: 'add',
364
+ removeNodeBefore: 'removeBefore',
365
+ removeNodeAfter: 'removeAfter',
366
+ getNodeIterator: 'getIterator',
367
+ getReverseNodeIterator: 'getReverseIterator'
368
+ });
369
+
370
+ export default ExtList;
@@ -0,0 +1,262 @@
1
+ 'use strict';
2
+
3
+ import {isRangeLike, normalizeNode, normalizeRange} from '../list-helpers.js';
4
+ import {addAlias, copyDescriptors} from '../meta-utils.js';
5
+
6
+ export const isNodeLike = ({nextName, prevName}, node) => node && node[prevName] && node[nextName];
7
+ export const isStandAlone = ({nextName, prevName}, node) => node && node[prevName] === node && node[nextName] === node;
8
+ export const isCompatible = (options1, options2) => options1.nextName === options2.nextName && options1.prevName === options2.prevName;
9
+
10
+ export class Node {
11
+ constructor({nextName = 'next', prevName = 'prev'} = {}) {
12
+ this.nextName = nextName;
13
+ this.prevName = prevName;
14
+ this[nextName] = this[prevName] = this;
15
+ }
16
+ get isStandAlone() {
17
+ return this[this.nextName] === this;
18
+ }
19
+ }
20
+
21
+ export class HeadNode extends Node {
22
+ isNodeLike(node) {
23
+ if (!node) return false;
24
+ const next = node[this.nextName];
25
+ if (!next || typeof next != 'object') return false;
26
+ const prev = node[this.prevName];
27
+ return prev && typeof prev == 'object';
28
+ }
29
+
30
+ isCompatibleNames({nextName, prevName}) {
31
+ return this.nextName === nextName && this.prevName === prevName;
32
+ }
33
+
34
+ isCompatible(list) {
35
+ return list === this || (list instanceof HeadNode && this.nextName === list.nextName && this.prevName === list.prevName);
36
+ }
37
+
38
+ isCompatiblePtr(ptr) {
39
+ return (
40
+ ptr instanceof PtrBase &&
41
+ (ptr.list === this || (ptr.list instanceof HeadNode && this.nextName === ptr.list.nextName && this.prevName === ptr.list.prevName))
42
+ );
43
+ }
44
+
45
+ isCompatibleRange(range) {
46
+ return isRangeLike(this, range);
47
+ }
48
+
49
+ get isEmpty() {
50
+ return this[this.nextName] === this;
51
+ }
52
+
53
+ get isOne() {
54
+ return this[this.nextName] !== this && this[this.nextName][this.nextName] === this;
55
+ }
56
+
57
+ get isOneOrEmpty() {
58
+ return this[this.nextName][this.nextName] === this;
59
+ }
60
+
61
+ get head() {
62
+ return this;
63
+ }
64
+
65
+ get front() {
66
+ return this[this.nextName];
67
+ }
68
+
69
+ get back() {
70
+ return this[this.prevName];
71
+ }
72
+
73
+ get range() {
74
+ return this[this.nextName] === this ? null : {from: this[this.nextName], to: this[this.prevName], list: this};
75
+ }
76
+
77
+ getLength() {
78
+ let n = 0;
79
+ const nextName = this.nextName;
80
+ for (let p = this[nextName]; p !== this; ++n, p = p[nextName]);
81
+ return n;
82
+ }
83
+
84
+ adoptNode(nodeOrPtr) {
85
+ const node = nodeOrPtr instanceof PtrBase ? nodeOrPtr.node : nodeOrPtr;
86
+ if (node[this.nextName] || node[this.prevName]) {
87
+ if (node[this.nextName] === node && node[this.prevName] === node) return node;
88
+ throw new Error('node is already a part of a list, or there is a name clash');
89
+ }
90
+ node[this.nextName] = node[this.prevName] = node;
91
+ if (nodeOrPtr instanceof PtrBase) nodeOrPtr.list = this;
92
+ return node;
93
+ }
94
+
95
+ normalizeNode(nodeOrPtr) {
96
+ const node = normalizeNode(this, nodeOrPtr, PtrBase);
97
+ if (nodeOrPtr instanceof PtrBase) nodeOrPtr.list = this;
98
+ return node;
99
+ }
100
+
101
+ normalizeRange(range) {
102
+ return normalizeRange(this, range, PtrBase);
103
+ }
104
+ }
105
+
106
+ addAlias(HeadNode.prototype, 'adoptNode', 'adoptValue');
107
+
108
+ export class ValueNode extends Node {
109
+ constructor(value, options) {
110
+ super(options);
111
+ this.value = value;
112
+ }
113
+ }
114
+
115
+ export class PtrBase {
116
+ constructor(list, node, ListClass) {
117
+ if (list instanceof PtrBase) {
118
+ this.list = list.list;
119
+ this.node = list.node;
120
+ return;
121
+ }
122
+ if (!(list instanceof ListClass)) throw new Error('"list" is not a compatible list');
123
+ if (node instanceof PtrBase) {
124
+ if (list !== node.list) throw new Error('Node specified by a pointer must belong to the same list');
125
+ this.list = list;
126
+ this.node = node.node;
127
+ } else {
128
+ this.list = list;
129
+ this.node = node;
130
+ }
131
+ if (this.node && !isNodeLike(this.list, this.node)) throw new Error('"node" is not a compatible node');
132
+ if (!this.node) this.node = this.list.front;
133
+ }
134
+
135
+ get nextNode() {
136
+ return this.node[this.list.nextName];
137
+ }
138
+
139
+ get prevNode() {
140
+ return this.node[this.list.prevName];
141
+ }
142
+
143
+ isPrevNodeValid() {
144
+ return true;
145
+ }
146
+
147
+ next() {
148
+ this.node = this.node[this.list.nextName];
149
+ return this;
150
+ }
151
+
152
+ prev() {
153
+ this.node = this.node[this.list.prevName];
154
+ return this;
155
+ }
156
+ }
157
+
158
+ export class ExtListBase {
159
+ constructor(head = null, {nextName = 'next', prevName = 'prev'} = {}) {
160
+ if (head instanceof ExtListBase) {
161
+ this.nextName = head.nextName;
162
+ this.prevName = head.prevName;
163
+ this.attach(head.head);
164
+ return;
165
+ }
166
+ if (head instanceof PtrBase) {
167
+ this.nextName = head.list.nextName;
168
+ this.prevName = head.list.prevName;
169
+ this.attach(head.node);
170
+ return;
171
+ }
172
+ this.nextName = nextName;
173
+ this.prevName = prevName;
174
+ this.attach(head);
175
+ }
176
+
177
+ isCompatible(list) {
178
+ return list === this || (list instanceof ExtListBase && this.nextName === list.nextName && this.prevName === list.prevName);
179
+ }
180
+
181
+ isCompatiblePtr(ptr) {
182
+ return (
183
+ ptr instanceof PtrBase &&
184
+ (ptr.list === this || (ptr.list instanceof ExtListBase && this.nextName === ptr.list.nextName && this.prevName === ptr.list.prevName))
185
+ );
186
+ }
187
+
188
+ get isEmpty() {
189
+ return !this.head;
190
+ }
191
+
192
+ get isOne() {
193
+ return this.head && this.head[this.nextName] === this.head;
194
+ }
195
+
196
+ get isOneOrEmpty() {
197
+ return !this.head || this.head[this.nextName] === this.head;
198
+ }
199
+
200
+ get front() {
201
+ return this.head;
202
+ }
203
+
204
+ get back() {
205
+ return this.head?.[this.prevName];
206
+ }
207
+
208
+ get range() {
209
+ return this.head ? {from: this.head, to: this.head[this.prevName], list: this.head} : null;
210
+ }
211
+
212
+ getLength() {
213
+ if (!this.head) return 0;
214
+
215
+ let n = 0,
216
+ current = this.head;
217
+ do {
218
+ current = current[this.nextName];
219
+ ++n;
220
+ } while (current !== this.head);
221
+
222
+ return n;
223
+ }
224
+
225
+ attach(head = null) {
226
+ const oldHead = this.head;
227
+ if (head instanceof PtrBase) {
228
+ if (!this.isCompatible(head.list)) throw new Error('Incompatible lists');
229
+ this.head = head.node;
230
+ } else {
231
+ if (head && !this.isNodeLike(head)) throw new Error('"head" is not a compatible node');
232
+ this.head = head;
233
+ }
234
+ return oldHead;
235
+ }
236
+
237
+ detach() {
238
+ const oldHead = this.head;
239
+ this.head = null;
240
+ return oldHead;
241
+ }
242
+
243
+ next() {
244
+ if (this.head) this.head = this.head[this.nextName];
245
+ return this;
246
+ }
247
+
248
+ prev() {
249
+ if (this.head) this.head = this.head[this.prevName];
250
+ return this;
251
+ }
252
+ }
253
+
254
+ copyDescriptors(ExtListBase.prototype, HeadNode.prototype, [
255
+ 'isNodeLike',
256
+ 'isCompatibleNames',
257
+ 'isCompatibleRange',
258
+ 'normalizeNode',
259
+ 'normalizeRange',
260
+ 'adoptNode',
261
+ 'adoptValue'
262
+ ]);
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ import {HeadNode, PtrBase} from './nodes.js';
4
+ import {pop, splice} from './basics.js';
5
+
6
+ export class Ptr extends PtrBase {
7
+ constructor(list, node) {
8
+ super(list, node, HeadNode);
9
+ }
10
+ get isHead() {
11
+ return this.node === this.list;
12
+ }
13
+ clone() {
14
+ return new Ptr(this);
15
+ }
16
+ removeCurrent() {
17
+ if (this.node === this.list) return null;
18
+ const node = this.node;
19
+ this.node = node[this.list.nextName];
20
+ return pop(this.list, node).extracted;
21
+ }
22
+ addBefore(value) {
23
+ const node = this.list.adoptValue(value);
24
+ splice(this.list, this.node[this.list.prevName], node);
25
+ return this.list.makePtr(node);
26
+ }
27
+ addNodeBefore(node) {
28
+ node = this.list.adoptNode(node);
29
+ splice(this.list, this.node[this.list.prevName], node);
30
+ return this.list.makePtr(node);
31
+ }
32
+ addAfter(value) {
33
+ const node = this.list.adoptValue(value);
34
+ splice(this.list, this.node, node);
35
+ return this.list.makePtr(node);
36
+ }
37
+ addNodeAfter(node) {
38
+ node = this.list.adoptNode(node);
39
+ splice(this.list, this.node, node);
40
+ return this.list.makePtr(node);
41
+ }
42
+ insertBefore(list) {
43
+ if (!this.list.isCompatible(list)) throw new Error('Incompatible lists');
44
+ if (list.isEmpty) return null;
45
+ const head = pop(list, list).rest;
46
+ splice(this.list, this.node[this.list.prevName], head);
47
+ return this.list.makePtr(head);
48
+ }
49
+ insertAfter(list) {
50
+ if (!this.list.isCompatible(list)) throw new Error('Incompatible lists');
51
+ if (list.isEmpty) return null;
52
+ const head = pop(list, list).rest;
53
+ splice(this.list, this.node, head);
54
+ return this.list.makePtr(head);
55
+ }
56
+ }
57
+
58
+ export default Ptr;