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 there are more valueBits left than can be fit into
// a full charCode, stream bit by charCode sized chunks
while (valueBits >= 8) {
valueBits -= 8;
this.stream.push((value >>> valueBits) & 0xFF);
}
this.valOut = 0;
this.remainingOutBits = 8;
}
// At this point valueBits < remainingvalOutBits. If there are bits left
// to stream, put them into valOut
if (valueBits > 0) {
var valueMask = (1 << valueBits) - 1;
this.remainingOutBits -= valueBits;
this.valOut = this.valOut | ((value & valueMask) << this.remainingOutBits);
}
// if we filled up our valOut, stream it.
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;
}
}
/**
* @param {number} valueBits
*/
strIn(valueBits) {
// Move to next valIn value if this one is finished
if (this.remainingInBits === 0) {
this.remainingInBits = 8;
this.valIn = this.getNextVal();
}
// // only get a valIn if still inside data
// if (streamIdx >= this.stream.length) return null;
let value = 0;
// while more bits are asked than current valIn has remaining,
// put bit chunks into the output value and get new char values
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 there are still required bits left, get them from valIn
// Note: valueBits < remainingBits is ensured due to above if+while section
if (valueBits > 0) {
let valueMask = (1 << valueBits) - 1;
this.remainingInBits -= valueBits;
value = value | ((this.valIn >>> this.remainingInBits) & valueMask);
}
return value;
}
/**
* @param {number} value
* @param {number} totalValues
*/
phaseOut(value, totalValues) {
value = totalValues - 1 - value;
let valueBits = 32 - Math.clz32(totalValues - 1);
const nextPow2 = (1 << valueBits) >>> 0;
// Once we have this power of two we can determine the treshold value.
// Any value below the treshold will require one fewer bit.
const treshold = nextPow2 - totalValues;
if (value < treshold) {
valueBits--;
}
else {
value += treshold;
}
this.strOut(value, valueBits);
}
/**
* @param {number} totalValues
*/
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;
}
}