typedfastbitset
Version:
Speed-optimized BitSet implementation for modern browsers and JavaScript engines, using typed arrays
1,307 lines • 53.9 kB
JavaScript
"use strict";
/**
* TypedFastBitSet.js : a fast bit set implementation in JavaScript.
* (c) the authors
* Licensed under the Apache License, Version 2.0.
*
* Speed-optimized BitSet implementation for modern browsers and JavaScript engines.
*
* Alternative version to TypedFastBitSet
* This starts of as storing entries as an array in a Uint32Array Typed Array
* The largest set value is first in the array. Everything else has no defined order
* The largest set value is used when converting into a bitset to correctly size new Array
* Once more than 256 entries have been added structure will convert to a bitset if it will create a smaller array
* Very sparse data will remain an array until 1024 entries where it will convert to a bitset
*/
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SparseTypedFastBitSet = void 0;
var utils_1 = require("./utils");
var Type;
(function (Type) {
Type[Type["ARRAY"] = 0] = "ARRAY";
Type[Type["BITSET"] = 1] = "BITSET";
Type[Type["MIXED"] = 2] = "MIXED";
})(Type || (Type = {}));
function isIterable(obj) {
if (obj) {
return obj[Symbol.iterator] !== undefined;
}
return false;
}
/**
* you can provide an iterable
* an exception is thrown if typed arrays are not supported
*/
var SparseTypedFastBitSet = /** @class */ (function () {
function SparseTypedFastBitSet(iterable, data) {
var e_1, _a;
if (data === void 0) { data = new Uint32Array(8); }
this.data = data;
// -1 means we are bitset
this.arraySize = 0;
if (isIterable(iterable)) {
try {
for (var iterable_1 = __values(iterable), iterable_1_1 = iterable_1.next(); !iterable_1_1.done; iterable_1_1 = iterable_1.next()) {
var key = iterable_1_1.value;
this.add(key);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) _a.call(iterable_1);
}
finally { if (e_1) throw e_1.error; }
}
}
}
Object.defineProperty(SparseTypedFastBitSet.prototype, "words", {
get: function () {
if (this.arraySize !== -1) {
this.data = this.toBitset();
this.arraySize = -1;
}
return this.data;
},
enumerable: false,
configurable: true
});
SparseTypedFastBitSet.prototype.toBitset = function () {
var array = this.data;
// currently converts its internal type to bitset
var count = (array[0] + 32) >>> 5;
var newWords = new Uint32Array(count << 1);
for (var i = 0; i < this.arraySize; i++) {
var add = array[i];
newWords[add >>> 5] |= 1 << add;
}
return newWords;
};
/**
* Add the value (Set the bit at index to true)
*/
SparseTypedFastBitSet.prototype.add = function (index) {
var type = this.resize(index);
if (type === Type.ARRAY) {
var array = this.data;
// zero will match the fill value so make sure match is within set area
// store biggest index first just for resize help
if (this.arraySize === 0) {
array[this.arraySize++] = index;
return;
}
var offset = array.indexOf(index);
if (offset === -1 || offset >= this.arraySize) {
var biggest = array[0];
if (index > biggest) {
array[0] = index;
array[this.arraySize++] = biggest;
}
else {
array[this.arraySize++] = index;
}
}
}
else {
this.data[index >>> 5] |= 1 << index;
}
};
/**
* If the value was not in the set, add it, otherwise remove it (flip bit at index)
*/
SparseTypedFastBitSet.prototype.flip = function (index) {
var type = this.resize(index);
if (type === Type.ARRAY) {
var array = this.data;
var arrayIndex = array.indexOf(index);
if (arrayIndex === -1) {
if (this.arraySize > 0 && index > array[0]) {
array[this.arraySize++] = array[0];
array[0] = index;
}
else {
array[this.arraySize++] = index;
}
}
else {
if (arrayIndex === 0 && this.arraySize > 1) {
// removing our largest marker need to find next largest
var largest = array[1];
var largestIndex = 1;
for (var i = 2; i < this.arraySize; i++) {
if (array[i] > largest) {
largest = array[i];
largestIndex = i;
}
}
array[0] = array[largestIndex];
array[largestIndex] = array[--this.arraySize];
}
else {
array[arrayIndex] = array[--this.arraySize];
}
}
}
else {
this.data[index >>> 5] ^= 1 << index;
}
};
/**
* Remove all values, reset memory usage
*/
SparseTypedFastBitSet.prototype.clear = function () {
this.arraySize = 0;
this.data = new Uint32Array(8);
};
/**
* Set the bit at index to false
*/
SparseTypedFastBitSet.prototype.remove = function (index) {
var type = this.resize(index);
if (type === Type.ARRAY) {
var array = this.data;
var arrayIndex = array.indexOf(index);
if (arrayIndex !== -1 && arrayIndex < this.arraySize) {
if (arrayIndex == this.arraySize - 1) {
this.arraySize--;
}
else if (arrayIndex === 0 && this.arraySize > 1) {
// removing our largest marker need to find next largest
var largest = array[1];
var largestIndex = 1;
for (var i = 2; i < this.arraySize; i++) {
if (array[i] > largest) {
largest = array[i];
largestIndex = i;
}
}
array[0] = array[largestIndex];
array[largestIndex] = array[--this.arraySize];
}
else {
array[arrayIndex] = array[--this.arraySize];
}
}
}
else {
this.data[index >>> 5] &= ~(1 << index);
}
};
/**
* Set bits from start (inclusive) to end (exclusive)
*/
SparseTypedFastBitSet.prototype.addRange = function (start, end) {
if (start >= end) {
return;
}
var type = this.resize(end, end - start - 1);
if (type === Type.ARRAY) {
var array = this.data;
var biggestAdd = end-- - 1;
if (this.arraySize === 0) {
array[this.arraySize++] = biggestAdd;
}
else {
var offset = array.indexOf(biggestAdd);
if (offset === -1 || offset >= this.arraySize) {
var biggest = array[0];
if (biggestAdd > biggest) {
array[0] = biggestAdd;
array[this.arraySize++] = biggest;
}
else {
array[this.arraySize++] = biggestAdd;
}
}
}
for (; start < end; start++) {
var offset = array.indexOf(start);
if (offset === -1 || offset >= this.arraySize) {
array[this.arraySize++] = start;
}
}
}
else {
var words = this.data;
var firstword = start >> 5;
var endword = (end - 1) >> 5;
if (firstword === endword) {
words[firstword] |= (~0 << start) & (~0 >>> -end);
return;
}
words[firstword] |= ~0 << start;
words.fill(~0, firstword + 1, endword);
words[endword] |= ~0 >>> -end;
}
};
/**
* Remove bits from start (inclusive) to end (exclusive)
*/
SparseTypedFastBitSet.prototype.removeRange = function (start, end) {
if (start >= end) {
return;
}
if (this.arraySize !== -1) {
var array = this.data;
var findBiggest = false;
for (var i = 0; i < this.arraySize; i++) {
if (array[i] >= start && array[i] < end) {
if (i === 0) {
findBiggest = true;
}
array[i--] = array[--this.arraySize];
}
}
if (findBiggest && this.arraySize > 1) {
var largest = array[0];
var largestIndex = 0;
for (var i = 1; i < this.arraySize; i++) {
if (array[i] > largest) {
largest = array[i];
largestIndex = i;
}
}
var current = array[0];
array[0] = array[largestIndex];
array[largestIndex] = current;
}
}
else {
var words = this.data;
start = Math.min(start, (words.length << 5) - 1);
end = Math.min(end, (words.length << 5) - 1);
var firstword = start >> 5;
var endword = (end - 1) >> 5;
if (firstword === endword) {
words[firstword] &= ~((~0 << start) & (~0 >>> -end));
return;
}
words[firstword] &= ~(~0 << start);
words.fill(0, firstword + 1, endword);
words[endword] &= ~(~0 >>> -end);
}
};
/**
* @returns true if no bit is set
*/
SparseTypedFastBitSet.prototype.isEmpty = function () {
if (this.arraySize === 0) {
return true;
}
if (this.arraySize > 0) {
return false;
}
var words = this.data;
var c = words.length;
for (var i = 0; i < c; i++) {
if (words[i] !== 0)
return false;
}
return true;
};
/**
* Is the value contained in the set? Is the bit at index true or false?
*/
SparseTypedFastBitSet.prototype.has = function (index) {
if (this.arraySize === -1) {
return (this.data[index >>> 5] & (1 << index)) !== 0;
}
else {
var offset = this.data.indexOf(index);
return offset !== -1 && offset < this.arraySize;
}
};
/**
* Tries to add the value (Set the bit at index to true)
*
* @returns 1 if the value was added, 0 if the value was already present
*/
SparseTypedFastBitSet.prototype.checkedAdd = function (index) {
var type = this.resize(index);
if (type === Type.ARRAY) {
var array = this.data;
if (this.arraySize === 0) {
array[this.arraySize++] = index;
return 1;
}
var offset = array.indexOf(index);
if (offset === -1 || offset >= this.arraySize) {
var biggest = array[0];
if (index > biggest) {
array[0] = index;
array[this.arraySize++] = biggest;
}
else {
array[this.arraySize++] = index;
}
return 1;
}
return 0;
}
else {
var words = this.data;
var word = words[index >>> 5];
var newword = word | (1 << index);
words[index >>> 5] = newword;
return ((newword ^ word) >>> index);
}
};
/**
* Reduce the memory usage to a minimum
*/
SparseTypedFastBitSet.prototype.trim = function () {
var size = this.size();
if (this.arraySize === -1) {
var words = this.data;
var nl = words.length;
while (nl > 0 && words[nl - 1] === 0) {
nl--;
}
// sparse array will be smaller
if (size < nl) {
var newArray = new Uint32Array(size);
var pos = 0 | 0;
var c = words.length;
for (var k = 0; k < c; ++k) {
var w = words[k];
while (w != 0) {
var t = w & -w;
newArray[pos++] = (k << 5) + (0, utils_1.hammingWeight)((t - 1) | 0);
w ^= t;
}
}
var first = newArray[0];
newArray[0] = newArray[size - 1];
newArray[size - 1] = first;
this.data = newArray;
this.arraySize = size;
}
else {
this.data = words.slice(0, nl);
}
}
else {
// dense bitset will be smaller
if (this.arraySize > 0 && this.data[0] >>> 5 < size) {
var count = (this.data[0] + 32) >>> 5;
var newWords = new Uint32Array(count);
for (var i = 0; i < this.arraySize; i++) {
var add = this.data[i];
newWords[add >>> 5] |= 1 << add;
}
this.data = newWords;
this.arraySize = -1;
}
else {
this.data = this.data.slice(0, this.arraySize);
}
}
};
/**
* Resize the bitset so that we can write a value at index
*/
SparseTypedFastBitSet.prototype.resize = function (index, capacity) {
if (capacity === void 0) { capacity = 0; }
if (this.arraySize === -1) {
var words = this.data;
if (words.length << 5 > index)
return Type.BITSET;
var count = (index + 32) >>> 5; // just what is needed
var newwords = new Uint32Array(count << 1);
newwords.set(words); // hopefully, this copy is fast
this.data = newwords;
return Type.BITSET;
}
else {
var array = this.data;
if (this.arraySize + capacity < array.length) {
return Type.ARRAY;
}
if (array.length + capacity < 256) {
var newData = new Uint32Array((array.length + capacity) << 1);
newData.set(array);
this.data = newData;
return Type.ARRAY;
}
else {
var count = (Math.max(array[0], index) + 32) >>> 5;
// very sparse grow array some more
if (count > array.length + capacity &&
(array.length + capacity) << 1 < 1024) {
var newData = new Uint32Array((array.length + capacity) << 1);
newData.set(array);
this.data = newData;
return Type.ARRAY;
}
else {
var newwords = new Uint32Array(count << 1);
for (var i = 0; i < this.arraySize; i++) {
var add = array[i];
newwords[add >>> 5] |= 1 << add;
}
this.arraySize = -1;
this.data = newwords;
return Type.BITSET;
}
}
}
};
/**
* How many values stored in the set? How many set bits?
*/
SparseTypedFastBitSet.prototype.size = function () {
if (this.arraySize === -1) {
var words = this.data;
var answer = 0;
var c = words.length;
var k = 0 | 0;
for (; k + 4 < c; k += 4) {
answer += (0, utils_1.hammingWeight4)(words[k] | 0, words[k + 1] | 0, words[k + 2] | 0, words[k + 3] | 0);
}
for (; k < c; ++k) {
answer += (0, utils_1.hammingWeight)(words[k] | 0);
}
return answer;
}
else {
return this.arraySize;
}
};
/**
* @returns the set bit locations (values)
*/
SparseTypedFastBitSet.prototype.array = function () {
if (this.arraySize === -1) {
var words = this.data;
var answer = new Array(this.size());
var pos = 0 | 0;
var c = words.length;
for (var k = 0; k < c; ++k) {
var w = words[k];
while (w != 0) {
var t = w & -w;
answer[pos++] = (k << 5) + (0, utils_1.hammingWeight)((t - 1) | 0);
w ^= t;
}
}
return answer;
}
else {
var array = this.data;
var answer = new Array(this.arraySize);
for (var i = 0; i < this.arraySize; i++) {
answer[i] = array[i];
}
return answer;
}
};
SparseTypedFastBitSet.prototype.forEach = function (fnc) {
if (this.arraySize === -1) {
var words = this.data;
var c = words.length;
for (var k = 0; k < c; ++k) {
var w = words[k];
while (w != 0) {
var t = w & -w;
fnc(((k << 5) + (0, utils_1.hammingWeight)(t - 1)) | 0);
w ^= t;
}
}
}
else {
var array = this.data;
for (var i = 0; i < this.arraySize; i++) {
var v = array[i];
fnc(v);
if (v !== array[i]) {
i--;
}
}
}
};
/**
* Iterator of set bit locations (values)
*/
SparseTypedFastBitSet.prototype[Symbol.iterator] = function () {
var _a, _b;
if (this.arraySize === -1) {
var words_1 = this.data;
var c_1 = words_1.length;
var k_1 = 0;
var w_1 = words_1[k_1];
return _a = {},
_a[Symbol.iterator] = function () {
return this;
},
_a.next = function () {
while (k_1 < c_1) {
if (w_1 !== 0) {
var t = w_1 & -w_1;
var value = (k_1 << 5) + (0, utils_1.hammingWeight)((t - 1) | 0);
w_1 ^= t;
return { done: false, value: value };
}
else {
k_1++;
if (k_1 < c_1) {
w_1 = words_1[k_1];
}
}
}
return { done: true, value: undefined };
},
_a;
}
else {
var array_1 = this.data;
var arraySize_1 = this.arraySize;
var i_1 = 0;
return _b = {},
_b[Symbol.iterator] = function () {
return this;
},
_b.next = function () {
if (i_1 < arraySize_1) {
var v = array_1[i_1];
var result = { done: false, value: v };
if (v !== array_1[i_1]) {
i_1--;
}
i_1++;
return result;
}
else {
return { done: true, value: undefined };
}
},
_b;
}
};
/**
* Creates a copy of this bitmap
*/
SparseTypedFastBitSet.prototype.clone = function () {
var bitset = new SparseTypedFastBitSet(undefined, new Uint32Array(this.data) // Correction : pas d'annotation générique
);
bitset.arraySize = this.arraySize;
return bitset;
};
/**
* Check if this bitset intersects with another one,
* no bitmap is modified
*/
SparseTypedFastBitSet.prototype.intersects = function (otherbitmap) {
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var firstWords = order.first.words;
var secondWords = order.second.words;
var newcount = Math.min(firstWords.length, secondWords.length);
for (var k = 0 | 0; k < newcount; ++k) {
if ((firstWords[k] & secondWords[k]) !== 0)
return true;
}
return false;
}
case Type.MIXED:
case Type.ARRAY: {
for (var i = 0; i < order.first.arraySize; i++) {
if (order.second.has(order.first.data[i])) {
return true;
}
}
return false;
}
}
};
/**
* Computes the intersection between this bitset and another one,
* the current bitmap is modified (and returned by the function)
*/
SparseTypedFastBitSet.prototype.intersection = function (otherbitmap) {
if (this.arraySize === -1) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var words = this.data;
var otherWords = otherbitmap.words;
var newcount = Math.min(words.length, otherWords.length);
var k = 0 | 0;
for (; k + 7 < newcount; k += 8) {
words[k] &= otherWords[k];
words[k + 1] &= otherWords[k + 1];
words[k + 2] &= otherWords[k + 2];
words[k + 3] &= otherWords[k + 3];
words[k + 4] &= otherWords[k + 4];
words[k + 5] &= otherWords[k + 5];
words[k + 6] &= otherWords[k + 6];
words[k + 7] &= otherWords[k + 7];
}
for (; k < newcount; ++k) {
words[k] &= otherWords[k];
}
var c = words.length;
for (k = newcount; k < c; ++k) {
words[k] = 0;
}
return this;
}
else {
var newWord = new Uint32Array(otherbitmap.data.length);
// iterate through target as it will be smaller
var otherArray = otherbitmap.data;
var newSize = 0;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
if (this.has(index)) {
if (newSize > 0 && index > newWord[0]) {
newWord[newSize++] = newWord[0];
newWord[0] = index;
}
else {
newWord[newSize++] = index;
}
}
}
this.data = newWord;
this.arraySize = newSize;
return this;
}
}
else {
var array = this.data;
for (var i = 0; i < this.arraySize; i++) {
var v = array[i];
if (otherbitmap.has(v)) {
if (i > 0 && v > array[0]) {
array[i] = array[0];
array[0] = v;
}
}
else {
array[i--] = array[--this.arraySize];
}
}
return this;
}
};
/**
* Computes the size of the intersection between this bitset and another one
*/
SparseTypedFastBitSet.prototype.intersection_size = function (otherbitmap) {
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var words = order.first.words;
var otherWords = order.second.words;
var newcount = Math.min(words.length, otherWords.length);
var answer = 0 | 0;
for (var k = 0 | 0; k < newcount; ++k) {
answer += (0, utils_1.hammingWeight)(words[k] & otherWords[k]);
}
return answer;
}
case Type.MIXED:
case Type.ARRAY: {
var answer = 0;
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
if (order.second.has(array[i])) {
answer++;
}
}
return answer;
}
}
};
/**
* Computes the intersection between this bitset and another one,
* a new bitmap is generated
*/
SparseTypedFastBitSet.prototype.new_intersection = function (otherbitmap) {
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var words = order.first.words;
var otherWords = order.second.words;
var count = Math.min(words.length, otherWords.length);
var newWords = new Uint32Array(count);
var k = 0 | 0;
for (; k + 7 < count; k += 8) {
newWords[k] = words[k] & otherWords[k];
newWords[k + 1] = words[k + 1] & otherWords[k + 1];
newWords[k + 2] = words[k + 2] & otherWords[k + 2];
newWords[k + 3] = words[k + 3] & otherWords[k + 3];
newWords[k + 4] = words[k + 4] & otherWords[k + 4];
newWords[k + 5] = words[k + 5] & otherWords[k + 5];
newWords[k + 6] = words[k + 6] & otherWords[k + 6];
newWords[k + 7] = words[k + 7] & otherWords[k + 7];
}
for (; k < count; ++k) {
newWords[k] = words[k] & otherWords[k];
}
var answer = new SparseTypedFastBitSet(undefined, newWords);
answer.arraySize = -1;
return answer;
}
case Type.MIXED:
case Type.ARRAY: {
var newArray = new Uint32Array(order.first.data.length);
// iterate through target as it will be smaller
var newSize = 0;
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
var index = array[i];
if (order.second.has(index)) {
if (newSize > 0 && index > newArray[0]) {
newArray[newSize++] = newArray[0];
newArray[0] = index;
}
else {
newArray[newSize++] = index;
}
}
}
var answer = new SparseTypedFastBitSet(undefined, newArray);
answer.arraySize = newSize;
return answer;
}
}
};
/**
* Computes the intersection between this bitset and another one,
* the current bitmap is modified
*/
SparseTypedFastBitSet.prototype.equals = function (otherbitmap) {
if (this === otherbitmap) {
return true;
}
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var words = this.words;
var otherWords = otherbitmap.words;
var mcount = Math.min(words.length, otherWords.length);
for (var k = 0 | 0; k < mcount; ++k) {
if (words[k] != otherWords[k])
return false;
}
if (words.length < otherWords.length) {
var c = otherWords.length;
for (var k = words.length; k < c; ++k) {
if (otherWords[k] != 0)
return false;
}
}
else if (otherWords.length < words.length) {
var c = words.length;
for (var k = otherWords.length; k < c; ++k) {
if (words[k] != 0)
return false;
}
}
return true;
}
case Type.ARRAY:
case Type.MIXED: {
if (order.first.size() !== order.second.size()) {
return false;
}
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
if (!order.second.has(array[i])) {
return false;
}
}
return true;
}
}
};
/**
* Computes the difference between this bitset and another one,
* the current bitset is modified (and returned by the function)
*/
SparseTypedFastBitSet.prototype.difference = function (otherbitmap) {
if (this.arraySize === -1) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var words = this.words;
var otherWords = otherbitmap.words;
var newcount = Math.min(words.length, otherWords.length);
var k = 0 | 0;
for (; k + 7 < newcount; k += 8) {
words[k] &= ~otherWords[k];
words[k + 1] &= ~otherWords[k + 1];
words[k + 2] &= ~otherWords[k + 2];
words[k + 3] &= ~otherWords[k + 3];
words[k + 4] &= ~otherWords[k + 4];
words[k + 5] &= ~otherWords[k + 5];
words[k + 6] &= ~otherWords[k + 6];
words[k + 7] &= ~otherWords[k + 7];
}
for (; k < newcount; ++k) {
words[k] &= ~otherWords[k];
}
return this;
}
else {
var otherArray = otherbitmap.data;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
if (this.has(index)) {
this.remove(index);
}
}
return this;
}
}
else {
var array = this.data;
var findBiggest = false;
for (var i = 0; i < this.arraySize; i++) {
if (otherbitmap.has(array[i])) {
if (i === 0) {
findBiggest = true;
}
array[i--] = array[--this.arraySize];
}
}
if (findBiggest && this.arraySize > 1) {
var largest = array[0];
var largestIndex = 0;
for (var i = 1; i < this.arraySize; i++) {
if (array[i] > largest) {
largest = array[i];
largestIndex = i;
}
}
var current = array[0];
array[0] = array[largestIndex];
array[largestIndex] = current;
}
return this;
}
};
/**
* Computes the difference between this bitset and another one,
* the other bitset is modified (and returned by the function)
*
* (for this set A and other set B, this computes B = A - B and returns B)
*/
SparseTypedFastBitSet.prototype.difference2 = function (otherbitmap) {
if (this.arraySize === -1 ||
!(otherbitmap instanceof SparseTypedFastBitSet)) {
var words = this.words;
var mincount = Math.min(words.length, otherbitmap.words.length);
otherbitmap.resize((words.length << 5) - 1);
var otherWords = otherbitmap.words;
var k = 0 | 0;
for (; k + 7 < mincount; k += 8) {
otherWords[k] = words[k] & ~otherWords[k];
otherWords[k + 1] = words[k + 1] & ~otherWords[k + 1];
otherWords[k + 2] = words[k + 2] & ~otherWords[k + 2];
otherWords[k + 3] = words[k + 3] & ~otherWords[k + 3];
otherWords[k + 4] = words[k + 4] & ~otherWords[k + 4];
otherWords[k + 5] = words[k + 5] & ~otherWords[k + 5];
otherWords[k + 6] = words[k + 6] & ~otherWords[k + 6];
otherWords[k + 7] = words[k + 7] & ~otherWords[k + 7];
}
for (; k < mincount; ++k) {
otherWords[k] = words[k] & ~otherWords[k];
}
// remaining words are all part of difference
for (; k < words.length; ++k) {
otherWords[k] = words[k];
}
otherWords.fill(0, k);
return otherbitmap;
}
else {
var array = new Uint32Array(this.data);
var arraySize = this.arraySize;
var findBiggest = false;
for (var i = 0; i < arraySize; i++) {
if (otherbitmap.has(array[i])) {
if (i === 0) {
findBiggest = true;
}
array[i--] = array[--arraySize];
}
}
if (findBiggest && arraySize > 1) {
var largest = array[0];
var largestIndex = 0;
for (var i = 1; i < arraySize; i++) {
if (array[i] > largest) {
largest = array[i];
largestIndex = i;
}
}
var current = array[0];
array[0] = array[largestIndex];
array[largestIndex] = current;
}
otherbitmap.data = array;
otherbitmap.arraySize = arraySize;
return otherbitmap;
}
};
/**
* Computes the difference between this bitset and another one,
* a new bitmap is generated
*/
SparseTypedFastBitSet.prototype.new_difference = function (otherbitmap) {
return this.clone().difference(otherbitmap);
};
/**
* Computes the size of the difference between this bitset and another one
*/
SparseTypedFastBitSet.prototype.difference_size = function (otherbitmap) {
if (this.arraySize === -1) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var words = this.words;
var otherWords = otherbitmap.words;
var newcount = Math.min(words.length, otherWords.length);
var answer = 0 | 0;
var k = 0 | 0;
for (; k < newcount; ++k) {
answer += (0, utils_1.hammingWeight)(words[k] & ~otherWords[k]);
}
var c = words.length;
for (; k < c; ++k) {
answer += (0, utils_1.hammingWeight)(words[k]);
}
return answer;
}
else {
var answer = this.size();
var otherArray = otherbitmap.data;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
if (this.has(index)) {
answer--;
}
}
return answer;
}
}
else {
var answer = this.arraySize;
var array = this.data;
for (var i = 0; i < this.arraySize; i++) {
if (otherbitmap.has(array[i])) {
answer--;
}
}
return answer;
}
};
/**
* Computes the changed elements (XOR) between this bitset and another one,
* the current bitset is modified (and returned by the function)
*/
SparseTypedFastBitSet.prototype.change = function (otherbitmap) {
if (this.arraySize === -1) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var otherWords = otherbitmap.words;
var mincount = Math.min(this.words.length, otherWords.length);
this.resize((otherWords.length << 5) - 1);
var words = this.words;
var k = 0 | 0;
for (; k + 7 < mincount; k += 8) {
words[k] ^= otherWords[k];
words[k + 1] ^= otherWords[k + 1];
words[k + 2] ^= otherWords[k + 2];
words[k + 3] ^= otherWords[k + 3];
words[k + 4] ^= otherWords[k + 4];
words[k + 5] ^= otherWords[k + 5];
words[k + 6] ^= otherWords[k + 6];
words[k + 7] ^= otherWords[k + 7];
}
for (; k < mincount; ++k) {
words[k] ^= otherWords[k];
}
// remaining words are all part of change
for (; k < otherWords.length; ++k) {
words[k] = otherWords[k];
}
return this;
}
else if (otherbitmap.arraySize > 0) {
var otherArray = otherbitmap.data;
this.resize(otherArray[0]);
var words = this.words;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
if ((words[index >>> 5] & (1 << index)) !== 0) {
words[index >>> 5] &= ~(1 << index);
}
else {
words[index >>> 5] |= 1 << index;
}
}
return this;
}
else {
return this;
}
}
else {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var words = new Uint32Array(Math.max(otherbitmap.words.length, this.arraySize > 0 ? this.data[0] << (5 + 32) : 0));
words.set(otherbitmap.words);
var array = this.data;
for (var i = 0; i < this.arraySize; i++) {
var index = array[i];
if ((words[index >>> 5] & (1 << index)) !== 0) {
words[index >>> 5] &= ~(1 << index);
}
else {
words[index >>> 5] |= 1 << index;
}
}
this.data = words;
this.arraySize = -1;
}
else {
var otherArray = otherbitmap.data;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
if (this.has(index)) {
this.remove(index);
}
else {
this.add(index);
}
}
}
return this;
}
};
/**
* Computes the change between this bitset and another one,
* a new bitmap is generated
*/
SparseTypedFastBitSet.prototype.new_change = function (otherbitmap) {
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var words = this.words;
var otherWords = otherbitmap.words;
var count = Math.max(words.length, otherWords.length);
var answer = new SparseTypedFastBitSet(undefined, new Uint32Array(count));
answer.arraySize = -1;
var mcount = Math.min(words.length, otherWords.length);
var k = 0;
for (; k + 7 < mcount; k += 8) {
answer.words[k] = words[k] ^ otherWords[k];
answer.words[k + 1] = words[k + 1] ^ otherWords[k + 1];
answer.words[k + 2] = words[k + 2] ^ otherWords[k + 2];
answer.words[k + 3] = words[k + 3] ^ otherWords[k + 3];
answer.words[k + 4] = words[k + 4] ^ otherWords[k + 4];
answer.words[k + 5] = words[k + 5] ^ otherWords[k + 5];
answer.words[k + 6] = words[k + 6] ^ otherWords[k + 6];
answer.words[k + 7] = words[k + 7] ^ otherWords[k + 7];
}
for (; k < mcount; ++k) {
answer.words[k] = words[k] ^ otherWords[k];
}
var c = words.length;
for (k = mcount; k < c; ++k) {
answer.words[k] = words[k];
}
var c2 = otherWords.length;
for (k = mcount; k < c2; ++k) {
answer.words[k] = otherWords[k];
}
return answer;
}
case Type.MIXED: {
var words = new Uint32Array(Math.max(order.second.words.length, order.first.arraySize > 0 ? (order.first.data[0] + 32) << 5 : 0));
words.set(order.second.words);
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
var index = array[i];
if ((words[index >>> 5] & (1 << index)) !== 0) {
words[index >>> 5] &= ~(1 << index);
}
else {
words[index >>> 5] |= 1 << index;
}
}
var answer = new SparseTypedFastBitSet(undefined, words);
answer.arraySize = -1;
return answer;
}
case Type.ARRAY: {
var newArray = new Uint32Array(order.first.data.length + order.second.data.length);
newArray.set(order.second.data);
// iterate through target as it will be smaller
var newSize = order.second.arraySize;
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
var index = array[i];
var offset = newArray.indexOf(index);
if (offset !== -1 && offset < newSize) {
newArray[offset] = newArray[--newSize];
}
else {
newArray[newSize++] = index;
}
}
if (newSize > 1) {
var largest = newArray[0];
var largestIndex = 0;
for (var i = 1; i < newSize; i++) {
if (newArray[i] > largest) {
largest = newArray[i];
largestIndex = i;
}
}
var current = newArray[0];
newArray[0] = newArray[largestIndex];
newArray[largestIndex] = current;
}
var answer = new SparseTypedFastBitSet(undefined, newArray);
answer.arraySize = newSize;
return answer;
}
}
};
/**
* Computes the number of changed elements between this bitset and another one
*/
SparseTypedFastBitSet.prototype.change_size = function (otherbitmap) {
var order = SparseTypedFastBitSet.order(this, otherbitmap);
switch (order.type) {
case Type.BITSET: {
var words = this.words;
var otherWords = otherbitmap.words;
var mincount = Math.min(words.length, otherWords.length);
var answer = 0 | 0;
var k = 0 | 0;
for (; k < mincount; ++k) {
answer += (0, utils_1.hammingWeight)(words[k] ^ otherWords[k]);
}
var longer = words.length > otherWords.length ? this : otherbitmap;
var c = longer.words.length;
for (; k < c; ++k) {
answer += (0, utils_1.hammingWeight)(longer.words[k]);
}
return answer;
}
case Type.MIXED: {
var array = order.first.data;
var answer = order.second.size();
for (var i = 0; i < order.first.arraySize; i++) {
var index = array[i];
if (order.second.has(index)) {
answer--;
}
else {
answer++;
}
}
return answer;
}
case Type.ARRAY: {
// iterate through target as it will be smaller
var answer = order.second.arraySize;
var array = order.first.data;
for (var i = 0; i < order.first.arraySize; i++) {
var index = array[i];
if (order.second.has(index)) {
answer--;
}
else {
answer++;
}
}
return answer;
}
}
};
/**
* @returns a string representation
*/
SparseTypedFastBitSet.prototype.toString = function () {
return "{" + this.array().join(",") + "}";
};
/**
* Computes the union between this bitset and another one,
* the current bitset is modified (and returned by the function)
*/
SparseTypedFastBitSet.prototype.union = function (otherbitmap) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
if (this.arraySize !== -1) {
this.data = this.toBitset();
this.arraySize = -1;
}
var words = this.data;
var otherWords = otherbitmap.words;
var mcount = Math.min(words.length, otherWords.length);
var k = 0 | 0;
for (; k + 7 < mcount; k += 8) {
words[k] |= otherWords[k];
words[k + 1] |= otherWords[k + 1];
words[k + 2] |= otherWords[k + 2];
words[k + 3] |= otherWords[k + 3];
words[k + 4] |= otherWords[k + 4];
words[k + 5] |= otherWords[k + 5];
words[k + 6] |= otherWords[k + 6];
words[k + 7] |= otherWords[k + 7];
}
for (; k < mcount; ++k) {
words[k] |= otherWords[k];
}
if (words.length < otherWords.length) {
this.resize((otherWords.length << 5) - 1);
words = this.data;
var c = otherWords.length;
for (k = mcount; k < c; ++k) {
words[k] = otherWords[k];
}
}
return this;
}
else {
var otherArray = otherbitmap.data;
for (var i = 0; i < otherbitmap.arraySize; i++) {
var index = otherArray[i];
this.add(index);
}
return this;
}
};
/**
* Computes the union between this bitset and another one,
* a new bitmap is generated
*/
SparseTypedFastBitSet.prototype.new_union = function (otherbitmap) {
if (!(otherbitmap instanceof SparseTypedFastBitSet) ||
otherbitmap.arraySize === -1) {
var words = this.data;
if (this.arraySize !== -1) {
words = this.toBitset();
}
var otherWords = otherbitmap.words;
var count = Math.max(words.length, otherWords.length);
var answer = new SparseTypedFastBitSet(undefined, new Uint32Array(count));
answer.arraySize = -1;
var mcount = Math.min(words.length, otherWords.length);
for (var k = 0; k < mcount; ++k) {
answer.words[k] = words[k] | othe