From 9e64b23d9fdd5aaec5e6d894650fd5b49603b643 Mon Sep 17 00:00:00 2001 From: Salvatore Previti Date: Thu, 8 Nov 2018 16:53:25 +0000 Subject: [PATCH 1/4] range-cardinality, optimizations --- documentation/api/index.d/roaringbitmap32.md | 194 ++++++++++-------- index.d.ts | 18 +- package-lock.json | 17 +- package.json | 1 - src/cpp/CRoaringUnityBuild | 2 +- src/cpp/RoaringBitmap32/RoaringBitmap32.cpp | 16 +- src/cpp/RoaringBitmap32/RoaringBitmap32.h | 1 + .../RoaringBitmap32_operations.cpp | 85 +++----- .../RoaringBitmap32.ranges.test.ts | 28 +++ 9 files changed, 187 insertions(+), 175 deletions(-) diff --git a/documentation/api/index.d/roaringbitmap32.md b/documentation/api/index.d/roaringbitmap32.md index 592f284..628aae8 100644 --- a/documentation/api/index.d/roaringbitmap32.md +++ b/documentation/api/index.d/roaringbitmap32.md @@ -9,7 +9,7 @@ * [fromArrayAsync(values)][MethodDeclaration-2] * [fromArrayAsync(values, callback)][MethodDeclaration-3] * [deserialize(serialized, portable)][MethodDeclaration-4] - * [deserialize(serialized, portable)][MethodDeclaration-61] + * [deserialize(serialized, portable)][MethodDeclaration-62] * [deserializeAsync(serialized, portable)][MethodDeclaration-5] * [deserializeAsync(serialized, callback)][MethodDeclaration-6] * [deserializeAsync(serialized, portable, callback)][MethodDeclaration-7] @@ -29,45 +29,46 @@ * [maximum()][MethodDeclaration-23] * [has(value)][MethodDeclaration-24] * [hasRange(rangeStart, rangeEnd)][MethodDeclaration-25] - * [copyFrom(values)][MethodDeclaration-26] - * [add(value)][MethodDeclaration-27] - * [tryAdd(value)][MethodDeclaration-28] - * [addMany(values)][MethodDeclaration-29] - * [delete(value)][MethodDeclaration-30] - * [remove(value)][MethodDeclaration-31] - * [removeMany(values)][MethodDeclaration-32] - * [flipRange(rangeStart, rangeEnd)][MethodDeclaration-33] - * [addRange(rangeStart, rangeEnd)][MethodDeclaration-34] - * [removeRange(rangeStart, rangeEnd)][MethodDeclaration-35] - * [clear()][MethodDeclaration-36] - * [orInPlace(values)][MethodDeclaration-37] - * [andNotInPlace(values)][MethodDeclaration-38] - * [andInPlace(values)][MethodDeclaration-39] - * [xorInPlace(values)][MethodDeclaration-40] - * [isSubset(other)][MethodDeclaration-41] - * [isStrictSubset(other)][MethodDeclaration-42] - * [isEqual(other)][MethodDeclaration-43] - * [intersects(other)][MethodDeclaration-44] - * [andCardinality(other)][MethodDeclaration-45] - * [orCardinality(other)][MethodDeclaration-46] - * [andNotCardinality(other)][MethodDeclaration-47] - * [xorCardinality(other)][MethodDeclaration-48] - * [jaccardIndex(other)][MethodDeclaration-49] - * [removeRunCompression()][MethodDeclaration-50] - * [runOptimize()][MethodDeclaration-51] - * [shrinkToFit()][MethodDeclaration-52] - * [rank(maxValue)][MethodDeclaration-53] - * [select(rank)][MethodDeclaration-54] - * [toUint32Array()][MethodDeclaration-55] - * [toArray()][MethodDeclaration-56] - * [toSet()][MethodDeclaration-57] - * [toJSON()][MethodDeclaration-58] - * [getSerializationSizeInBytes(portable)][MethodDeclaration-59] - * [serialize(portable)][MethodDeclaration-60] - * [clone()][MethodDeclaration-62] - * [toString()][MethodDeclaration-63] - * [contentToString(maxLength)][MethodDeclaration-64] - * [statistics()][MethodDeclaration-65] + * [rangeCardinality(rangeStart, rangeEnd)][MethodDeclaration-26] + * [copyFrom(values)][MethodDeclaration-27] + * [add(value)][MethodDeclaration-28] + * [tryAdd(value)][MethodDeclaration-29] + * [addMany(values)][MethodDeclaration-30] + * [delete(value)][MethodDeclaration-31] + * [remove(value)][MethodDeclaration-32] + * [removeMany(values)][MethodDeclaration-33] + * [flipRange(rangeStart, rangeEnd)][MethodDeclaration-34] + * [addRange(rangeStart, rangeEnd)][MethodDeclaration-35] + * [removeRange(rangeStart, rangeEnd)][MethodDeclaration-36] + * [clear()][MethodDeclaration-37] + * [orInPlace(values)][MethodDeclaration-38] + * [andNotInPlace(values)][MethodDeclaration-39] + * [andInPlace(values)][MethodDeclaration-40] + * [xorInPlace(values)][MethodDeclaration-41] + * [isSubset(other)][MethodDeclaration-42] + * [isStrictSubset(other)][MethodDeclaration-43] + * [isEqual(other)][MethodDeclaration-44] + * [intersects(other)][MethodDeclaration-45] + * [andCardinality(other)][MethodDeclaration-46] + * [orCardinality(other)][MethodDeclaration-47] + * [andNotCardinality(other)][MethodDeclaration-48] + * [xorCardinality(other)][MethodDeclaration-49] + * [jaccardIndex(other)][MethodDeclaration-50] + * [removeRunCompression()][MethodDeclaration-51] + * [runOptimize()][MethodDeclaration-52] + * [shrinkToFit()][MethodDeclaration-53] + * [rank(maxValue)][MethodDeclaration-54] + * [select(rank)][MethodDeclaration-55] + * [toUint32Array()][MethodDeclaration-56] + * [toArray()][MethodDeclaration-57] + * [toSet()][MethodDeclaration-58] + * [toJSON()][MethodDeclaration-59] + * [getSerializationSizeInBytes(portable)][MethodDeclaration-60] + * [serialize(portable)][MethodDeclaration-61] + * [clone()][MethodDeclaration-63] + * [toString()][MethodDeclaration-64] + * [contentToString(maxLength)][MethodDeclaration-65] + * [statistics()][MethodDeclaration-66] * Properties * [size][PropertyDeclaration-0] * [isEmpty][PropertyDeclaration-1] @@ -735,7 +736,7 @@ boolean ### hasRange(rangeStart, rangeEnd) -Check whether a range of values from range_start (included) to range_end (excluded) is present +Check whether a range of values from rangeStart (included) to rangeEnd (excluded) is present ```typescript public hasRange(rangeStart: number, rangeEnd: number): boolean; @@ -743,10 +744,10 @@ public hasRange(rangeStart: number, rangeEnd: number): boolean; **Parameters** -| Name | Type | Description | -| ---------- | ------ | ---------------- | -| rangeStart | number | The start index. | -| rangeEnd | number | The end index. | +| Name | Type | Description | +| ---------- | ------ | ---------------------------- | +| rangeStart | number | The start index (inclusive). | +| rangeEnd | number | The end index (exclusive). | **Return type** @@ -754,6 +755,28 @@ boolean ---------- +### rangeCardinality(rangeStart, rangeEnd) + +Gets the cardinality (number of elements) between rangeStart (included) to rangeEnd (excluded) of the bitmap. +Returns 0 if range is invalid or if no element was found in the given range. + +```typescript +public rangeCardinality(rangeStart: number, rangeEnd: number): number; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------ | ---------------------------- | +| rangeStart | number | The start index (inclusive). | +| rangeEnd | number | The end index (exclusive). | + +**Return type** + +number + +---------- + ### copyFrom(values) Overwrite the content of this bitmap copying it from an Iterable or another RoaringBitmap32. @@ -1631,7 +1654,7 @@ boolean [TypeAliasDeclaration-0]: ../index.d.md#roaringbitmap32callback [MethodDeclaration-4]: roaringbitmap32.md#deserializeserialized-portable [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-61]: roaringbitmap32.md#deserializeserialized-portable +[MethodDeclaration-62]: roaringbitmap32.md#deserializeserialized-portable [MethodDeclaration-5]: roaringbitmap32.md#deserializeasyncserialized-portable [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 [MethodDeclaration-6]: roaringbitmap32.md#deserializeasyncserialized-callback @@ -1677,63 +1700,64 @@ boolean [MethodDeclaration-23]: roaringbitmap32.md#maximum [MethodDeclaration-24]: roaringbitmap32.md#hasvalue [MethodDeclaration-25]: roaringbitmap32.md#hasrangerangestart-rangeend -[MethodDeclaration-26]: roaringbitmap32.md#copyfromvalues -[MethodDeclaration-27]: roaringbitmap32.md#addvalue +[MethodDeclaration-26]: roaringbitmap32.md#rangecardinalityrangestart-rangeend +[MethodDeclaration-27]: roaringbitmap32.md#copyfromvalues +[MethodDeclaration-28]: roaringbitmap32.md#addvalue [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-28]: roaringbitmap32.md#tryaddvalue -[MethodDeclaration-29]: roaringbitmap32.md#addmanyvalues +[MethodDeclaration-29]: roaringbitmap32.md#tryaddvalue +[MethodDeclaration-30]: roaringbitmap32.md#addmanyvalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-30]: roaringbitmap32.md#deletevalue -[MethodDeclaration-31]: roaringbitmap32.md#removevalue -[MethodDeclaration-32]: roaringbitmap32.md#removemanyvalues +[MethodDeclaration-31]: roaringbitmap32.md#deletevalue +[MethodDeclaration-32]: roaringbitmap32.md#removevalue +[MethodDeclaration-33]: roaringbitmap32.md#removemanyvalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-33]: roaringbitmap32.md#fliprangerangestart-rangeend -[MethodDeclaration-34]: roaringbitmap32.md#addrangerangestart-rangeend -[MethodDeclaration-35]: roaringbitmap32.md#removerangerangestart-rangeend -[MethodDeclaration-36]: roaringbitmap32.md#clear -[MethodDeclaration-37]: roaringbitmap32.md#orinplacevalues +[MethodDeclaration-34]: roaringbitmap32.md#fliprangerangestart-rangeend +[MethodDeclaration-35]: roaringbitmap32.md#addrangerangestart-rangeend +[MethodDeclaration-36]: roaringbitmap32.md#removerangerangestart-rangeend +[MethodDeclaration-37]: roaringbitmap32.md#clear +[MethodDeclaration-38]: roaringbitmap32.md#orinplacevalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-38]: roaringbitmap32.md#andnotinplacevalues +[MethodDeclaration-39]: roaringbitmap32.md#andnotinplacevalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-39]: roaringbitmap32.md#andinplacevalues +[MethodDeclaration-40]: roaringbitmap32.md#andinplacevalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-40]: roaringbitmap32.md#xorinplacevalues +[MethodDeclaration-41]: roaringbitmap32.md#xorinplacevalues [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-41]: roaringbitmap32.md#issubsetother +[MethodDeclaration-42]: roaringbitmap32.md#issubsetother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-42]: roaringbitmap32.md#isstrictsubsetother +[MethodDeclaration-43]: roaringbitmap32.md#isstrictsubsetother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-43]: roaringbitmap32.md#isequalother +[MethodDeclaration-44]: roaringbitmap32.md#isequalother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-44]: roaringbitmap32.md#intersectsother +[MethodDeclaration-45]: roaringbitmap32.md#intersectsother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-45]: roaringbitmap32.md#andcardinalityother +[MethodDeclaration-46]: roaringbitmap32.md#andcardinalityother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-46]: roaringbitmap32.md#orcardinalityother +[MethodDeclaration-47]: roaringbitmap32.md#orcardinalityother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-47]: roaringbitmap32.md#andnotcardinalityother +[MethodDeclaration-48]: roaringbitmap32.md#andnotcardinalityother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-48]: roaringbitmap32.md#xorcardinalityother +[MethodDeclaration-49]: roaringbitmap32.md#xorcardinalityother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-49]: roaringbitmap32.md#jaccardindexother +[MethodDeclaration-50]: roaringbitmap32.md#jaccardindexother [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-50]: roaringbitmap32.md#removeruncompression -[MethodDeclaration-51]: roaringbitmap32.md#runoptimize -[MethodDeclaration-52]: roaringbitmap32.md#shrinktofit -[MethodDeclaration-53]: roaringbitmap32.md#rankmaxvalue -[MethodDeclaration-54]: roaringbitmap32.md#selectrank -[MethodDeclaration-55]: roaringbitmap32.md#touint32array -[MethodDeclaration-56]: roaringbitmap32.md#toarray -[MethodDeclaration-57]: roaringbitmap32.md#toset -[MethodDeclaration-58]: roaringbitmap32.md#tojson -[MethodDeclaration-59]: roaringbitmap32.md#getserializationsizeinbytesportable -[MethodDeclaration-60]: roaringbitmap32.md#serializeportable +[MethodDeclaration-51]: roaringbitmap32.md#removeruncompression +[MethodDeclaration-52]: roaringbitmap32.md#runoptimize +[MethodDeclaration-53]: roaringbitmap32.md#shrinktofit +[MethodDeclaration-54]: roaringbitmap32.md#rankmaxvalue +[MethodDeclaration-55]: roaringbitmap32.md#selectrank +[MethodDeclaration-56]: roaringbitmap32.md#touint32array +[MethodDeclaration-57]: roaringbitmap32.md#toarray +[MethodDeclaration-58]: roaringbitmap32.md#toset +[MethodDeclaration-59]: roaringbitmap32.md#tojson +[MethodDeclaration-60]: roaringbitmap32.md#getserializationsizeinbytesportable +[MethodDeclaration-61]: roaringbitmap32.md#serializeportable [InterfaceDeclaration-0]: ../index.d.md#indexdts -[MethodDeclaration-62]: roaringbitmap32.md#clone +[MethodDeclaration-63]: roaringbitmap32.md#clone [ClassDeclaration-0]: roaringbitmap32.md#roaringbitmap32 -[MethodDeclaration-63]: roaringbitmap32.md#tostring -[MethodDeclaration-64]: roaringbitmap32.md#contenttostringmaxlength -[MethodDeclaration-65]: roaringbitmap32.md#statistics +[MethodDeclaration-64]: roaringbitmap32.md#tostring +[MethodDeclaration-65]: roaringbitmap32.md#contenttostringmaxlength +[MethodDeclaration-66]: roaringbitmap32.md#statistics [InterfaceDeclaration-1]: ../index.d.md#roaringbitmap32statistics [PropertyDeclaration-0]: roaringbitmap32.md#size [PropertyDeclaration-1]: roaringbitmap32.md#isempty \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 6a5f976..043575d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -374,15 +374,25 @@ export class RoaringBitmap32 implements Iterable { public has(value: number): boolean /** - * Check whether a range of values from range_start (included) to range_end (excluded) is present + * Check whether a range of values from rangeStart (included) to rangeEnd (excluded) is present * - * @param {number} rangeStart The start index. - * @param {number} rangeEnd The end index. - * @returns {boolean} True if the bitmap contains the whole range of values from range_start (included) to range_end (excluded), false if not. + * @param {number} rangeStart The start index (inclusive). + * @param {number} rangeEnd The end index (exclusive). + * @returns {boolean} True if the bitmap contains the whole range of values from rangeStart (included) to rangeEnd (excluded), false if not. * @memberof RoaringBitmap32 */ public hasRange(rangeStart: number, rangeEnd: number): boolean + /** + * Gets the cardinality (number of elements) between rangeStart (included) to rangeEnd (excluded) of the bitmap. + * Returns 0 if range is invalid or if no element was found in the given range. + * + * @param {number} rangeStart The start index (inclusive). + * @param {number} rangeEnd The end index (exclusive). + * @returns {number} The number of elements between rangeStart (included) to rangeEnd (excluded). + */ + public rangeCardinality(rangeStart: number, rangeEnd: number): number + /** * Overwrite the content of this bitmap copying it from an Iterable or another RoaringBitmap32. * diff --git a/package-lock.json b/package-lock.json index 0c5c2e7..0e93fe3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "roaring", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2013,15 +2013,6 @@ } } }, - "eslint-config-prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz", - "integrity": "sha512-QYGfmzuc4q4J6XIhlp8vRKdI/fI0tQfQPy1dME3UOLprE+v4ssH/3W9LM2Q7h5qBcy5m0ehCrBDU2YF8q6OY8w==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - } - }, "eslint-config-quick": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/eslint-config-quick/-/eslint-config-quick-0.1.15.tgz", @@ -3122,12 +3113,6 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, "get-stream": { "version": "3.0.0", "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", diff --git a/package.json b/package.json index 11c3563..4863af3 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "benchmark": "^2.1.4", "chalk": "^2.4.1", "eslint": "^5.8.0", - "eslint-config-prettier": "^3.1.0", "eslint-config-quick": "^0.1.15", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jest": "^22.0.0", diff --git a/src/cpp/CRoaringUnityBuild b/src/cpp/CRoaringUnityBuild index ca33362..43fe35e 160000 --- a/src/cpp/CRoaringUnityBuild +++ b/src/cpp/CRoaringUnityBuild @@ -1 +1 @@ -Subproject commit ca33362189a125ed48318aad3a1064e051c8d54c +Subproject commit 43fe35e5b6942917867d6fed5edb6f3f68a113f6 diff --git a/src/cpp/RoaringBitmap32/RoaringBitmap32.cpp b/src/cpp/RoaringBitmap32/RoaringBitmap32.cpp index 7b679bf..acd9587 100644 --- a/src/cpp/RoaringBitmap32/RoaringBitmap32.cpp +++ b/src/cpp/RoaringBitmap32/RoaringBitmap32.cpp @@ -72,6 +72,7 @@ void RoaringBitmap32::Init(v8::Local exports) { NODE_SET_PROTOTYPE_METHOD(ctor, "containsRange", hasRange); NODE_SET_PROTOTYPE_METHOD(ctor, "hasRange", hasRange); + NODE_SET_PROTOTYPE_METHOD(ctor, "rangeCardinality", rangeCardinality); NODE_SET_PROTOTYPE_METHOD(ctor, "flipRange", flipRange); NODE_SET_PROTOTYPE_METHOD(ctor, "addRange", addRange); NODE_SET_PROTOTYPE_METHOD(ctor, "removeRange", removeRange); @@ -172,7 +173,6 @@ void RoaringBitmap32::isEmpty_getter(v8::Local property, const v8::P void RoaringBitmap32::has(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); uint32_t v; if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { @@ -185,7 +185,6 @@ void RoaringBitmap32::has(const v8::FunctionCallbackInfo & info) { void RoaringBitmap32::hasRange(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); v8::Local context = isolate->GetCurrentContext(); double minimum, maximum; @@ -228,7 +227,6 @@ void RoaringBitmap32::maximum(const v8::FunctionCallbackInfo & info) void RoaringBitmap32::rank(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); uint32_t v; if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { @@ -241,7 +239,6 @@ void RoaringBitmap32::rank(const v8::FunctionCallbackInfo & info) { void RoaringBitmap32::select(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); uint32_t v; if (info.Length() >= 1 && info[0]->IsUint32() && info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); @@ -252,7 +249,6 @@ void RoaringBitmap32::select(const v8::FunctionCallbackInfo & info) { } void RoaringBitmap32::removeRunCompression(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); bool removed = roaring_bitmap_remove_run_compression(&self->roaring); if (removed) { @@ -262,13 +258,11 @@ void RoaringBitmap32::removeRunCompression(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set(roaring_bitmap_run_optimize(&self->roaring)); } void RoaringBitmap32::shrinkToFit(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set((double)roaring_bitmap_shrink_to_fit(&self->roaring)); self->invalidate(); @@ -444,9 +438,6 @@ v8::Local RoaringBitmap32FactoryAsyncWorker::done() { ///// Serialization ///// void RoaringBitmap32::getSerializationSizeInBytes(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); bool portable = info.Length() > 0 && info[0]->IsTrue(); @@ -476,7 +467,7 @@ void RoaringBitmap32::serialize(const v8::FunctionCallbackInfo & info auto portablesize = roaring_bitmap_portable_size_in_bytes(&self->roaring); if (portable) { - auto typedArray = JSTypes::bufferAllocUnsafe(info.GetIsolate(), portablesize); + auto typedArray = JSTypes::bufferAllocUnsafe(isolate, portablesize); const v8utils::TypedArrayContent buf(typedArray); if (!buf.length || !buf.data) return v8utils::throwError("RoaringBitmap32::serialize - failed to allocate"); @@ -592,8 +583,7 @@ void RoaringBitmap32::deserializeStatic(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); + v8::EscapableHandleScope scope(info.GetIsolate()); if (info.Length() == 0 || (!info[0]->IsUint8Array() && !info[0]->IsInt8Array() && !info[0]->IsUint8ClampedArray())) return v8utils::throwTypeError("RoaringBitmap32::deserialize requires an argument of type Uint8Array or Buffer"); diff --git a/src/cpp/RoaringBitmap32/RoaringBitmap32.h b/src/cpp/RoaringBitmap32/RoaringBitmap32.h index 2677d56..2082895 100644 --- a/src/cpp/RoaringBitmap32/RoaringBitmap32.h +++ b/src/cpp/RoaringBitmap32/RoaringBitmap32.h @@ -53,6 +53,7 @@ class RoaringBitmap32 : public v8utils::ObjectWrap { static void jaccardIndex(const v8::FunctionCallbackInfo & info); static void rank(const v8::FunctionCallbackInfo & info); static void select(const v8::FunctionCallbackInfo & info); + static void rangeCardinality(const v8::FunctionCallbackInfo & info); static void removeRunCompression(const v8::FunctionCallbackInfo & info); static void runOptimize(const v8::FunctionCallbackInfo & info); diff --git a/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp b/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp index c9f3a2c..7d229e1 100644 --- a/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp +++ b/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp @@ -1,63 +1,54 @@ #include "RoaringBitmap32.h" void RoaringBitmap32::isSubset(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self == other || (self && other && roaring_bitmap_is_subset(&self->roaring, &other->roaring))); } void RoaringBitmap32::isStrictSubset(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other && roaring_bitmap_is_strict_subset(&self->roaring, &other->roaring)); } void RoaringBitmap32::isEqual(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self == other || (self && other && roaring_bitmap_equals(&self->roaring, &other->roaring))); } void RoaringBitmap32::intersects(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other && roaring_bitmap_intersect(&self->roaring, &other->roaring)); } void RoaringBitmap32::andCardinality(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other ? (double)roaring_bitmap_and_cardinality(&self->roaring, &other->roaring) : -1); } void RoaringBitmap32::orCardinality(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other ? (double)roaring_bitmap_or_cardinality(&self->roaring, &other->roaring) : -1); } void RoaringBitmap32::andNotCardinality(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(other ? (double)roaring_bitmap_andnot_cardinality(&self->roaring, &other->roaring) : -1); } void RoaringBitmap32::xorCardinality(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other ? (double)roaring_bitmap_xor_cardinality(&self->roaring, &other->roaring) : -1); } void RoaringBitmap32::jaccardIndex(const v8::FunctionCallbackInfo & info) { - v8::HandleScope scope(info.GetIsolate()); RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(info, 0, RoaringBitmap32::constructorTemplate); info.GetReturnValue().Set(self && other ? roaring_bitmap_jaccard_index(&self->roaring, &other->roaring) : -1); @@ -125,8 +116,6 @@ inline bool roaringAddMany(v8::Isolate * isolate, RoaringBitmap32 * self, v8::Lo void RoaringBitmap32::copyFrom(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); if (info.Length() == 0 || !roaringAddMany(isolate, self, info[0], true)) { return v8utils::throwError("RoaringBitmap32::copyFrom expects a RoaringBitmap32, an Uint32Array or an Iterable"); @@ -135,22 +124,17 @@ void RoaringBitmap32::copyFrom(const v8::FunctionCallbackInfo & info) } void RoaringBitmap32::addMany(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); if (info.Length() > 0) { RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); self->invalidate(); if (roaringAddMany(info.GetIsolate(), self, info[0])) { - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } } return v8utils::throwTypeError("Uint32Array, RoaringBitmap32 or Iterable expected"); } void RoaringBitmap32::add(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); - uint32_t v; if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(info.GetIsolate()->GetCurrentContext()).To(&v)) { return v8utils::throwTypeError("RoaringBitmap32::add - 32 bit unsigned integer expected"); @@ -159,15 +143,12 @@ void RoaringBitmap32::add(const v8::FunctionCallbackInfo & info) { RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); roaring_bitmap_add(&self->roaring, v); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } void RoaringBitmap32::tryAdd(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); - uint32_t v; - if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { + if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(info.GetIsolate()->GetCurrentContext()).To(&v)) { return info.GetReturnValue().Set(false); } @@ -180,10 +161,8 @@ void RoaringBitmap32::tryAdd(const v8::FunctionCallbackInfo & info) { } void RoaringBitmap32::removeMany(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); - if (info.Length() > 0) { + v8::Isolate * isolate = info.GetIsolate(); auto const & arg = info[0]; RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); @@ -191,13 +170,13 @@ void RoaringBitmap32::removeMany(const v8::FunctionCallbackInfo & inf if (other) { roaring_bitmap_andnot_inplace(&self->roaring, &other->roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } else { RoaringBitmap32 tmp; - if (roaringAddMany(info.GetIsolate(), &tmp, arg)) { + if (roaringAddMany(isolate, &tmp, arg)) { roaring_bitmap_andnot_inplace(&self->roaring, &tmp.roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } } } @@ -206,23 +185,21 @@ void RoaringBitmap32::removeMany(const v8::FunctionCallbackInfo & inf } void RoaringBitmap32::andInPlace(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); - if (info.Length() > 0) { + v8::Isolate * isolate = info.GetIsolate(); auto const & arg = info[0]; RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(arg, RoaringBitmap32::constructorTemplate, isolate); if (other) { roaring_bitmap_and_inplace(&self->roaring, &other->roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } else { RoaringBitmap32 tmp; - if (roaringAddMany(info.GetIsolate(), &tmp, arg)) { + if (roaringAddMany(isolate, &tmp, arg)) { roaring_bitmap_and_inplace(&self->roaring, &tmp.roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } } } @@ -231,23 +208,21 @@ void RoaringBitmap32::andInPlace(const v8::FunctionCallbackInfo & inf } void RoaringBitmap32::xorInPlace(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::EscapableHandleScope scope(isolate); - if (info.Length() > 0) { + v8::Isolate * isolate = info.GetIsolate(); auto const & arg = info[0]; RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(arg, RoaringBitmap32::constructorTemplate, isolate); if (other) { roaring_bitmap_xor_inplace(&self->roaring, &other->roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } else { RoaringBitmap32 tmp; roaringAddMany(info.GetIsolate(), &tmp, arg); roaring_bitmap_xor_inplace(&self->roaring, &tmp.roaring); self->invalidate(); - return info.GetReturnValue().Set(scope.Escape(info.Holder())); + return info.GetReturnValue().Set(info.Holder()); } } @@ -255,10 +230,8 @@ void RoaringBitmap32::xorInPlace(const v8::FunctionCallbackInfo & inf } void RoaringBitmap32::remove(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); uint32_t v; - if (info.Length() >= 1 && info[0]->IsUint32() && info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { + if (info.Length() >= 1 && info[0]->IsUint32() && info[0]->Uint32Value(info.GetIsolate()->GetCurrentContext()).To(&v)) { RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); roaring_bitmap_remove(&self->roaring, v); self->invalidate(); @@ -266,14 +239,10 @@ void RoaringBitmap32::remove(const v8::FunctionCallbackInfo & info) { } void RoaringBitmap32::removeChecked(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - uint32_t v; - if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(isolate->GetCurrentContext()).To(&v)) { + if (info.Length() < 1 || !info[0]->IsUint32() || !info[0]->Uint32Value(info.GetIsolate()->GetCurrentContext()).To(&v)) { return info.GetReturnValue().Set(false); } - RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); bool result = roaring_bitmap_remove_checked(&self->roaring, v); if (result) { @@ -283,9 +252,6 @@ void RoaringBitmap32::removeChecked(const v8::FunctionCallbackInfo & } void RoaringBitmap32::clear(const v8::FunctionCallbackInfo & info) { - v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); if (self->roaring.high_low_container.size == 0) { info.GetReturnValue().Set(false); @@ -298,13 +264,11 @@ void RoaringBitmap32::clear(const v8::FunctionCallbackInfo & info) { } inline static bool getRangeOperationParameters(const v8::FunctionCallbackInfo & info, uint64_t & minInteger, uint64_t & maxInteger) { - v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - if (info.Length() < 2 || !info[0]->IsNumber() || !info[1]->IsNumber()) { return false; } + v8::Isolate * isolate = info.GetIsolate(); double minimum, maximum; if (!info[0]->NumberValue(isolate->GetCurrentContext()).To(&minimum) || std::isnan(minimum)) { @@ -331,6 +295,19 @@ inline static bool getRangeOperationParameters(const v8::FunctionCallbackInfo & info) { + uint64_t minInteger, maxInteger; + if (getRangeOperationParameters(info, minInteger, maxInteger)) { + RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); + auto card = roaring_bitmap_range_cardinality(&self->roaring, minInteger, maxInteger); + if (card <= 0xFFFFFFFF) { + return info.GetReturnValue().Set((uint32_t)card); + } + return info.GetReturnValue().Set((double)card); + } + return info.GetReturnValue().Set(0u); +} + void RoaringBitmap32::flipRange(const v8::FunctionCallbackInfo & info) { uint64_t minInteger, maxInteger; if (getRangeOperationParameters(info, minInteger, maxInteger)) { @@ -360,8 +337,6 @@ void RoaringBitmap32::removeRange(const v8::FunctionCallbackInfo & in void RoaringBitmap32::swapStatic(const v8::FunctionCallbackInfo & info) { v8::Isolate * isolate = info.GetIsolate(); - v8::HandleScope scope(isolate); - if (info.Length() < 2) return v8utils::throwTypeError("RoaringBitmap32::swap expects 2 arguments"); diff --git a/test/RoaringBitmap32/RoaringBitmap32.ranges.test.ts b/test/RoaringBitmap32/RoaringBitmap32.ranges.test.ts index 23dcd52..a1ce594 100644 --- a/test/RoaringBitmap32/RoaringBitmap32.ranges.test.ts +++ b/test/RoaringBitmap32/RoaringBitmap32.ranges.test.ts @@ -158,6 +158,34 @@ describe('RoaringBitmap32 ranges', () => { }) }) + describe('rangeCardinality', () => { + it('returns the valid size for the basic test', () => { + const s = 65536 + const r = new RoaringBitmap32() + r.addRange(s * 2, s * 10) + + // single container (minhb == maxhb) + expect(r.rangeCardinality(s * 2, s * 3)).toBe(s) + expect(r.rangeCardinality(s * 2 + 100, s * 3)).toBe(s - 100) + expect(r.rangeCardinality(s * 2, s * 3 - 200)).toBe(s - 200) + expect(r.rangeCardinality(s * 2 + 100, s * 3 - 200)).toBe(s - 300) + // multiple containers (maxhb > minhb) + expect(r.rangeCardinality(s * 2, s * 5)).toBe(s * 3) + expect(r.rangeCardinality(s * 2 + 100, s * 5)).toBe(s * 3 - 100) + expect(r.rangeCardinality(s * 2, s * 5 - 200)).toBe(s * 3 - 200) + expect(r.rangeCardinality(s * 2 + 100, s * 5 - 200)).toBe(s * 3 - 300) + // boundary checks + expect(r.rangeCardinality(s * 20, s * 21)).toBe(0) + expect(r.rangeCardinality(100, 100)).toBe(0) + expect(r.rangeCardinality(0, s * 7)).toBe(s * 5) + expect(r.rangeCardinality(s * 7, Number.MAX_SAFE_INTEGER)).toBe(s * 3) + // Extremes + expect(r.rangeCardinality(s * 7, Number.POSITIVE_INFINITY)).toBe(s * 3) + expect(r.rangeCardinality(-1, Number.POSITIVE_INFINITY)).toBe(r.size) + expect(r.rangeCardinality(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY)).toBe(r.size) + }) + }) + describe('addRange', () => { it('does nothing for invalid values', () => { const bitmap = new RoaringBitmap32([1, 2]) From e341479599b9817ea33e3b101bf1c05d66817504 Mon Sep 17 00:00:00 2001 From: Salvatore Previti Date: Thu, 8 Nov 2018 16:53:48 +0000 Subject: [PATCH 2/4] version upgrade --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4863af3..3f112be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "roaring", - "version": "1.0.2", + "version": "1.0.3", "description": "CRoaring official port for NodeJS", "main": "index.js", "types": "index.d.ts", From 6d6d5a3946d0645d1c73eca6564e02c025a00802 Mon Sep 17 00:00:00 2001 From: Salvatore Previti Date: Thu, 8 Nov 2018 17:03:06 +0000 Subject: [PATCH 3/4] optimized removeMany --- .../RoaringBitmap32_operations.cpp | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp b/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp index 7d229e1..a1f1b94 100644 --- a/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp +++ b/src/cpp/RoaringBitmap32/RoaringBitmap32_operations.cpp @@ -161,27 +161,49 @@ void RoaringBitmap32::tryAdd(const v8::FunctionCallbackInfo & info) { } void RoaringBitmap32::removeMany(const v8::FunctionCallbackInfo & info) { + bool done = false; + if (info.Length() > 0) { v8::Isolate * isolate = info.GetIsolate(); auto const & arg = info[0]; RoaringBitmap32 * self = v8utils::ObjectWrap::Unwrap(info.Holder()); - RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(arg, RoaringBitmap32::constructorTemplate, isolate); - if (other) { - roaring_bitmap_andnot_inplace(&self->roaring, &other->roaring); + if (arg->IsUint32Array() || arg->IsInt32Array()) { + const v8utils::TypedArrayContent typedArray(arg); + roaring_bitmap_remove_many(&self->roaring, typedArray.length, typedArray.data); self->invalidate(); - return info.GetReturnValue().Set(info.Holder()); + done = true; } else { - RoaringBitmap32 tmp; - if (roaringAddMany(isolate, &tmp, arg)) { - roaring_bitmap_andnot_inplace(&self->roaring, &tmp.roaring); + RoaringBitmap32 * other = v8utils::ObjectWrap::TryUnwrap(arg, RoaringBitmap32::constructorTemplate, isolate); + if (other) { + roaring_bitmap_andnot_inplace(&self->roaring, &other->roaring); self->invalidate(); - return info.GetReturnValue().Set(info.Holder()); + done = true; + } else { + v8::Local argv[] = {arg}; + auto t = JSTypes::Uint32Array_from.Get(isolate)->Call(JSTypes::Uint32Array.Get(isolate), 1, argv); + if (!t.IsEmpty()) { + const v8utils::TypedArrayContent typedArray(t); + roaring_bitmap_remove_many(&self->roaring, typedArray.length, typedArray.data); + self->invalidate(); + done = true; + } else { + RoaringBitmap32 tmp; + if (roaringAddMany(isolate, &tmp, arg)) { + roaring_bitmap_andnot_inplace(&self->roaring, &tmp.roaring); + self->invalidate(); + done = true; + } + } } } } - return v8utils::throwTypeError("Uint32Array, RoaringBitmap32 or Iterable expected"); + if (done) { + info.GetReturnValue().Set(info.Holder()); + } else { + v8utils::throwTypeError("Uint32Array, RoaringBitmap32 or Iterable expected"); + } } void RoaringBitmap32::andInPlace(const v8::FunctionCallbackInfo & info) { From 328cdc8d382d30994e254a8b3387e2fa77e2db66 Mon Sep 17 00:00:00 2001 From: Salvatore Previti Date: Thu, 8 Nov 2018 17:04:58 +0000 Subject: [PATCH 4/4] removeMany uint32array test --- test/RoaringBitmap32/RoaringBitmap32.operations.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/RoaringBitmap32/RoaringBitmap32.operations.test.ts b/test/RoaringBitmap32/RoaringBitmap32.operations.test.ts index b3001f0..3c25516 100644 --- a/test/RoaringBitmap32/RoaringBitmap32.operations.test.ts +++ b/test/RoaringBitmap32/RoaringBitmap32.operations.test.ts @@ -165,6 +165,12 @@ describe('RoaringBitmap32 operations', () => { bitmap.removeMany(new RoaringBitmap32([123, 5, 6])) expect(bitmap.toArray()).toEqual([1, 2, 3, 4]) }) + + it('removeMany removes multiple items (Uint32Array)', () => { + const bitmap = new RoaringBitmap32([1, 2, 123, 3, 4, 5, 6]) + bitmap.removeMany(new Uint32Array([123, 5, 6])) + expect(bitmap.toArray()).toEqual([1, 2, 3, 4]) + }) }) describe('andInPlace', () => {