recursive-set 3.0.0 → 4.0.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/dist/cjs/index.js CHANGED
@@ -1,289 +1,502 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
2
+ /**
3
+ * @module recursive-set
4
+ * High-Performance Mutable Recursive Set backed by Sorted Arrays.
5
+ * Optimized for small sets, structural equality, and deterministic hashing.
6
+ */
5
7
  Object.defineProperty(exports, "__esModule", { value: true });
6
8
  exports.RecursiveSet = exports.Tuple = void 0;
7
9
  exports.emptySet = emptySet;
8
10
  exports.singleton = singleton;
9
11
  exports.fromIterable = fromIterable;
10
- const functional_red_black_tree_1 = __importDefault(require("functional-red-black-tree"));
12
+ // === HASHING ENGINE ===
11
13
  /**
12
- * @module recursive-set
13
- * A mutable recursive set implementation.
14
- * Powered by functional Red-Black Trees for O(log n) operations and O(1) cloning.
14
+ * FNV-1a Hash implementation for strings.
15
+ * Constants inlined for V8 optimization.
15
16
  */
17
+ function hashString(str) {
18
+ let hash = 0x811c9dc5;
19
+ for (let i = 0; i < str.length; i++) {
20
+ hash ^= str.charCodeAt(i);
21
+ hash = Math.imul(hash, 0x01000193);
22
+ }
23
+ return hash >>> 0;
24
+ }
16
25
  /**
17
- * A lightweight wrapper for Tuples to enable Value-Equality in RecursiveSet.
18
- * Immutable by design.
26
+ * Universal Hash Function.
27
+ * Calculates deterministic hashes for Primitives, Sequences (Order Dependent), and Sets.
19
28
  */
