byte-rw
Version:
Byte reader/writer for buffers and streams in typescript/javascript
182 lines (181 loc) • 7.85 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { copy } from "../utils/copy.js";
import { DataViewByteReaderAsync } from "./reader-async.js";
export class DataViewByteReaderAsyncChunked extends DataViewByteReaderAsync {
get currentChunk() {
return this._currentChunk;
}
set currentChunk(currentChunk) {
this._currentChunk = currentChunk;
this._dataview = currentChunk.view instanceof DataView ?
currentChunk.view :
new DataView(currentChunk.view.buffer, currentChunk.view.byteOffset, currentChunk.view.byteLength);
}
get _bytesRemaining() {
let remaining = this._bytesRemaining_currentChunk;
for (const pendingChunk of this.pendingChunks)
remaining += pendingChunk.bytesWritten;
return remaining;
}
get _bytesRemaining_currentChunk() {
return this.currentChunk.bytesWritten - this._byteOffset;
}
constructor(littleEndian, defaultChunkSize = 4096) {
super(new DataView(new ArrayBuffer(defaultChunkSize)), littleEndian);
this.defaultChunkSize = defaultChunkSize;
this.pendingChunks = [];
this._currentChunk = {
view: this._dataview,
bytesWritten: 0
};
}
pendChunk(chunk) {
chunk !== null && chunk !== void 0 ? chunk : (chunk = {
view: {
buffer: new ArrayBuffer(this.defaultChunkSize),
byteOffset: 0,
byteLength: this.defaultChunkSize
},
bytesWritten: 0
});
this.pendingChunks.push(chunk);
return chunk;
}
/**
* Attempts to ensure that a specified number of bytes are available in the
* current chunk.
*
* @param bytes the number of bytes to fill (total bytesWritten should
* increase by this amount at least)
* @returns the number of bytes at least made available in the current
* chunk, up to the requested number of bytes
*/
tryEnsureAvailable(bytes) {
return __awaiter(this, void 0, void 0, function* () {
if (bytes <= this._bytesRemaining_currentChunk)
return bytes;
function resizeCurrentChunk(size) {
const currentChunk_length = this._bytesRemaining_currentChunk;
if (currentChunk_length >= size)
return size;
const tmpChunk_buffer = new ArrayBuffer(size);
let tmpChunk_bytesWritten = 0;
copy({
buffer: this.currentChunk.view.buffer,
byteOffset: this.currentChunk.view.byteOffset + this._byteOffset,
byteLength: currentChunk_length
}, {
buffer: tmpChunk_buffer,
byteOffset: 0,
byteLength: currentChunk_length
});
tmpChunk_bytesWritten += currentChunk_length;
while (tmpChunk_bytesWritten < size) {
const pendingChunk = this.pendingChunks.shift();
if (!pendingChunk)
break;
const toCopy = Math.min(pendingChunk.bytesWritten, size - tmpChunk_bytesWritten);
copy({
buffer: pendingChunk.view.buffer,
byteOffset: pendingChunk.view.byteOffset,
byteLength: toCopy
}, {
buffer: tmpChunk_buffer,
byteOffset: tmpChunk_bytesWritten,
byteLength: toCopy
});
if (toCopy < pendingChunk.bytesWritten) {
this.pendingChunks.unshift({
view: {
buffer: pendingChunk.view.buffer,
byteOffset: pendingChunk.view.byteOffset + toCopy,
byteLength: pendingChunk.view.byteLength + toCopy
},
bytesWritten: pendingChunk.bytesWritten + toCopy,
});
}
tmpChunk_bytesWritten += toCopy;
}
this.currentChunk = {
view: {
buffer: tmpChunk_buffer,
byteOffset: 0,
byteLength: size
},
bytesWritten: tmpChunk_bytesWritten
};
this._byteOffset = 0;
return tmpChunk_bytesWritten;
}
if (this._bytesRemaining_currentChunk === 0) {
const pendingChunk = this.pendingChunks.shift();
if (pendingChunk) {
if (pendingChunk.bytesWritten < bytes)
this.pendingChunks.unshift(pendingChunk);
else {
this.currentChunk = pendingChunk;
this._byteOffset = 0;
return bytes;
}
}
yield this.fill(bytes - this._bytesRemaining);
return resizeCurrentChunk.call(this, bytes);
}
else {
const toFill = bytes - this._bytesRemaining;
yield this.fill(toFill);
return resizeCurrentChunk.call(this, bytes);
}
});
}
tryReadBytes(view) {
return __awaiter(this, void 0, void 0, function* () {
let read = 0;
function copyFromCurrentChunk() {
const toCopy_remaining = view.byteLength - read;
const toCopy = Math.min(this._bytesRemaining_currentChunk, toCopy_remaining);
copy({
buffer: this.currentChunk.view.buffer,
byteOffset: this.currentChunk.view.byteOffset + this._byteOffset,
byteLength: toCopy
}, {
buffer: view.buffer,
byteOffset: view.byteOffset,
byteLength: toCopy
});
read += toCopy;
this._byteOffset += toCopy;
}
if (this._bytesRemaining_currentChunk > 0)
copyFromCurrentChunk.call(this);
while (read < view.byteLength &&
this.pendingChunks.length > 0) {
this.currentChunk = this.pendingChunks.shift();
this._byteOffset = 0;
copyFromCurrentChunk.call(this);
}
if (read < view.byteLength) {
this.currentChunk = {
view,
bytesWritten: read
};
const toFill = view.byteLength - read;
const filled = yield this.fill(toFill);
read += Math.min(toFill, filled);
if (this.pendingChunks.length === 0)
this.pendChunk();
this.currentChunk = this.pendingChunks.shift();
this._byteOffset = 0;
}
return read;
});
}
}