UNPKG

typedfastbitset

Version:

Speed-optimized BitSet implementation for modern browsers and JavaScript engines, using typed arrays

1,307 lines 53.9 kB
"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