Skip to content

Instantly share code, notes, and snippets.

@kissgyorgy
Created January 10, 2023 00:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kissgyorgy/39623a7d0ba2f6faafb464b72a1d412d to your computer and use it in GitHub Desktop.
Save kissgyorgy/39623a7d0ba2f6faafb464b72a1d412d to your computer and use it in GitHub Desktop.
JavaScript: BitArray
import { inflateRaw, deflateRaw } from "pako";
// https://en.wikipedia.org/wiki/Run-length_encoding
const Z_RLE = 3;
class BitArray {
constructor(bitSize) {
const remainder = Math.min(1, bitSize % 8);
const byteSize = Math.floor(bitSize / 8) + remainder;
const buffer = new ArrayBuffer(byteSize);
this._arr = new Uint8Array(buffer);
this._bitSize = bitSize;
}
*[Symbol.iterator]() {
for (let bit = 0; bit < this._bitSize; bit++) {
yield this.isSet(bit);
}
}
toUrlSafeBase64() {
var compressedBytes = deflateRaw(this._arr, { strategy: Z_RLE, to: "string" });
const base64 = btoa(compressedBytes);
const makeUrlSafe = (m) => ({ "+": "-", "/": "_", "=": "" }[m]);
return base64.replace(/[+/=]/g, makeUrlSafe);
}
static fromUrlSafeBase64(urlSafeBase64) {
const makeOriginal = (match) => ({ "-": "+", _: "/" }[match]);
const base64 = urlSafeBase64.replace(/[-_]/g, makeOriginal);
const compressedBytes = atob(base64);
// FIXME: handle errors
const bytesArr = inflateRaw(compressedBytes, { strategy: Z_RLE });
const obj = new this(bytesArr.length * 8);
obj._arr = bytesArr;
return obj;
}
set(bitPos) {
const bytePos = Math.ceil(bitPos / 8);
const bytePosVal = 2 ** (bitPos % 8);
this._arr[bytePos] |= bytePosVal;
}
isSet(bitPos) {
const bytePos = Math.ceil(bitPos / 8);
const bytePosVal = 2 ** (bitPos % 8);
return (this._arr[bytePos] & bytePosVal) !== 0;
}
}
export default BitArray;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment