list-toolkit 1.0.1

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/src/MinHeap.js ADDED
@@ -0,0 +1,283 @@
1
+ 'use strict';
2
+
3
+ import {copyOptions} from './utils.js';
4
+
5
+ // the following functions are inlined:
6
+
7
+ // const left = i => (i << 1) + 1;
8
+ // const right = i => (i + 1) << 1;
9
+ // const parent = i => (i - 1) >> 1;
10
+
11
+ const defaultLess = (a, b) => a < b;
12
+ const defaultEqual = (a, b) => a === b;
13
+
14
+ const up = (array, i, less = defaultLess) => {
15
+ for (let p = (i - 1) >> 1; i > 0; i = p, p = (i - 1) >> 1) {
16
+ const iValue = array[i],
17
+ pValue = array[p];
18
+ if (!less(iValue, pValue)) break;
19
+ array[i] = pValue;
20
+ array[p] = iValue;
21
+ }
22
+ return array;
23
+ };
24
+
25
+ const down = (array, i, less = defaultLess, n = array.length) => {
26
+ for (;;) {
27
+ const l = (i << 1) + 1;
28
+ if (l >= n) break;
29
+ let c = l,
30
+ cValue = array[c];
31
+ const r = c + 1;
32
+ if (r < n) {
33
+ const rValue = array[r];
34
+ if (less(rValue, cValue)) {
35
+ c = r;
36
+ cValue = rValue;
37
+ }
38
+ }
39
+ const iValue = array[i];
40
+ if (!less(cValue, iValue)) break;
41
+ array[i] = cValue;
42
+ array[c] = iValue;
43
+ i = c;
44
+ }
45
+ return array;
46
+ };
47
+
48
+ class MinHeap {
49
+ constructor(options, ...args) {
50
+ copyOptions(this, MinHeap.defaults, options);
51
+ this.array = [];
52
+ this.merge(...args);
53
+ }
54
+
55
+ get length() {
56
+ return this.array.length;
57
+ }
58
+
59
+ get isEmpty() {
60
+ return !this.array.length;
61
+ }
62
+
63
+ get top() {
64
+ return this.array[0];
65
+ }
66
+
67
+ clear() {
68
+ this.array = [];
69
+ return this;
70
+ }
71
+
72
+ pop() {
73
+ // return MinHeap.pop(this.array, this.less); // inlined
74
+ switch (this.array.length) {
75
+ case 0:
76
+ return;
77
+ case 1:
78
+ return this.array.pop();
79
+ }
80
+ const top = this.array[0];
81
+ this.array[0] = this.array.pop();
82
+ // down(this.array, 0, this.less); // inlined
83
+ const n = this.array.length;
84
+ for (let i = 0; ; ) {
85
+ const l = (i << 1) + 1;
86
+ if (l >= n) break;
87
+ let c = l,
88
+ cValue = this.array[c];
89
+ const r = c + 1;
90
+ if (r < n) {
91
+ const rValue = this.array[r];
92
+ if (this.less(rValue, cValue)) {
93
+ c = r;
94
+ cValue = rValue;
95
+ }
96
+ }
97
+ const iValue = this.array[i];
98
+ if (!this.less(cValue, iValue)) break;
99
+ this.array[i] = cValue;
100
+ this.array[c] = iValue;
101
+ i = c;
102
+ }
103
+ return top;
104
+ }
105
+
106
+ push(value) {
107
+ // MinHeap.push(this.array, value, this.less); // inlined
108
+ let i = this.array.length;
109
+ this.array.push(value);
110
+ // up(this.array, i, this.less); // inlined
111
+ for (let p = (i - 1) >> 1; i > 0; i = p, p = (i - 1) >> 1) {
112
+ const iValue = this.array[i],
113
+ pValue = this.array[p];
114
+ if (!this.less(iValue, pValue)) break;
115
+ this.array[i] = pValue;
116
+ this.array[p] = iValue;
117
+ }
118
+ return this;
119
+ }
120
+
121
+ pushPop(value) {
122
+ // return MinHeap.pushPop(this.array, value, this.less); // inlined
123
+ if (!this.array.length || this.less(value, this.array[0])) return value;
124
+ const top = this.array[0];
125
+ this.array[0] = value;
126
+ // down(this.array, 0, this.less); // inlined
127
+ const n = this.array.length;
128
+ for (let i = 0; ; ) {
129
+ const l = (i << 1) + 1;
130
+ if (l >= n) break;
131
+ let c = l,
132
+ cValue = this.array[c];
133
+ const r = c + 1;
134
+ if (r < n) {
135
+ const rValue = this.array[r];
136
+ if (this.less(rValue, cValue)) {
137
+ c = r;
138
+ cValue = rValue;
139
+ }
140
+ }
141
+ const iValue = this.array[i];
142
+ if (!this.less(cValue, iValue)) break;
143
+ this.array[i] = cValue;
144
+ this.array[c] = iValue;
145
+ i = c;
146
+ }
147
+ return top;
148
+ }
149
+
150
+ replaceTop(value) {
151
+ // return MinHeap.replaceTop(this.array, value, this.less); // inlined
152
+ const top = this.array[0];
153
+ this.array[0] = value;
154
+ // down(this.array, 0, this.less); // inlined
155
+ const n = this.array.length;
156
+ for (let i = 0; ; ) {
157
+ const l = (i << 1) + 1;
158
+ if (l >= n) break;
159
+ let c = l,
160
+ cValue = this.array[c];
161
+ const r = c + 1;
162
+ if (r < n) {
163
+ const rValue = this.array[r];
164
+ if (this.less(rValue, cValue)) {
165
+ c = r;
166
+ cValue = rValue;
167
+ }
168
+ }
169
+ const iValue = this.array[i];
170
+ if (!this.less(cValue, iValue)) break;
171
+ this.array[i] = cValue;
172
+ this.array[c] = iValue;
173
+ i = c;
174
+ }
175
+ return top;
176
+ }
177
+
178
+ releaseSorted() {
179
+ MinHeap.sort(this.array, this.less);
180
+ const array = this.array;
181
+ this.array = [];
182
+ return array;
183
+ }
184
+
185
+ merge(...args) {
186
+ if (!args.length) return this;
187
+ this.array = MinHeap.build(
188
+ this.array.concat(
189
+ ...args.map(item => {
190
+ if (item instanceof MinHeap) return item.array;
191
+ if (!item) return [];
192
+ return item;
193
+ })
194
+ ),
195
+ this.less
196
+ );
197
+ return this;
198
+ }
199
+
200
+ make(...args) {
201
+ return new MinHeap(this, ...args);
202
+ }
203
+
204
+ clone() {
205
+ const heap = new MinHeap(this);
206
+ heap.array = this.array.slice(0);
207
+ return heap;
208
+ }
209
+
210
+ static build(array, less = MinHeap.defaults.less) {
211
+ if (array.length <= 1) return array;
212
+ for (let n = array.length, j = (n >> 1) - 1; j >= 0; --j) {
213
+ // down(array, j, less, n); // inlined
214
+ for (let i = j; ; ) {
215
+ const l = (i << 1) + 1;
216
+ if (l >= n) break;
217
+ let c = l,
218
+ cValue = array[c];
219
+ const r = c + 1;
220
+ if (r < n) {
221
+ const rValue = array[r];
222
+ if (less(rValue, cValue)) {
223
+ c = r;
224
+ cValue = rValue;
225
+ }
226
+ }
227
+ const iValue = array[i];
228
+ if (!less(cValue, iValue)) break;
229
+ array[i] = cValue;
230
+ array[c] = iValue;
231
+ i = c;
232
+ }
233
+ }
234
+ return array;
235
+ }
236
+
237
+ static pop(heapArray, less = MinHeap.defaults.less) {
238
+ switch (heapArray.length) {
239
+ case 0:
240
+ return;
241
+ case 1:
242
+ return heapArray.pop();
243
+ }
244
+ const top = heapArray[0];
245
+ heapArray[0] = heapArray.pop();
246
+ down(heapArray, 0, less);
247
+ return top;
248
+ }
249
+
250
+ static push(heapArray, item, less = MinHeap.defaults.less) {
251
+ const i = heapArray.length;
252
+ heapArray.push(item);
253
+ return up(heapArray, i, less);
254
+ }
255
+
256
+ static pushPop(heapArray, item, less = MinHeap.defaults.less) {
257
+ if (!heapArray.length || less(item, heapArray[0])) return item;
258
+ const top = heapArray[0];
259
+ heapArray[0] = item;
260
+ down(heapArray, 0, less);
261
+ return top;
262
+ }
263
+
264
+ static replaceTop(heapArray, item, less = MinHeap.defaults.less) {
265
+ const top = heapArray[0];
266
+ heapArray[0] = item;
267
+ down(heapArray, 0, less);
268
+ return top;
269
+ }
270
+
271
+ static sort(heapArray, less = MinHeap.defaults.less) {
272
+ if (heapArray.length <= 1) return heapArray;
273
+ for (let n = heapArray.length - 1; n; --n) {
274
+ [heapArray[0], heapArray[n]] = [heapArray[n], heapArray[0]];
275
+ down(heapArray, 0, less, n);
276
+ }
277
+ return heapArray;
278
+ }
279
+ }
280
+
281
+ MinHeap.defaults = {less: defaultLess, equal: defaultEqual};
282
+
283
+ export default MinHeap;
package/src/SList.js ADDED
@@ -0,0 +1,329 @@
1
+ 'use strict';
2
+
3
+ class SListNode {
4
+ constructor() {
5
+ this.next = this;
6
+ }
7
+ }
8
+
9
+ const pop = prev => {
10
+ const node = prev.next;
11
+ prev.next = node.next;
12
+ node.next = node;
13
+ return {node, list: prev};
14
+ };
15
+
16
+ const extract = (prevFrom, nodeTo) => {
17
+ const node = prevFrom.next;
18
+ if (prevFrom === nodeTo) return {prev: prevFrom, node};
19
+ prevFrom.next = nodeTo.next;
20
+ nodeTo.next = node;
21
+ return {prev: nodeTo, node};
22
+ };
23
+
24
+ const splice = (prev1, {prev, node}) => {
25
+ prev.next = prev1.next;
26
+ prev1.next = node;
27
+ return prev1;
28
+ };
29
+
30
+ const getPrevPrev = (list, node) => {
31
+ let prev = list,
32
+ current = prev.next;
33
+ while (current.next !== list) {
34
+ if (node && current.next === node) return prev;
35
+ prev = current;
36
+ current = prev.next;
37
+ }
38
+ if (node) {
39
+ if (list.next === node) return current;
40
+ throw new Error('node does not belong to the list');
41
+ }
42
+ return prev;
43
+ };
44
+
45
+ const getPrev = (list, node) => {
46
+ return getPrevPrev(list, node).next;
47
+ };
48
+
49
+ class SListValueNode extends SListNode {
50
+ constructor(value) {
51
+ super();
52
+ this.value = value;
53
+ }
54
+
55
+ addAfter(value) {
56
+ const node = new SListValueNode(value);
57
+ splice(this, {prev: node, node});
58
+ return this;
59
+ }
60
+
61
+ insertAfter(list) {
62
+ const node = getPrev(pop(list).list);
63
+ splice(this, {prev: node, node});
64
+ return this;
65
+ }
66
+ }
67
+
68
+ class SList extends SListNode {
69
+ get isEmpty() {
70
+ return this.next === this;
71
+ }
72
+
73
+ get front() {
74
+ return this.next;
75
+ }
76
+
77
+ getBack() {
78
+ return getPrev(this);
79
+ }
80
+
81
+ getLength() {
82
+ let n = 0;
83
+ for (let p = this.next; p !== this; ++n, p = p.next);
84
+ return n;
85
+ }
86
+
87
+ getPtr() {
88
+ return new SList.SListPtr(this);
89
+ }
90
+
91
+ popFront() {
92
+ if (this.next !== this) {
93
+ return pop(this).node.value;
94
+ }
95
+ }
96
+
97
+ popBack() {
98
+ if (this.next !== this) {
99
+ const prevLast = getPrevPrev(this);
100
+ return pop(prevLast).node.value;
101
+ }
102
+ }
103
+
104
+ pushFront(value) {
105
+ const node = new SListValueNode(value);
106
+ splice(this, {prev: node, node});
107
+ return this;
108
+ }
109
+
110
+ pushBack(value) {
111
+ const node = new SListValueNode(value),
112
+ last = getPrev(this);
113
+ splice(last, {prev: node, node});
114
+ return this;
115
+ }
116
+
117
+ appendFront(list) {
118
+ if (list.next === list) return this;
119
+ let prevFrom = list,
120
+ nodeTo = getPrev(list);
121
+ splice(this, extract(prevFrom, nodeTo));
122
+ return this;
123
+ }
124
+
125
+ appendBack(list) {
126
+ if (list.next === list) return this;
127
+ let prevFrom = list,
128
+ nodeTo = getPrev(list),
129
+ last = getPrev(this);
130
+ splice(last, extract(prevFrom, nodeTo));
131
+ return this;
132
+ }
133
+
134
+ moveToFront(node) {
135
+ let prev;
136
+ if (node instanceof SList.SListPtr) {
137
+ prev = node.prev;
138
+ node = node.node;
139
+ if (this.next === node) return this;
140
+ } else {
141
+ if (this.next === node) return this;
142
+ prev = getPrev(this, node);
143
+ }
144
+ splice(this, extract(prev, node));
145
+ return this;
146
+ }
147
+
148
+ moveToBack(node) {
149
+ let prev;
150
+ if (node instanceof SList.SListPtr) {
151
+ prev = node.prev;
152
+ node = node.node;
153
+ } else {
154
+ prev = getPrev(this, node);
155
+ }
156
+ const last = getPrev(this);
157
+ splice(last, extract(prev, node));
158
+ return this;
159
+ }
160
+
161
+ clear() {
162
+ this.next = this;
163
+ return this;
164
+ }
165
+
166
+ remove(from, to = from) {
167
+ const prevFrom = from instanceof SList.SListPtr ? from.prev : getPrev(this, from),
168
+ nodeTo = to instanceof SList.SListPtr ? to.node : to;
169
+ extract(prevFrom, nodeTo);
170
+ return this;
171
+ }
172
+
173
+ extract(from, to) {
174
+ const prevFrom = from instanceof SList.SListPtr ? from.prev : getPrev(this, from),
175
+ nodeTo = to instanceof SList.SListPtr ? to.node : to;
176
+ return splice(new SList(), extract(prevFrom, nodeTo));
177
+ }
178
+
179
+ reverse() {
180
+ let prev = this,
181
+ current = prev.next;
182
+ while (current !== this) {
183
+ const next = current.next;
184
+ current.next = prev;
185
+ prev = current;
186
+ current = next;
187
+ }
188
+ this.next = prev;
189
+ return this;
190
+ }
191
+
192
+ sort(compareFn) {
193
+ let current = this.next;
194
+ for (const value of Array.from(this).sort(compareFn)) {
195
+ current.value = value;
196
+ current = current.next;
197
+ }
198
+ return this;
199
+ }
200
+
201
+ // iterators
202
+
203
+ [Symbol.iterator]() {
204
+ let current = this.next;
205
+ return {
206
+ next: () => {
207
+ if (current === this) return {done: true};
208
+ const node = current;
209
+ current = current.next;
210
+ return {value: node.value};
211
+ }
212
+ };
213
+ }
214
+
215
+ getIterable(from, to) {
216
+ return {
217
+ [Symbol.iterator]: () => {
218
+ let current = (from instanceof SList.SListPtr && from.node) || from || this.next;
219
+ const stop = to ? ((to instanceof SList.SListPtr && to.node) || to).next : this;
220
+ return {
221
+ next: () => {
222
+ if (current === stop) return {done: true};
223
+ const node = current;
224
+ current = current.next;
225
+ return {value: node.value};
226
+ }
227
+ };
228
+ }
229
+ };
230
+ }
231
+
232
+ getNodeIterable(from, to) {
233
+ return {
234
+ [Symbol.iterator]: () => {
235
+ let current = (from instanceof SList.SListPtr && from.node) || from || this.next;
236
+ const stop = to ? ((to instanceof SList.SListPtr && to.node) || to).next : this;
237
+ return {
238
+ next: () => {
239
+ if (current === stop) return {done: true};
240
+ const node = current;
241
+ current = current.next;
242
+ return {value: node};
243
+ }
244
+ };
245
+ }
246
+ };
247
+ }
248
+
249
+ getPtrIterable(from, to) {
250
+ return {
251
+ [Symbol.iterator]: () => {
252
+ let current = from instanceof SList.SListPtr ? from.clone() : from ? new SList.SListPtr(this, getPrev(this.head, from)) : this.getPtr();
253
+ const stop = to ? ((to instanceof SList.SListPtr && to.node) || to).next : this;
254
+ return {
255
+ next: () => {
256
+ if (current.node === stop) return {done: true};
257
+ const value = current.clone();
258
+ current.next();
259
+ return {value};
260
+ }
261
+ };
262
+ }
263
+ };
264
+ }
265
+
266
+ // helpers
267
+
268
+ makeFrom(values) {
269
+ return SList.from(values);
270
+ }
271
+
272
+ pushValuesFront(values) {
273
+ for (const value of values) {
274
+ this.pushFront(value);
275
+ }
276
+ return this;
277
+ }
278
+
279
+ appendValuesFront(values) {
280
+ return this.appendFront(SList.from(values));
281
+ }
282
+
283
+ static from(values) {
284
+ const list = new SList();
285
+ let prev = list;
286
+ for (const value of values) {
287
+ const node = new SListValueNode(value);
288
+ prev.next = node;
289
+ prev = node;
290
+ }
291
+ prev.next = list;
292
+ return list;
293
+ }
294
+ }
295
+
296
+ SList.pop = pop;
297
+ SList.extract = extract;
298
+ SList.splice = splice;
299
+ SList.getPrev = getPrev;
300
+ SList.getPrevPrev = getPrevPrev;
301
+
302
+ SList.Node = SListNode;
303
+ SList.ValueNode = SListValueNode;
304
+
305
+ SList.prototype.pop = SList.prototype.popFront;
306
+ SList.prototype.push = SList.prototype.pushFront;
307
+ SList.prototype.append = SList.prototype.appendBack;
308
+
309
+ SList.SListPtr = class SListPtr {
310
+ constructor(list, prev) {
311
+ this.list = list;
312
+ this.prev = prev || list;
313
+ }
314
+ get node() {
315
+ return this.prev.next;
316
+ }
317
+ get isHead() {
318
+ return this.prev.next === this.list;
319
+ }
320
+ next() {
321
+ this.prev = this.prev.next;
322
+ return this;
323
+ }
324
+ clone() {
325
+ return new SList.SListPtr(this.list, this.prev);
326
+ }
327
+ };
328
+
329
+ export default SList;