UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

257 lines 7.26 kB
import { equals } from "./eq"; import { assert } from "./assert"; import { has_refs } from "./refs"; import { logger } from "../logging"; export class BitSet { size; static __name__ = "BitSet"; [Symbol.toStringTag] = "BitSet"; static [has_refs] = false; static _word_length = 32; _array; _nwords; constructor(size, init = 0) { this.size = size; this._nwords = Math.ceil(size / BitSet._word_length); if (init == 0 || init == 1) { this._array = new Uint32Array(this._nwords); if (init == 1) { this._array.fill(0xffffffff); } } else { assert(init.length == this._nwords, "Initializer size mismatch"); this._array = init; } } clone() { return new BitSet(this.size, new Uint32Array(this._array)); } [equals](that, cmp) { if (!cmp.eq(this.size, that.size)) { return false; } const { _nwords } = this; const trailing = this.size % BitSet._word_length; const n = trailing == 0 ? _nwords : _nwords - 1; for (let i = 0; i < n; i++) { if (this._array[i] != that._array[i]) { return false; } } if (trailing == 0) { return true; } else { const msb = 1 << (trailing - 1); const mask = (msb - 1) ^ msb; return (this._array[n] & mask) == (that._array[n] & mask); } } static all_set(size) { return new BitSet(size, 1); } static all_unset(size) { return new BitSet(size, 0); } static from_indices(size, indices) { const bits = new BitSet(size); for (const i of indices) { bits.set(i); } return bits; } static from_booleans(size, booleans) { const bits = new BitSet(size); let i = 0; for (const boolean of booleans) { if (i == size) { break; } if (boolean) { bits.set(i); } i += 1; } return bits; } get_unchecked(k) { const i = k >>> 5; // Math.floor(k/32) const j = k & 0x1f; // k % 32 return ((this._array[i] >> j) & 0b1) == 0b1; } set_unchecked(k, v = true) { this._count = null; const i = k >>> 5; // Math.floor(k/32) const j = k & 0x1f; // k % 32 if (v) { this._array[i] |= 0b1 << j; } else { this._array[i] &= ~(0b1 << j); } } get(k) { const { size } = this; if (0 <= k && k < size) { return this.get_unchecked(k); } else if (-size <= k && k <= -1) { return this.get_unchecked(size + k); } else { return false; } } set(k, v = true) { const { size } = this; if (0 <= k && k < size) { this.set_unchecked(k, v); } else if (-size <= k && k <= -1) { this.set_unchecked(size + k, v); } else { logger.warn(`out of bounds access: index=${k >= 0 ? k : size + k} >= size=${size}`); } } unset(k) { this.set(k, false); } *[Symbol.iterator]() { yield* this.ones(); } _count = null; get count() { let count = this._count; if (count == null) { this._count = count = this._get_count(); } return count; } _get_count() { const { _array, _nwords, size } = this; let c = 0; for (let k = 0, i = 0; i < _nwords; i++) { const word = _array[i]; if (word == 0) { k += BitSet._word_length; } else { for (let j = 0; j < BitSet._word_length && k < size; j++, k++) { if (((word >>> j) & 0b1) == 0b1) { c += 1; } } } } return c; } ones() { const indices = new Array(this.count); let index = 0; const { _array, _nwords, size } = this; for (let k = 0, i = 0; i < _nwords; i++) { const word = _array[i]; if (word == 0) { k += BitSet._word_length; continue; } for (let j = 0; j < BitSet._word_length && k < size; j++, k++) { if (((word >>> j) & 0b1) == 0b1) { indices[index++] = k; } } } return indices; } zeros() { const indices = new Array(this.count); let index = 0; const { _array, _nwords, size } = this; for (let k = 0, i = 0; i < _nwords; i++) { const word = _array[i]; if (word == 0xffffffff) { k += BitSet._word_length; continue; } for (let j = 0; j < BitSet._word_length && k < size; j++, k++) { if (((word >>> j) & 0b1) == 0b0) { indices[index++] = k; } } } return indices; } _check_size(other) { assert(this.size == other.size, `Size mismatch (${this.size} != ${other.size})`); } invert() { for (let i = 0; i < this._nwords; i++) { this._array[i] = ~this._array[i] >>> 0; } } add(other) { this._check_size(other); for (let i = 0; i < this._nwords; i++) { this._array[i] |= other._array[i]; } } intersect(other) { this._check_size(other); for (let i = 0; i < this._nwords; i++) { this._array[i] &= other._array[i]; } } subtract(other) { this._check_size(other); for (let i = 0; i < this._nwords; i++) { const a = this._array[i]; const b = other._array[i]; this._array[i] = (a ^ b) & a; } } symmetric_subtract(other) { this._check_size(other); for (let i = 0; i < this._nwords; i++) { this._array[i] ^= other._array[i]; } } inversion() { const result = this.clone(); result.invert(); return result; } union(other) { const result = this.clone(); result.add(other); return result; } intersection(other) { const result = this.clone(); result.intersect(other); return result; } difference(other) { const result = this.clone(); result.subtract(other); return result; } symmetric_difference(other) { const result = this.clone(); result.symmetric_subtract(other); return result; } select(array) { assert(this.size <= array.length, "Size mismatch"); const n = this.count; const result = new array.constructor(n); const indices = this.ones(); let i = 0; for (let j = 0; j < indices.length; j++) { result[i++] = array[indices[j]]; } return result; } } //# sourceMappingURL=bitset.js.map