@woosh/meep-engine 2.33.25 → 2.33.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/core/binary/BitSet.js +151 -167
  2. package/core/binary/BitSet.spec.js +99 -1
  3. package/core/binary/ValidatingBitSetWrapper.js +81 -0
  4. package/core/bvh2/aabb3/AABB3.js +3 -10
  5. package/core/cache/Cache.d.ts +4 -2
  6. package/core/cache/Cache.js +5 -2
  7. package/core/collection/HashMap.d.ts +9 -2
  8. package/core/collection/HashSet.d.ts +7 -2
  9. package/core/collection/HashSet.js +7 -2
  10. package/core/collection/array/typed/typed_array_copy.js +1 -1
  11. package/core/geom/3d/frustum/array_setFromProjectionMatrix.js +3 -3
  12. package/core/geom/3d/shape/AbstractShape3D.js +28 -1
  13. package/core/geom/3d/shape/TransformedShape3D.js +65 -10
  14. package/core/geom/3d/shape/TransformedShape3D.spec.js +33 -0
  15. package/core/geom/3d/shape/{CompositeShape.js → UnionShape3D.js} +27 -12
  16. package/core/geom/3d/shape/UnitCubeShape3D.js +77 -0
  17. package/core/geom/3d/shape/UnitCubeShape3D.spec.js +42 -0
  18. package/core/geom/3d/shape/UnitSphereShape3D.js +32 -1
  19. package/core/geom/3d/shape/util/compute_signed_distance_gradient_by_sampling.js +48 -0
  20. package/core/geom/3d/shape/util/shape_to_visual_entity.js +3 -3
  21. package/core/model/ObservedBoolean.d.ts +2 -0
  22. package/core/parser/simple/Token.d.ts +13 -0
  23. package/core/parser/simple/Token.js +61 -27
  24. package/editor/tools/FoliagePaintTool.js +4 -4
  25. package/engine/asset/loaders/GLTFAssetLoader.js +52 -1
  26. package/engine/asset/loaders/image/ImageDecoderWorker.js +4 -3
  27. package/engine/asset/loaders/image/ImageRGBADataAsset.js +3 -2
  28. package/engine/asset/loaders/image/ImageRGBADataLoader.js +3 -3
  29. package/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  30. package/engine/asset/loaders/image/png/PNG.js +113 -6
  31. package/engine/asset/loaders/image/png/PNGReader.js +5 -0
  32. package/engine/asset/loaders/material/bitmap2sampler_gl.js +1 -1
  33. package/engine/asset/loaders/material/computeImageBitmapEquality.js +6 -1
  34. package/engine/asset/loaders/material/computeTextureEquality.js +40 -49
  35. package/engine/ecs/EntityComponentDataset.js +1 -1
  36. package/engine/ecs/foliage/InstancedFoliage.js +277 -266
  37. package/engine/ecs/foliage/ecs/Foliage2System.js +7 -7
  38. package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +37 -0
  39. package/engine/ecs/foliage/ecs/{Foliage2.js → InstancedMeshLayer.js} +3 -45
  40. package/engine/ecs/foliage/ecs/InstancedMeshSerializationAdapter.js +6 -5
  41. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +7 -6
  42. package/engine/ecs/storage/binary/BinarySerializationRegistry.js +1 -1
  43. package/engine/ecs/terrain/ecs/layers/TerrainLayer.js +12 -16
  44. package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +2 -2
  45. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +14 -72
  46. package/engine/graphics/geometry/instancing/rewriteMaterial.js +70 -0
  47. package/engine/graphics/material/manager/MaterialManager.js +2 -1
  48. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +6 -4
  49. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +0 -2
  50. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +1 -2
  51. package/engine/graphics/particles/particular/engine/shader/debugAtlas.js +1 -1
  52. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +12 -9
  53. package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +3 -4
  54. package/engine/graphics/render/forward_plus/materials/FPlusDebugMaterial.js +3 -3
  55. package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +1 -1
  56. package/engine/graphics/render/forward_plus/prototypeLightManager.js +4 -4
  57. package/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +10 -9
  58. package/engine/graphics/shadows/ShadowMapRenderer.js +8 -2
  59. package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +12 -1
  60. package/engine/graphics/texture/sampler/Sampler2D.js +3 -1
  61. package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +1 -1
  62. package/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js +66 -0
  63. package/engine/input/devices/KeyCodes.d.ts +1 -0
  64. package/package.json +1 -1
  65. package/view/minimap/gl/MinimapWorldGL.js +12 -5
