@thi.ng/bitstream
Advanced tools
Comparing version 2.2.35 to 2.2.36
# Change Log | ||
- **Last updated**: 2023-12-09T19:12:03Z | ||
- **Last updated**: 2023-12-11T10:07:09Z | ||
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub) | ||
@@ -5,0 +5,0 @@ |
210
input.js
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; | ||
import { illegalState } from "@thi.ng/errors/illegal-state"; | ||
const U32 = Math.pow(2, 32); | ||
export class BitInputStream { | ||
buffer; | ||
start; | ||
limit; | ||
pos; | ||
bitPos; | ||
bit; | ||
constructor(buffer, offset = 0, limit = buffer.length << 3) { | ||
this.buffer = buffer; | ||
this.start = offset; | ||
this.limit = limit; | ||
this.seek(offset); | ||
class BitInputStream { | ||
buffer; | ||
start; | ||
limit; | ||
pos; | ||
bitPos; | ||
bit; | ||
constructor(buffer, offset = 0, limit = buffer.length << 3) { | ||
this.buffer = buffer; | ||
this.start = offset; | ||
this.limit = limit; | ||
this.seek(offset); | ||
} | ||
*[Symbol.iterator]() { | ||
let j = this.start; | ||
let i = j >>> 3; | ||
let b = 7 - (j & 7); | ||
while (j < this.limit) { | ||
yield this.buffer[i] >>> b & 1; | ||
if (--b < 0) { | ||
i++; | ||
b = 7; | ||
} | ||
j++; | ||
} | ||
*[Symbol.iterator]() { | ||
let j = this.start; | ||
let i = j >>> 3; | ||
let b = 7 - (j & 0x7); | ||
while (j < this.limit) { | ||
yield (this.buffer[i] >>> b) & 1; | ||
if (--b < 0) { | ||
i++; | ||
b = 7; | ||
} | ||
j++; | ||
} | ||
} | ||
get length() { | ||
return this.limit; | ||
} | ||
get position() { | ||
return this.bitPos; | ||
} | ||
seek(pos) { | ||
if (pos < this.start || pos >= this.limit) { | ||
illegalArgs(`seek pos out of bounds: ${pos}`); | ||
} | ||
get length() { | ||
return this.limit; | ||
this.pos = pos >>> 3; | ||
this.bit = 8 - (pos & 7); | ||
this.bitPos = pos; | ||
return this; | ||
} | ||
read(wordSize = 1) { | ||
if (wordSize > 32) { | ||
return this.read(wordSize - 32) * U32 + this.read(32); | ||
} else if (wordSize > 8) { | ||
let out = 0; | ||
let n = wordSize & -8; | ||
let msb = wordSize - n; | ||
if (msb > 0) { | ||
out = this._read(msb); | ||
} | ||
while (n > 0) { | ||
out = (out << 8 | this._read(8)) >>> 0; | ||
n -= 8; | ||
} | ||
return out; | ||
} else { | ||
return this._read(wordSize); | ||
} | ||
get position() { | ||
return this.bitPos; | ||
} | ||
readFields(fields) { | ||
return fields.map((word) => this.read(word)); | ||
} | ||
readWords(n, wordSize = 8) { | ||
let out = []; | ||
while (n-- > 0) { | ||
out.push(this.read(wordSize)); | ||
} | ||
seek(pos) { | ||
if (pos < this.start || pos >= this.limit) { | ||
illegalArgs(`seek pos out of bounds: ${pos}`); | ||
} | ||
this.pos = pos >>> 3; | ||
this.bit = 8 - (pos & 0x7); | ||
this.bitPos = pos; | ||
return this; | ||
return out; | ||
} | ||
readStruct(fields) { | ||
return fields.reduce((acc, [id, word]) => { | ||
return acc[id] = this.read(word), acc; | ||
}, {}); | ||
} | ||
readBit() { | ||
this.checkLimit(1); | ||
this.bit--; | ||
this.bitPos++; | ||
let out = this.buffer[this.pos] >>> this.bit & 1; | ||
if (this.bit === 0) { | ||
this.pos++; | ||
this.bit = 8; | ||
} | ||
read(wordSize = 1) { | ||
if (wordSize > 32) { | ||
return this.read(wordSize - 32) * U32 + this.read(32); | ||
} | ||
else if (wordSize > 8) { | ||
let out = 0; | ||
let n = wordSize & -8; | ||
let msb = wordSize - n; | ||
if (msb > 0) { | ||
out = this._read(msb); | ||
} | ||
while (n > 0) { | ||
out = ((out << 8) | this._read(8)) >>> 0; | ||
n -= 8; | ||
} | ||
return out; | ||
} | ||
else { | ||
return this._read(wordSize); | ||
} | ||
return out; | ||
} | ||
_read(wordSize) { | ||
this.checkLimit(wordSize); | ||
let l = this.bit - wordSize, out; | ||
if (l >= 0) { | ||
this.bit = l; | ||
out = this.buffer[this.pos] >>> l & (1 << wordSize) - 1; | ||
if (l === 0) { | ||
this.pos++; | ||
this.bit = 8; | ||
} | ||
} else { | ||
out = (this.buffer[this.pos++] & (1 << this.bit) - 1) << -l; | ||
this.bit = 8 + l; | ||
out = out | this.buffer[this.pos] >>> this.bit; | ||
} | ||
readFields(fields) { | ||
return fields.map((word) => this.read(word)); | ||
this.bitPos += wordSize; | ||
return out; | ||
} | ||
checkLimit(requested) { | ||
if (this.bitPos + requested > this.limit) { | ||
illegalState(`can't read past EOF`); | ||
} | ||
readWords(n, wordSize = 8) { | ||
let out = []; | ||
while (n-- > 0) { | ||
out.push(this.read(wordSize)); | ||
} | ||
return out; | ||
} | ||
readStruct(fields) { | ||
return fields.reduce((acc, [id, word]) => { | ||
return (acc[id] = this.read(word)), acc; | ||
}, {}); | ||
} | ||
readBit() { | ||
this.checkLimit(1); | ||
this.bit--; | ||
this.bitPos++; | ||
let out = (this.buffer[this.pos] >>> this.bit) & 1; | ||
if (this.bit === 0) { | ||
this.pos++; | ||
this.bit = 8; | ||
} | ||
return out; | ||
} | ||
_read(wordSize) { | ||
this.checkLimit(wordSize); | ||
let l = this.bit - wordSize, out; | ||
if (l >= 0) { | ||
this.bit = l; | ||
out = (this.buffer[this.pos] >>> l) & ((1 << wordSize) - 1); | ||
if (l === 0) { | ||
this.pos++; | ||
this.bit = 8; | ||
} | ||
} | ||
else { | ||
out = (this.buffer[this.pos++] & ((1 << this.bit) - 1)) << -l; | ||
this.bit = 8 + l; | ||
out = out | (this.buffer[this.pos] >>> this.bit); | ||
} | ||
this.bitPos += wordSize; | ||
return out; | ||
} | ||
checkLimit(requested) { | ||
if (this.bitPos + requested > this.limit) { | ||
illegalState(`can't read past EOF`); | ||
} | ||
} | ||
} | ||
} | ||
export { | ||
BitInputStream | ||
}; |
206
output.js
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; | ||
import { BitInputStream } from "./input.js"; | ||
const DEFAULT_BUF_SIZE = 0x10; | ||
const DEFAULT_BUF_SIZE = 16; | ||
const U32 = Math.pow(2, 32); | ||
export class BitOutputStream { | ||
buffer; | ||
start; | ||
pos; | ||
bit; | ||
bitPos; | ||
constructor(buffer, offset = 0) { | ||
this.buffer = | ||
typeof buffer === "undefined" | ||
? new Uint8Array(DEFAULT_BUF_SIZE) | ||
: typeof buffer === "number" | ||
? new Uint8Array(buffer) | ||
: buffer; | ||
this.start = offset; | ||
this.seek(offset); | ||
this.buffer[this.pos] &= ~((1 << this.bit) - 1); | ||
class BitOutputStream { | ||
buffer; | ||
start; | ||
pos; | ||
bit; | ||
bitPos; | ||
constructor(buffer, offset = 0) { | ||
this.buffer = typeof buffer === "undefined" ? new Uint8Array(DEFAULT_BUF_SIZE) : typeof buffer === "number" ? new Uint8Array(buffer) : buffer; | ||
this.start = offset; | ||
this.seek(offset); | ||
this.buffer[this.pos] &= ~((1 << this.bit) - 1); | ||
} | ||
get position() { | ||
return this.bitPos; | ||
} | ||
seek(pos) { | ||
if (pos < this.start || pos >= this.buffer.length << 3) { | ||
illegalArgs(`seek pos out of bounds: ${pos}`); | ||
} | ||
get position() { | ||
return this.bitPos; | ||
this.pos = pos >>> 3; | ||
this.bit = 8 - (pos & 7); | ||
this.bitPos = pos; | ||
return this; | ||
} | ||
bytes() { | ||
return this.buffer.slice(0, this.pos + (this.bit & 7 ? 1 : 0)); | ||
} | ||
reader(from = 0) { | ||
return new BitInputStream(this.buffer, from, this.position); | ||
} | ||
write(x, wordSize = 1) { | ||
if (wordSize > 32) { | ||
let hi = Math.floor(x / U32); | ||
this.write(hi, wordSize - 32); | ||
this.write(x - hi * U32, 32); | ||
} else if (wordSize > 8) { | ||
let n = wordSize & -8; | ||
let msb = wordSize - n; | ||
if (msb > 0) { | ||
this._write(x >>> n, msb); | ||
} | ||
n -= 8; | ||
while (n >= 0) { | ||
this._write(x >>> n, 8); | ||
n -= 8; | ||
} | ||
} else { | ||
this._write(x, wordSize); | ||
} | ||
seek(pos) { | ||
if (pos < this.start || pos >= this.buffer.length << 3) { | ||
illegalArgs(`seek pos out of bounds: ${pos}`); | ||
} | ||
this.pos = pos >>> 3; | ||
this.bit = 8 - (pos & 0x7); | ||
this.bitPos = pos; | ||
return this; | ||
return this; | ||
} | ||
writeWords(input, wordSize = 8) { | ||
let iter = input[Symbol.iterator](); | ||
let v; | ||
while (v = iter.next(), !v.done) { | ||
this.write(v.value, wordSize); | ||
} | ||
bytes() { | ||
return this.buffer.slice(0, this.pos + (this.bit & 7 ? 1 : 0)); | ||
} | ||
writeBit(x) { | ||
this.bit--; | ||
this.buffer[this.pos] = this.buffer[this.pos] & ~(1 << this.bit) | x << this.bit; | ||
if (this.bit === 0) { | ||
this.ensureSize(); | ||
this.bit = 8; | ||
} | ||
reader(from = 0) { | ||
return new BitInputStream(this.buffer, from, this.position); | ||
this.bitPos++; | ||
return this; | ||
} | ||
_write(x, wordSize) { | ||
x &= (1 << wordSize) - 1; | ||
let buf = this.buffer; | ||
let pos = this.pos; | ||
let bit = this.bit; | ||
let b = bit - wordSize; | ||
let m = bit < 8 ? ~((1 << bit) - 1) : 0; | ||
if (b >= 0) { | ||
m |= (1 << b) - 1; | ||
buf[pos] = buf[pos] & m | x << b & ~m; | ||
if (b === 0) { | ||
this.ensureSize(); | ||
this.bit = 8; | ||
} else { | ||
this.bit = b; | ||
} | ||
} else { | ||
this.bit = bit = 8 + b; | ||
buf[pos] = buf[pos] & m | x >>> -b & ~m; | ||
this.ensureSize(); | ||
this.buffer[this.pos] = this.buffer[this.pos] & (1 << bit) - 1 | x << bit & 255; | ||
} | ||
write(x, wordSize = 1) { | ||
if (wordSize > 32) { | ||
let hi = Math.floor(x / U32); | ||
this.write(hi, wordSize - 32); | ||
this.write(x - hi * U32, 32); | ||
} | ||
else if (wordSize > 8) { | ||
let n = wordSize & -8; | ||
let msb = wordSize - n; | ||
if (msb > 0) { | ||
this._write(x >>> n, msb); | ||
} | ||
n -= 8; | ||
while (n >= 0) { | ||
this._write(x >>> n, 8); | ||
n -= 8; | ||
} | ||
} | ||
else { | ||
this._write(x, wordSize); | ||
} | ||
return this; | ||
this.bitPos += wordSize; | ||
return this; | ||
} | ||
ensureSize() { | ||
if (++this.pos === this.buffer.length) { | ||
let b = new Uint8Array(this.buffer.length << 1); | ||
b.set(this.buffer); | ||
this.buffer = b; | ||
} | ||
writeWords(input, wordSize = 8) { | ||
let iter = input[Symbol.iterator](); | ||
let v; | ||
while (((v = iter.next()), !v.done)) { | ||
this.write(v.value, wordSize); | ||
} | ||
} | ||
writeBit(x) { | ||
this.bit--; | ||
this.buffer[this.pos] = | ||
(this.buffer[this.pos] & ~(1 << this.bit)) | (x << this.bit); | ||
if (this.bit === 0) { | ||
this.ensureSize(); | ||
//this.buffer[this.pos] = 0; | ||
this.bit = 8; | ||
} | ||
this.bitPos++; | ||
return this; | ||
} | ||
_write(x, wordSize) { | ||
x &= (1 << wordSize) - 1; | ||
let buf = this.buffer; | ||
let pos = this.pos; | ||
let bit = this.bit; | ||
let b = bit - wordSize; | ||
let m = bit < 8 ? ~((1 << bit) - 1) : 0; | ||
if (b >= 0) { | ||
m |= (1 << b) - 1; | ||
buf[pos] = (buf[pos] & m) | ((x << b) & ~m); | ||
if (b === 0) { | ||
this.ensureSize(); | ||
this.bit = 8; | ||
} | ||
else { | ||
this.bit = b; | ||
} | ||
} | ||
else { | ||
this.bit = bit = 8 + b; | ||
buf[pos] = (buf[pos] & m) | ((x >>> -b) & ~m); | ||
this.ensureSize(); | ||
this.buffer[this.pos] = | ||
(this.buffer[this.pos] & ((1 << bit) - 1)) | | ||
((x << bit) & 0xff); | ||
} | ||
this.bitPos += wordSize; | ||
return this; | ||
} | ||
ensureSize() { | ||
if (++this.pos === this.buffer.length) { | ||
let b = new Uint8Array(this.buffer.length << 1); | ||
b.set(this.buffer); | ||
this.buffer = b; | ||
} | ||
} | ||
} | ||
} | ||
export { | ||
BitOutputStream | ||
}; |
{ | ||
"name": "@thi.ng/bitstream", | ||
"version": "2.2.35", | ||
"version": "2.2.36", | ||
"description": "ES6 iterator based read/write bit streams with support for variable word widths", | ||
@@ -27,3 +27,5 @@ "type": "module", | ||
"scripts": { | ||
"build": "yarn clean && tsc --declaration", | ||
"build": "yarn build:esbuild && yarn build:decl", | ||
"build:decl": "tsc --declaration --emitDeclarationOnly", | ||
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts", | ||
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc", | ||
@@ -37,6 +39,7 @@ "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts", | ||
"dependencies": { | ||
"@thi.ng/errors": "^2.4.5" | ||
"@thi.ng/errors": "^2.4.6" | ||
}, | ||
"devDependencies": { | ||
"@microsoft/api-extractor": "^7.38.3", | ||
"esbuild": "^0.19.8", | ||
"rimraf": "^5.0.5", | ||
@@ -84,3 +87,3 @@ "tools": "^0.0.1", | ||
}, | ||
"gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n" | ||
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n" | ||
} |
133
simple.js
@@ -1,79 +0,60 @@ | ||
/** | ||
* Barebones alternative to {@link BitOutputStream} for word sizes <= 8 and with | ||
* minimal API surface. The returned object only exposes 2 functions: | ||
* | ||
* - `write(x, size)` - writes a single value of given bit size (default: 1 bit) | ||
* - `bytes()` - retrieve all bytes written so far | ||
* | ||
* @remarks | ||
* The internal backing buffer automatically resizes on demand. The optionally | ||
* provided `capacity` is only the initial buffer size. | ||
* | ||
* @param capacity - initial capacity | ||
*/ | ||
export const bitWriter = (capacity = 16) => { | ||
let buf = new Uint8Array(capacity); | ||
let pos = 0; | ||
let bit = 8; | ||
const ensure = () => { | ||
if (++pos === buf.length) { | ||
let b = new Uint8Array(buf.length << 1); | ||
b.set(buf); | ||
buf = b; | ||
const bitWriter = (capacity = 16) => { | ||
let buf = new Uint8Array(capacity); | ||
let pos = 0; | ||
let bit = 8; | ||
const ensure = () => { | ||
if (++pos === buf.length) { | ||
let b = new Uint8Array(buf.length << 1); | ||
b.set(buf); | ||
buf = b; | ||
} | ||
}; | ||
return { | ||
write: (x, n = 1) => { | ||
x &= (1 << n) - 1; | ||
let b = bit - n; | ||
let m = bit < 8 ? ~((1 << bit) - 1) : 0; | ||
if (b >= 0) { | ||
m |= (1 << b) - 1; | ||
buf[pos] = buf[pos] & m | x << b & ~m; | ||
if (b === 0) { | ||
ensure(); | ||
bit = 8; | ||
} else { | ||
bit = b; | ||
} | ||
}; | ||
return { | ||
write: (x, n = 1) => { | ||
x &= (1 << n) - 1; | ||
let b = bit - n; | ||
let m = bit < 8 ? ~((1 << bit) - 1) : 0; | ||
if (b >= 0) { | ||
m |= (1 << b) - 1; | ||
buf[pos] = (buf[pos] & m) | ((x << b) & ~m); | ||
if (b === 0) { | ||
ensure(); | ||
bit = 8; | ||
} | ||
else { | ||
bit = b; | ||
} | ||
} | ||
else { | ||
bit = 8 + b; | ||
buf[pos] = (buf[pos] & m) | ((x >>> -b) & ~m); | ||
ensure(); | ||
buf[pos] = (buf[pos] & ((1 << bit) - 1)) | ((x << bit) & 0xff); | ||
} | ||
}, | ||
bytes: () => buf.slice(0, pos + (bit & 7 ? 1 : 0)), | ||
}; | ||
} else { | ||
bit = 8 + b; | ||
buf[pos] = buf[pos] & m | x >>> -b & ~m; | ||
ensure(); | ||
buf[pos] = buf[pos] & (1 << bit) - 1 | x << bit & 255; | ||
} | ||
}, | ||
bytes: () => buf.slice(0, pos + (bit & 7 ? 1 : 0)) | ||
}; | ||
}; | ||
/** | ||
* Barebones alternative to {@link BitInputStream} for word sizes <= 8 and with | ||
* minimal API surface and WITHOUT bounds checking of any form! The returned | ||
* function reads `n` bits from the originally provided buffer. | ||
* | ||
* @param buf | ||
*/ | ||
export const bitReader = (buf) => { | ||
let p = 0; | ||
let b = 8; | ||
return (n = 1) => { | ||
let l = b - n; | ||
let out; | ||
if (l >= 0) { | ||
b = l; | ||
out = (buf[p] >>> l) & ((1 << n) - 1); | ||
if (!l) { | ||
p++; | ||
b = 8; | ||
} | ||
} | ||
else { | ||
out = (buf[p++] & ((1 << b) - 1)) << -l; | ||
b = 8 + l; | ||
out = out | (buf[p] >>> b); | ||
} | ||
return out; | ||
}; | ||
const bitReader = (buf) => { | ||
let p = 0; | ||
let b = 8; | ||
return (n = 1) => { | ||
let l = b - n; | ||
let out; | ||
if (l >= 0) { | ||
b = l; | ||
out = buf[p] >>> l & (1 << n) - 1; | ||
if (!l) { | ||
p++; | ||
b = 8; | ||
} | ||
} else { | ||
out = (buf[p++] & (1 << b) - 1) << -l; | ||
b = 8 + l; | ||
out = out | buf[p] >>> b; | ||
} | ||
return out; | ||
}; | ||
}; | ||
export { | ||
bitReader, | ||
bitWriter | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34502
6
353
Updated@thi.ng/errors@^2.4.6