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,364 @@
1
+ 'use strict';
2
+
3
+ import {addAliases, normalizeIterator} from '../meta-utils.js';
4
+ import {ExtListBase, HeadNode} from './nodes.js';
5
+ import {append} from './basics.js';
6
+ import Ptr from './ptr.js';
7
+
8
+ export class SList extends HeadNode {
9
+ get frontPtr() {
10
+ return new Ptr(this);
11
+ }
12
+
13
+ get ptrRange() {
14
+ return this.isEmpty ? null : {from: new Ptr(this), to: this.last};
15
+ }
16
+
17
+ makePtr(node) {
18
+ if (node && !this.isNodeLike(node)) throw new Error('"node" is not a compatible node');
19
+ return new Ptr(this, node);
20
+ }
21
+
22
+ makePtrFromPrev(prev) {
23
+ if (prev && !this.isNodeLike(prev)) throw new Error('"prev" is not a compatible node');
24
+ return new Ptr(this, null, prev || this);
25
+ }
26
+
27
+ popFrontNode() {
28
+ if (this[this.nextName] === this) return undefined;
29
+ const node = this[this.nextName];
30
+ this[this.nextName] = node[this.nextName];
31
+ if (this[this.nextName] === this) this.last = this;
32
+ return (node[this.nextName] = node);
33
+ }
34
+
35
+ pushFront(value) {
36
+ const node = this.adoptValue(value);
37
+ node[this.nextName] = this[this.nextName];
38
+ this[this.nextName] = node;
39
+ if (node[this.nextName] === this) this.last = node;
40
+ return this.makePtr();
41
+ }
42
+
43
+ pushBack(value) {
44
+ const node = this.adoptValue(value);
45
+ node[this.nextName] = this;
46
+ const last = this.last;
47
+ this.last = last[this.nextName] = node;
48
+ return this.makePtrFromPrev(last);
49
+ }
50
+
51
+ pushFrontNode(nodeOrPtr) {
52
+ const node = this.adoptNode(nodeOrPtr);
53
+ node[this.nextName] = this[this.nextName];
54
+ this[this.nextName] = node;
55
+ if (node[this.nextName] === this) this.last = node;
56
+ return this.makePtr();
57
+ }
58
+
59
+ pushBackNode(nodeOrPtr) {
60
+ const node = this.adoptNode(nodeOrPtr);
61
+ node[this.nextName] = this;
62
+ const last = this.last;
63
+ this.last = last[this.nextName] = node;
64
+ return this.makePtrFromPrev(last);
65
+ }
66
+
67
+ appendFront(list) {
68
+ if (!this.isCompatible(list)) throw new Error('Incompatible lists');
69
+ if (list.isEmpty) return this;
70
+
71
+ list.last[this.nextName] = this[this.nextName];
72
+ this[this.nextName] = list[this.nextName];
73
+ if (list.last[this.nextName] === this) this.last = list.last;
74
+
75
+ list[this.nextName] = list.last = list; // clear the list
76
+ return this.makePtr();
77
+ }
78
+
79
+ appendBack(list) {
80
+ if (!this.isCompatible(list)) throw new Error('Incompatible lists');
81
+ if (list.isEmpty) return this;
82
+
83
+ this.last[this.nextName] = list[this.nextName];
84
+ list.last[this.nextName] = this;
85
+
86
+ const last = this.last;
87
+ this.last = list.last;
88
+
89
+ list[this.nextName] = list.last = list; // clear the list
90
+ return this.makePtrFromPrev(last);
91
+ }
92
+
93
+ moveToFront(ptr) {
94
+ if (!this.isCompatiblePtr(ptr)) throw new Error('Incompatible pointer');
95
+ ptr.list = this;
96
+ if (ptr.isHead) return this;
97
+ const node = ptr.removeCurrent();
98
+ ptr.prevNode = this;
99
+ return this.pushFrontNode(node);
100
+ }
101
+
102
+ moveToBack(ptr) {
103
+ if (!this.isCompatiblePtr(ptr)) throw new Error('Incompatible pointer');
104
+ ptr.list = this;
105
+ if (ptr.isHead) return this;
106
+ const node = ptr.removeCurrent();
107
+ ptr.prevNode = this.last;
108
+ return this.pushBackNode(node);
109
+ }
110
+
111
+ clear(drop) {
112
+ if (drop) {
113
+ let current = this;
114
+ do {
115
+ const next = current[this.nextName];
116
+ current[this.nextName] = current;
117
+ current = next;
118
+ } while (current !== this);
119
+ } else {
120
+ this[this.nextName] = this;
121
+ }
122
+ this.last = this;
123
+ return this;
124
+ }
125
+
126
+ removeNode(ptr) {
127
+ if (!ptr.isPrevNodeValid()) throw new Error('Cannot remove node: "prevNode" is invalid');
128
+ if (!this.isCompatiblePtr(ptr)) throw new Error('Incompatible pointer');
129
+ const node = ptr.prevNode[this.nextName];
130
+ if (node === this || node === ptr.prevNode) return null;
131
+ if (this.last === node) this.last = ptr.prevNode;
132
+ ptr.prevNode[this.nextName] = node[this.nextName];
133
+ ptr.list = this;
134
+ node[this.nextName] = node;
135
+ return node;
136
+ }
137
+
138
+ removeRange(ptrRange, drop) {
139
+ return this.extractRange(ptrRange).clear(drop);
140
+ }
141
+
142
+ extractRange(ptrRange = {}) {
143
+ const originalTo = ptrRange.to;
144
+ ptrRange = this.normalizePtrRange(ptrRange.from ? ptrRange : {...ptrRange, from: this.frontPtr});
145
+ if (!ptrRange.from.isPrevNodeValid()) throw new Error('Cannot extract range: "prevNode" is invalid');
146
+ ptrRange.to ||= this.last;
147
+
148
+ const extracted = this.make();
149
+ append(this, extracted, {prevFrom: ptrRange.from.prevNode, to: ptrRange.to});
150
+ extracted.last = ptrRange.to;
151
+ ptrRange.from.list = extracted;
152
+ if (originalTo instanceof Ptr) originalTo.list = extracted;
153
+
154
+ if (ptrRange.to === this.last) this.last = ptrRange.from.prevNode;
155
+
156
+ return extracted;
157
+ }
158
+
159
+ extractBy(condition) {
160
+ const extracted = this.make();
161
+ if (this.isEmpty) return extracted;
162
+
163
+ for (const ptr = this.frontPtr; !ptr.isHead; ) {
164
+ if (condition(ptr.node)) {
165
+ extracted.pushBackNode(ptr.removeCurrent());
166
+ } else {
167
+ ptr.next();
168
+ }
169
+ }
170
+ return extracted;
171
+ }
172
+
173
+ reverse() {
174
+ if (this.isOneOrEmpty) return this;
175
+ this.last = this[this.nextName];
176
+ let prev = this,
177
+ current = prev[this.nextName];
178
+ do {
179
+ const next = current[this.nextName];
180
+ current[this.nextName] = prev;
181
+ prev = current;
182
+ current = next;
183
+ } while (current !== this);
184
+ this[this.nextName] = prev;
185
+ return this;
186
+ }
187
+
188
+ sort(lessFn) {
189
+ if (this.isOneOrEmpty) return this;
190
+
191
+ const left = this.make(),
192
+ right = this.make();
193
+
194
+ // split into two sublists
195
+ for (let isLeft = true; !this.isEmpty; isLeft = !isLeft) {
196
+ (isLeft ? left : right).pushBackNode(this.popFrontNode());
197
+ }
198
+ // the list is empty now
199
+
200
+ // sort sublists
201
+ left.sort(lessFn);
202
+ right.sort(lessFn);
203
+
204
+ // merge sublists
205
+ while (!left.isEmpty && !right.isEmpty) {
206
+ this.pushBackNode((lessFn(left.front, right.front) ? left : right).popFrontNode());
207
+ }
208
+ if (!left.isEmpty) this.appendBack(left);
209
+ if (!right.isEmpty) this.appendBack(right);
210
+
211
+ return this;
212
+ }
213
+
214
+ releaseAsPtrRange() {
215
+ if (this.isEmpty) return null;
216
+ const head = this[this.nextName],
217
+ tail = this.last;
218
+ this.clear();
219
+ tail[this.nextName] = head;
220
+ return {from: new Ptr(this, null, tail), to: tail};
221
+ }
222
+
223
+ releaseRawList() {
224
+ if (this.isEmpty) return null;
225
+ const head = this[this.nextName],
226
+ tail = this.last;
227
+ this.clear();
228
+ tail[this.nextName] = head;
229
+ return head;
230
+ }
231
+
232
+ releaseNTList() {
233
+ if (this.isEmpty) return null;
234
+ const head = this[this.nextName],
235
+ tail = this.last;
236
+ this.clear();
237
+ tail[this.nextName] = null;
238
+ return {head, tail};
239
+ }
240
+
241
+ validateRange(range = {}) {
242
+ range = this.normalizeRange(range);
243
+ let current = range.from;
244
+ do {
245
+ if (current === this) return false;
246
+ current = current[this.nextName];
247
+ } while (current !== range.to);
248
+ return true;
249
+ }
250
+
251
+ // iterators
252
+
253
+ [Symbol.iterator]() {
254
+ let current = this[this.nextName],
255
+ readyToStop = this.isEmpty;
256
+ return normalizeIterator({
257
+ next: () => {
258
+ if (readyToStop && current === this) return {done: true};
259
+ readyToStop = true;
260
+ const value = current;
261
+ current = current[this.nextName];
262
+ return {value};
263
+ }
264
+ });
265
+ }
266
+
267
+ getNodeIterator(range = {}) {
268
+ range = this.normalizeRange(range);
269
+ const {from, to} = range;
270
+ return {
271
+ [Symbol.iterator]: () => {
272
+ let current = from || this[this.nextName],
273
+ readyToStop = this.isEmpty;
274
+ const stop = to ? to[this.nextName] : this;
275
+ return normalizeIterator({
276
+ next: () => {
277
+ if (readyToStop && current === stop) return {done: true};
278
+ readyToStop = true;
279
+ const value = current;
280
+ current = current[this.nextName];
281
+ return {value};
282
+ }
283
+ });
284
+ }
285
+ };
286
+ }
287
+
288
+ getPtrIterator(ptrRange = {}) {
289
+ if (!ptrRange.from) ptrRange = Object.assign({from: this.frontPtr}, ptrRange);
290
+ ptrRange = this.normalizePtrRange(ptrRange);
291
+ const {from: fromPtr, to} = ptrRange;
292
+ return {
293
+ [Symbol.iterator]: () => {
294
+ let current = fromPtr.clone(),
295
+ readyToStop = this.isEmpty;
296
+ const stop = to ? to[this.nextName] : this;
297
+ return normalizeIterator({
298
+ next: () => {
299
+ if (readyToStop && current.node === stop) return {done: true};
300
+ readyToStop = true;
301
+ const value = current.clone();
302
+ current = current.next();
303
+ return {value};
304
+ }
305
+ });
306
+ }
307
+ };
308
+ }
309
+
310
+ // meta helpers
311
+
312
+ make() {
313
+ return new SList(this);
314
+ }
315
+
316
+ makeFrom(values) {
317
+ return SList.from(values, this);
318
+ }
319
+
320
+ makeFromRange(range) {
321
+ return SList.fromRange(range, this);
322
+ }
323
+
324
+ static from(values, options) {
325
+ const list = new SList(options);
326
+ for (const value of values) list.pushBack(value);
327
+ return list;
328
+ }
329
+
330
+ static fromPtrRange(ptrRange, options) {
331
+ const list = new SList(options);
332
+ if (!list.isCompatiblePtrRange(ptrRange)) throw new Error('"range" is not a compatible range');
333
+ if (ptrRange) append(list, list, ptrRange);
334
+ return list;
335
+ }
336
+
337
+ static fromExtList(extList) {
338
+ if (!(extList instanceof ExtListBase)) throw new Error('Not a circular list');
339
+
340
+ const list = new SList(extList);
341
+ if (extList.isEmpty) return list;
342
+
343
+ const range = extList.range;
344
+ if (range) {
345
+ append(list, list, range);
346
+ extList.clear();
347
+ }
348
+
349
+ return list;
350
+ }
351
+ }
352
+
353
+ SList.Ptr = Ptr;
354
+
355
+ addAliases(SList.prototype, {
356
+ popFrontNode: 'popFront, pop',
357
+ popBackNode: 'popBack',
358
+ pushFront: 'push',
359
+ appendBack: 'append',
360
+ getNodeIterator: 'getIterator'
361
+ });
362
+
363
+ export {Ptr};
364
+ export default SList;
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ import ExtSList, {Ptr} from './ext.js';
4
+ import {ValueNode} from './nodes.js';
5
+ import {addAlias, mapIterator, normalizeIterator} from '../meta-utils.js';
6
+
7
+ export class ExtValueSList extends ExtSList {
8
+ adoptValue(value) {
9
+ if (value instanceof Ptr) {
10
+ if (!this.isCompatiblePtr(value)) throw new Error('Incompatible pointer');
11
+ if (value.node instanceof ValueNode) {
12
+ value.list = this;
13
+ return super.adoptNode(value);
14
+ }
15
+ return new ValueNode(value.node, this);
16
+ }
17
+ if (value instanceof ValueNode) {
18
+ if (!this.isNodeLike(value)) throw new Error('Incompatible node');
19
+ return super.adoptNode(value);
20
+ }
21
+ return new ValueNode(value, this);
22
+ }
23
+
24
+ // iterators
25
+
26
+ [Symbol.iterator]() {
27
+ let current = this.head,
28
+ readyToStop = this.isEmpty;
29
+ return normalizeIterator({
30
+ next: () => {
31
+ if (readyToStop && current === this.head) return {done: true};
32
+ readyToStop = true;
33
+ const value = current.value;
34
+ current = current[this.nextName];
35
+ return {value};
36
+ }
37
+ });
38
+ }
39
+
40
+ getValueIterator(range) {
41
+ return mapIterator(this.getNodeIterator(range), node => node.value);
42
+ }
43
+
44
+ // meta helpers
45
+
46
+ clone() {
47
+ return new ExtValueSList(this);
48
+ }
49
+
50
+ make(head = null) {
51
+ return new ExtValueSList(head, this);
52
+ }
53
+
54
+ makeFrom(values) {
55
+ return ExtValueSList.from(values, this);
56
+ }
57
+
58
+ static from(values, options) {
59
+ const list = new ExtValueSList(null, options);
60
+ for (const value of values) {
61
+ list.addAfter(value);
62
+ list.next();
63
+ }
64
+ return list.next();
65
+ }
66
+ }
67
+
68
+ ExtValueSList.Ptr = Ptr;
69
+ ExtValueSList.ValueNode = ValueNode;
70
+
71
+ addAlias(ExtValueSList.prototype, 'getIterator', 'getValueIterator');
72
+
73
+ export {ValueNode};
74
+ export default ExtValueSList;