@@ -3,55 +3,42 @@ import { max3 } from "../math/max3.js";
3
3
  import { min2 } from "../math/min2.js";
4
4
 
5
5
  /**
6
- * @readonly
7
- * @type {number[]}
6
+ * de Bruijn sequence
7
+ * @see https://graphics.stanford.edu/~seander/bithacks.html
8
+ * @type {Uint16Array}
8
9
  */
9
- const MaskSet = [
10
- 0x01,
11
- 0x02,
12
- 0x04,
13
- 0x08,
14
- 0x10,
15
- 0x20,
16
- 0x40,
17
- 0x80,
18
- ];
10
+ const msb_lut = new Uint16Array([
11
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
12
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
13
+ ]);
19
14
 
20
15
  /**
21
- *
22
- * @type {number[]}
16
+ * get most significant set bit
17
+ * @see https://graphics.stanford.edu/~seander/bithacks.html
18
+ * @param {number} v 32 bit integer
19
+ * @returns {number} integer position of most significant bit
23
20
  */
24
- const MaskClear = [];
25
- for (let i = 0; i < 8; i++) {
26
- MaskClear[i] = ~MaskSet[i];
21
+ function msb_32(v) {
22
+ v |= v >>> 1;
23
+ v |= v >>> 2;
24
+ v |= v >>> 4;
25
+ v |= v >>> 8;
26
+ v |= v >>> 16;
27
+ v = (v >>> 1) + 1;
28
+ return msb_lut[(v * 0x077CB531) >>> 27];
27
29
  }
28
30
 
29
31
  /**
30
- * Lookup table where each byte index is mapped to position of the first set bit
31
- * TODO consider bithacks: https://stackoverflow.com/questions/21623614/finding-the-first-set-bit-in-a-binary-number
32
- * http://graphics.stanford.edu/~seander/bithacks.html
33
- * @type {number[]}
32
+ * get least significant set bit
33
+ * @see https://graphics.stanford.edu/~seander/bithacks.html
34
+ * @param {number} v
35
+ * @returns {number}
34
36
  */
35
- const FirstSetBitLookup = [8];
36
- const FirstClearBitLookup = [0];
37
- FirstClearBitLookup[255] = 8;
38
-
39
- for (let i = 1; i < 256; i++) {
40
- for (let j = 0; j < 8; j++) {
41
- if ((MaskSet[j] & i) !== 0) {
42
- FirstSetBitLookup[i] = j;
43
- break;
44
- }
45
- }
46
-
47
- for (let j = 0; j < 8; j++) {
48
- if ((MaskSet[j] & i) === 0) {
49
- FirstClearBitLookup[i] = j;
50
- break;
51
- }
52
- }
37
+ function lsb_32(v) {
38
+ return msb_lut[((v & -v) * 0x077CB531) >>> 27];
53
39
  }
54
40
 
41
+
55
42
  /**
56
43
  * Used for overallocating space when bit set needs to grow
57
44
  * @constant
@@ -93,29 +80,34 @@ function BitSet() {
93
80
  this.__capacity = 64;
94
81
 
95
82
  /**
83
+ * Uint32-backed storage
84
+ * @type {Uint32Array}
96
85
  * @private
97
- * @type {Uint8Array}
98
86
  */
99
- this.__data = new Uint8Array(this.__capacity >> 3);
87
+ this.__data_uint32 = new Uint32Array(this.__capacity >> 5);
100
88
 
101
89
  /**
102
90
  *
103
91
  * @type {number}
104
92
  */
105
93
  this.__shrinkFactor = SHRINK_FACTOR;
106
-
107
- /**
108
- * Acceleration parameter. Used to speed up search for next clear bit.
109
- * @type {number}
110
- * @private
111
- */
112
- this.__firstClearBitIndex = 0;
113
94
  }
114
95
 
115
96
  BitSet.prototype.preventShrink = function () {
116
97
  this.__shrinkFactor = 0;
117
98
  }
118
99
 
100
+ /**
101
+ *
102
+ * @param {number} x
103
+ */
104
+ BitSet.prototype.setShrinkFactor = function (x) {
105
+ assert.greaterThanOrEqual(x, 0, 'x >= 0');
106
+ assert.lessThan(x, 1, 'x < 1');
107
+
108
+ this.__shrinkFactor = x;
109
+ }
110
+
119
111
  /**
120
112
  *
121
113
  * @param {number} numBits
@@ -151,54 +143,56 @@ BitSet.prototype.capacity = function () {
151
143
  BitSet.prototype.__resize = function (bitCapacity) {
152
144
  assert.isNonNegativeInteger(bitCapacity, 'bitCapacity');
153
145
 
154
- const byteCapacity = Math.ceil(bitCapacity / 8);
146
+ const uint32_capacity = Math.ceil(bitCapacity / 32);
155
147
 
156
- const oldData = this.__data;
157
- const newData = new Uint8Array(byteCapacity);
148
+ const oldData = this.__data_uint32;
149
+ const newData = new Uint32Array(uint32_capacity);
158
150
 
159
151
  //copy data from old container
160
152
 
161
153
  const oldDataSize = oldData.length;
162
154
 
163
- if (oldDataSize < byteCapacity) {
155
+ if (oldDataSize < uint32_capacity) {
164
156
  newData.set(oldData);
165
157
  } else {
166
158
  //creating a sub-array is using heap memory, so we prefer to avoid it
167
- newData.set(oldData.subarray(0, byteCapacity));
159
+ newData.set(oldData.subarray(0, uint32_capacity));
168
160
  }
169
161
 
170
- this.__data = newData;
162
+ this.__data_uint32 = newData;
171
163
 
172
- this.__capacity = byteCapacity * 8;
164
+ this.__capacity = uint32_capacity * 32;
173
165
  };
174
166
 
175
167
  /**
176
168
  *
177
- * @param {int} newLength
169
+ * @param {int} new_length
178
170
  * @private
179
171
  */
180
- BitSet.prototype.__setLength = function (newLength) {
181
- this.__length = newLength;
172
+ BitSet.prototype.__setLength = function (new_length) {
173
+ this.__length = new_length;
182
174
 
183
175
  const capacity = this.__capacity;
184
176
 
185
- if (newLength > capacity) {
177
+ if (new_length > capacity) {
186
178
 
187
- const growSize = Math.ceil(max3(newLength, capacity + RESIZE_COUNT_THRESHOLD, capacity * GROW_FACTOR));
179
+ const growSize = Math.ceil(max3(
180
+ new_length,
181
+ capacity + RESIZE_COUNT_THRESHOLD,
182
+ capacity * GROW_FACTOR
183
+ ));
188
184
 
189
185
  this.__resize(growSize);
190
186
 
191
187
  } else {
192
- if (newLength < capacity - RESIZE_COUNT_THRESHOLD && newLength < capacity * this.__shrinkFactor) {
188
+ if (
189
+ new_length < capacity - RESIZE_COUNT_THRESHOLD
190
+ && new_length < capacity * this.__shrinkFactor
191
+ ) {
193
192
 
194
- this.__resize(newLength);
193
+ this.__resize(new_length);
195
194
 
196
195
  }
197
-
198
- if (this.__firstClearBitIndex > newLength) {
199
- //update first clear bit index when shrinking
200
- this.__firstClearBitIndex = newLength;
201
- }
202
196
  }
203
197
  };
204
198
 
@@ -212,32 +206,32 @@ BitSet.prototype.previousSetBit = function (fromIndex) {
212
206
 
213
207
  const index = min2(fromIndex, this.__length - 1);
214
208
 
215
- let byteIndex = index >> 3;
216
- let bitIndex = index & 7; // modulo operation is slow, bitwise and is fast, this is the same as %8
209
+ let word_index = index >> 5;
210
+ let bit_index = index & 31; // modulo operation is slow, bitwise and is fast, this is the same as %8
217
211
 
218
- const data = this.__data;
212
+ const data = this.__data_uint32;
219
213
 
220
- let byte = data[byteIndex];
214
+ let word = data[word_index];
221
215
 
222
216
  //handle first byte separately due to potential partial traversal
223
- for (; bitIndex >= 0; bitIndex--) {
224
- if ((byte & MaskSet[bitIndex]) !== 0) {
225
- return byteIndex * 8 + bitIndex;
217
+ for (; bit_index >= 0; bit_index--) {
218
+ if ((word & (1 << bit_index)) !== 0) {
219
+ return word_index * 32 + bit_index;
226
220
  }
227
221
  }
228
222
 
229
223
  //unwind first byte
230
- byteIndex--;
224
+ word_index--;
231
225
 
232
226
  //scan the rest
233
- for (; byteIndex >= 0; byteIndex--) {
227
+ for (; word_index >= 0; word_index--) {
234
228
 
235
- byte = data[byteIndex];
229
+ word = data[word_index];
236
230
 
237
- for (bitIndex = 7; bitIndex >= 0; bitIndex--) {
231
+ for (bit_index = 31; bit_index >= 0; bit_index--) {
238
232
 
239
- if ((byte & MaskSet[bitIndex]) !== 0) {
240
- return byteIndex * 8 + bitIndex;
233
+ if ((word & (1 << bit_index)) !== 0) {
234
+ return word_index * 32 + bit_index;
241
235
  }
242
236
 
243
237
  }
@@ -255,45 +249,50 @@ BitSet.prototype.nextSetBit = function (fromIndex) {
255
249
  // assert.ok(fromIndex >= 0, `fromIndex must be greater or equal to 0, instead was ${fromIndex}`);
256
250
  // assert.ok(Number.isInteger(fromIndex), `fromIndex must be an integer, instead was ${fromIndex}`);
257
251
 
258
- const bitLength = this.__length;
259
- if (fromIndex >= bitLength) {
252
+ const bit_length = this.__length;
253
+ if (fromIndex >= bit_length) {
260
254
  //index is out of bounds, return -1
261
255
  return -1;
262
256
  }
263
257
 
264
- let byteIndex = fromIndex >> 3;
265
- let bitIndex = fromIndex & 7; //replacement for %8
258
+ const data = this.__data_uint32;
266
259
 
267
- const data = this.__data;
260
+ let word_index = fromIndex >> 5;
261
+ let word;
262
+ let bit_address;
268
263
 
269
- let byte = data[byteIndex];
270
- let bitAddress;
264
+ let bit_index = fromIndex & 31;
271
265
 
266
+ if (bit_index !== 0) {
267
+ // bit offset boundary in inside the word, we need to mask part of the word
272
268
 
273
- //handle first byte separately due to potential partial traversal
274
- for (; bitIndex < 8; bitIndex++) {
275
- if ((byte & MaskSet[bitIndex]) !== 0) {
276
- bitAddress = byteIndex * 8 + bitIndex;
269
+ const fill_mask = ~((1 << bit_index) - 1);
270
+
271
+ const masked_word = data[word_index] & fill_mask;
277
272
 
278
- return bitAddress;
273
+ if (masked_word !== 0) {
274
+ bit_index = lsb_32(masked_word);
275
+ return (word_index << 5) + bit_index;
279
276
  }
277
+
278
+ word_index++;
280
279
  }
281
280
 
282
- //unwind first byte
283
- byteIndex++;
284
281
 
285
282
  //scan the rest
286
- const byteLength = bitLength / 8;
287
- for (; byteIndex < byteLength; byteIndex++) {
288
- byte = data[byteIndex];
283
+ const word_count = bit_length / 32;
284
+ for (; word_index < word_count; word_index++) {
285
+ word = data[word_index];
286
+
287
+ if (word === 0) {
288
+ continue;
289
+ }
289
290
 
290
- const bitIndex = FirstSetBitLookup[byte];
291
+ bit_index = lsb_32(word);
291
292
 
292
- if (bitIndex < 8) {
293
- bitAddress = byteIndex * 8 + bitIndex;
293
+ bit_address = (word_index << 5) + bit_index;
294
294
 
295
- return bitAddress;
296
- }
295
+ return bit_address;
297
296
  }
298
297
 
299
298
 
@@ -309,55 +308,50 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
309
308
  //assert.ok(fromIndex >= 0, `fromIndex must be greater or equal to 0, instead was ${fromIndex}`);
310
309
  //assert.ok(Number.isInteger(fromIndex), `fromIndex must be an integer, instead was ${fromIndex}`);
311
310
 
312
- if (fromIndex <= this.__firstClearBitIndex) {
313
- return this.__firstClearBitIndex;
314
- }
311
+ let word_index = fromIndex >> 5;
315
312
 
316
- let byteIndex = fromIndex >> 3;
317
- let bitIndex = fromIndex & 7;
313
+ let word;
318
314
 
319
- let byte = this.__data[byteIndex];
320
- let bitAddress;
315
+ // treat first word specially, as we may need to mask out portion of a word to skip certain number of bits
316
+ let bit_index = fromIndex & 31;
321
317
 
318
+ const set_length = this.__length;
319
+ const word_count = set_length / 32;
320
+ const data = this.__data_uint32;
322
321
 
323
- //handle first byte separately due to potential partial traversal
324
- for (; bitIndex < 8; bitIndex++) {
325
- if ((byte & MaskSet[bitIndex]) === 0) {
326
- bitAddress = byteIndex * 8 + bitIndex;
322
+ if (bit_index !== 0) {
323
+ // bit offset boundary in inside the word, we need to mask part of the word
327
324
 
328
- if (this.__firstClearBitIndex === -1) {
329
- this.__firstClearBitIndex = bitAddress;
330
- }
325
+ word = data[word_index];
331
326
 
332
- return bitAddress;
333
- }
334
- }
327
+ const fill_mask = (1 << bit_index) - 1;
335
328
 
336
- //unwind first byte
337
- byteIndex++;
338
-
339
- //scan the rest
340
- for (; byteIndex < this.__length; byteIndex++) {
341
- byte = this.__data[byteIndex];
329
+ // apply mask and convert to uint32 via shift
330
+ const masked_word = (word | fill_mask) >>> 0;
342
331
 
343
- const firstClearBit = FirstClearBitLookup[byte];
344
- if (firstClearBit < 8) {
332
+ if (masked_word !== 4294967295) {
333
+ bit_index = lsb_32(~masked_word);
334
+ return bit_index + word_index * 32;
335
+ }
345
336
 
346
- bitAddress = byteIndex * 8 + firstClearBit;
337
+ word_index++;
338
+ }
347
339
 
348
- if (this.__firstClearBitIndex === -1) {
349
- this.__firstClearBitIndex = bitAddress;
350
- }
340
+ //scan the rest
341
+ for (; word_index < word_count; word_index++) {
342
+ word = data[word_index];
351
343
 
352
- return bitAddress;
344
+ if (word === 4294967295) {
345
+ // no 0s
346
+ continue;
353
347
  }
354
- }
355
348
 
356
- if (this.__firstClearBitIndex === -1) {
357
- this.__firstClearBitIndex = this.__length;
349
+ bit_index = lsb_32(~word);
350
+ return bit_index + word_index * 32;
351
+
358
352
  }
359
353
 
360
- return this.__length;
354
+ return set_length;
361
355
  };
362
356
 
363
357
  /**
@@ -384,11 +378,13 @@ BitSet.prototype.set = function (bitIndex, value) {
384
378
  //assert.ok(typeof bitIndex, 'number', `bitIndex must be a number, instead was '${typeof bitIndex}'`);
385
379
  //assert.ok(typeof value, 'boolean', `value must be a boolean, instead was '${typeof bitIndex}'`);
386
380
 
387
- const byteOffset = bitIndex >> 3;
388
- const bitOffset = bitIndex & 7;
381
+ const word_offset = bitIndex >> 5;
382
+ const bit_offset = bitIndex & 31;
389
383
 
390
384
  //const oldLength = this.__length;
391
385
 
386
+ const word_mask = 1 << bit_offset;
387
+
392
388
  if (value) {
393
389
  const bitIndexInc = bitIndex + 1;
394
390
 
@@ -397,31 +393,17 @@ BitSet.prototype.set = function (bitIndex, value) {
397
393
  }
398
394
 
399
395
  //set
400
- this.__data[byteOffset] |= MaskSet[bitOffset];
401
-
402
-
403
- if (bitIndex === this.__firstClearBitIndex) {
404
- if (bitIndexInc === this.__length) {
405
- //this was the end bit, move clear bit forward
406
- this.__firstClearBitIndex = this.__length;
407
- } else {
408
- //reset first clear bit index
409
- this.__firstClearBitIndex = -1;
410
- }
411
- }
396
+ this.__data_uint32[word_offset] |= word_mask;
412
397
 
413
398
 
414
399
  } else if (bitIndex < this.__length) {
415
400
  //clear
416
- this.__data[byteOffset] &= MaskClear[bitOffset];
401
+ this.__data_uint32[word_offset] &= ~word_mask;
417
402
 
418
403
  if (bitIndex === this.__length - 1) {
419
404
  const newLastSetBit = this.previousSetBit(bitIndex);
420
405
 
421
406
  this.__setLength(newLastSetBit + 1);
422
- } else if (bitIndex < this.__firstClearBitIndex) {
423
- //update first clear bit index
424
- this.__firstClearBitIndex = bitIndex;
425
407
  }
426
408
  }
427
409
 
@@ -487,12 +469,12 @@ BitSet.prototype.get = function (bitIndex) {
487
469
  return false;
488
470
  }
489
471
 
490
- const byteOffset = bitIndex >> 3;
491
- const bitOffset = bitIndex & 7;
472
+ const byteOffset = bitIndex >> 5;
473
+ const bitOffset = bitIndex & 31;
492
474
 
493
- const byte = this.__data[byteOffset];
475
+ const byte = this.__data_uint32[byteOffset];
494
476
 
495
- const maskedValue = byte & MaskSet[bitOffset];
477
+ const maskedValue = byte & (1 << bitOffset);
496
478
 
497
479
  return maskedValue !== 0;
498
480
  };
@@ -531,8 +513,7 @@ BitSet.prototype.getAndClear = function (index) {
531
513
  * Sets all of the bits in this BitSet to false.
532
514
  */
533
515
  BitSet.prototype.reset = function () {
534
- this.__data.fill(0, 0, Math.ceil(this.__length / 8));
535
- this.__firstClearBitIndex = 0;
516
+ this.__data_uint32.fill(0, 0, Math.ceil(this.__length / 32));
536
517
  this.__length = 0;
537
518
  };
538
519
 
@@ -543,7 +524,7 @@ BitSet.prototype.reset = function () {
543
524
  BitSet.prototype.copy = function (other) {
544
525
  const length = other.__length;
545
526
 
546
- const byte_size = length >> 3;
527
+ const uint32_size = length >> 5;
547
528
 
548
529
  const old_length = this.__length;
549
530
 
@@ -554,18 +535,18 @@ BitSet.prototype.copy = function (other) {
554
535
  this.__resize(length);
555
536
  } else {
556
537
  // clear everything past the target region
557
- this.__data.fill(0, byte_size);
538
+ this.__data_uint32.fill(0, uint32_size);
558
539
  }
559
540
 
560
541
  this.__length = length;
561
542
  }
562
543
 
563
544
 
564
- for (let i = 0; i < byte_size; i++) {
565
- this.__data[i] = other.__data[i];
545
+ for (let i = 0; i < uint32_size; i++) {
546
+ this.__data_uint32[i] = other.__data_uint32[i];
566
547
  }
567
548
 
568
- const byte_aligned_bit_size = byte_size << 3;
549
+ const byte_aligned_bit_size = uint32_size << 5;
569
550
 
570
551
  const overflow_bits = length - byte_aligned_bit_size;
571
552
 
@@ -574,10 +555,13 @@ BitSet.prototype.copy = function (other) {
574
555
 
575
556
  this.set(bitIndex, other.get(bitIndex));
576
557
  }
577
-
578
- this.__firstClearBitIndex = other.__firstClearBitIndex;
579
558
  };
580
559
 
560
+ /**
561
+ *
562
+ * @param {number} x
563
+ * @returns {BitSet}
564
+ */
581
565
  BitSet.fixedSize = function (x) {
582
566
  const r = new BitSet();
583
567
 
@@ -61,6 +61,20 @@ test("resizing down should throw when requested capacity is smaller than actual
61
61
  }).toThrow();
62
62
  });
63
63
 
64
+ test('previousSetBit with set bit 31', () => {
65
+ const bits = new BitSet();
66
+
67
+ bits.set(31, true);
68
+
69
+ expect(bits.previousSetBit(8)).toBe(-1);
70
+ expect(bits.previousSetBit(16)).toBe(-1);
71
+ expect(bits.previousSetBit(30)).toBe(-1);
72
+
73
+ expect(bits.previousSetBit(31)).toBe(31);
74
+ expect(bits.previousSetBit(32)).toBe(31);
75
+ expect(bits.previousSetBit(33)).toBe(31);
76
+ });
77
+
64
78
  test("previousSetBit method works correctly", () => {
65
79
  const bits = new BitSet();
66
80
 
@@ -139,6 +153,16 @@ test("nextClearBit stability", () => {
139
153
  expect(bits.nextClearBit(0)).toBe(0);
140
154
  });
141
155
 
156
+ test('nextClearBit from index 8, with 32 continuous set bits', () => {
157
+ const bits = new BitSet();
158
+
159
+ for (let i = 0; i < 32; i++) {
160
+ bits.set(i, true);
161
+ }
162
+
163
+ expect(bits.nextClearBit(8)).toBe(32);
164
+ });
165
+
142
166
  test("combination of set and clear", () => {
143
167
 
144
168
  const bits = new BitSet();
@@ -213,6 +237,33 @@ test("combination of set and clear", () => {
213
237
  expect(bits.size()).toBe(4);
214
238
  });
215
239
 
240
+ test("nextSetBit with only bit 31 set", () => {
241
+
242
+ const bits = new BitSet();
243
+
244
+ bits.set(31, true);
245
+
246
+ expect(bits.nextSetBit(0)).toBe(31);
247
+ expect(bits.nextSetBit(1)).toBe(31);
248
+ expect(bits.nextSetBit(31)).toBe(31);
249
+
250
+ expect(bits.nextSetBit(32)).toBe(-1);
251
+ });
252
+
253
+ test("nextSetBit with only bit 33 set", () => {
254
+
255
+ const bits = new BitSet();
256
+
257
+ bits.set(33, true);
258
+
259
+ expect(bits.nextSetBit(0)).toBe(33);
260
+ expect(bits.nextSetBit(1)).toBe(33);
261
+
262
+ expect(bits.nextSetBit(33)).toBe(33);
263
+
264
+ expect(bits.nextSetBit(34)).toBe(-1);
265
+ });
266
+
216
267
  test("nextSetBit method works correctly", () => {
217
268
  const bits = new BitSet();
218
269
 
@@ -353,4 +404,51 @@ test("setRange 0 to 35", () => {
353
404
 
354
405
  expect(set.nextSetBit(0)).toBe(0)
355
406
  expect(set.nextClearBit(0)).toBe(36)
356
- });
407
+ });
408
+
409
+ test('copy empty', () => {
410
+ const a = new BitSet();
411
+
412
+ const b = new BitSet();
413
+
414
+ b.copy(a);
415
+
416
+ expect(b.size()).toBe(0);
417
+ });
418
+
419
+ test('copy with only bit 33 set', () => {
420
+ const a = new BitSet();
421
+
422
+ a.set(33, true);
423
+
424
+ const b = new BitSet();
425
+
426
+ b.copy(a);
427
+
428
+ expect(b.get(32)).toBe(false);
429
+ expect(b.get(33)).toBe(true);
430
+ expect(b.get(34)).toBe(false);
431
+
432
+ expect(b.size()).toBe(34);
433
+ });
434
+
435
+ test('performance, next set from 0', () => {
436
+ const s = new BitSet();
437
+
438
+ s.set(1024, true);
439
+
440
+ for (let i = 0; i < 1000000; i++) {
441
+ const v = s.nextSetBit(0);
442
+ }
443
+ });
444
+ test('performance, next clear from 0', () => {
445
+ const s = new BitSet();
446
+
447
+ for (let i = 0; i < 1024; i++) {
448
+ s.set(i, true);
449
+ }
450
+
451
+ for (let i = 0; i < 1000000; i++) {
452
+ const v = s.nextClearBit(0);
453
+ }
454
+ });