@isopodlabs/utilities 1.5.7 → 1.5.9

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/bits.d.ts CHANGED
@@ -1,20 +1,26 @@
1
1
  export declare function lowestSet32(x: number): number;
2
2
  export declare function highestSet32(x: number): number;
3
3
  export declare function countSet32(x: number): number;
4
+ export declare function nthSet32(x: number, i: number): number;
4
5
  export declare function highestSet(x: bigint | number): number;
5
6
  export declare function lowestSet(x: number | bigint): number;
6
7
  export declare function countSet(x: bigint | number): number;
8
+ export declare function nthSet(x: bigint | number, i: number): number;
7
9
  export declare function highestClear(x: number | bigint): number;
8
10
  export declare function lowestClear(x: number | bigint): number;
9
11
  export declare function countClear(x: bigint | number): number;
12
+ export declare function clearLowest(x: bigint): bigint;
13
+ export declare function clearLowest(x: number): number;
14
+ export declare function clearLowest(x: bigint | number): bigint | number;
10
15
  export interface immutableBitSet {
16
+ test(a: number): boolean;
11
17
  countSet(): number;
18
+ nthSet(a: number): number;
12
19
  complement(): this;
13
20
  intersect(other: this): this;
14
21
  union(other: this): this;
15
22
  xor(other: this): this;
16
23
  contains(other: this): boolean;
17
- test(a: number): boolean;
18
24
  next(a: number, set: boolean): number;
19
25
  where(set: boolean, from?: number): {
20
26
  [Symbol.iterator](): Generator<number>;
@@ -22,6 +28,7 @@ export interface immutableBitSet {
22
28
  ranges(): {
23
29
  [Symbol.iterator](): Generator<number[]>;
24
30
  };
31
+ [Symbol.iterator](): Generator<number>;
25
32
  }
26
33
  export interface BitSet extends immutableBitSet {
27
34
  set(a: number): void;
@@ -44,16 +51,15 @@ export declare class ImmutableSparseBits implements immutableBitSet {
44
51
  static fromEntries<T extends ImmutableSparseBits>(this: new (initial?: boolean) => T, entries: Record<number, number> | [number, number][], initial?: boolean): T;
45
52
  keys(): number[];
46
53
  entries(): [number, number][];
54
+ test(a: number): boolean;
55
+ countSet(): number;
56
+ nthSet(a: number): number;
47
57
  complement(): this;
48
58
  intersect(other: ImmutableSparseBits): this;
49
59
  union(other: ImmutableSparseBits): this;
50
60
  xor(other: ImmutableSparseBits): this;
51
- clean(): this;
52
61
  contains(other: ImmutableSparseBits): boolean;
53
- test(a: number): boolean;
54
- countSet(): number;
55
62
  next(a: number, set?: boolean): number;
56
- toDense(): DenseBits;
57
63
  where(set: boolean, from?: number): {
58
64
  [Symbol.iterator]: () => Generator<number, any, any>;
59
65
  };
@@ -61,33 +67,35 @@ export declare class ImmutableSparseBits implements immutableBitSet {
61
67
  [Symbol.iterator](): Generator<number[]>;
62
68
  };
63
69
  [Symbol.iterator](): Generator<number>;
70
+ clean(): this;
71
+ toDense(): DenseBits;
64
72
  }
65
73
  export declare class SparseBits extends ImmutableSparseBits implements BitSet {
66
74
  private setMask;
67
75
  private clearMask;
68
- selfComplement(): this;
69
- selfIntersect(other: SparseBits): this;
70
- selfUnion(other: SparseBits): this;
71
- selfXor(other: SparseBits): this;
72
76
  set(a: number): void;
73
77
  clear(a: number): void;
74
- test(a: number): boolean;
75
78
  setRange(a: number, b: number): this;
76
79
  clearRange(a: number, b: number): this;
80
+ selfComplement(): this;
81
+ selfIntersect(other: SparseBits): this;
82
+ selfUnion(other: SparseBits): this;
83
+ selfXor(other: SparseBits): this;
77
84
  }
78
85
  export declare class ImmutableDenseBits implements immutableBitSet {
79
86
  protected bits: bigint;
80
87
  constructor(bits?: bigint);
81
88
  protected create(bits?: bigint): this;
89
+ get length(): number;
90
+ test(a: number): boolean;
91
+ countSet(): number;
92
+ nthSet(a: number): number;
82
93
  complement(): this;
83
94
  intersect(other: ImmutableDenseBits): this;
84
95
  union(other: ImmutableDenseBits): this;
85
96
  xor(other: ImmutableDenseBits): this;
86
- test(a: number): boolean;
87
97
  contains(other: this): boolean;
88
98
  next(a: number, set?: boolean): number;
89
- countSet(): number;
90
- get length(): number;
91
99
  where(set: boolean, from?: number): {
92
100
  [Symbol.iterator](): Generator<number>;
93
101
  };
@@ -98,14 +106,14 @@ export declare class ImmutableDenseBits implements immutableBitSet {
98
106
  toSparse(): SparseBits;
99
107
  }
100
108
  export declare class DenseBits extends ImmutableDenseBits implements BitSet {
101
- private setMask;
102
- private clearMask;
103
- selfComplement(): this;
104
- selfIntersect(other: DenseBits): this;
105
- selfUnion(other: DenseBits): this;
106
- selfXor(other: DenseBits): this;
109
+ protected setMask(m: bigint): void;
110
+ protected clearMask(m: bigint): void;
107
111
  set(a: number): void;
108
112
  clear(a: number): void;
109
113
  setRange(a: number, b: number): this;
110
114
  clearRange(a: number, b: number): this;
115
+ selfComplement(): this;
116
+ selfIntersect(other: DenseBits): this;
117
+ selfUnion(other: DenseBits): this;
118
+ selfXor(other: DenseBits): this;
111
119
  }
package/dist/bits.js CHANGED
@@ -4,27 +4,63 @@ exports.DenseBits = exports.ImmutableDenseBits = exports.SparseBits = exports.Im
4
4
  exports.lowestSet32 = lowestSet32;
5
5
  exports.highestSet32 = highestSet32;
6
6
  exports.countSet32 = countSet32;
7
+ exports.nthSet32 = nthSet32;
7
8
  exports.highestSet = highestSet;
8
9
  exports.lowestSet = lowestSet;
9
10
  exports.countSet = countSet;
11
+ exports.nthSet = nthSet;
10
12
  exports.highestClear = highestClear;
11
13
  exports.lowestClear = lowestClear;
12
14
  exports.countClear = countClear;
15
+ exports.clearLowest = clearLowest;
13
16
  const algorithm_1 = require("./algorithm");
14
17
  //-----------------------------------------------------------------------------
15
18
  // Bit twiddling functions
16
19
  //-----------------------------------------------------------------------------
20
+ // Returns the index (0-31) of the lowest set bit, or 32 if none
17
21
  function lowestSet32(x) {
18
22
  return x === 0 ? 32 : 31 - Math.clz32(x & -x);
19
23
  }
24
+ // Returns the index (1-32) of the highest set bit, or 0 if none
20
25
  function highestSet32(x) {
21
26
  return x ? 32 - Math.clz32(x) : 0;
22
27
  }
28
+ // Returns the number of set bits
23
29
  function countSet32(x) {
24
30
  x = x - ((x >> 1) & 0x55555555);
25
31
  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
26
32
  return ((x + (x >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
27
33
  }
34
+ // Returns the index (0-31) of the nth set bit, or 32 if none
35
+ function nthSet32(x, i) {
36
+ let b2 = x - ((x >> 1) & 0x55555555);
37
+ let b4 = (b2 & 0x33333333) + ((b2 >> 2) & 0x33333333);
38
+ let b8 = (b4 + (b4 >> 4) & 0xF0F0F0F);
39
+ let b16 = (b8 + (b8 >> 8)) & 0xff;
40
+ let n = 0;
41
+ if (i >= b16) {
42
+ i -= b16;
43
+ n += 16;
44
+ }
45
+ b8 = (b8 >> n) & 0xff;
46
+ if (i >= b8) {
47
+ i -= b8;
48
+ n += 8;
49
+ }
50
+ b4 = (b4 >> n) & 0x0f;
51
+ if (i >= b4) {
52
+ i -= b4;
53
+ n += 4;
54
+ }
55
+ b2 = (b2 >> n) & 0x03;
56
+ if (i >= b2) {
57
+ i -= b2;
58
+ n += 2;
59
+ }
60
+ if (i >= ((x >> n) & 1))
61
+ ++n;
62
+ return n;
63
+ }
28
64
  /*
29
65
  const testersShift: bigint[] = []; //32 << i
30
66
  const testers: bigint[] = []; //1 << (32 << i)
@@ -85,42 +121,45 @@ export function bitcountCached(x: bigint): number {
85
121
  return Number(x & 0xFFFFFFFFn);
86
122
  }
87
123
  */
88
- function highestSet(x) {
89
- if (x < 0)
90
- x = ~x;
91
- if (x < 0x100000000)
92
- return highestSet32(Number(x));
93
- // For numbers within safe float range, use log2
94
- if (x <= Number.MAX_VALUE) {
95
- const b = Math.floor(Math.log2(Number(x)));
96
- return (1n << BigInt(b)) <= x ? b + 1 : b;
97
- }
98
- // For arbitrarily large bigints, use bit-shifting method
99
- let y = BigInt(x);
124
+ function highestSetBig(x) {
100
125
  let s = 0;
101
126
  let k = 0;
102
- for (let t = y >> 32n; t; t >>= BigInt(s)) {
127
+ for (let t = x >> 32n; t; t >>= BigInt(s)) {
103
128
  s = 32 << k++;
104
- y = t;
129
+ x = t;
105
130
  }
106
131
  if (k) {
107
132
  // determine length by bisection
108
133
  k--;
109
134
  while (k--) {
110
- const b = y >> BigInt(32 << k);
135
+ const b = x >> BigInt(32 << k);
111
136
  if (b) {
112
137
  s += 32 << k;
113
- y = b;
138
+ x = b;
114
139
  }
115
140
  }
116
141
  }
117
- return (s + 32) - Math.clz32(Number(y));
142
+ return (s + 32) - Math.clz32(Number(x));
143
+ }
144
+ function highestSet(x) {
145
+ if (x < 0)
146
+ x = ~x;
147
+ if (x < 0x100000000)
148
+ return highestSet32(Number(x));
149
+ // For < 1024 bits, use log2
150
+ if (x <= Number.MAX_VALUE) {
151
+ const b = Math.floor(Math.log2(Number(x)));
152
+ return (1n << BigInt(b)) <= x ? b + 1 : b;
153
+ }
154
+ return highestSetBig(BigInt(x));
118
155
  }
119
156
  function lowestSet(x) {
157
+ if (x < 0)
158
+ x = ~x;
120
159
  if (x < 0x100000000)
121
160
  return lowestSet32(Number(x));
122
- const xb = BigInt(x < 0 ? ~x : x);
123
- return highestSet(xb & -xb) - 1;
161
+ x = BigInt(x);
162
+ return highestSetBig(x & -x) - 1;
124
163
  }
125
164
  function countSet(x) {
126
165
  if (x < 0)
@@ -133,9 +172,9 @@ function countSet(x) {
133
172
  t >>= BigInt(1 << k++);
134
173
  const n = 1 << k;
135
174
  const limit = 1n << BigInt(n);
136
- let i = 1;
137
- for (; i < k; i <<= 1) {
138
- const bi = BigInt(i);
175
+ let s = 1;
176
+ for (; s < k; s <<= 1) {
177
+ const bi = BigInt(s);
139
178
  const mask = limit / ((1n << bi) + 1n);
140
179
  x = (x & mask) + ((x >> bi) & mask);
141
180
  }
@@ -143,19 +182,60 @@ function countSet(x) {
143
182
  //const mask = limit / ((1n << bi) - 1n);
144
183
  //x = (x * mask) >> BigInt(n - i);
145
184
  //we can skip the masking when the total can fit
146
- for (; i < n; i <<= 1)
147
- x += x >> BigInt(i);
148
- return Number(x & 0xffffffffn);
185
+ for (; s < n; s <<= 1)
186
+ x += x >> BigInt(s);
187
+ return Number(x & ((1n << BigInt(k)) - 1n));
188
+ }
189
+ function nthSet(x, i) {
190
+ if (x < 0)
191
+ x = ~x;
192
+ if (x < 0x100000000)
193
+ return nthSet32(Number(x), i);
194
+ x = BigInt(x);
195
+ let k = 5;
196
+ for (let t = x >> 32n; t;)
197
+ t >>= BigInt(1 << k++);
198
+ const limit = 1n << BigInt(1 << k);
199
+ const counts = [];
200
+ counts.push(x);
201
+ let s = 1;
202
+ for (; s < k; s <<= 1) {
203
+ const bi = BigInt(s);
204
+ const mask = limit / ((1n << bi) + 1n);
205
+ x = (x & mask) + ((x >> bi) & mask);
206
+ counts.push(x);
207
+ }
208
+ while (counts.length < k) {
209
+ x += x >> BigInt(s);
210
+ counts.push(x);
211
+ s <<= 1;
212
+ }
213
+ let n = 0;
214
+ for (let j = k; j--;) {
215
+ const s = 1 << j;
216
+ const b = Number((counts[j] >> BigInt(n)) & 0xffffffffn) & (s * 2 - 1);
217
+ if (i >= b) {
218
+ i -= b;
219
+ n += s;
220
+ }
221
+ }
222
+ return n;
149
223
  }
224
+ // Returns the index of the highest clear bit
150
225
  function highestClear(x) {
151
226
  return highestSet(~x);
152
227
  }
228
+ // Returns the index of the lowest clear bit
153
229
  function lowestClear(x) {
154
230
  return lowestSet(~x);
155
231
  }
232
+ // Returns the number of clear bits
156
233
  function countClear(x) {
157
234
  return countSet(~x);
158
235
  }
236
+ function clearLowest(x) {
237
+ return typeof x === 'bigint' ? x & (x - 1n) : x & (x - 1);
238
+ }
159
239
  //-----------------------------------------------------------------------------
160
240
  // SparseBits - a sparse bitset implementation, where each entry in the 'bits' array represents 32 bits
161
241
  // The 'undef' member indicates whether undefined entries are treated as 0 or 0xffffffff
@@ -238,6 +318,42 @@ class ImmutableSparseBits {
238
318
  //return this.bits;
239
319
  return Object.entries(this.bits).map(([k, v]) => [+k, v]);
240
320
  }
321
+ test(a) {
322
+ return !!((this.bits[a >> 5] ?? this.undef) & (1 << (a & 0x1f)));
323
+ }
324
+ countSet() {
325
+ let count = 0;
326
+ for (const i in this.bits)
327
+ count += countSet32(this.bits[i]);
328
+ return count;
329
+ }
330
+ nthSet(a) {
331
+ if (this.undef === 0) {
332
+ for (const i in this.bits) {
333
+ const v = this.bits[i];
334
+ const n = countSet32(v);
335
+ if (a < n)
336
+ return (+i << 5) + nthSet32(v, a);
337
+ a -= n;
338
+ }
339
+ }
340
+ else {
341
+ let prev = 0;
342
+ for (const i in this.bits) {
343
+ const m = (+i - prev) << 5;
344
+ if (a < m)
345
+ return (prev << 5) + a;
346
+ a -= m;
347
+ const v = this.bits[i];
348
+ const n = countSet32(v);
349
+ if (a < n)
350
+ return (+i << 5) + nthSet32(v, a);
351
+ a -= n;
352
+ prev = +i + 1;
353
+ }
354
+ }
355
+ return -1;
356
+ }
241
357
  complement() {
242
358
  const result = this.create(this.undef === 0);
243
359
  for (const i in this.bits)
@@ -262,13 +378,6 @@ class ImmutableSparseBits {
262
378
  result.bits[i] = this.bits[i] ^ other.bits[i];
263
379
  return this.undef ? result.flipUndefined(other) : result.copyUndefined(other);
264
380
  }
265
- clean() {
266
- for (const i in this.bits) {
267
- if (this.bits[i] === this.undef)
268
- delete this.bits[i];
269
- }
270
- return this;
271
- }
272
381
  contains(other) {
273
382
  if (other.undef && !this.undef)
274
383
  return false;
@@ -278,15 +387,6 @@ class ImmutableSparseBits {
278
387
  }
279
388
  return true;
280
389
  }
281
- test(a) {
282
- return !!((this.bits[a >> 5] ?? this.undef) & (1 << (a & 0x1f)));
283
- }
284
- countSet() {
285
- let count = 0;
286
- for (const i in this.bits)
287
- count += countSet32(this.bits[i]);
288
- return count;
289
- }
290
390
  next(a, set = true) {
291
391
  ++a;
292
392
  const xor = this.undef;
@@ -323,19 +423,6 @@ class ImmutableSparseBits {
323
423
  return (i << 5) + lowestSet32(~v);
324
424
  }
325
425
  }
326
- toDense() {
327
- let bits = 0n;
328
- if (this.undef) {
329
- for (const i in this.bits)
330
- bits |= BigInt(~this.bits[i]) << BigInt(+i * 32);
331
- bits = ~bits;
332
- }
333
- else {
334
- for (const i in this.bits)
335
- bits |= BigInt(this.bits[i]) << BigInt(+i * 32);
336
- }
337
- return new DenseBits(bits);
338
- }
339
426
  where(set, from = -1) {
340
427
  return {
341
428
  [Symbol.iterator]: () => ImmutableSparseBits.whereGenerator(this.bits, this.undef, set, from)
@@ -382,6 +469,26 @@ class ImmutableSparseBits {
382
469
  //for (let i = this.next(-1); i !== -1; i = this.next(i))
383
470
  // yield i;
384
471
  }
472
+ clean() {
473
+ for (const i in this.bits) {
474
+ if (this.bits[i] === this.undef)
475
+ delete this.bits[i];
476
+ }
477
+ return this;
478
+ }
479
+ toDense() {
480
+ let bits = 0n;
481
+ if (this.undef) {
482
+ for (const i in this.bits)
483
+ bits |= BigInt(~this.bits[i]) << BigInt(+i * 32);
484
+ bits = ~bits;
485
+ }
486
+ else {
487
+ for (const i in this.bits)
488
+ bits |= BigInt(this.bits[i]) << BigInt(+i * 32);
489
+ }
490
+ return new DenseBits(bits);
491
+ }
385
492
  }
386
493
  exports.ImmutableSparseBits = ImmutableSparseBits;
387
494
  class SparseBits extends ImmutableSparseBits {
@@ -397,48 +504,12 @@ class SparseBits extends ImmutableSparseBits {
397
504
  else if (this.undef)
398
505
  this.bits[i] = ~m;
399
506
  }
400
- selfComplement() {
401
- this.undef = ~this.undef;
402
- for (const i in this.bits)
403
- this.bits[i] = ~this.bits[i];
404
- return this;
405
- }
406
- selfIntersect(other) {
407
- for (const i in this.bits)
408
- this.bits[i] &= other.bits[i];
409
- if (this.undef)
410
- this.copyUndefined(other);
411
- this.undef &= other.undef;
412
- return this;
413
- }
414
- selfUnion(other) {
415
- for (const i in other.bits)
416
- this.bits[i] |= other.bits[i];
417
- if (!this.undef)
418
- this.copyUndefined(other);
419
- this.undef |= other.undef;
420
- return this;
421
- }
422
- selfXor(other) {
423
- for (const i in this.bits)
424
- this.bits[i] ^= other.bits[i];
425
- if (this.undef)
426
- this.flipUndefined(other);
427
- else
428
- this.copyUndefined(other);
429
- this.undef &= other.undef;
430
- return this;
431
- }
432
507
  set(a) {
433
508
  this.setMask(a >> 5, 1 << (a & 0x1f));
434
509
  }
435
510
  clear(a) {
436
511
  this.clearMask(a >> 5, 1 << (a & 0x1f));
437
512
  }
438
- test(a) {
439
- const i = a >> 5;
440
- return !!((this.bits[i] ?? this.undef) & (1 << (a & 0x1f)));
441
- }
442
513
  setRange(a, b) {
443
514
  let i = a >> 5, j = b >> 5;
444
515
  if (i === j) {
@@ -477,6 +548,38 @@ class SparseBits extends ImmutableSparseBits {
477
548
  }
478
549
  return this;
479
550
  }
551
+ selfComplement() {
552
+ this.undef = ~this.undef;
553
+ for (const i in this.bits)
554
+ this.bits[i] = ~this.bits[i];
555
+ return this;
556
+ }
557
+ selfIntersect(other) {
558
+ for (const i in this.bits)
559
+ this.bits[i] &= other.bits[i];
560
+ if (this.undef)
561
+ this.copyUndefined(other);
562
+ this.undef &= other.undef;
563
+ return this;
564
+ }
565
+ selfUnion(other) {
566
+ for (const i in other.bits)
567
+ this.bits[i] |= other.bits[i];
568
+ if (!this.undef)
569
+ this.copyUndefined(other);
570
+ this.undef |= other.undef;
571
+ return this;
572
+ }
573
+ selfXor(other) {
574
+ for (const i in this.bits)
575
+ this.bits[i] ^= other.bits[i];
576
+ if (this.undef)
577
+ this.flipUndefined(other);
578
+ else
579
+ this.copyUndefined(other);
580
+ this.undef &= other.undef;
581
+ return this;
582
+ }
480
583
  }
481
584
  exports.SparseBits = SparseBits;
482
585
  ;
@@ -491,6 +594,18 @@ class ImmutableDenseBits {
491
594
  create(bits) {
492
595
  return new this.constructor(bits);
493
596
  }
597
+ get length() {
598
+ return highestSet(this.bits);
599
+ }
600
+ test(a) {
601
+ return !!(this.bits & (1n << BigInt(a)));
602
+ }
603
+ countSet() {
604
+ return countSet(this.bits);
605
+ }
606
+ nthSet(a) {
607
+ return nthSet(this.bits, a);
608
+ }
494
609
  complement() {
495
610
  return this.create(~this.bits);
496
611
  }
@@ -503,9 +618,6 @@ class ImmutableDenseBits {
503
618
  xor(other) {
504
619
  return this.create(this.bits ^ other.bits);
505
620
  }
506
- test(a) {
507
- return !!(this.bits & (1n << BigInt(a)));
508
- }
509
621
  contains(other) {
510
622
  return (this.bits & other.bits) === other.bits;
511
623
  }
@@ -514,12 +626,6 @@ class ImmutableDenseBits {
514
626
  s = set ? s & -s : (s + 1n) & ~s;
515
627
  return s ? a + highestSet(s) : -1;
516
628
  }
517
- countSet() {
518
- return countSet(this.bits);
519
- }
520
- get length() {
521
- return highestSet(this.bits);
522
- }
523
629
  where(set, from = -1) {
524
630
  let bits = this.bits >> BigInt(from + 1);
525
631
  return {
@@ -582,6 +688,20 @@ class DenseBits extends ImmutableDenseBits {
582
688
  clearMask(m) {
583
689
  this.bits &= ~m;
584
690
  }
691
+ set(a) {
692
+ this.setMask(1n << BigInt(a));
693
+ }
694
+ clear(a) {
695
+ this.clearMask(1n << BigInt(a));
696
+ }
697
+ setRange(a, b) {
698
+ this.setMask((1n << BigInt(b)) - (1n << BigInt(a)));
699
+ return this;
700
+ }
701
+ clearRange(a, b) {
702
+ this.clearMask((1n << BigInt(b)) - (1n << BigInt(a)));
703
+ return this;
704
+ }
585
705
  selfComplement() {
586
706
  this.bits = ~this.bits;
587
707
  return this;
@@ -598,20 +718,6 @@ class DenseBits extends ImmutableDenseBits {
598
718
  this.bits ^= other.bits;
599
719
  return this;
600
720
  }
601
- set(a) {
602
- this.setMask(1n << BigInt(a));
603
- }
604
- clear(a) {
605
- this.clearMask(1n << BigInt(a));
606
- }
607
- setRange(a, b) {
608
- this.setMask((1n << BigInt(b)) - (1n << BigInt(a)));
609
- return this;
610
- }
611
- clearRange(a, b) {
612
- this.clearMask((1n << BigInt(b)) - (1n << BigInt(a)));
613
- return this;
614
- }
615
721
  }
616
722
  exports.DenseBits = DenseBits;
617
723
  ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isopodlabs/utilities",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "Various typescript helpers.",
5
5
  "repository": {
6
6
  "type": "git",