antlr4ts
Version:
ANTLR 4 runtime for JavaScript written in Typescript
671 lines • 22.5 kB
JavaScript
"use strict";
/*!
* Copyright 2016 The ANTLR Project. All rights reserved.
* Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BitSet = void 0;
const util = require("util");
const MurmurHash_1 = require("./MurmurHash");
/**
* Private empty array used to construct empty BitSets
*/
const EMPTY_DATA = new Uint16Array(0);
/**
* Gets the word index of the `UInt16` element in `BitSet.data` containing the bit with the specified index.
*/
function getIndex(bitNumber) {
return bitNumber >>> 4;
}
/**
* Convert a word index into the bit index of the LSB of that word
*/
function unIndex(n) {
return n * 16;
}
/**
* Get's the bit number of the least signficant bit set LSB which is set in a word non-zero word;
* Bit numbers run from LSB to MSB starting with 0.
*/
function findLSBSet(word) {
let bit = 1;
for (let i = 0; i < 16; i++) {
if ((word & bit) !== 0) {
return i;
}
bit = (bit << 1) >>> 0;
}
throw new RangeError("No specified bit found");
}
function findMSBSet(word) {
let bit = (1 << 15) >>> 0;
for (let i = 15; i >= 0; i--) {
if ((word & bit) !== 0) {
return i;
}
bit = bit >>> 1;
}
throw new RangeError("No specified bit found");
}
/**
* Gets a 16-bit mask with bit numbers fromBit to toBit (inclusive) set.
* Bit numbers run from LSB to MSB starting with 0.
*/
function bitsFor(fromBit, toBit) {
fromBit &= 0xF;
toBit &= 0xF;
if (fromBit === toBit) {
return (1 << fromBit) >>> 0;
}
return ((0xFFFF >>> (15 - toBit)) ^ (0xFFFF >>> (16 - fromBit)));
}
/**
* A lookup table for number of set bits in a 16-bit integer. This is used to quickly count the cardinality (number of unique elements) of a BitSet.
*/
const POP_CNT = new Uint8Array(65536);
for (let i = 0; i < 16; i++) {
const stride = (1 << i) >>> 0;
let index = 0;
while (index < POP_CNT.length) {
// skip the numbers where the bit isn't set
index += stride;
// increment the ones where the bit is set
for (let j = 0; j < stride; j++) {
POP_CNT[index]++;
index++;
}
}
}
class BitSet {
/*
** constructor implementation
*/
constructor(arg) {
if (!arg) {
// covering the case of unspecified and nbits===0
this.data = EMPTY_DATA;
}
else if (typeof arg === "number") {
if (arg < 0) {
throw new RangeError("nbits cannot be negative");
}
else {
this.data = new Uint16Array(getIndex(arg - 1) + 1);
}
}
else {
if (arg instanceof BitSet) {
this.data = arg.data.slice(0); // Clone the data
}
else {
let max = -1;
for (let v of arg) {
if (max < v) {
max = v;
}
}
this.data = new Uint16Array(getIndex(max - 1) + 1);
for (let v of arg) {
this.set(v);
}
}
}
}
/**
* Performs a logical **AND** of this target bit set with the argument bit set. This bit set is modified so that
* each bit in it has the value `true` if and only if it both initially had the value `true` and the corresponding
* bit in the bit set argument also had the value `true`.
*/
and(set) {
const data = this.data;
const other = set.data;
const words = Math.min(data.length, other.length);
let lastWord = -1; // Keep track of index of last non-zero word
for (let i = 0; i < words; i++) {
let value = data[i] &= other[i];
if (value !== 0) {
lastWord = i;
}
}
if (lastWord === -1) {
this.data = EMPTY_DATA;
}
if (lastWord < data.length - 1) {
this.data = data.slice(0, lastWord + 1);
}
}
/**
* Clears all of the bits in this `BitSet` whose corresponding bit is set in the specified `BitSet`.
*/
andNot(set) {
const data = this.data;
const other = set.data;
const words = Math.min(data.length, other.length);
let lastWord = -1; // Keep track of index of last non-zero word
for (let i = 0; i < words; i++) {
let value = data[i] &= (other[i] ^ 0xFFFF);
if (value !== 0) {
lastWord = i;
}
}
if (lastWord === -1) {
this.data = EMPTY_DATA;
}
if (lastWord < data.length - 1) {
this.data = data.slice(0, lastWord + 1);
}
}
/**
* Returns the number of bits set to `true` in this `BitSet`.
*/
cardinality() {
if (this.isEmpty) {
return 0;
}
const data = this.data;
const length = data.length;
let result = 0;
for (let i = 0; i < length; i++) {
result += POP_CNT[data[i]];
}
return result;
}
clear(fromIndex, toIndex) {
if (fromIndex == null) {
this.data.fill(0);
}
else if (toIndex == null) {
this.set(fromIndex, false);
}
else {
this.set(fromIndex, toIndex, false);
}
}
flip(fromIndex, toIndex) {
if (toIndex == null) {
toIndex = fromIndex;
}
if (fromIndex < 0 || toIndex < fromIndex) {
throw new RangeError();
}
let word = getIndex(fromIndex);
const lastWord = getIndex(toIndex);
if (word === lastWord) {
this.data[word] ^= bitsFor(fromIndex, toIndex);
}
else {
this.data[word++] ^= bitsFor(fromIndex, 15);
while (word < lastWord) {
this.data[word++] ^= 0xFFFF;
}
this.data[word++] ^= bitsFor(0, toIndex);
}
}
get(fromIndex, toIndex) {
if (toIndex === undefined) {
return !!(this.data[getIndex(fromIndex)] & bitsFor(fromIndex, fromIndex));
}
else {
// return a BitSet
let result = new BitSet(toIndex + 1);
for (let i = fromIndex; i <= toIndex; i++) {
result.set(i, this.get(i));
}
return result;
}
}
/**
* Returns true if the specified `BitSet` has any bits set to `true` that are also set to `true` in this `BitSet`.
*
* @param set `BitSet` to intersect with
*/
intersects(set) {
let smallerLength = Math.min(this.length(), set.length());
if (smallerLength === 0) {
return false;
}
let bound = getIndex(smallerLength - 1);
for (let i = 0; i <= bound; i++) {
if ((this.data[i] & set.data[i]) !== 0) {
return true;
}
}
return false;
}
/**
* Returns true if this `BitSet` contains no bits that are set to `true`.
*/
get isEmpty() {
return this.length() === 0;
}
/**
* Returns the "logical size" of this `BitSet`: the index of the highest set bit in the `BitSet` plus one. Returns
* zero if the `BitSet` contains no set bits.
*/
length() {
if (!this.data.length) {
return 0;
}
return this.previousSetBit(unIndex(this.data.length) - 1) + 1;
}
/**
* Returns the index of the first bit that is set to `false` that occurs on or after the specified starting index,
* If no such bit exists then `-1` is returned.
*
* @param fromIndex the index to start checking from (inclusive)
*
* @throws RangeError if the specified index is negative
*/
nextClearBit(fromIndex) {
if (fromIndex < 0) {
throw new RangeError("fromIndex cannot be negative");
}
const data = this.data;
const length = data.length;
let word = getIndex(fromIndex);
if (word > length) {
return -1;
}
let ignore = 0xFFFF ^ bitsFor(fromIndex, 15);
if ((data[word] | ignore) === 0xFFFF) {
word++;
ignore = 0;
for (; word < length; word++) {
if (data[word] !== 0xFFFF) {
break;
}
}
if (word === length) {
// Hit the end
return -1;
}
}
return unIndex(word) + findLSBSet((data[word] | ignore) ^ 0xFFFF);
}
/**
* Returns the index of the first bit that is set to `true` that occurs on or after the specified starting index.
* If no such bit exists then `-1` is returned.
*
* To iterate over the `true` bits in a `BitSet`, use the following loop:
*
* ```
* for (let i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
* // operate on index i here
* }
* ```
*
* @param fromIndex the index to start checking from (inclusive)
*
* @throws RangeError if the specified index is negative
*/
nextSetBit(fromIndex) {
if (fromIndex < 0) {
throw new RangeError("fromIndex cannot be negative");
}
const data = this.data;
const length = data.length;
let word = getIndex(fromIndex);
if (word > length) {
return -1;
}
let mask = bitsFor(fromIndex, 15);
if ((data[word] & mask) === 0) {
word++;
mask = 0xFFFF;
for (; word < length; word++) {
if (data[word] !== 0) {
break;
}
}
if (word >= length) {
return -1;
}
}
return unIndex(word) + findLSBSet(data[word] & mask);
}
/**
* Performs a logical **OR** of this bit set with the bit set argument. This bit set is modified so that a bit in it
* has the value `true` if and only if it either already had the value `true` or the corresponding bit in the bit
* set argument has the value `true`.
*/
or(set) {
const data = this.data;
const other = set.data;
const minWords = Math.min(data.length, other.length);
const words = Math.max(data.length, other.length);
const dest = data.length === words ? data : new Uint16Array(words);
let lastWord = -1;
// Or those words both sets have in common
for (let i = 0; i < minWords; i++) {
let value = dest[i] = data[i] | other[i];
if (value !== 0) {
lastWord = i;
}
}
// Copy words from larger set (if there is one)
const longer = data.length > other.length ? data : other;
for (let i = minWords; i < words; i++) {
let value = dest[i] = longer[i];
if (value !== 0) {
lastWord = i;
}
}
if (lastWord === -1) {
this.data = EMPTY_DATA;
}
else if (dest.length === lastWord + 1) {
this.data = dest;
}
else {
this.data = dest.slice(0, lastWord);
}
}
/**
* Returns the index of the nearest bit that is set to `false` that occurs on or before the specified starting
* index. If no such bit exists, or if `-1` is given as the starting index, then `-1` is returned.
*
* @param fromIndex the index to start checking from (inclusive)
*
* @throws RangeError if the specified index is less than `-1`
*/
previousClearBit(fromIndex) {
if (fromIndex < 0) {
throw new RangeError("fromIndex cannot be negative");
}
const data = this.data;
const length = data.length;
let word = getIndex(fromIndex);
if (word >= length) {
word = length - 1;
}
let ignore = 0xFFFF ^ bitsFor(0, fromIndex);
if ((data[word] | ignore) === 0xFFFF) {
ignore = 0;
word--;
for (; word >= 0; word--) {
if (data[word] !== 0xFFFF) {
break;
}
}
if (word < 0) {
// Hit the end
return -1;
}
}
return unIndex(word) + findMSBSet((data[word] | ignore) ^ 0xFFFF);
}
/**
* Returns the index of the nearest bit that is set to `true` that occurs on or before the specified starting index.
* If no such bit exists, or if `-1` is given as the starting index, then `-1` is returned.
*
* To iterate over the `true` bits in a `BitSet`, use the following loop:
*
* ```
* for (let i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
* // operate on index i here
* }
* ```
*
* @param fromIndex the index to start checking from (inclusive)
*
* @throws RangeError if the specified index is less than `-1`
*/
previousSetBit(fromIndex) {
if (fromIndex < 0) {
throw new RangeError("fromIndex cannot be negative");
}
const data = this.data;
const length = data.length;
let word = getIndex(fromIndex);
if (word >= length) {
word = length - 1;
}
let mask = bitsFor(0, fromIndex);
if ((data[word] & mask) === 0) {
word--;
mask = 0xFFFF;
for (; word >= 0; word--) {
if (data[word] !== 0) {
break;
}
}
if (word < 0) {
return -1;
}
}
return unIndex(word) + findMSBSet(data[word] & mask);
}
set(fromIndex, toIndex, value) {
if (toIndex === undefined) {
toIndex = fromIndex;
value = true;
}
else if (typeof toIndex === "boolean") {
value = toIndex;
toIndex = fromIndex;
}
if (value === undefined) {
value = true;
}
if (fromIndex < 0 || fromIndex > toIndex) {
throw new RangeError();
}
let word = getIndex(fromIndex);
let lastWord = getIndex(toIndex);
if (value && lastWord >= this.data.length) {
// Grow array "just enough" for bits we need to set
let temp = new Uint16Array(lastWord + 1);
this.data.forEach((value, index) => temp[index] = value);
this.data = temp;
}
else if (!value) {
// But there is no need to grow array to clear bits.
if (word >= this.data.length) {
// Early exit
return;
}
if (lastWord >= this.data.length) {
// Adjust work to fit array
lastWord = this.data.length - 1;
toIndex = this.data.length * 16 - 1;
}
}
if (word === lastWord) {
this._setBits(word, value, bitsFor(fromIndex, toIndex));
}
else {
this._setBits(word++, value, bitsFor(fromIndex, 15));
while (word < lastWord) {
this.data[word++] = value ? 0xFFFF : 0;
}
this._setBits(word, value, bitsFor(0, toIndex));
}
}
_setBits(word, value, mask) {
if (value) {
this.data[word] |= mask;
}
else {
this.data[word] &= 0xFFFF ^ mask;
}
}
/**
* Returns the number of bits of space actually in use by this `BitSet` to represent bit values. The maximum element
* in the set is the size - 1st element.
*/
get size() {
return this.data.byteLength * 8;
}
/**
* Returns a new byte array containing all the bits in this bit set.
*
* More precisely, if
* `let bytes = s.toByteArray();`
* then `bytes.length === (s.length()+7)/8` and `s.get(n) === ((bytes[n/8] & (1<<(n%8))) != 0)` for all
* `n < 8 * bytes.length`.
*/
// toByteArray(): Int8Array {
// throw new Error("NOT IMPLEMENTED");
// }
/**
* Returns a new integer array containing all the bits in this bit set.
*
* More precisely, if
* `let integers = s.toIntegerArray();`
* then `integers.length === (s.length()+31)/32` and `s.get(n) === ((integers[n/32] & (1<<(n%32))) != 0)` for all
* `n < 32 * integers.length`.
*/
// toIntegerArray(): Int32Array {
// throw new Error("NOT IMPLEMENTED");
// }
hashCode() {
return MurmurHash_1.MurmurHash.hashCode(this.data, 22);
}
/**
* Compares this object against the specified object. The result is `true` if and only if the argument is not
* `undefined` and is a `Bitset` object that has exactly the same set of bits set to `true` as this bit set. That
* is, for every nonnegative index `k`,
*
* ```
* ((BitSet)obj).get(k) == this.get(k)
* ```
*
* must be true. The current sizes of the two bit sets are not compared.
*/
equals(obj) {
if (obj === this) {
return true;
}
else if (!(obj instanceof BitSet)) {
return false;
}
const len = this.length();
if (len !== obj.length()) {
return false;
}
if (len === 0) {
return true;
}
let bound = getIndex(len - 1);
for (let i = 0; i <= bound; i++) {
if (this.data[i] !== obj.data[i]) {
return false;
}
}
return true;
}
/**
* Returns a string representation of this bit set. For every index for which this `BitSet` contains a bit in the
* set state, the decimal representation of that index is included in the result. Such indices are listed in order
* from lowest to highest, separated by ", " (a comma and a space) and surrounded by braces, resulting in the usual
* mathematical notation for a set of integers.
*
* Example:
*
* BitSet drPepper = new BitSet();
*
* Now `drPepper.toString()` returns `"{}"`.
*
* drPepper.set(2);
*
* Now `drPepper.toString()` returns `"{2}"`.
*
* drPepper.set(4);
* drPepper.set(10);
*
* Now `drPepper.toString()` returns `"{2, 4, 10}"`.
*/
toString() {
let result = "{";
let first = true;
for (let i = this.nextSetBit(0); i >= 0; i = this.nextSetBit(i + 1)) {
if (first) {
first = false;
}
else {
result += ", ";
}
result += i;
}
result += "}";
return result;
}
// static valueOf(bytes: Int8Array): BitSet;
// static valueOf(buffer: ArrayBuffer): BitSet;
// static valueOf(integers: Int32Array): BitSet;
// static valueOf(data: Int8Array | Int32Array | ArrayBuffer): BitSet {
// throw new Error("NOT IMPLEMENTED");
// }
/**
* Performs a logical **XOR** of this bit set with the bit set argument. This bit set is modified so that a bit in
* it has the value `true` if and only if one of the following statements holds:
*
* * The bit initially has the value `true`, and the corresponding bit in the argument has the value `false`.
* * The bit initially has the value `false`, and the corresponding bit in the argument has the value `true`.
*/
xor(set) {
const data = this.data;
const other = set.data;
const minWords = Math.min(data.length, other.length);
const words = Math.max(data.length, other.length);
const dest = data.length === words ? data : new Uint16Array(words);
let lastWord = -1;
// Xor those words both sets have in common
for (let i = 0; i < minWords; i++) {
let value = dest[i] = data[i] ^ other[i];
if (value !== 0) {
lastWord = i;
}
}
// Copy words from larger set (if there is one)
const longer = data.length > other.length ? data : other;
for (let i = minWords; i < words; i++) {
let value = dest[i] = longer[i];
if (value !== 0) {
lastWord = i;
}
}
if (lastWord === -1) {
this.data = EMPTY_DATA;
}
else if (dest.length === lastWord + 1) {
this.data = dest;
}
else {
this.data = dest.slice(0, lastWord + 1);
}
}
clone() {
return new BitSet(this);
}
[Symbol.iterator]() {
return new BitSetIterator(this.data);
}
// Overrides formatting for nodejs assert etc.
[util.inspect.custom]() {
return "BitSet " + this.toString();
}
}
exports.BitSet = BitSet;
class BitSetIterator {
constructor(data) {
this.data = data;
this.index = 0;
this.mask = 0xFFFF;
}
next() {
while (this.index < this.data.length) {
const bits = this.data[this.index] & this.mask;
if (bits !== 0) {
const bitNumber = unIndex(this.index) + findLSBSet(bits);
this.mask = bitsFor(bitNumber + 1, 15);
return { done: false, value: bitNumber };
}
this.index++;
this.mask = 0xFFFF;
}
return { done: true, value: -1 };
}
[Symbol.iterator]() { return this; }
}
//# sourceMappingURL=BitSet.js.map