list-toolkit 2.0.0 → 2.1.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/README.md CHANGED
@@ -101,8 +101,8 @@ const john = new Person('John'),
101
101
 
102
102
  const people = List.from([john, jane, jim, jill]);
103
103
 
104
- // iterator over the list manually:
105
- for (let node = people.front; node !== people; node = node[list.nextName]) {
104
+ // iterate over the list manually:
105
+ for (let node = people.front; node !== people; node = node[people.nextName]) {
106
106
  console.log(node.name); // John, Jane, Jim, Jill
107
107
  }
108
108
  // yes, the link names are customizable, can be strings or symbols, for example:
@@ -146,6 +146,8 @@ BSD 3-Clause "New" or "Revised" License. See the LICENSE file for details.
146
146
 
147
147
  ## Release History
148
148
 
149
+ * 2.1.1 *Allowed functions to be used as nodes. Updated deps.*
150
+ * 2.1.0 *Added splay tree. Updated deps.*
149
151
  * 2.0.0 *New major release.*
150
152
  * 1.0.1 *Fixed exports. Added more methods to `MinHeap`.*
151
153
  * 1.0.1 *Initial release.*
@@ -27,17 +27,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
27
27
  for (;;) {
28
28
  const l = (i << 1) + 1;
29
29
  if (l >= n) break;
30
- let c = l,
30
+ const r = l + 1,
31
+ c = r < n && less(array[r], array[l]) ? r : l,
32
+ iValue = array[i],
31
33
  cValue = array[c];
32
- const r = c + 1;
33
- if (r < n) {
34
- const rValue = array[r];
35
- if (less(rValue, cValue)) {
36
- c = r;
37
- cValue = rValue;
38
- }
39
- }
40
- const iValue = array[i];
41
34
  if (!less(cValue, iValue)) break;
42
35
  array[i] = cValue;
43
36
  array[c] = iValue;
@@ -48,6 +41,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
48
41
  class MinHeap {
49
42
  constructor(options, ...args) {
50
43
  (0, _metaUtils.copyOptions)(this, MinHeap.defaults, options);
44
+ if (typeof this.compare == 'function') {
45
+ this.less = (a, b) => this.compare(a, b) < 0;
46
+ this.equal = (a, b) => !this.compare(a, b);
47
+ }
51
48
  this.array = [];
52
49
  this.merge(...args);
53
50
  }
@@ -78,17 +75,10 @@ class MinHeap {
78
75
  for (let i = 0;;) {
79
76
  const l = (i << 1) + 1;
80
77
  if (l >= n) break;
81
- let c = l,
78
+ const r = l + 1,
79
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
80
+ iValue = this.array[i],
82
81
  cValue = this.array[c];
83
- const r = c + 1;
84
- if (r < n) {
85
- const rValue = this.array[r];
86
- if (this.less(rValue, cValue)) {
87
- c = r;
88
- cValue = rValue;
89
- }
90
- }
91
- const iValue = this.array[i];
92
82
  if (!this.less(cValue, iValue)) break;
93
83
  this.array[i] = cValue;
94
84
  this.array[c] = iValue;
@@ -120,17 +110,10 @@ class MinHeap {
120
110
  for (let i = 0;;) {
121
111
  const l = (i << 1) + 1;
122
112
  if (l >= n) break;
123
- let c = l,
113
+ const r = l + 1,
114
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
115
+ iValue = this.array[i],
124
116
  cValue = this.array[c];
125
- const r = c + 1;
126
- if (r < n) {
127
- const rValue = this.array[r];
128
- if (this.less(rValue, cValue)) {
129
- c = r;
130
- cValue = rValue;
131
- }
132
- }
133
- const iValue = this.array[i];
134
117
  if (!this.less(cValue, iValue)) break;
135
118
  this.array[i] = cValue;
136
119
  this.array[c] = iValue;
@@ -147,17 +130,10 @@ class MinHeap {
147
130
  for (let i = 0;;) {
148
131
  const l = (i << 1) + 1;
149
132
  if (l >= n) break;
150
- let c = l,
133
+ const r = l + 1,
134
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
135
+ iValue = this.array[i],
151
136
  cValue = this.array[c];
152
- const r = c + 1;
153
- if (r < n) {
154
- const rValue = this.array[r];
155
- if (this.less(rValue, cValue)) {
156
- c = r;
157
- cValue = rValue;
158
- }
159
- }
160
- const iValue = this.array[i];
161
137
  if (!this.less(cValue, iValue)) break;
162
138
  this.array[i] = cValue;
163
139
  this.array[c] = iValue;
@@ -230,17 +206,10 @@ class MinHeap {
230
206
  for (let i = j;;) {
231
207
  const l = (i << 1) + 1;
232
208
  if (l >= n) break;
233
- let c = l,
209
+ const r = l + 1,
210
+ c = r < n && less(array[r], array[l]) ? r : l,
211
+ iValue = array[i],
234
212
  cValue = array[c];
235
- const r = c + 1;
236
- if (r < n) {
237
- const rValue = array[r];
238
- if (less(rValue, cValue)) {
239
- c = r;
240
- cValue = rValue;
241
- }
242
- }
243
- const iValue = array[i];
244
213
  if (!less(cValue, iValue)) break;
245
214
  array[i] = cValue;
246
215
  array[c] = iValue;
@@ -323,6 +292,7 @@ class MinHeap {
323
292
  exports.MinHeap = MinHeap;
324
293
  MinHeap.defaults = {
325
294
  less: defaultLess,
326
- equal: defaultEqual
295
+ equal: defaultEqual,
296
+ compare: null
327
297
  };
328
298
  var _default = exports.default = MinHeap;
package/cjs/list/nodes.js CHANGED
@@ -36,9 +36,9 @@ class HeadNode extends Node {
36
36
  isNodeLike(node) {
37
37
  if (!node) return false;
38
38
  const next = node[this.nextName];
39
- if (!next || typeof next != 'object') return false;
39
+ if (!next || _metaUtils.canHaveProps[typeof next] !== 1) return false;
40
40
  const prev = node[this.prevName];
41
- return prev && typeof prev == 'object';
41
+ return prev && _metaUtils.canHaveProps[typeof prev] === 1;
42
42
  }
43
43
  isCompatibleNames({
44
44
  nextName,
package/cjs/meta-utils.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.toSnakeCase = exports.toPascalCase = exports.toKebabCase = exports.toCamelCase = exports.toAllCapsSnakeCase = exports.normalizeIterator = exports.mapIterator = exports.fromSnakeCase = exports.fromSetter = exports.fromPascalCase = exports.fromKebabCase = exports.fromGetter = exports.fromCamelCase = exports.fromAccessors = exports.defaultDescriptor = exports.copyOptions = exports.copyDescriptors = exports.capitalize = exports.augmentIterator = exports.addGetters = exports.addDescriptors = exports.addDescriptor = exports.addAliases = exports.addAlias = exports.addAccessor = void 0;
6
+ exports.toSnakeCase = exports.toPascalCase = exports.toKebabCase = exports.toCamelCase = exports.toAllCapsSnakeCase = exports.normalizeIterator = exports.mapIterator = exports.fromSnakeCase = exports.fromSetter = exports.fromPascalCase = exports.fromKebabCase = exports.fromGetter = exports.fromCamelCase = exports.fromAccessors = exports.defaultDescriptor = exports.copyOptions = exports.copyDescriptors = exports.capitalize = exports.canHaveProps = exports.augmentIterator = exports.addGetters = exports.addDescriptors = exports.addDescriptor = exports.addAliases = exports.addAlias = exports.addAccessor = void 0;
7
7
  const capitalize = name => name ? name[0].toUpperCase() + name.substring(1).toLowerCase() : name;
8
8
  exports.capitalize = capitalize;
9
9
  const toCamelCase = names => names.map((name, index) => index ? capitalize(name) : name.toLowerCase()).join('');
@@ -119,7 +119,7 @@ exports.addAlias = addAlias;
119
119
  const addAliases = (object, dict, force) => copyDescriptors(object, object, dict, force);
120
120
  exports.addAliases = addAliases;
121
121
  const augmentIterator = iterator => {
122
- if (!Object.hasOwnProperty(Symbol.iterator)) {
122
+ if (!iterator.hasOwnProperty(Symbol.iterator)) {
123
123
  iterator[Symbol.iterator] = function () {
124
124
  return this;
125
125
  };
@@ -150,6 +150,10 @@ const mapIterator = (iterator, callbackFn) => {
150
150
  };
151
151
  };
152
152
  exports.mapIterator = mapIterator;
153
+ const canHaveProps = exports.canHaveProps = {
154
+ object: 1,
155
+ function: 1
156
+ };
153
157
  const copyOptions = (target, pattern, ...sources) => {
154
158
  target = target || {};
155
159
  const keys = Object.keys(pattern);
@@ -157,7 +161,7 @@ const copyOptions = (target, pattern, ...sources) => {
157
161
  target[key] = pattern[key];
158
162
  }
159
163
  for (const source of sources) {
160
- if (!source || typeof source !== 'object') continue;
164
+ if (!source || canHaveProps[typeof source] !== 1) continue;
161
165
  for (const key of keys) {
162
166
  if (key in source) target[key] = source[key];
163
167
  }
@@ -36,7 +36,7 @@ class HeadNode extends Node {
36
36
  isNodeLike(node) {
37
37
  if (!node) return false;
38
38
  const next = node[this.nextName];
39
- return next && typeof next == 'object';
39
+ return next && _metaUtils.canHaveProps[typeof next] === 1;
40
40
  }
41
41
  isCompatibleNames({
42
42
  nextName
@@ -0,0 +1,362 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.SplayTreeNode = exports.SplayTree = void 0;
7
+ var _metaUtils = require("../meta-utils.js");
8
+ const defaultLess = (a, b) => a < b;
9
+ const zig = tree => {
10
+ const newTree = tree.left,
11
+ parent = newTree.parent = tree.parent;
12
+ if (parent) {
13
+ if (parent.left === tree) parent.left = newTree;else parent.right = newTree;
14
+ }
15
+ tree.parent = newTree;
16
+ const child = tree.left = newTree.right;
17
+ if (child) child.parent = tree;
18
+ newTree.right = tree;
19
+ return newTree;
20
+ };
21
+ const zag = tree => {
22
+ const newTree = tree.right,
23
+ parent = newTree.parent = tree.parent;
24
+ if (parent) {
25
+ if (parent.left === tree) parent.left = newTree;else parent.right = newTree;
26
+ }
27
+ tree.parent = newTree;
28
+ const child = tree.right = newTree.left;
29
+ if (child) child.parent = tree;
30
+ newTree.left = tree;
31
+ return newTree;
32
+ };
33
+ const splay = node => {
34
+ while (node.parent) {
35
+ if (!node.parent.parent) {
36
+ node.parent.left === node ? zig(node.parent) : zag(node.parent);
37
+ } else if (node.parent.left === node && node.parent.parent.left === node.parent) {
38
+ zig(node.parent.parent);
39
+ zig(node.parent);
40
+ } else if (node.parent.right === node && node.parent.parent.right === node.parent) {
41
+ zag(node.parent.parent);
42
+ zag(node.parent);
43
+ } else if (node.parent.left === node && node.parent.parent.right === node.parent) {
44
+ zig(node.parent);
45
+ zag(node.parent);
46
+ } else {
47
+ zag(node.parent);
48
+ zig(node.parent);
49
+ }
50
+ }
51
+ return node;
52
+ };
53
+ const count = tree => tree ? count(tree.left) + count(tree.right) + 1 : 0;
54
+ class SplayTreeNode {
55
+ constructor(value) {
56
+ this.left = this.right = this.parent = null;
57
+ this.value = value;
58
+ }
59
+ getMin() {
60
+ let z = this;
61
+ while (z.left) z = z.left;
62
+ return z;
63
+ }
64
+ getMax() {
65
+ let z = this;
66
+ while (z.right) z = z.right;
67
+ return z;
68
+ }
69
+ }
70
+ exports.SplayTreeNode = SplayTreeNode;
71
+ class SplayTree {
72
+ constructor(options) {
73
+ (0, _metaUtils.copyOptions)(this, SplayTree.defaults, options);
74
+ if (typeof this.compare == 'function') {
75
+ this.less = (a, b) => this.compare(a, b) < 0;
76
+ this.find = this.findWithCompare;
77
+ this.insert = this.insertWithCompare;
78
+ this.splitMaxTree = this.splitMaxTreeWithCompare;
79
+ }
80
+ this.root = null;
81
+ this.size = 0;
82
+ }
83
+ get isEmpty() {
84
+ return !this.root;
85
+ }
86
+ get length() {
87
+ return this.size;
88
+ }
89
+ getMin() {
90
+ return this.root.getMin();
91
+ }
92
+ getMax() {
93
+ return this.root.getMax();
94
+ }
95
+ find(value) {
96
+ for (let z = this.root; z;) {
97
+ if (this.less(z.value, value)) z = z.right;else if (this.less(value, z.value)) z = z.left;else return z;
98
+ }
99
+ return null;
100
+ }
101
+ findWithCompare(value) {
102
+ for (let z = this.root; z;) {
103
+ const cmp = this.compare(value, z.value);
104
+ if (cmp < 0) z = z.left;else if (cmp > 0) z = z.right;else return z;
105
+ }
106
+ return null;
107
+ }
108
+ promote(value) {
109
+ const z = this.find(value);
110
+ if (z) {
111
+ this.root = splay(z);
112
+ }
113
+ return z;
114
+ }
115
+ splay(node) {
116
+ this.root = splay(node);
117
+ return this;
118
+ }
119
+ insert(value) {
120
+ let z = this.root,
121
+ parent = null;
122
+ while (z) {
123
+ parent = z;
124
+ if (this.less(z.value, value)) z = z.right;else if (this.less(value, z.value)) z = z.left;else break;
125
+ }
126
+ if (!z) {
127
+ z = new SplayTreeNode(value);
128
+ z.parent = parent;
129
+ if (parent) {
130
+ if (this.less(parent.value, value)) parent.right = z;else parent.left = z;
131
+ }
132
+ ++this.size;
133
+ }
134
+ this.root = splay(z);
135
+ return this;
136
+ }
137
+ insertWithCompare(value) {
138
+ let z = this.root,
139
+ parent = null;
140
+ while (z) {
141
+ parent = z;
142
+ const cmp = this.compare(value, z.value);
143
+ if (cmp < 0) z = z.left;else if (cmp > 0) z = z.right;else break;
144
+ }
145
+ if (!z) {
146
+ z = new SplayTreeNode(value);
147
+ z.parent = parent;
148
+ if (parent) {
149
+ if (this.compare(parent.value, value) < 0) parent.right = z;else parent.left = z;
150
+ }
151
+ ++this.size;
152
+ }
153
+ this.root = splay(z);
154
+ return this;
155
+ }
156
+ remove(value) {
157
+ const z = this.find(value);
158
+ if (!z) return this;
159
+ splay(z);
160
+ this.root = null;
161
+ let maxNode = null;
162
+ if (z.left) {
163
+ z.left.parent = null;
164
+ maxNode = z.left.getMax();
165
+ this.root = splay(maxNode);
166
+ }
167
+ if (z.right) {
168
+ if (maxNode) maxNode.right = z.right;else this.root = z.right;
169
+ z.right.parent = maxNode;
170
+ }
171
+ --this.size;
172
+ return this;
173
+ }
174
+ clear() {
175
+ this.root = null;
176
+ this.size = 0;
177
+ return this;
178
+ }
179
+ splitMaxTree(value) {
180
+ if (!this.root) return new SplayTree(this);
181
+ let z = this.root,
182
+ parent = null,
183
+ right;
184
+ while (z) {
185
+ parent = z;
186
+ if (this.less(z.value, value)) {
187
+ z = z.right;
188
+ right = true;
189
+ } else if (this.less(value, z.value)) {
190
+ z = z.left;
191
+ right = false;
192
+ } else break;
193
+ }
194
+ this.root = splay(z || parent);
195
+ const newTree = new SplayTree(this);
196
+ if (z || right) {
197
+ newTree.root = this.root.right;
198
+ if (newTree.root) {
199
+ newTree.root.parent = null;
200
+ newTree.size = count(newTree.root);
201
+ this.root.right = null;
202
+ this.size -= newTree.size;
203
+ }
204
+ } else {
205
+ newTree.root = this.root;
206
+ newTree.size = this.size;
207
+ this.root = this.root.left;
208
+ if (this.root) {
209
+ this.root.parent = null;
210
+ this.size = count(this.root);
211
+ newTree.root.left = null;
212
+ newTree.size -= this.size;
213
+ }
214
+ }
215
+ return newTree;
216
+ }
217
+ splitMaxTreeWithCompare(value) {
218
+ if (!this.root) return new SplayTree(this);
219
+ let z = this.root,
220
+ parent = null,
221
+ right;
222
+ while (z) {
223
+ parent = z;
224
+ const cmp = this.compare(value, z.value);
225
+ if (cmp < 0) {
226
+ z = z.left;
227
+ right = false;
228
+ } else if (cmp > 0) {
229
+ z = z.right;
230
+ right = true;
231
+ } else break;
232
+ }
233
+ this.root = splay(z || parent);
234
+ const newTree = new SplayTree(this);
235
+ if (z || right) {
236
+ newTree.root = this.root.right;
237
+ if (newTree.root) {
238
+ newTree.root.parent = null;
239
+ newTree.size = count(newTree.root);
240
+ this.root.right = null;
241
+ this.size -= newTree.size;
242
+ }
243
+ } else {
244
+ newTree.root = this.root;
245
+ newTree.size = this.size;
246
+ this.root = this.root.left;
247
+ if (this.root) {
248
+ this.root.parent = null;
249
+ this.size = count(this.root);
250
+ newTree.root.left = null;
251
+ newTree.size -= this.size;
252
+ }
253
+ }
254
+ return newTree;
255
+ }
256
+ joinMaxTreeUnsafe(tree) {
257
+ if (this.root.right) {
258
+ this.splay(this.getMax());
259
+ }
260
+ this.root.right = tree.root;
261
+ tree.root.parent = this.root;
262
+ this.size += tree.size;
263
+ tree.clear();
264
+ return this;
265
+ }
266
+ join(tree) {
267
+ if (!tree.root) return this;
268
+ if (!this.root) {
269
+ this.root = tree.root;
270
+ this.size = tree.size;
271
+ tree.clear();
272
+ return this;
273
+ }
274
+ const leftMax = this.getMax(),
275
+ rightMin = tree.getMin();
276
+ if (this.less(leftMax.value, rightMin.value)) {
277
+ return this.splay(leftMax).joinMaxTreeUnsafe(tree);
278
+ }
279
+ for (const value of tree) {
280
+ this.insert(value);
281
+ }
282
+ tree.clear();
283
+ return this;
284
+ }
285
+ [Symbol.iterator]() {
286
+ let current = this.root ? this.root.getMin() : null;
287
+ return {
288
+ next: () => {
289
+ if (!current) return {
290
+ done: true
291
+ };
292
+ const last = current;
293
+ if (current.right) {
294
+ current = current.right.getMin();
295
+ } else {
296
+ for (;;) {
297
+ const parent = current.parent;
298
+ if (!parent) {
299
+ current = null;
300
+ break;
301
+ }
302
+ if (parent.left === current) {
303
+ current = parent;
304
+ break;
305
+ }
306
+ current = parent;
307
+ }
308
+ }
309
+ return {
310
+ value: last.value
311
+ };
312
+ }
313
+ };
314
+ }
315
+ getReverseIterator() {
316
+ return {
317
+ [Symbol.iterator]: () => {
318
+ let current = this.root ? this.root.getMax() : null;
319
+ return {
320
+ next: () => {
321
+ if (!current) return {
322
+ done: true
323
+ };
324
+ const last = current;
325
+ if (current.left) {
326
+ current = current.left.getMax();
327
+ } else {
328
+ for (;;) {
329
+ const parent = current.parent;
330
+ if (!parent) {
331
+ current = null;
332
+ break;
333
+ }
334
+ if (parent.right === current) {
335
+ current = parent;
336
+ break;
337
+ }
338
+ current = parent;
339
+ }
340
+ }
341
+ return {
342
+ value: last.value
343
+ };
344
+ }
345
+ };
346
+ }
347
+ };
348
+ }
349
+ static from(values, options) {
350
+ const tree = new SplayTree(options);
351
+ for (const value of values) {
352
+ tree.insert(value);
353
+ }
354
+ return tree;
355
+ }
356
+ }
357
+ exports.SplayTree = SplayTree;
358
+ SplayTree.defaults = {
359
+ less: defaultLess,
360
+ compare: null
361
+ };
362
+ var _default = exports.default = SplayTree;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "list-toolkit",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "List-based data structures to organize your objects.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -10,10 +10,14 @@
10
10
  }
11
11
  },
12
12
  "scripts": {
13
- "test": "tape6 --flags FO",
14
13
  "prepare-dist": "node scripts/prepare-dist.js",
15
14
  "build": "babel src --out-dir cjs",
16
- "prepublishOnly": "npm run prepare-dist && npm run build"
15
+ "prepublishOnly": "npm run prepare-dist && npm run build",
16
+ "test": "tape6 --flags FO",
17
+ "test:bun": "tape6-bun --flags FO",
18
+ "test:deno-original": "tape6-deno --flags FO",
19
+ "test:deno": "deno run -A `tape6-runner main` --flags FO",
20
+ "start": "tape6-server --trace"
17
21
  },
18
22
  "repository": {
19
23
  "type": "git",
@@ -33,10 +37,10 @@
33
37
  },
34
38
  "homepage": "https://github.com/uhop/list-toolkit#readme",
35
39
  "devDependencies": {
36
- "@babel/cli": "^7.24.7",
37
- "@babel/core": "^7.24.7",
38
- "@babel/preset-env": "^7.24.7",
39
- "tape-six": "^0.9.5"
40
+ "@babel/cli": "^7.25.6",
41
+ "@babel/core": "^7.25.2",
42
+ "@babel/preset-env": "^7.25.4",
43
+ "tape-six": "^0.12.2"
40
44
  },
41
45
  "files": [
42
46
  "/src",
@@ -57,6 +61,12 @@
57
61
  "tape6": {
58
62
  "tests": [
59
63
  "/tests/test-*.*js"
60
- ]
64
+ ],
65
+ "importmap": {
66
+ "imports": {
67
+ "tape-six": "/node_modules/tape-six/index.js",
68
+ "list-toolkit/": "/src/"
69
+ }
70
+ }
61
71
  }
62
72
  }
@@ -26,17 +26,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
26
26
  for (;;) {
27
27
  const l = (i << 1) + 1;
28
28
  if (l >= n) break;
29
- let c = l,
29
+ const r = l + 1,
30
+ c = r < n && less(array[r], array[l]) ? r : l,
31
+ iValue = array[i],
30
32
  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
33
  if (!less(cValue, iValue)) break;
41
34
  array[i] = cValue;
42
35
  array[c] = iValue;
@@ -48,6 +41,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
48
41
  export class MinHeap {
49
42
  constructor(options, ...args) {
50
43
  copyOptions(this, MinHeap.defaults, options);
44
+ if (typeof this.compare == 'function') {
45
+ this.less = (a, b) => this.compare(a, b) < 0;
46
+ this.equal = (a, b) => !this.compare(a, b);
47
+ }
51
48
  this.array = [];
52
49
  this.merge(...args);
53
50
  }
@@ -83,17 +80,10 @@ export class MinHeap {
83
80
  for (let i = 0; ; ) {
84
81
  const l = (i << 1) + 1;
85
82
  if (l >= n) break;
86
- let c = l,
83
+ const r = l + 1,
84
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
85
+ iValue = this.array[i],
87
86
  cValue = this.array[c];
88
- const r = c + 1;
89
- if (r < n) {
90
- const rValue = this.array[r];
91
- if (this.less(rValue, cValue)) {
92
- c = r;
93
- cValue = rValue;
94
- }
95
- }
96
- const iValue = this.array[i];
97
87
  if (!this.less(cValue, iValue)) break;
98
88
  this.array[i] = cValue;
99
89
  this.array[c] = iValue;
@@ -127,17 +117,10 @@ export class MinHeap {
127
117
  for (let i = 0; ; ) {
128
118
  const l = (i << 1) + 1;
129
119
  if (l >= n) break;
130
- let c = l,
120
+ const r = l + 1,
121
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
122
+ iValue = this.array[i],
131
123
  cValue = this.array[c];
132
- const r = c + 1;
133
- if (r < n) {
134
- const rValue = this.array[r];
135
- if (this.less(rValue, cValue)) {
136
- c = r;
137
- cValue = rValue;
138
- }
139
- }
140
- const iValue = this.array[i];
141
124
  if (!this.less(cValue, iValue)) break;
142
125
  this.array[i] = cValue;
143
126
  this.array[c] = iValue;
@@ -155,17 +138,10 @@ export class MinHeap {
155
138
  for (let i = 0; ; ) {
156
139
  const l = (i << 1) + 1;
157
140
  if (l >= n) break;
158
- let c = l,
141
+ const r = l + 1,
142
+ c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
143
+ iValue = this.array[i],
159
144
  cValue = this.array[c];
160
- const r = c + 1;
161
- if (r < n) {
162
- const rValue = this.array[r];
163
- if (this.less(rValue, cValue)) {
164
- c = r;
165
- cValue = rValue;
166
- }
167
- }
168
- const iValue = this.array[i];
169
145
  if (!this.less(cValue, iValue)) break;
170
146
  this.array[i] = cValue;
171
147
  this.array[c] = iValue;
@@ -257,17 +233,10 @@ export class MinHeap {
257
233
  for (let i = j; ; ) {
258
234
  const l = (i << 1) + 1;
259
235
  if (l >= n) break;
260
- let c = l,
236
+ const r = l + 1,
237
+ c = r < n && less(array[r], array[l]) ? r : l,
238
+ iValue = array[i],
261
239
  cValue = array[c];
262
- const r = c + 1;
263
- if (r < n) {
264
- const rValue = array[r];
265
- if (less(rValue, cValue)) {
266
- c = r;
267
- cValue = rValue;
268
- }
269
- }
270
- const iValue = array[i];
271
240
  if (!less(cValue, iValue)) break;
272
241
  array[i] = cValue;
273
242
  array[c] = iValue;
@@ -321,7 +290,7 @@ export class MinHeap {
321
290
  const last = heapArray.length - 1;
322
291
  if (index !== last) {
323
292
  const item = heapArray[index],
324
- newItem = heapArray[index] = heapArray.pop();
293
+ newItem = (heapArray[index] = heapArray.pop());
325
294
  return MinHeap.updateByIndex(heapArray, index, less(newItem, item), less);
326
295
  }
327
296
  heapArray.pop();
@@ -360,6 +329,6 @@ export class MinHeap {
360
329
  }
361
330
  }
362
331
 
363
- MinHeap.defaults = {less: defaultLess, equal: defaultEqual};
332
+ MinHeap.defaults = {less: defaultLess, equal: defaultEqual, compare: null};
364
333
 
365
334
  export default MinHeap;
package/src/list/nodes.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  import {isRangeLike, normalizeNode, normalizeRange} from '../list-helpers.js';
4
- import {addAlias, copyDescriptors} from '../meta-utils.js';
4
+ import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
5
5
 
6
6
  export const isNodeLike = ({nextName, prevName}, node) => node && node[prevName] && node[nextName];
7
7
  export const isStandAlone = ({nextName, prevName}, node) => node && node[prevName] === node && node[nextName] === node;
@@ -22,9 +22,9 @@ export class HeadNode extends Node {
22
22
  isNodeLike(node) {
23
23
  if (!node) return false;
24
24
  const next = node[this.nextName];
25
- if (!next || typeof next != 'object') return false;
25
+ if (!next || canHaveProps[typeof next] !== 1) return false;
26
26
  const prev = node[this.prevName];
27
- return prev && typeof prev == 'object';
27
+ return prev && canHaveProps[typeof prev] === 1;
28
28
  }
29
29
 
30
30
  isCompatibleNames({nextName, prevName}) {
package/src/meta-utils.js CHANGED
@@ -100,7 +100,7 @@ export const addAlias = (object, name, aliases, force) => addDescriptor(object,
100
100
  export const addAliases = (object, dict, force) => copyDescriptors(object, object, dict, force);
101
101
 
102
102
  export const augmentIterator = iterator => {
103
- if (!Object.hasOwnProperty(Symbol.iterator)) {
103
+ if (!iterator.hasOwnProperty(Symbol.iterator)) {
104
104
  iterator[Symbol.iterator] = function () {
105
105
  return this;
106
106
  };
@@ -131,6 +131,8 @@ export const mapIterator = (iterator, callbackFn) => {
131
131
  };
132
132
  };
133
133
 
134
+ export const canHaveProps = {object: 1, function: 1};
135
+
134
136
  export const copyOptions = (target, pattern, ...sources) => {
135
137
  target = target || {};
136
138
  const keys = Object.keys(pattern);
@@ -138,7 +140,7 @@ export const copyOptions = (target, pattern, ...sources) => {
138
140
  target[key] = pattern[key];
139
141
  }
140
142
  for (const source of sources) {
141
- if (!source || typeof source !== 'object') continue;
143
+ if (!source || canHaveProps[typeof source] !== 1) continue;
142
144
  for (const key of keys) {
143
145
  if (key in source) target[key] = source[key];
144
146
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  import {isRangeLike, normalizeNode, normalizeRange, normalizePtrRange} from '../list-helpers.js';
4
- import {addAlias, copyDescriptors} from '../meta-utils.js';
4
+ import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
5
5
 
6
6
  export const isNodeLike = ({nextName}, node) => node && node[nextName];
7
7
  export const isStandAlone = ({nextName}, node) => node && node[nextName] === node;
@@ -25,7 +25,7 @@ export class HeadNode extends Node {
25
25
  isNodeLike(node) {
26
26
  if (!node) return false;
27
27
  const next = node[this.nextName];
28
- return next && typeof next == 'object';
28
+ return next && canHaveProps[typeof next] === 1;
29
29
  }
30
30
  isCompatibleNames({nextName}) {
31
31
  return this.nextName === nextName;
@@ -0,0 +1,378 @@
1
+ 'use strict';
2
+
3
+ import {copyOptions} from '../meta-utils.js';
4
+
5
+ const defaultLess = (a, b) => a < b;
6
+
7
+ const zig = tree => {
8
+ const newTree = tree.left,
9
+ parent = (newTree.parent = tree.parent);
10
+ if (parent) {
11
+ if (parent.left === tree) parent.left = newTree;
12
+ else parent.right = newTree;
13
+ }
14
+ tree.parent = newTree;
15
+ const child = (tree.left = newTree.right);
16
+ if (child) child.parent = tree;
17
+ newTree.right = tree;
18
+ return newTree;
19
+ };
20
+
21
+ const zag = tree => {
22
+ const newTree = tree.right,
23
+ parent = (newTree.parent = tree.parent);
24
+ if (parent) {
25
+ if (parent.left === tree) parent.left = newTree;
26
+ else parent.right = newTree;
27
+ }
28
+ tree.parent = newTree;
29
+ const child = (tree.right = newTree.left);
30
+ if (child) child.parent = tree;
31
+ newTree.left = tree;
32
+ return newTree;
33
+ };
34
+
35
+ const splay = node => {
36
+ while (node.parent) {
37
+ if (!node.parent.parent) {
38
+ node.parent.left === node ? zig(node.parent) : zag(node.parent);
39
+ } else if (node.parent.left === node && node.parent.parent.left === node.parent) {
40
+ zig(node.parent.parent);
41
+ zig(node.parent);
42
+ } else if (node.parent.right === node && node.parent.parent.right === node.parent) {
43
+ zag(node.parent.parent);
44
+ zag(node.parent);
45
+ } else if (node.parent.left === node && node.parent.parent.right === node.parent) {
46
+ zig(node.parent);
47
+ zag(node.parent);
48
+ } else {
49
+ zag(node.parent);
50
+ zig(node.parent);
51
+ }
52
+ }
53
+ return node;
54
+ };
55
+
56
+ const count = tree => (tree ? count(tree.left) + count(tree.right) + 1 : 0);
57
+
58
+ export class SplayTreeNode {
59
+ constructor(value) {
60
+ this.left = this.right = this.parent = null;
61
+ this.value = value;
62
+ }
63
+ getMin() {
64
+ let z = this;
65
+ while (z.left) z = z.left;
66
+ return z;
67
+ }
68
+ getMax() {
69
+ let z = this;
70
+ while (z.right) z = z.right;
71
+ return z;
72
+ }
73
+ }
74
+
75
+ export class SplayTree {
76
+ constructor(options) {
77
+ copyOptions(this, SplayTree.defaults, options);
78
+ if (typeof this.compare == 'function') {
79
+ this.less = (a, b) => this.compare(a, b) < 0;
80
+ this.find = this.findWithCompare;
81
+ this.insert = this.insertWithCompare;
82
+ this.splitMaxTree = this.splitMaxTreeWithCompare;
83
+ }
84
+ this.root = null;
85
+ this.size = 0;
86
+ }
87
+ get isEmpty() {
88
+ return !this.root;
89
+ }
90
+ get length() {
91
+ return this.size;
92
+ }
93
+ getMin() {
94
+ return this.root.getMin();
95
+ }
96
+ getMax() {
97
+ return this.root.getMax();
98
+ }
99
+ find(value) {
100
+ for (let z = this.root; z; ) {
101
+ if (this.less(z.value, value)) z = z.right;
102
+ else if (this.less(value, z.value)) z = z.left;
103
+ else return z;
104
+ }
105
+ return null;
106
+ }
107
+ findWithCompare(value) {
108
+ for (let z = this.root; z; ) {
109
+ const cmp = this.compare(value, z.value);
110
+ if (cmp < 0) z = z.left;
111
+ else if (cmp > 0) z = z.right;
112
+ else return z;
113
+ }
114
+ return null;
115
+ }
116
+ promote(value) {
117
+ const z = this.find(value);
118
+ if (z) {
119
+ this.root = splay(z);
120
+ }
121
+ return z;
122
+ }
123
+ splay(node) {
124
+ this.root = splay(node);
125
+ return this;
126
+ }
127
+ insert(value) {
128
+ let z = this.root,
129
+ parent = null;
130
+ while (z) {
131
+ parent = z;
132
+ if (this.less(z.value, value)) z = z.right;
133
+ else if (this.less(value, z.value)) z = z.left;
134
+ else break;
135
+ }
136
+ if (!z) {
137
+ z = new SplayTreeNode(value);
138
+ z.parent = parent;
139
+ if (parent) {
140
+ if (this.less(parent.value, value)) parent.right = z;
141
+ else parent.left = z;
142
+ }
143
+ ++this.size;
144
+ }
145
+ this.root = splay(z);
146
+ return this;
147
+ }
148
+ insertWithCompare(value) {
149
+ let z = this.root,
150
+ parent = null;
151
+ while (z) {
152
+ parent = z;
153
+ const cmp = this.compare(value, z.value);
154
+ if (cmp < 0) z = z.left;
155
+ else if (cmp > 0) z = z.right;
156
+ else break;
157
+ }
158
+ if (!z) {
159
+ z = new SplayTreeNode(value);
160
+ z.parent = parent;
161
+ if (parent) {
162
+ if (this.compare(parent.value, value) < 0) parent.right = z;
163
+ else parent.left = z;
164
+ }
165
+ ++this.size;
166
+ }
167
+ this.root = splay(z);
168
+ return this;
169
+ }
170
+ remove(value) {
171
+ const z = this.find(value);
172
+ if (!z) return this;
173
+
174
+ splay(z);
175
+ this.root = null;
176
+
177
+ let maxNode = null;
178
+ if (z.left) {
179
+ z.left.parent = null;
180
+ maxNode = z.left.getMax();
181
+ this.root = splay(maxNode);
182
+ }
183
+ if (z.right) {
184
+ if (maxNode) maxNode.right = z.right;
185
+ else this.root = z.right;
186
+ z.right.parent = maxNode;
187
+ }
188
+
189
+ --this.size;
190
+
191
+ return this;
192
+ }
193
+ clear() {
194
+ this.root = null;
195
+ this.size = 0;
196
+ return this;
197
+ }
198
+ splitMaxTree(value) {
199
+ if (!this.root) return new SplayTree(this);
200
+ let z = this.root,
201
+ parent = null,
202
+ right;
203
+ while (z) {
204
+ parent = z;
205
+ if (this.less(z.value, value)) {
206
+ z = z.right;
207
+ right = true;
208
+ } else if (this.less(value, z.value)) {
209
+ z = z.left;
210
+ right = false;
211
+ } else break;
212
+ }
213
+ this.root = splay(z || parent);
214
+
215
+ const newTree = new SplayTree(this);
216
+ if (z || right) {
217
+ newTree.root = this.root.right;
218
+ if (newTree.root) {
219
+ newTree.root.parent = null;
220
+ newTree.size = count(newTree.root);
221
+ this.root.right = null;
222
+ this.size -= newTree.size;
223
+ }
224
+ } else {
225
+ newTree.root = this.root;
226
+ newTree.size = this.size;
227
+ this.root = this.root.left;
228
+ if (this.root) {
229
+ this.root.parent = null;
230
+ this.size = count(this.root);
231
+ newTree.root.left = null;
232
+ newTree.size -= this.size;
233
+ }
234
+ }
235
+ return newTree;
236
+ }
237
+ splitMaxTreeWithCompare(value) {
238
+ if (!this.root) return new SplayTree(this);
239
+ let z = this.root,
240
+ parent = null,
241
+ right;
242
+ while (z) {
243
+ parent = z;
244
+ const cmp = this.compare(value, z.value);
245
+ if (cmp < 0) {
246
+ z = z.left;
247
+ right = false;
248
+ } else if (cmp > 0) {
249
+ z = z.right;
250
+ right = true;
251
+ } else break;
252
+ }
253
+ this.root = splay(z || parent);
254
+
255
+ const newTree = new SplayTree(this);
256
+ if (z || right) {
257
+ newTree.root = this.root.right;
258
+ if (newTree.root) {
259
+ newTree.root.parent = null;
260
+ newTree.size = count(newTree.root);
261
+ this.root.right = null;
262
+ this.size -= newTree.size;
263
+ }
264
+ } else {
265
+ newTree.root = this.root;
266
+ newTree.size = this.size;
267
+ this.root = this.root.left;
268
+ if (this.root) {
269
+ this.root.parent = null;
270
+ this.size = count(this.root);
271
+ newTree.root.left = null;
272
+ newTree.size -= this.size;
273
+ }
274
+ }
275
+ return newTree;
276
+ }
277
+ joinMaxTreeUnsafe(tree) {
278
+ if (this.root.right) {
279
+ this.splay(this.getMax());
280
+ }
281
+
282
+ this.root.right = tree.root;
283
+ tree.root.parent = this.root;
284
+ this.size += tree.size;
285
+
286
+ tree.clear();
287
+
288
+ return this;
289
+ }
290
+ join(tree) {
291
+ if (!tree.root) return this;
292
+ if (!this.root) {
293
+ this.root = tree.root;
294
+ this.size = tree.size;
295
+ tree.clear();
296
+ return this;
297
+ }
298
+
299
+ const leftMax = this.getMax(), rightMin = tree.getMin();
300
+ if (this.less(leftMax.value, rightMin.value)) {
301
+ return this.splay(leftMax).joinMaxTreeUnsafe(tree);
302
+ }
303
+
304
+ for (const value of tree) {
305
+ this.insert(value);
306
+ }
307
+
308
+ tree.clear();
309
+ return this;
310
+ }
311
+ [Symbol.iterator]() {
312
+ let current = this.root ? this.root.getMin() : null;
313
+ return {
314
+ next: () => {
315
+ if (!current) return {done: true};
316
+ const last = current;
317
+ if (current.right) {
318
+ current = current.right.getMin();
319
+ } else {
320
+ for (;;) {
321
+ const parent = current.parent;
322
+ if (!parent) {
323
+ current = null;
324
+ break;
325
+ }
326
+ if (parent.left === current) {
327
+ current = parent;
328
+ break;
329
+ }
330
+ current = parent;
331
+ }
332
+ }
333
+ return {value: last.value};
334
+ }
335
+ };
336
+ }
337
+ getReverseIterator() {
338
+ return {
339
+ [Symbol.iterator]: () => {
340
+ let current = this.root ? this.root.getMax() : null;
341
+ return {
342
+ next: () => {
343
+ if (!current) return {done: true};
344
+ const last = current;
345
+ if (current.left) {
346
+ current = current.left.getMax();
347
+ } else {
348
+ for (;;) {
349
+ const parent = current.parent;
350
+ if (!parent) {
351
+ current = null;
352
+ break;
353
+ }
354
+ if (parent.right === current) {
355
+ current = parent;
356
+ break;
357
+ }
358
+ current = parent;
359
+ }
360
+ }
361
+ return {value: last.value};
362
+ }
363
+ };
364
+ }
365
+ };
366
+ }
367
+ static from(values, options) {
368
+ const tree = new SplayTree(options);
369
+ for (const value of values) {
370
+ tree.insert(value);
371
+ }
372
+ return tree;
373
+ }
374
+ }
375
+
376
+ SplayTree.defaults = {less: defaultLess, compare: null};
377
+
378
+ export default SplayTree;