class ByteStream {
constructor() {
this.stream = new CircularU8();
this.valOut = 0;
this.remainingOutBits = 8;
this.valInPos = 0;
this.valIn = 0;
this.remainingInBits = 0;
}
clear() {
this.stream = [];
this.valOut = 0;
this.remainingOutBits = 8;
this.valInPos = -1;
this.valIn = 0;
this.remainingInBits = 0;
}
getNextVal() {
return this.stream.data[this.valInPos++];
}
strOut(value, valueBits) {
if (valueBits > this.remainingOutBits) {
valueBits -= this.remainingOutBits;
let valueChunk = value >>> valueBits;
this.valOut = this.valOut | valueChunk;
this.stream.push(this.valOut);
while (valueBits >= 8) {
valueBits -= 8;
this.stream.push((value >>> valueBits) & 0xFF);
}
this.valOut = 0;
this.remainingOutBits = 8;
}
if (valueBits > 0) {
var valueMask = (1 << valueBits) - 1;
this.remainingOutBits -= valueBits;
this.valOut = this.valOut | ((value & valueMask) << this.remainingOutBits);
}
if (this.remainingOutBits === 0) {
this.stream.push(this.valOut);
this.valOut = 0;
this.remainingOutBits = 8;
}
}
flush() {
if (this.remainingOutBits < 8) {
this.stream.push(this.valOut);
this.valOut = 0;
this.remainingOutBits = 8;
}
}
strIn(valueBits) {
if (this.remainingInBits === 0) {
this.remainingInBits = 8;
this.valIn = this.getNextVal();
}
let value = 0;
if (valueBits > this.remainingInBits) {
let valueMask = (1 << this.remainingInBits) - 1;
valueBits -= this.remainingInBits;
this.remainingInBits = 8;
value = (this.valIn & valueMask) << valueBits;
while (valueBits > 8) {
valueBits -= 8;
value = value | (this.getNextVal() << valueBits);
}
this.valIn = this.getNextVal();
}
if (valueBits > 0) {
let valueMask = (1 << valueBits) - 1;
this.remainingInBits -= valueBits;
value = value | ((this.valIn >>> this.remainingInBits) & valueMask);
}
return value;
}
phaseOut(value, totalValues) {
value = totalValues - 1 - value;
let valueBits = 32 - Math.clz32(totalValues - 1);
const nextPow2 = (1 << valueBits) >>> 0;
const treshold = nextPow2 - totalValues;
if (value < treshold) {
valueBits--;
}
else {
value += treshold;
}
this.strOut(value, valueBits);
}
phaseIn(totalValues) {
const valueBits = 32 - Math.clz32(totalValues - 1);
const nextPow2 = (1 << valueBits) >>> 0;
const treshold = nextPow2 - totalValues;
let value = this.strIn(valueBits - 1);
if (value >= treshold)
value = ((value << 1) + this.strIn(1) - treshold) >>> 0;
return totalValues - 1 - value;
}
}