Projektstart
This commit is contained in:
550
backend/node_modules/mnemonist/bit-vector.js
generated
vendored
Normal file
550
backend/node_modules/mnemonist/bit-vector.js
generated
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
/**
|
||||
* Mnemonist BitVector
|
||||
* ====================
|
||||
*
|
||||
* JavaScript implementation of a dynamic BitSet based upon a Uint32Array.
|
||||
*
|
||||
* Notes:
|
||||
* - (i >> 5) is the same as ((i / 32) | 0)
|
||||
* - (i & 0x0000001f) is the same as (i % 32)
|
||||
* - I could use a Float64Array to store more in less blocks but I would lose
|
||||
* the benefits of byte comparison to keep track of size without popcounts.
|
||||
*/
|
||||
var Iterator = require('obliterator/iterator'),
|
||||
bitwise = require('./utils/bitwise.js');
|
||||
|
||||
/**
|
||||
* Constants.
|
||||
*/
|
||||
var DEFAULT_GROWING_POLICY = function(capacity) {
|
||||
return Math.max(1, Math.ceil(capacity * 1.5));
|
||||
};
|
||||
|
||||
/**
|
||||
* Helpers.
|
||||
*/
|
||||
function createByteArray(capacity) {
|
||||
return new Uint32Array(Math.ceil(capacity / 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* BitVector.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function BitVector(initialLengthOrOptions) {
|
||||
var initialLength = initialLengthOrOptions || 0,
|
||||
policy = DEFAULT_GROWING_POLICY;
|
||||
|
||||
if (typeof initialLengthOrOptions === 'object') {
|
||||
initialLength = (
|
||||
initialLengthOrOptions.initialLength ||
|
||||
initialLengthOrOptions.initialCapacity ||
|
||||
0
|
||||
);
|
||||
policy = initialLengthOrOptions.policy || policy;
|
||||
}
|
||||
|
||||
this.size = 0;
|
||||
this.length = initialLength;
|
||||
this.capacity = Math.ceil(this.length / 32) * 32;
|
||||
this.policy = policy;
|
||||
this.array = createByteArray(this.capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to set the given bit's value.
|
||||
*
|
||||
* @param {number} index - Target bit index.
|
||||
* @param {number|boolean} value - Value to set.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.set = function(index, value) {
|
||||
|
||||
// Out of bounds?
|
||||
if (this.length < index)
|
||||
throw new Error('BitVector.set: index out of bounds.');
|
||||
|
||||
var byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f,
|
||||
oldBytes = this.array[byteIndex],
|
||||
newBytes;
|
||||
|
||||
if (value === 0 || value === false)
|
||||
newBytes = this.array[byteIndex] &= ~(1 << pos);
|
||||
else
|
||||
newBytes = this.array[byteIndex] |= (1 << pos);
|
||||
|
||||
// Get unsigned representation.
|
||||
newBytes = newBytes >>> 0;
|
||||
|
||||
// Updating size
|
||||
if (newBytes > oldBytes)
|
||||
this.size++;
|
||||
else if (newBytes < oldBytes)
|
||||
this.size--;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to reset the given bit's value.
|
||||
*
|
||||
* @param {number} index - Target bit index.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.reset = function(index) {
|
||||
var byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f,
|
||||
oldBytes = this.array[byteIndex],
|
||||
newBytes;
|
||||
|
||||
newBytes = this.array[byteIndex] &= ~(1 << pos);
|
||||
|
||||
// Updating size
|
||||
if (newBytes < oldBytes)
|
||||
this.size--;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to flip the value of the given bit.
|
||||
*
|
||||
* @param {number} index - Target bit index.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.flip = function(index) {
|
||||
var byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f,
|
||||
oldBytes = this.array[byteIndex];
|
||||
|
||||
var newBytes = this.array[byteIndex] ^= (1 << pos);
|
||||
|
||||
// Get unsigned representation.
|
||||
newBytes = newBytes >>> 0;
|
||||
|
||||
// Updating size
|
||||
if (newBytes > oldBytes)
|
||||
this.size++;
|
||||
else if (newBytes < oldBytes)
|
||||
this.size--;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to apply the growing policy.
|
||||
*
|
||||
* @param {number} [override] - Override capacity.
|
||||
* @return {number}
|
||||
*/
|
||||
BitVector.prototype.applyPolicy = function(override) {
|
||||
var newCapacity = this.policy(override || this.capacity);
|
||||
|
||||
if (typeof newCapacity !== 'number' || newCapacity < 0)
|
||||
throw new Error('mnemonist/bit-vector.applyPolicy: policy returned an invalid value (expecting a positive integer).');
|
||||
|
||||
if (newCapacity <= this.capacity)
|
||||
throw new Error('mnemonist/bit-vector.applyPolicy: policy returned a less or equal capacity to allocate.');
|
||||
|
||||
// TODO: we should probably check that the returned number is an integer
|
||||
|
||||
// Ceil to nearest 32
|
||||
return Math.ceil(newCapacity / 32) * 32;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to reallocate the underlying array.
|
||||
*
|
||||
* @param {number} capacity - Target capacity.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.reallocate = function(capacity) {
|
||||
var virtualCapacity = capacity;
|
||||
|
||||
capacity = Math.ceil(capacity / 32) * 32;
|
||||
|
||||
if (virtualCapacity < this.length)
|
||||
this.length = virtualCapacity;
|
||||
|
||||
if (capacity === this.capacity)
|
||||
return this;
|
||||
|
||||
var oldArray = this.array;
|
||||
|
||||
var storageLength = capacity / 32;
|
||||
|
||||
if (storageLength === this.array.length)
|
||||
return this;
|
||||
|
||||
if (storageLength > this.array.length) {
|
||||
this.array = new Uint32Array(storageLength);
|
||||
this.array.set(oldArray, 0);
|
||||
}
|
||||
else {
|
||||
this.array = oldArray.slice(0, storageLength);
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to grow the array.
|
||||
*
|
||||
* @param {number} [capacity] - Optional capacity to match.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.grow = function(capacity) {
|
||||
var newCapacity;
|
||||
|
||||
if (typeof capacity === 'number') {
|
||||
|
||||
if (this.capacity >= capacity)
|
||||
return this;
|
||||
|
||||
// We need to match the given capacity
|
||||
newCapacity = this.capacity;
|
||||
|
||||
while (newCapacity < capacity)
|
||||
newCapacity = this.applyPolicy(newCapacity);
|
||||
|
||||
this.reallocate(newCapacity);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// We need to run the policy once
|
||||
newCapacity = this.applyPolicy();
|
||||
this.reallocate(newCapacity);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to resize the array. Won't deallocate.
|
||||
*
|
||||
* @param {number} length - Target length.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.resize = function(length) {
|
||||
if (length === this.length)
|
||||
return this;
|
||||
|
||||
if (length < this.length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.length = length;
|
||||
this.reallocate(length);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to push a value in the set.
|
||||
*
|
||||
* @param {number|boolean} value
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.push = function(value) {
|
||||
if (this.capacity === this.length)
|
||||
this.grow();
|
||||
|
||||
if (value === 0 || value === false)
|
||||
return ++this.length;
|
||||
|
||||
this.size++;
|
||||
|
||||
var index = this.length++,
|
||||
byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f;
|
||||
|
||||
this.array[byteIndex] |= (1 << pos);
|
||||
|
||||
return this.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to pop the last value of the set.
|
||||
*
|
||||
* @return {number} - The popped value.
|
||||
*/
|
||||
BitVector.prototype.pop = function() {
|
||||
if (this.length === 0)
|
||||
return;
|
||||
|
||||
var index = --this.length;
|
||||
|
||||
var byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f;
|
||||
|
||||
return (this.array[byteIndex] >> pos) & 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to get the given bit's value.
|
||||
*
|
||||
* @param {number} index - Target bit index.
|
||||
* @return {number}
|
||||
*/
|
||||
BitVector.prototype.get = function(index) {
|
||||
if (this.length < index)
|
||||
return undefined;
|
||||
|
||||
var byteIndex = index >> 5,
|
||||
pos = index & 0x0000001f;
|
||||
|
||||
return (this.array[byteIndex] >> pos) & 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to test the given bit's value.
|
||||
*
|
||||
* @param {number} index - Target bit index.
|
||||
* @return {BitVector}
|
||||
*/
|
||||
BitVector.prototype.test = function(index) {
|
||||
if (this.length < index)
|
||||
return false;
|
||||
|
||||
return Boolean(this.get(index));
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to return the number of 1 from the beginning of the set up to
|
||||
* the ith index.
|
||||
*
|
||||
* @param {number} i - Ith index (cannot be > length).
|
||||
* @return {number}
|
||||
*/
|
||||
BitVector.prototype.rank = function(i) {
|
||||
if (this.size === 0)
|
||||
return 0;
|
||||
|
||||
var byteIndex = i >> 5,
|
||||
pos = i & 0x0000001f,
|
||||
r = 0;
|
||||
|
||||
// Accessing the bytes before the last one
|
||||
for (var j = 0; j < byteIndex; j++)
|
||||
r += bitwise.table8Popcount(this.array[j]);
|
||||
|
||||
// Handling masked last byte
|
||||
var maskedByte = this.array[byteIndex] & ((1 << pos) - 1);
|
||||
|
||||
r += bitwise.table8Popcount(maskedByte);
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to return the position of the rth 1 in the set or -1 if the
|
||||
* set is empty.
|
||||
*
|
||||
* Note: usually select is implemented using binary search over rank but I
|
||||
* tend to think the following linear implementation is faster since here
|
||||
* rank is O(n) anyway.
|
||||
*
|
||||
* @param {number} r - Rth 1 to select (should be < length).
|
||||
* @return {number}
|
||||
*/
|
||||
BitVector.prototype.select = function(r) {
|
||||
if (this.size === 0)
|
||||
return -1;
|
||||
|
||||
// TODO: throw?
|
||||
if (r >= this.length)
|
||||
return -1;
|
||||
|
||||
var byte,
|
||||
b = 32,
|
||||
p = 0,
|
||||
c = 0;
|
||||
|
||||
for (var i = 0, l = this.array.length; i < l; i++) {
|
||||
byte = this.array[i];
|
||||
|
||||
// The byte is empty, let's continue
|
||||
if (byte === 0)
|
||||
continue;
|
||||
|
||||
// TODO: This branching might not be useful here
|
||||
if (i === l - 1)
|
||||
b = this.length % 32 || 32;
|
||||
|
||||
// TODO: popcount should speed things up here
|
||||
|
||||
for (var j = 0; j < b; j++, p++) {
|
||||
c += (byte >> j) & 1;
|
||||
|
||||
if (c === r)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to iterate over the bit set's values.
|
||||
*
|
||||
* @param {function} callback - Function to call for each item.
|
||||
* @param {object} scope - Optional scope.
|
||||
* @return {undefined}
|
||||
*/
|
||||
BitVector.prototype.forEach = function(callback, scope) {
|
||||
scope = arguments.length > 1 ? scope : this;
|
||||
|
||||
var length = this.length,
|
||||
byte,
|
||||
bit,
|
||||
b = 32;
|
||||
|
||||
for (var i = 0, l = this.array.length; i < l; i++) {
|
||||
byte = this.array[i];
|
||||
|
||||
if (i === l - 1)
|
||||
b = length % 32 || 32;
|
||||
|
||||
for (var j = 0; j < b; j++) {
|
||||
bit = (byte >> j) & 1;
|
||||
|
||||
callback.call(scope, bit, i * 32 + j);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to create an iterator over a set's values.
|
||||
*
|
||||
* @return {Iterator}
|
||||
*/
|
||||
BitVector.prototype.values = function() {
|
||||
var length = this.length,
|
||||
inner = false,
|
||||
byte,
|
||||
bit,
|
||||
array = this.array,
|
||||
l = array.length,
|
||||
i = 0,
|
||||
j = -1,
|
||||
b = 32;
|
||||
|
||||
return new Iterator(function next() {
|
||||
if (!inner) {
|
||||
|
||||
if (i >= l)
|
||||
return {
|
||||
done: true
|
||||
};
|
||||
|
||||
if (i === l - 1)
|
||||
b = length % 32 || 32;
|
||||
|
||||
byte = array[i++];
|
||||
inner = true;
|
||||
j = -1;
|
||||
}
|
||||
|
||||
j++;
|
||||
|
||||
if (j >= b) {
|
||||
inner = false;
|
||||
return next();
|
||||
}
|
||||
|
||||
bit = (byte >> j) & 1;
|
||||
|
||||
return {
|
||||
value: bit
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Method used to create an iterator over a set's entries.
|
||||
*
|
||||
* @return {Iterator}
|
||||
*/
|
||||
BitVector.prototype.entries = function() {
|
||||
var length = this.length,
|
||||
inner = false,
|
||||
byte,
|
||||
bit,
|
||||
array = this.array,
|
||||
index,
|
||||
l = array.length,
|
||||
i = 0,
|
||||
j = -1,
|
||||
b = 32;
|
||||
|
||||
return new Iterator(function next() {
|
||||
if (!inner) {
|
||||
|
||||
if (i >= l)
|
||||
return {
|
||||
done: true
|
||||
};
|
||||
|
||||
if (i === l - 1)
|
||||
b = length % 32 || 32;
|
||||
|
||||
byte = array[i++];
|
||||
inner = true;
|
||||
j = -1;
|
||||
}
|
||||
|
||||
j++;
|
||||
index = (~-i) * 32 + j;
|
||||
|
||||
if (j >= b) {
|
||||
inner = false;
|
||||
return next();
|
||||
}
|
||||
|
||||
bit = (byte >> j) & 1;
|
||||
|
||||
return {
|
||||
value: [index, bit]
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaching the #.values method to Symbol.iterator if possible.
|
||||
*/
|
||||
if (typeof Symbol !== 'undefined')
|
||||
BitVector.prototype[Symbol.iterator] = BitVector.prototype.values;
|
||||
|
||||
/**
|
||||
* Convenience known methods.
|
||||
*/
|
||||
BitVector.prototype.inspect = function() {
|
||||
var proxy = new Uint8Array(this.length);
|
||||
|
||||
this.forEach(function(bit, i) {
|
||||
proxy[i] = bit;
|
||||
});
|
||||
|
||||
// Trick so that node displays the name of the constructor
|
||||
Object.defineProperty(proxy, 'constructor', {
|
||||
value: BitVector,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
return proxy;
|
||||
};
|
||||
|
||||
if (typeof Symbol !== 'undefined')
|
||||
BitVector.prototype[Symbol.for('nodejs.util.inspect.custom')] = BitVector.prototype.inspect;
|
||||
|
||||
BitVector.prototype.toJSON = function() {
|
||||
return Array.from(this.array.slice(0, (this.length >> 5) + 1));
|
||||
};
|
||||
|
||||
/**
|
||||
* Exporting.
|
||||
*/
|
||||
module.exports = BitVector;
|
||||
Reference in New Issue
Block a user