20
- class Tuple {
21
- values;
22
- constructor(...values) {
23
- this.values = values;
29
+ function hashValue(val) {
30
+ if (typeof val === 'string')
31
+ return hashString(val);
32
+ if (typeof val === 'number')
33
+ return val | 0;
34
+ // Fast Path: Objects with cached hash
35
+ if (val instanceof RecursiveSet)
36
+ return val.hashCode;
37
+ if (val instanceof Tuple)
38
+ return val.hashCode;
39
+ // Arrays: Treated as sequences (Rolling Hash)
40
+ if (Array.isArray(val)) {
41
+ let h = 0;
42
+ for (let i = 0; i < val.length; i++) {
43
+ let v = val[i];
44
+ let vh = 0;
45
+ if (typeof v === 'string')
46
+ vh = hashString(v);
47
+ else
48
+ vh = hashValue(v);
49
+ h = Math.imul(31, h) + vh;
50
+ }
51
+ return h >>> 0;
24
52
  }
25
- get length() {
26
- return this.values.length;
53
+ return 0;
54
+ }
55
+ // === COMPARATOR ===
56
+ /**
57
+ * High-performance comparator with hash short-circuiting.
58
+ * Order: Primitives (0) < Sequences (1) < Sets (2)
59
+ */
60
+ function compare(a, b) {
61
+ if (a === b)
62
+ return 0;
63
+ // 1. Hash Short-Circuit
64
+ // Using interface casting avoids runtime overhead of 'in' operator checks
65
+ const aH = a?.hashCode;
66
+ const bH = b?.hashCode;
67
+ const ha = (aH !== undefined) ? aH : hashValue(a);
68
+ const hb = (bH !== undefined) ? bH : hashValue(b);
69
+ if (ha !== hb)
70
+ return ha < hb ? -1 : 1;
71
+ // 2. Primitive Value Check
72
+ const typeA = typeof a;
73
+ const typeB = typeof b;
74
+ if (typeA === 'string' && typeB === 'string')
75
+ return a < b ? -1 : 1;
76
+ if (typeA === 'number' && typeB === 'number')
77
+ return a < b ? -1 : 1;
78
+ // 3. Structural Type Check
79
+ const isSetA = a instanceof RecursiveSet;
80
+ const isSetB = b instanceof RecursiveSet;
81
+ if (isSetA && isSetB) {
82
+ return a.compare(b);
27
83
  }
28
- get(index) {
29
- return this.values[index];
84
+ const isArrA = Array.isArray(a);
85
+ const isArrB = Array.isArray(b);
86
+ const isTupA = a instanceof Tuple;
87
+ const isTupB = b instanceof Tuple;
88
+ const isSeqA = isArrA || isTupA;
89
+ const isSeqB = isArrB || isTupB;
90
+ // Sort by Type Group if types differ
91
+ if (isSetA !== isSetB || isSeqA !== isSeqB) {
92
+ const scoreA = isSetA ? 2 : isSeqA ? 1 : 0;
93
+ const scoreB = isSetB ? 2 : isSeqB ? 1 : 0;
94
+ return scoreA - scoreB;
30
95
  }
31
- *[Symbol.iterator]() {
32
- for (const val of this.values) {
33
- yield val;
96
+ // 4. Sequence Comparison (Array/Tuple)
97
+ if (isSeqA && isSeqB) {
98
+ const valA = isTupA ? a.values : a;
99
+ const valB = isTupB ? b.values : b;
100
+ const len = valA.length;
101
+ if (len !== valB.length)
102
+ return len - valB.length;
103
+ for (let i = 0; i < len; i++) {
104
+ const diff = compare(valA[i], valB[i]);
105
+ if (diff !== 0)
106
+ return diff;
34
107
  }
108
+ return 0;
35
109
  }
36
- toString() {
37
- return `(${this.values.map(v => String(v)).join(', ')})`;
38
- }
39
- [Symbol.for('nodejs.util.inspect.custom')]() {
40
- return this.toString();
110
+ // Fallback for safe types
111
+ return a < b ? -1 : 1;
112
+ }
113
+ // === CLASSES ===
114
+ /**
115
+ * Immutable wrapper for sequence values.
116
+ * Useful when strict typing for sequences is required.
117
+ */
118
+ class Tuple {
119
+ values;
120
+ hashCode;
121
+ constructor(...values) {
122
+ this.values = values;
123
+ this.hashCode = hashValue(values);
41
124
  }
125
+ get length() { return this.values.length; }
126
+ get(i) { return this.values[i]; }
127
+ *[Symbol.iterator]() { yield* this.values; }
128
+ toString() { return `(${this.values.join(', ')})`; }
129
+ [Symbol.for('nodejs.util.inspect.custom')]() { return this.toString(); }
42
130
  }
43
131
  exports.Tuple = Tuple;
132
+ /**
133
+ * A Set implementation that supports deep structural equality and efficient hashing.
134
+ * Internally backed by a sorted array for optimal CPU cache locality on small sets.
135
+ */
44
136
  class RecursiveSet {
45
- _tree;
46
137
  /**
47
- * Static comparator for Red-Black Tree ordering.
48
- * Supports Primitives, RecursiveSets and Tuples.
49
- * REJECTS plain JS Objects and Arrays to enforce strict semantics.
138
+ * Internal storage. Public for inlining access within the module, but treated as private API.
50
139
  */
51
- static compare(a, b) {
52
- if (a === b)
53
- return 0;
54
- const isSetA = a instanceof RecursiveSet;
55
- const isSetB = b instanceof RecursiveSet;
56
- const isTupA = a instanceof Tuple;
57
- const isTupB = b instanceof Tuple;
58
- // Sort Order: Primitives (0) < Tuples (1) < Sets (2)
59
- const getTypeScore = (isSet, isTup) => {
60
- if (isSet)
61
- return 2;
62
- if (isTup)
63
- return 1;
64
- return 0;
65
- };
66
- const scoreA = getTypeScore(isSetA, isTupA);
67
- const scoreB = getTypeScore(isSetB, isTupB);
68
- if (scoreA !== scoreB)
69
- return scoreA < scoreB ? -1 : 1;
70
- // 1. Sets
71
- if (isSetA && isSetB) {
72
- const setA = a;
73
- const setB = b;
74
- if (setA.size !== setB.size)
75
- return setA.size < setB.size ? -1 : 1;
76
- let iterA = setA._tree.begin;
77
- let iterB = setB._tree.begin;
78
- while (iterA.valid && iterB.valid) {
79
- const cmp = RecursiveSet.compare(iterA.key, iterB.key);
80
- if (cmp !== 0)
81
- return cmp;
82
- iterA.next();
83
- iterB.next();
84
- }
85
- return 0;
140
+ _elements;
141
+ _hashCode = null;
142
+ static compare(a, b) { return compare(a, b); }
143
+ constructor(...elements) {
144
+ if (elements.length === 0) {
145
+ this._elements = [];
146
+ this._hashCode = 0;
86
147
  }
87
- // 2. Tuples
88
- if (isTupA && isTupB) {
89
- const tupA = a;
90
- const tupB = b;
91
- if (tupA.length !== tupB.length)
92
- return tupA.length < tupB.length ? -1 : 1;
93
- for (let i = 0; i < tupA.length; i++) {
94
- const cmp = RecursiveSet.compare(tupA.get(i), tupB.get(i));
95
- if (cmp !== 0)
96
- return cmp;
97
- }
98
- return 0;
148
+ else {
149
+ this._elements = elements;
150
+ this._elements.sort(compare);
151
+ this._unique();
99
152
  }
100
- // 3. Primitives (guaranteed by add() validation)
101
- const tA = typeof a;
102
- const tB = typeof b;
103
- if (tA !== tB)
104
- return tA > tB ? 1 : -1;
105
- // @ts-ignore
106
- if (a < b)
107
- return -1;
108
- // @ts-ignore
109
- if (a > b)
110
- return 1;
111
- return 0;
112
153
  }
113
- constructor(...elements) {
114
- this._tree = (0, functional_red_black_tree_1.default)(RecursiveSet.compare);
115
- for (const el of elements) {
116
- this.add(el);
154
+ _unique() {
155
+ const arr = this._elements;
156
+ const len = arr.length;
157
+ if (len < 2)
158
+ return;
159
+ let write = 1;
160
+ for (let read = 1; read < len; read++) {
161
+ if (compare(arr[read], arr[read - 1]) !== 0) {
162
+ arr[write++] = arr[read];
163
+ }
117
164
  }
165
+ arr.length = write;
118
166
  }
119
- // === Copy-on-Write Support ===
120
167
  /**
121
- * Creates a shallow copy of the set in O(1) time.
168
+ * Calculates the hash code for the set.
169
+ * Uses a rolling hash over sorted elements, ensuring determinstic results for equal sets.
122
170
  */
123
- clone() {
124
- const clone = new RecursiveSet();
125
- clone._tree = this._tree;
126
- return clone;
171
+ get hashCode() {
172
+ if (this._hashCode !== null)
173
+ return this._hashCode;
174
+ let h = 0;
175
+ const arr = this._elements;
176
+ const len = arr.length;
177
+ for (let i = 0; i < len; i++) {
178
+ h = Math.imul(31, h) + hashValue(arr[i]);
179
+ }
180
+ this._hashCode = h | 0;
181
+ return this._hashCode;
182
+ }
183
+ // Backward compatibility alias
184
+ getHashCode() { return this.hashCode; }
185
+ compare(other) {
186
+ if (this === other)
187
+ return 0;
188
+ const h1 = this.hashCode;
189
+ const h2 = other.hashCode;
190
+ if (h1 !== h2)
191
+ return h1 < h2 ? -1 : 1;
192
+ const arrA = this._elements;
193
+ const arrB = other._elements;
194
+ const len = arrA.length;
195
+ if (len !== arrB.length)
196
+ return len - arrB.length;
197
+ for (let i = 0; i < len; i++) {
198
+ const cmp = compare(arrA[i], arrB[i]);
199
+ if (cmp !== 0)
200
+ return cmp;
201
+ }
202
+ return 0;
203
+ }
204
+ get size() { return this._elements.length; }
205
+ isEmpty() { return this._elements.length === 0; }
206
+ has(element) {
207
+ const arr = this._elements;
208
+ const len = arr.length;
209
+ // Small Array Optimization: Linear Scan is faster than Binary Search overhead for N < 16
210
+ if (len < 16) {
211
+ for (let i = 0; i < len; i++) {
212
+ if (compare(arr[i], element) === 0)
213
+ return true;
214
+ }
215
+ return false;
216
+ }
217
+ let low = 0, high = len - 1;
218
+ while (low <= high) {
219
+ const mid = (low + high) >>> 1;
220
+ const cmp = compare(arr[mid], element);
221
+ if (cmp === 0)
222
+ return true;
223
+ if (cmp < 0)
224
+ low = mid + 1;
225
+ else
226
+ high = mid - 1;
227
+ }
228
+ return false;
127
229
  }
128
- // === Mutable Operations ===
129
230
  add(element) {
130
- // Validation
131
- if (typeof element === "number" && Number.isNaN(element)) {
231
+ // --- Validation Check ---
232
+ if (typeof element === 'object' && element !== null) {
233
+ const isSet = element instanceof RecursiveSet;
234
+ const isTup = element instanceof Tuple;
235
+ const isArr = Array.isArray(element);
236
+ if (!isSet && !isTup && !isArr) {
237
+ throw new Error("Plain Objects are not supported. Use Tuple, Array or RecursiveSet.");
238
+ }
239
+ }
240
+ else if (typeof element === "number" && Number.isNaN(element)) {
132
241
  throw new Error("NaN is not supported");
133
242
  }
134
- const isSet = element instanceof RecursiveSet;
135
- const isTup = element instanceof Tuple;
136
- const isObject = element !== null && typeof element === 'object' && !isSet && !isTup;
137
- if (isObject) {
138
- throw new Error("Plain Objects and Arrays are not supported. " +
139
- "Use Tuple for sequences or RecursiveSet for nested structures.");
243
+ // --- End Validation ---
244
+ const arr = this._elements;
245
+ const len = arr.length;
246
+ // Common Case: Appending a larger element (during ordered construction)
247
+ if (len > 0) {
248
+ const lastCmp = compare(arr[len - 1], element);
249
+ if (lastCmp < 0) {
250
+ arr.push(element);
251
+ this._hashCode = null;
252
+ return this;
253
+ }
254
+ if (lastCmp === 0)
255
+ return this;
256
+ }
257
+ else {
258
+ arr.push(element);
259
+ this._hashCode = null;
260
+ return this;
140
261
  }
141
- // Idempotency
142
- if (this.has(element))
262
+ // Small Array Strategy: Linear Scan + Splice
263
+ if (len < 16) {
264
+ for (let i = 0; i < len; i++) {
265
+ const cmp = compare(arr[i], element);
266
+ if (cmp === 0)
267
+ return this;
268
+ if (cmp > 0) {
269
+ arr.splice(i, 0, element);
270
+ this._hashCode = null;
271
+ return this;
272
+ }
273
+ }
143
274
  return this;
144
- this._tree = this._tree.insert(element, true);
275
+ }
276
+ // Large Array Strategy: Binary Search
277
+ let low = 0, high = len - 1, idx = 0;
278
+ while (low <= high) {
279
+ const mid = (low + high) >>> 1;
280
+ const cmp = compare(arr[mid], element);
281
+ if (cmp === 0)
282
+ return this;
283
+ if (cmp < 0) {
284
+ idx = mid + 1;
285
+ low = mid + 1;
286
+ }
287
+ else {
288
+ idx = mid;
289
+ high = mid - 1;
290
+ }
291
+ }
292
+ arr.splice(idx, 0, element);
293
+ this._hashCode = null;
145
294
  return this;
146
295
  }
147
296
  remove(element) {
148
- this._tree = this._tree.remove(element);
297
+ const arr = this._elements;
298
+ const len = arr.length;
299
+ if (len < 16) {
300
+ for (let i = 0; i < len; i++) {
301
+ if (compare(arr[i], element) === 0) {
302
+ arr.splice(i, 1);
303
+ this._hashCode = null;
304
+ return this;
305
+ }
306
+ }
307
+ return this;
308
+ }
309
+ let low = 0, high = len - 1;
310
+ while (low <= high) {
311
+ const mid = (low + high) >>> 1;
312
+ const cmp = compare(arr[mid], element);
313
+ if (cmp === 0) {
314
+ arr.splice(mid, 1);
315
+ this._hashCode = null;
316
+ return this;
317
+ }
318
+ if (cmp < 0)
319
+ low = mid + 1;
320
+ else
321
+ high = mid - 1;
322
+ }
149
323
  return this;
150
324
  }
151
325
  clear() {
152
- this._tree = (0, functional_red_black_tree_1.default)(RecursiveSet.compare);
326
+ this._elements = [];
327
+ this._hashCode = 0;
153
328
  return this;
154
329
  }
155
- // === Set Operations ===
330
+ clone() {
331
+ const s = new RecursiveSet();
332
+ s._elements = this._elements.slice();
333
+ s._hashCode = this._hashCode;
334
+ return s;
335
+ }
156
336
  union(other) {
157
- const result = this.clone();
158
- for (const el of other)
159
- result.add(el);
160
- return result;
337
+ const s = new RecursiveSet();
338
+ const arrA = this._elements;
339
+ const arrB = other._elements;
340
+ if (arrA.length === 0)
341
+ return other.clone();
342
+ if (arrB.length === 0)
343
+ return this.clone();
344
+ const res = [];
345
+ let i = 0, j = 0;
346
+ const lenA = arrA.length, lenB = arrB.length;
347
+ // Merge Sort Algorithm O(N + M)
348
+ while (i < lenA && j < lenB) {
349
+ const cmp = compare(arrA[i], arrB[j]);
350
+ if (cmp < 0)
351
+ res.push(arrA[i++]);
352
+ else if (cmp > 0)
353
+ res.push(arrB[j++]);
354
+ else {
355
+ res.push(arrA[i++]);
356
+ j++;
357
+ }
358
+ }
359
+ while (i < lenA)
360
+ res.push(arrA[i++]);
361
+ while (j < lenB)
362
+ res.push(arrB[j++]);
363
+ s._elements = res;
364
+ return s;
161
365
  }
162
366
  intersection(other) {
163
- const result = new RecursiveSet();
164
- const [smaller, larger] = this.size < other.size ? [this, other] : [other, this];
165
- for (const el of smaller) {
166
- if (larger.has(el)) {
167
- result.add(el);
367
+ const s = new RecursiveSet();
368
+ const arrA = this._elements;
369
+ const arrB = other._elements;
370
+ const res = [];
371
+ let i = 0, j = 0;
372
+ const lenA = arrA.length, lenB = arrB.length;
373
+ while (i < lenA && j < lenB) {
374
+ const cmp = compare(arrA[i], arrB[j]);
375
+ if (cmp < 0)
376
+ i++;
377
+ else if (cmp > 0)
378
+ j++;
379
+ else {
380
+ res.push(arrA[i++]);
381
+ j++;
168
382
  }
169
383
  }
170
- return result;
384
+ s._elements = res;
385
+ return s;
171
386
  }
172
387
  difference(other) {
173
- const result = new RecursiveSet();
174
- for (const el of this) {
175
- if (!other.has(el)) {
176
- result.add(el);
388
+ const s = new RecursiveSet();
389
+ const arrA = this._elements;
390
+ const arrB = other._elements;
391
+ const res = [];
392
+ let i = 0, j = 0;
393
+ const lenA = arrA.length, lenB = arrB.length;
394
+ while (i < lenA && j < lenB) {
395
+ const cmp = compare(arrA[i], arrB[j]);
396
+ if (cmp < 0)
397
+ res.push(arrA[i++]);
398
+ else if (cmp > 0)
399
+ j++;
400
+ else {
401
+ i++;
402
+ j++;
177
403
  }
178
404
  }
179
- return result;
405
+ while (i < lenA)
406
+ res.push(arrA[i++]);
407
+ s._elements = res;
408
+ return s;
180
409
  }
181
410
  symmetricDifference(other) {
182
- return this.difference(other).union(other.difference(this));
411
+ const s = new RecursiveSet();
412
+ const arrA = this._elements;
413
+ const arrB = other._elements;
414
+ const res = [];
415
+ let i = 0, j = 0;
416
+ const lenA = arrA.length, lenB = arrB.length;
417
+ while (i < lenA && j < lenB) {
418
+ const cmp = compare(arrA[i], arrB[j]);
419
+ if (cmp < 0)
420
+ res.push(arrA[i++]);
421
+ else if (cmp > 0)
422
+ res.push(arrB[j++]);
423
+ else {
424
+ i++;
425
+ j++;
426
+ }
427
+ }
428
+ while (i < lenA)
429
+ res.push(arrA[i++]);
430
+ while (j < lenB)
431
+ res.push(arrB[j++]);
432
+ s._elements = res;
433
+ return s;
183
434
  }
184
435
  powerset() {
185
436
  const n = this.size;
186
- if (n > 30)
187
- throw new Error("Powerset size exceeds 32-bit integer limit");
188
- const elements = [];
189
- this._tree.forEach((key) => { elements.push(key); });
437
+ if (n > 20)
438
+ throw new Error("Powerset too large");
190
439
  const subsets = [];
191
- for (let i = 0; i < (1 << n); i++) {
440
+ const max = 1 << n;
441
+ for (let i = 0; i < max; i++) {
192
442
  const subset = new RecursiveSet();
193
443
  for (let j = 0; j < n; j++) {
194
- if (i & (1 << j)) {
195
- subset.add(elements[j]);
196
- }
444
+ if (i & (1 << j))
445
+ subset._elements.push(this._elements[j]);
197
446
  }
198
447
  subsets.push(subset);
199
448
  }
200
449
  return new RecursiveSet(...subsets);
201
450
  }
202
- /**
203
- * Returns the Cartesian product as a set of Tuples.
204
- * Uses the Tuple class to ensure structural equality.
205
- */
206
451
  cartesianProduct(other) {
207
452
  const result = new RecursiveSet();
208
- for (const x of this) {
209
- for (const y of other) {
210
- result.add(new Tuple(x, y));
453
+ const arrA = this._elements;
454
+ const arrB = other._elements;
455
+ for (const x of arrA) {
456
+ for (const y of arrB) {
457
+ result._elements.push(new Tuple(x, y));
211
458
  }
212
459
  }
213
460
  return result;
214
461
  }
215
- // === Predicates ===
216
- has(element) {
217
- return this._tree.get(element) !== undefined;
218
- }
462
+ // Standard Set methods
219
463
  isSubset(other) {
220
464
  if (this.size > other.size)
221
465
  return false;
222
- for (const el of this) {
223
- if (!other.has(el))
466
+ let i = 0, j = 0;
467
+ const arrA = this._elements, arrB = other._elements;
468
+ while (i < arrA.length && j < arrB.length) {
469
+ const cmp = compare(arrA[i], arrB[j]);
470
+ if (cmp < 0)
224
471
  return false;
472
+ if (cmp > 0)
473
+ j++;
474
+ else {
475
+ i++;
476
+ j++;
477
+ }
225
478
  }
226
- return true;
227
- }
228
- isSuperset(other) {
229
- return other.isSubset(this);
230
- }
231
- isProperSubset(other) {
232
- return this.isSubset(other) && !this.equals(other);
233
- }
234
- isEmpty() {
235
- return this.size === 0;
236
- }
237
- equals(other) {
238
- return RecursiveSet.compare(this, other) === 0;
239
- }
240
- // === Utility ===
241
- get size() {
242
- return this._tree.length;
243
- }
244
- toSet() {
245
- const result = new Set();
246
- this._tree.forEach((key) => { result.add(key); });
247
- return result;
248
- }
249
- // Lazy Iterator
250
- *[Symbol.iterator]() {
251
- let iter = this._tree.begin;
252
- while (iter.valid) {
253
- yield iter.key;
254
- iter.next();
255
- }
479
+ return i === arrA.length;
256
480
  }
481
+ isSuperset(other) { return other.isSubset(this); }
482
+ isProperSubset(other) { return this.isSubset(other) && this.size < other.size; }
483
+ equals(other) { return this.compare(other) === 0; }
484
+ toSet() { return new Set(this._elements); }
485
+ *[Symbol.iterator]() { yield* this._elements; }
257
486
  toString() {
258
487
  if (this.isEmpty())
259
488
  return "∅";
260
- const elements = [];
261
- this._tree.forEach((key) => {
262
- if (key instanceof RecursiveSet) {
263
- elements.push(key.toString());
264
- }
265
- else if (key instanceof Tuple) {
266
- elements.push(key.toString());
267
- }
268
- else {
269
- elements.push(String(key));
270
- }
489
+ const elementsStr = this._elements.map(el => {
490
+ if (Array.isArray(el))
491
+ return `[${el.join(', ')}]`;
492
+ return String(el);
271
493
  });
272
- return `{${elements.join(", ")}}`;
273
- }
274
- [Symbol.for('nodejs.util.inspect.custom')]() {
275
- return this.toString();
494
+ return `{${elementsStr.join(', ')}}`;
276
495
  }
496
+ [Symbol.for('nodejs.util.inspect.custom')]() { return this.toString(); }
277
497
  }
278
498
  exports.RecursiveSet = RecursiveSet;
279
- // === Helpers ===
280
- function emptySet() {
281
- return new RecursiveSet();
282
- }
283
- function singleton(element) {
284
- return new RecursiveSet(element);
285
- }
286
- function fromIterable(iterable) {
287
- return new RecursiveSet(...iterable);
288
- }
499
+ function emptySet() { return new RecursiveSet(); }
500
+ function singleton(element) { return new RecursiveSet(element); }
501
+ function fromIterable(iterable) { return new RecursiveSet(...iterable); }
289
502
  //# sourceMappingURL=index.js.map