@haelp/teto
Version:
A typescript-based controllable TETR.IO client.
161 lines (160 loc) • 4.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Bits", {
enumerable: true,
get: function() {
return Bits;
}
});
const MAX_BITS = Number.MAX_SAFE_INTEGER.toString(2).length;
class Bits {
buffer;
_length;
_offset;
constructor(t){
if (typeof t === "number") {
this.buffer = Buffer.alloc(Math.ceil(t / 8));
} else if (t instanceof Buffer) {
this.buffer = t;
} else {
throw new TypeError("Initialize by specifying a bit-length or referencing a Buffer");
}
this._length = this.buffer.length * 8;
this._offset = 0;
}
static alloc(t, r, n) {
return new Bits(Buffer.alloc(t, r ?? 0, n));
}
static from(t, r, n) {
return new Bits(Buffer.from(t, r, n));
}
get eof() {
return this._offset === this._length;
}
get length() {
return this._length;
}
get offset() {
return this._offset;
}
set offset(t) {
if (t < 0) {
throw new RangeError("Cannot set offset below 0");
}
if (t > this._length) {
throw new RangeError(`Cannot set offset to ${t}, buffer length is ${this._length}`);
}
this._offset = Math.floor(t);
}
get remaining() {
return this._length - this._offset;
}
clear(t = 0) {
this.buffer.fill(t);
this._offset = 0;
return this;
}
clearBit(t) {
this.insert(0, 1, t);
return this;
}
flipBit(t) {
const result = this.peek(1, t) ^ 1;
this.modifyBit(result, t);
return result;
}
getBit(t) {
return this.peek(1, t);
}
insert(val, bits = 1, pos) {
let r = typeof pos === "number" ? pos | 0 : this._offset;
if (r + bits > this._length) {
throw new RangeError(`Cannot write ${bits} bits, only ${this.remaining} bit(s) left`);
}
if (bits > MAX_BITS) {
throw new RangeError(`Cannot write ${bits} bits, max is ${MAX_BITS}`);
}
let i = bits;
while(i > 0){
const byteIndex = r >> 3;
const bitIndex = r & 7;
const o = Math.min(8 - bitIndex, i);
const mask = (1 << o) - 1;
const shift = 8 - o - bitIndex;
const u = (val >>> i - o & mask) << shift;
this.buffer[byteIndex] = this.buffer[byteIndex] & ~(mask << shift) | u;
r += o;
i -= o;
}
return r;
}
modifyBit(val, pos) {
this.insert(val, 1, pos);
return val;
}
peek(bits = 1, pos) {
let e = typeof pos === "number" ? pos | 0 : this._offset;
if (e + bits > this._length) {
throw new RangeError(`Cannot read ${bits} bits, only ${this.remaining} bit(s) left`);
}
if (bits > MAX_BITS) {
throw new RangeError(`Reading ${bits} bits would overflow result, max is ${MAX_BITS}`);
}
const bitOffset = e & 7;
const i = Math.min(8 - bitOffset, bits);
const mask = (1 << i) - 1;
let s = this.buffer[e >> 3] >> 8 - i - bitOffset & mask;
e += i;
let remainingBits = bits - i;
while(remainingBits >= 8){
s <<= 8;
s |= this.buffer[e >> 3];
e += 8;
remainingBits -= 8;
}
if (remainingBits > 0) {
const shift = 8 - remainingBits;
s <<= remainingBits;
s |= this.buffer[e >> 3] >> shift & 255 >> shift;
}
return s;
}
read(bits = 1) {
const val = this.peek(bits, this._offset);
this._offset += bits;
return val;
}
seek(t, mode = 1) {
switch(mode){
case 2:
this.offset = this._offset + t;
break;
case 3:
this.offset = this.length - t;
break;
default:
this.offset = t;
}
return this;
}
setBit(t) {
this.insert(1, 1, t);
return this;
}
skip(t) {
return this.seek(t, 2);
}
testBit(t) {
return !!this.peek(1, t);
}
toString(encoding = "utf8") {
return this.buffer.toString(encoding);
}
write(val, bits = 1) {
this._offset = this.insert(val, bits, this._offset);
return this;
}
}
//# sourceMappingURL=bits.js.map