@woosh/meep-engine 2.33.26 → 2.33.27
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/core/binary/BitSet.js +151 -167
- package/core/binary/BitSet.spec.js +99 -1
- package/core/binary/ValidatingBitSetWrapper.js +81 -0
- package/core/bvh2/aabb3/AABB3.js +3 -10
- package/core/cache/Cache.d.ts +4 -2
- package/core/cache/Cache.js +5 -2
- package/core/collection/HashMap.d.ts +9 -2
- package/core/collection/HashSet.d.ts +7 -2
- package/core/collection/HashSet.js +7 -2
- package/core/collection/array/typed/typed_array_copy.js +1 -1
- package/core/geom/3d/frustum/array_setFromProjectionMatrix.js +3 -3
- package/core/parser/simple/Token.d.ts +13 -0
- package/core/parser/simple/Token.js +61 -27
- package/editor/tools/FoliagePaintTool.js +4 -4
- package/engine/asset/loaders/GLTFAssetLoader.js +52 -1
- package/engine/asset/loaders/image/ImageDecoderWorker.js +4 -3
- package/engine/asset/loaders/image/ImageRGBADataAsset.js +3 -2
- package/engine/asset/loaders/image/ImageRGBADataLoader.js +3 -3
- package/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
- package/engine/asset/loaders/image/png/PNG.js +113 -6
- package/engine/asset/loaders/image/png/PNGReader.js +5 -0
- package/engine/asset/loaders/material/bitmap2sampler_gl.js +1 -1
- package/engine/asset/loaders/material/computeImageBitmapEquality.js +6 -1
- package/engine/asset/loaders/material/computeTextureEquality.js +40 -49
- package/engine/ecs/EntityComponentDataset.js +1 -1
- package/engine/ecs/foliage/InstancedFoliage.js +277 -266
- package/engine/ecs/foliage/ecs/Foliage2System.js +7 -7
- package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +37 -0
- package/engine/ecs/foliage/ecs/{Foliage2.js → InstancedMeshLayer.js} +3 -45
- package/engine/ecs/foliage/ecs/InstancedMeshSerializationAdapter.js +6 -5
- package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +7 -6
- package/engine/ecs/storage/binary/BinarySerializationRegistry.js +1 -1
- package/engine/ecs/terrain/ecs/layers/TerrainLayer.js +12 -16
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +14 -72
- package/engine/graphics/geometry/instancing/rewriteMaterial.js +70 -0
- package/engine/graphics/material/manager/MaterialManager.js +2 -1
- package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +6 -4
- package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +0 -2
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +1 -2
- package/engine/graphics/particles/particular/engine/shader/debugAtlas.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +5 -2
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +3 -4
- package/engine/graphics/render/forward_plus/materials/FPlusDebugMaterial.js +3 -3
- package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +1 -1
- package/engine/graphics/render/forward_plus/prototypeLightManager.js +4 -4
- package/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +10 -9
- package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +12 -1
- package/engine/graphics/texture/sampler/Sampler2D.js +3 -1
- package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +1 -1
- package/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js +66 -0
- package/package.json +1 -1
- package/view/minimap/gl/MinimapWorldGL.js +12 -5
package/core/binary/BitSet.js
CHANGED
|
@@ -3,55 +3,42 @@ import { max3 } from "../math/max3.js";
|
|
|
3
3
|
import { min2 } from "../math/min2.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @
|
|
6
|
+
* de Bruijn sequence
|
|
7
|
+
* @see https://graphics.stanford.edu/~seander/bithacks.html
|
|
8
|
+
* @type {Uint16Array}
|
|
8
9
|
*/
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
* @
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* @
|
|
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
|
-
|
|
36
|
-
|
|
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.
|
|
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
|
|
146
|
+
const uint32_capacity = Math.ceil(bitCapacity / 32);
|
|
155
147
|
|
|
156
|
-
const oldData = this.
|
|
157
|
-
const newData = new
|
|
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 <
|
|
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,
|
|
159
|
+
newData.set(oldData.subarray(0, uint32_capacity));
|
|
168
160
|
}
|
|
169
161
|
|
|
170
|
-
this.
|
|
162
|
+
this.__data_uint32 = newData;
|
|
171
163
|
|
|
172
|
-
this.__capacity =
|
|
164
|
+
this.__capacity = uint32_capacity * 32;
|
|
173
165
|
};
|
|
174
166
|
|
|
175
167
|
/**
|
|
176
168
|
*
|
|
177
|
-
* @param {int}
|
|
169
|
+
* @param {int} new_length
|
|
178
170
|
* @private
|
|
179
171
|
*/
|
|
180
|
-
BitSet.prototype.__setLength = function (
|
|
181
|
-
this.__length =
|
|
172
|
+
BitSet.prototype.__setLength = function (new_length) {
|
|
173
|
+
this.__length = new_length;
|
|
182
174
|
|
|
183
175
|
const capacity = this.__capacity;
|
|
184
176
|
|
|
185
|
-
if (
|
|
177
|
+
if (new_length > capacity) {
|
|
186
178
|
|
|
187
|
-
const growSize = Math.ceil(max3(
|
|
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 (
|
|
188
|
+
if (
|
|
189
|
+
new_length < capacity - RESIZE_COUNT_THRESHOLD
|
|
190
|
+
&& new_length < capacity * this.__shrinkFactor
|
|
191
|
+
) {
|
|
193
192
|
|
|
194
|
-
this.__resize(
|
|
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
|
|
216
|
-
let
|
|
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.
|
|
212
|
+
const data = this.__data_uint32;
|
|
219
213
|
|
|
220
|
-
let
|
|
214
|
+
let word = data[word_index];
|
|
221
215
|
|
|
222
216
|
//handle first byte separately due to potential partial traversal
|
|
223
|
-
for (;
|
|
224
|
-
if ((
|
|
225
|
-
return
|
|
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
|
-
|
|
224
|
+
word_index--;
|
|
231
225
|
|
|
232
226
|
//scan the rest
|
|
233
|
-
for (;
|
|
227
|
+
for (; word_index >= 0; word_index--) {
|
|
234
228
|
|
|
235
|
-
|
|
229
|
+
word = data[word_index];
|
|
236
230
|
|
|
237
|
-
for (
|
|
231
|
+
for (bit_index = 31; bit_index >= 0; bit_index--) {
|
|
238
232
|
|
|
239
|
-
if ((
|
|
240
|
-
return
|
|
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
|
|
259
|
-
if (fromIndex >=
|
|
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
|
-
|
|
265
|
-
let bitIndex = fromIndex & 7; //replacement for %8
|
|
258
|
+
const data = this.__data_uint32;
|
|
266
259
|
|
|
267
|
-
|
|
260
|
+
let word_index = fromIndex >> 5;
|
|
261
|
+
let word;
|
|
262
|
+
let bit_address;
|
|
268
263
|
|
|
269
|
-
let
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
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
|
|
287
|
-
for (;
|
|
288
|
-
|
|
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
|
-
|
|
291
|
+
bit_index = lsb_32(word);
|
|
291
292
|
|
|
292
|
-
|
|
293
|
-
bitAddress = byteIndex * 8 + bitIndex;
|
|
293
|
+
bit_address = (word_index << 5) + bit_index;
|
|
294
294
|
|
|
295
|
-
|
|
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
|
-
|
|
313
|
-
return this.__firstClearBitIndex;
|
|
314
|
-
}
|
|
311
|
+
let word_index = fromIndex >> 5;
|
|
315
312
|
|
|
316
|
-
let
|
|
317
|
-
let bitIndex = fromIndex & 7;
|
|
313
|
+
let word;
|
|
318
314
|
|
|
319
|
-
|
|
320
|
-
let
|
|
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
|
-
|
|
324
|
-
|
|
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
|
-
|
|
329
|
-
this.__firstClearBitIndex = bitAddress;
|
|
330
|
-
}
|
|
325
|
+
word = data[word_index];
|
|
331
326
|
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
}
|
|
327
|
+
const fill_mask = (1 << bit_index) - 1;
|
|
335
328
|
|
|
336
|
-
|
|
337
|
-
|
|
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
|
-
|
|
344
|
-
|
|
332
|
+
if (masked_word !== 4294967295) {
|
|
333
|
+
bit_index = lsb_32(~masked_word);
|
|
334
|
+
return bit_index + word_index * 32;
|
|
335
|
+
}
|
|
345
336
|
|
|
346
|
-
|
|
337
|
+
word_index++;
|
|
338
|
+
}
|
|
347
339
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
340
|
+
//scan the rest
|
|
341
|
+
for (; word_index < word_count; word_index++) {
|
|
342
|
+
word = data[word_index];
|
|
351
343
|
|
|
352
|
-
|
|
344
|
+
if (word === 4294967295) {
|
|
345
|
+
// no 0s
|
|
346
|
+
continue;
|
|
353
347
|
}
|
|
354
|
-
}
|
|
355
348
|
|
|
356
|
-
|
|
357
|
-
|
|
349
|
+
bit_index = lsb_32(~word);
|
|
350
|
+
return bit_index + word_index * 32;
|
|
351
|
+
|
|
358
352
|
}
|
|
359
353
|
|
|
360
|
-
return
|
|
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
|
|
388
|
-
const
|
|
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.
|
|
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.
|
|
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 >>
|
|
491
|
-
const bitOffset = bitIndex &
|
|
472
|
+
const byteOffset = bitIndex >> 5;
|
|
473
|
+
const bitOffset = bitIndex & 31;
|
|
492
474
|
|
|
493
|
-
const byte = this.
|
|
475
|
+
const byte = this.__data_uint32[byteOffset];
|
|
494
476
|
|
|
495
|
-
const maskedValue = byte &
|
|
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.
|
|
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
|
|
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.
|
|
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 <
|
|
565
|
-
this.
|
|
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 =
|
|
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
|
+
});
|