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
52 changes: 46 additions & 6 deletions src/Reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@ import {decodeUtf8} from './utf8/decodeUtf8';
import type {IReader, IReaderResettable} from './types';

export class Reader implements IReader, IReaderResettable {
public uint8: Uint8Array = new Uint8Array([]);
public view: DataView = new DataView(this.uint8.buffer);
public x = 0;
constructor(
public uint8: Uint8Array = new Uint8Array([]),
public view: DataView = new DataView(uint8.buffer as ArrayBuffer, uint8.byteOffset, uint8.length),
public x: number = 0,
public end: number = uint8.length,
) {}

public reset(uint8: Uint8Array): void {
this.x = 0;
this.uint8 = uint8;
this.view = new DataView(uint8.buffer as ArrayBuffer, uint8.byteOffset, uint8.length);
}

public size(): number {
return this.end - this.x;
}

/**
* Get current byte value without advancing the cursor.
*/
Expand All @@ -30,13 +37,46 @@ export class Reader implements IReader, IReaderResettable {
this.x += length;
}

public buf(size: number): Uint8Array {
const end = this.x + size;
const bin = this.uint8.subarray(this.x, end);
public buf(size: number = this.size()): Uint8Array {
const x = this.x;
const end = x + size;
const bin = this.uint8.subarray(x, end);
this.x = end;
return bin;
}

/**
* Creates a new {@link Reader} that references the same underlying memory
* buffer. But with independent cursor and end.
*
* Preferred over {@link buf} since it also provides a DataView and is much
* faster to allocate a new {@link Slice} than a new {@link Uint8Array}.
*
* @param start Start offset relative to the current cursor position.
* @param end End offset relative to the current cursor position.
* @returns A new {@link Reader} instance.
*/
public slice(start: number = 0, end?: number): Reader {
const x = this.x;
const actualStart = x + start;
const actualEnd = typeof end === 'number' ? x + end : this.end;
return new Reader(this.uint8, this.view, actualStart, actualEnd);
}

/**
* Similar to {@link slice} but also advances the cursor. Returns a new
* {@link Reader} that references the same underlying memory buffer, starting
* from the current cursor position.
*
* @param size Number of bytes to cut from the current position.
* @returns A new {@link Reader} instance.
*/
public cut(size: number = this.size()): Reader {
const slice = this.slice(0, size);
this.skip(size);
return slice;
}

public u8(): number {
return this.uint8[this.x++];
// return this.view.getUint8(this.x++);
Expand Down
3 changes: 3 additions & 0 deletions src/Slice.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @deprecated Use {@link Reader} instead.
*/
export class Slice {
constructor(
public readonly uint8: Uint8Array,
Expand Down
6 changes: 6 additions & 0 deletions src/StreamingOctetReader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
const fromCharCode = String.fromCharCode;

/**
* A streaming reader which internally manages multiple chunks of
* Uint8Array instances. For performance it does not merge the chunks into
* a single Uint8Array instance. Instead it keeps track of the chunks and
* reads across chunk boundaries as needed.
*/
export class StreamingOctetReader {
protected readonly chunks: Uint8Array[] = [];

Expand Down
32 changes: 31 additions & 1 deletion src/StreamingReader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Writer} from './Writer';
import {decodeUtf8} from './utf8/decodeUtf8';
import type {IReader, IReaderResettable} from './types';
import {Reader} from './Reader';

export class StreamingReader implements IReader, IReaderResettable {
protected readonly writer: Writer;
Expand Down Expand Up @@ -86,14 +87,43 @@ export class StreamingReader implements IReader, IReaderResettable {
this.x += length;
}

public buf(size: number): Uint8Array {
public buf(size: number = this.size()): Uint8Array {
this.assertSize(size);
const end = this.x + size;
const bin = this.uint8.subarray(this.x, end);
this.x = end;
return bin;
}

/**
* Creates a new {@link Reader} that references the same underlying memory
* buffer. But with independent cursor and end.
*
* @param start Start offset relative to the current cursor position.
* @param end End offset relative to the current cursor position.
* @returns A new {@link Reader} instance.
*/
public slice(start: number = 0, end?: number): Reader {
const x = this.x;
const actualStart = x + start;
const actualEnd = typeof end === 'number' ? x + end : this.size() + x - start;
return new Reader(this.uint8, this.view, actualStart, actualEnd);
}

/**
* Similar to {@link slice} but also advances the cursor. Returns a new
* {@link Reader} that references the same underlying memory buffer, starting
* from the current cursor position.
*
* @param size Number of bytes to cut from the current position.
* @returns A new {@link Reader} instance.
*/
public cut(size: number = this.size()): Reader {
const slice = this.slice(0, size);
this.skip(size);
return slice;
}

public u8(): number {
this.assertSize(1);
return this.view.getUint8(this.x++);
Expand Down
2 changes: 1 addition & 1 deletion src/Writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const from = hasBuffer ? Buffer.from : null;
const textEncoder = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null;

/**
* Encoder class provides an efficient way to encode binary data. It grows the
* Writer class provides an efficient way to encode binary data. It grows the
* internal memory buffer automatically as more space is required. It is useful
* in cases when it is not known in advance the size of memory needed.
*/
Expand Down
Loading