Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/index.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.cjs.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.mjs.map

Large diffs are not rendered by default.

375 changes: 104 additions & 271 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tinybuf",
"version": "1.8.6",
"version": "1.8.7",
"author": "Reece Como <reece.como@gmail.com>",
"authors": [
"Reece Como <reece.como@gmail.com>",
Expand Down
26 changes: 26 additions & 0 deletions src/__tests__/BufferWriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,30 @@ describe("BufferWriter", () => {
const text = new TextDecoder("utf-8").decode(writer.$copyBytes());
expect(text).toBe(input);
});

it("should resize until the limit", () => {
const writer = new BufferWriter(256);

// cheeky check of the underlying implementation
expect((writer as any)._$dataView.byteOffset).toBe(0);
expect((writer as any)._$dataView.byteLength).toBe(256);

const textA = "a".repeat(1200);
const textBufferA = $utf8encode(textA);
writer.$writeBytes(textBufferA);

expect((writer as any)._$dataView.byteOffset).toBe(0);
expect((writer as any)._$dataView.byteLength).toBe(1280);

const textB = "b".repeat(100);
const textBufferB = $utf8encode(textB);
writer.$writeBytes(textBufferB);

// caps resize to encodingBufferMaxSize
expect((writer as any)._$dataView.byteOffset).toBe(0);
expect((writer as any)._$dataView.byteLength).toBe(1500);

const text = new TextDecoder("utf-8").decode(writer.$copyBytes());
expect(text).toBe(textA + textB);
});
});
3 changes: 1 addition & 2 deletions src/core/BufferFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ export class BufferFormat<EncoderType extends EncoderDefinition, HeaderType exte
private static _$initWriter(): BufferWriter {
if (cfg.useGlobalEncodingBuffer) {
if (!BufferFormat._$globalWriter) {
// lazy init: global encoding buffer created at max size
this._$globalWriter = new BufferWriter(cfg.encodingBufferInitialSize);
this._$globalWriter = new BufferWriter(cfg.encodingBufferMaxSize);
}

return this._$globalWriter;
Expand Down
56 changes: 37 additions & 19 deletions src/core/lib/BufferWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,40 +33,40 @@ export class BufferWriter {
// ----- Writers: -----

public $writeInt8(value: number): void {
this._$alloc(1).setInt8(this._$writeHead, value);
this._$pre(1).setInt8(this._$writeHead, value);
}

public $writeInt16(value: number): void {
this._$alloc(2).setInt16(this._$writeHead, value, true);
this._$pre(2).setInt16(this._$writeHead, value, true);
}

public $writeInt32(value: number): void {
this._$alloc(4).setInt32(this._$writeHead, value, true);
this._$pre(4).setInt32(this._$writeHead, value, true);
}

public $writeUint8(value: number): void {
this._$alloc(1).setUint8(this._$writeHead, value);
this._$pre(1).setUint8(this._$writeHead, value);
}

public $writeUint16(value: number): void {
this._$alloc(2).setUint16(this._$writeHead, value, false); // big-endian for varint
this._$pre(2).setUint16(this._$writeHead, value, false); // big-endian for varint
}

public $writeUint32(value: number): void {
this._$alloc(4).setUint32(this._$writeHead, value, false); // big-endian for varint
this._$pre(4).setUint32(this._$writeHead, value, false); // big-endian for varint
}

public $writeFloat32(value: number): void {
this._$alloc(4).setFloat32(this._$writeHead, value, true);
this._$pre(4).setFloat32(this._$writeHead, value, true);
}

public $writeFloat64(value: number): void {
this._$alloc(8).setFloat64(this._$writeHead, value, true);
this._$pre(8).setFloat64(this._$writeHead, value, true);
}

public $writeBytes(b: Uint8Array | ArrayBuffer | ArrayBufferView): void {
// allocate bytes first
this._$alloc(b.byteLength);
this._$pre(b.byteLength);

let bBytes: Uint8Array = ArrayBuffer.isView(b)
? b instanceof Uint8Array
Expand All @@ -84,12 +84,15 @@ export class BufferWriter {

// ----- Private methods: -----

private _$alloc(bytes: number): DataView {
/**
* Pre-allocate some bytes on the dataview, moving the write head into
* position.
*
* @throws TinybufError
*/
private _$pre(bytes: number): DataView {
if (this.$byteLength + bytes > this._$dataView.byteLength) {
const minBytesNeeded = this.$byteLength + bytes - this._$dataView.byteLength;
const requestedNewBytes = Math.ceil(minBytesNeeded / cfg.encodingBufferIncrement) * cfg.encodingBufferIncrement;
if (!this._$resizable) throw new TinybufError("exceeded buffer length: " + this._$dataView.byteLength);
this._$resizeBuffer(this._$dataView.byteLength + requestedNewBytes);
this._$malloc(bytes);
}

this._$writeHead = this.$byteLength;
Expand All @@ -98,14 +101,29 @@ export class BufferWriter {
return this._$dataView;
}

private _$resizeBuffer(newSize: number): void {
if (newSize > cfg.encodingBufferMaxSize) {
// safety check
throw new TinybufError(`exceeded encodingBufferMaxSize: ${cfg.encodingBufferMaxSize}`);
/**
* @throws TinybufError
*/
private _$malloc(bytes: number): void {
if (!this._$resizable) {
throw new TinybufError("exceeded buffer length: " + this._$dataView.byteLength);
}

const currentBytes = this._$dataView.byteLength;
const minNewBytes = this.$byteLength + bytes - currentBytes;
const availableBytes = cfg.encodingBufferMaxSize - currentBytes;

if (minNewBytes > availableBytes) {
throw new TinybufError("exceeded encodingBufferMaxSize: " + cfg.encodingBufferMaxSize);
}

const increment = cfg.encodingBufferIncrement;
const newBytes = Math.ceil(minNewBytes / increment) * increment;
const newSize = currentBytes + Math.min(newBytes, availableBytes);
const buf = new Uint8Array(newSize);
buf.set(this._$bytes); // copy bytes

// copy bytes
buf.set(this._$bytes);

// update refs
this._$dataView = new DataView(buf.buffer);
Expand Down