From 514ea9254f8f55f56767d5f06dea988d0365c3cc Mon Sep 17 00:00:00 2001 From: MierenManz Date: Tue, 9 Jan 2024 11:51:24 +0100 Subject: [PATCH 1/9] optimize array allocation Setting `Array.length` is not the correct way to allocate upfront. It seems fast but is not. `new Array(length)` is a lot faster --- src/array/array.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/array/array.ts b/src/array/array.ts index fe11b32..ee2dab5 100644 --- a/src/array/array.ts +++ b/src/array/array.ts @@ -7,8 +7,7 @@ export class ArrayType extends UnsizedType { readPacked(dt: DataView, options: Options = { byteOffset: 0 }): T[] { if (this.length === 0) return []; - const result = []; - result.length = this.length; + const result = new Array(this.length); for (let i = 0; i < this.length; i++) { result[i] = this.type.readPacked(dt, options); @@ -20,15 +19,14 @@ export class ArrayType extends UnsizedType { read(dt: DataView, options: Options = { byteOffset: 0 }): T[] { if (this.length === 0) return []; - const result: unknown[] = []; - result.length = this.length; + const result = new Array(this.length); for (let i = 0; i < this.length; i++) { result[i] = this.type.read(dt, options); // No need for the increment offset. This is handled by the `type.read` function } - return result as T[]; + return result; } writePacked( From b04ccf4dbfd74611ae63523f9c0db94585378475 Mon Sep 17 00:00:00 2001 From: MierenManz Date: Tue, 9 Jan 2024 12:20:23 +0100 Subject: [PATCH 2/9] use `result.length` Allows v8 to determine all inserts are inbound which makes it skip bound checks (5% faster) --- src/array/array.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array/array.ts b/src/array/array.ts index ee2dab5..6cfec8f 100644 --- a/src/array/array.ts +++ b/src/array/array.ts @@ -9,7 +9,7 @@ export class ArrayType extends UnsizedType { if (this.length === 0) return []; const result = new Array(this.length); - for (let i = 0; i < this.length; i++) { + for (let i = 0; i < result.length; i++) { result[i] = this.type.readPacked(dt, options); // No need for the increment offset. This is handled by the `type.readPacked` function } @@ -21,7 +21,7 @@ export class ArrayType extends UnsizedType { if (this.length === 0) return []; const result = new Array(this.length); - for (let i = 0; i < this.length; i++) { + for (let i = 0; i < result.length; i++) { result[i] = this.type.read(dt, options); // No need for the increment offset. This is handled by the `type.read` function } From 9d25fc65c29b8f8c7f52811240b31eec5d351273 Mon Sep 17 00:00:00 2001 From: MierenManz Date: Tue, 9 Jan 2024 12:27:19 +0100 Subject: [PATCH 3/9] destructure `this` and loop over `value.length` to skip bound check (6% faster) --- src/array/array.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/array/array.ts b/src/array/array.ts index 6cfec8f..9e70cbf 100644 --- a/src/array/array.ts +++ b/src/array/array.ts @@ -37,10 +37,12 @@ export class ArrayType extends UnsizedType { if (value.length !== this.length) { throw new TypeError("T[].length !== ArrayType.length"); } + if (value.length === 0) return; + const { type } = this; - for (let i = 0; i < this.length; i++) { - this.type.writePacked(value[i], dt, options); + for (let i = 0; i < value.length; i++) { + type.writePacked(value[i], dt, options); // No need for the increment offset. This is handled by the `type.writePacked` function } } From edd2e77fc731ac2537efc96e1be2fb384c785f32 Mon Sep 17 00:00:00 2001 From: MierenManz Date: Tue, 9 Jan 2024 12:27:56 +0100 Subject: [PATCH 4/9] ditto --- src/array/array.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/array/array.ts b/src/array/array.ts index 9e70cbf..bb54c89 100644 --- a/src/array/array.ts +++ b/src/array/array.ts @@ -55,10 +55,12 @@ export class ArrayType extends UnsizedType { if (value.length !== this.length) { throw new TypeError("T[].length !== ArrayType.length"); } + if (value.length === 0) return; + const { type } = this; - for (let i = 0; i < this.length; i++) { - this.type.write(value[i], dt, options); + for (let i = 0; i < value.length; i++) { + type.write(value[i], dt, options); // No need for the increment offset. This is handled by the `type.write` function } } From 81effdadbbf325205581f4deb58ef9b478e135cf Mon Sep 17 00:00:00 2001 From: MierenManz Date: Thu, 11 Jan 2024 09:00:19 +0100 Subject: [PATCH 5/9] x --- src/array/array.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/array/array.ts b/src/array/array.ts index 115cb71..44ceedb 100644 --- a/src/array/array.ts +++ b/src/array/array.ts @@ -8,16 +8,10 @@ export class ArrayType extends UnsizedType { readPacked(dt: DataView, options: Options = { byteOffset: 0 }): T[] { if (this.length === 0) return []; const result = new Array(this.length); -<<<<<<< HEAD - - for (let i = 0; i < result.length; i++) { - result[i] = this.type.readPacked(dt, options); -======= const { type } = this; for (let i = 0; i < result.length; i++) { result[i] = type.readPacked(dt, options); ->>>>>>> 3ece55a2b93a8535164340828ebbce8bc416a9e8 // No need for the increment offset. This is handled by the `type.readPacked` function } @@ -46,13 +40,7 @@ export class ArrayType extends UnsizedType { throw new TypeError("T[].length !== ArrayType.length"); } -<<<<<<< HEAD - if (value.length === 0) return; - const { type } = this; - -======= const { type } = this; ->>>>>>> 3ece55a2b93a8535164340828ebbce8bc416a9e8 for (let i = 0; i < value.length; i++) { type.writePacked(value[i], dt, options); // No need for the increment offset. This is handled by the `type.writePacked` function @@ -68,13 +56,7 @@ export class ArrayType extends UnsizedType { throw new TypeError("T[].length !== ArrayType.length"); } -<<<<<<< HEAD - if (value.length === 0) return; - const { type } = this; - -======= const { type } = this; ->>>>>>> 3ece55a2b93a8535164340828ebbce8bc416a9e8 for (let i = 0; i < value.length; i++) { type.write(value[i], dt, options); // No need for the increment offset. This is handled by the `type.write` function From 8691e158774c5d56411be9512e9eff58d89b3d14 Mon Sep 17 00:00:00 2001 From: MierenManz Date: Fri, 9 Feb 2024 10:10:14 +0100 Subject: [PATCH 6/9] small ints --- src/small_number/mod.ts | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/small_number/mod.ts diff --git a/src/small_number/mod.ts b/src/small_number/mod.ts new file mode 100644 index 0000000..c4321f2 --- /dev/null +++ b/src/small_number/mod.ts @@ -0,0 +1,49 @@ +import { type Options, SizedType } from "../mod.ts"; + +type U2Number = 0 | 1 | 2 | 3; +type U4Number = U2Number | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15; + +export class U2 extends SizedType { + constructor() { + super(1, 1); + } + + readPacked(dt: DataView, options: Options = { byteOffset: 0 }): U2Number { + const v = dt.getUint8(options.byteOffset) & 0b11; + super.incrementOffset(options); + return v as U2Number; + } + + writePacked( + value: U2Number, + dt: DataView, + options: Options = { byteOffset: 0 }, + ): void { + dt.setUint8(options.byteOffset, value & 0b11); + super.incrementOffset(options); + } +} + +export class U4 extends SizedType { + constructor() { + super(1, 1); + } + + readPacked(dt: DataView, options: Options = { byteOffset: 0 }): U4Number { + const v = dt.getUint8(options.byteOffset) & 0b1111; + super.incrementOffset(options); + return v as U4Number; + } + + writePacked( + value: U4Number, + dt: DataView, + options: Options = { byteOffset: 0 }, + ): void { + dt.setUint8(options.byteOffset, value & 0b1111); + super.incrementOffset(options); + } +} + +export const u2 = new U2(); +export const u4 = new U4(); From b38b550f238eaf114c3f6eb7be83341c5b7d2bdb Mon Sep 17 00:00:00 2001 From: Skye Date: Sun, 3 Mar 2024 23:13:56 +0100 Subject: [PATCH 7/9] ignores --- src/array/array_bench.ts | 1 + src/compound/tuple_bench.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/array/array_bench.ts b/src/array/array_bench.ts index 4e67ece..6fd9a8b 100644 --- a/src/array/array_bench.ts +++ b/src/array/array_bench.ts @@ -7,6 +7,7 @@ const AB = new Uint8Array(SIZE).map((_, i) => i).buffer; const DT = new DataView(AB); const atn = new ArrayType(u8, SIZE); +// @ts-ignore: const ato = new OArrayType(u8, SIZE); Deno.bench("nop", () => {}); diff --git a/src/compound/tuple_bench.ts b/src/compound/tuple_bench.ts index 8113ba6..f6dd9a3 100644 --- a/src/compound/tuple_bench.ts +++ b/src/compound/tuple_bench.ts @@ -3,6 +3,7 @@ import { Tuple, u32, u8 } from "../mod.ts"; const record = [u32, u8]; +// @ts-ignore: const oTuple = new OTuple(record); const nTuple = new Tuple(record); From 5b4329b9b826ca92ba1597bda675f5214870a661 Mon Sep 17 00:00:00 2001 From: Skye Date: Wed, 12 Jun 2024 22:22:10 +0200 Subject: [PATCH 8/9] remove unneeded benchmarks --- src/array/array_bench.ts | 73 ------------------------- src/bitflags/bitflags64_bench.ts | 92 -------------------------------- src/compound/tuple_bench.ts | 75 -------------------------- 3 files changed, 240 deletions(-) delete mode 100644 src/array/array_bench.ts delete mode 100644 src/bitflags/bitflags64_bench.ts delete mode 100644 src/compound/tuple_bench.ts diff --git a/src/array/array_bench.ts b/src/array/array_bench.ts deleted file mode 100644 index 6fd9a8b..0000000 --- a/src/array/array_bench.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ArrayType as OArrayType } from "https://raw.githubusercontent.com/denosaurs/byte_type/796f19a5d0e4368b3910aa1e13fac70d59a7221d/mod.ts"; -import { ArrayType, u8 } from "../../mod.ts"; - -const SIZE = 10; -const DATA = new Array(SIZE).fill(0).map((_, i) => i); -const AB = new Uint8Array(SIZE).map((_, i) => i).buffer; -const DT = new DataView(AB); - -const atn = new ArrayType(u8, SIZE); -// @ts-ignore: -const ato = new OArrayType(u8, SIZE); - -Deno.bench("nop", () => {}); -//#region READ BENCHMARKS -Deno.bench({ - name: "Old Read Packed", - group: "rp", - fn: () => { - ato.readPacked(DT); - }, -}); -Deno.bench({ - name: "New Read Packed", - group: "rp", - fn: () => { - atn.readPacked(DT); - }, -}); -Deno.bench({ - name: "Old Read", - group: "r", - fn: () => { - ato.read(DT); - }, -}); -Deno.bench({ - name: "New Read", - group: "r", - fn: () => { - atn.read(DT); - }, -}); -//#endregion -//#region WRITE BENCHMARKS -Deno.bench({ - name: "Old Write Packed", - group: "wp", - fn: () => { - ato.writePacked(DATA, DT); - }, -}); -Deno.bench({ - name: "New Write Packed", - group: "wp", - fn: () => { - atn.writePacked(DATA, DT); - }, -}); -Deno.bench({ - name: "Old Write", - group: "w", - fn: () => { - ato.write(DATA, DT); - }, -}); -Deno.bench({ - name: "New Write", - group: "w", - fn: () => { - atn.write(DATA, DT); - }, -}); -//#endregion diff --git a/src/bitflags/bitflags64_bench.ts b/src/bitflags/bitflags64_bench.ts deleted file mode 100644 index 77aede9..0000000 --- a/src/bitflags/bitflags64_bench.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { BitFlags64 as OBF8 } from "https://raw.githubusercontent.com/denosaurs/byte_type/796f19a5d0e4368b3910aa1e13fac70d59a7221d/mod.ts"; -import { BitFlags64 } from "./mod.ts"; - -const AB = new ArrayBuffer(8); -const DT = new DataView(AB); -const inputRecord = { - one: 1n, - two: 2n, - four: 4n, - eight: 8n, - sixteen: 16n, - thirtytwo: 32n, - sixtyfour: 64n, - onetwentyeight: 128n, -}; - -const dataRecord = { - one: true, - two: true, - four: true, - eight: true, - sixteen: true, - thirtytwo: true, - sixtyfour: true, - onetwentyeight: true, -}; - -const obf = new OBF8(inputRecord); -const nbf = new BitFlags64(inputRecord); - -Deno.bench("nop", () => {}); - -//#region READ BENCHMARKS -Deno.bench({ - name: "Old Read Packed", - group: "rp", - fn: () => { - obf.readPacked(DT); - }, -}); -Deno.bench({ - name: "New Read Packed", - group: "rp", - fn: () => { - nbf.readPacked(DT); - }, -}); -Deno.bench({ - name: "Old Read", - group: "r", - fn: () => { - obf.read(DT); - }, -}); -Deno.bench({ - name: "New Read", - group: "r", - fn: () => { - nbf.read(DT); - }, -}); -//#endregion -//#region WRITE BENCHMARKS -Deno.bench({ - name: "Old Write Packed", - group: "wp", - fn: () => { - obf.writePacked(dataRecord, DT); - }, -}); -Deno.bench({ - name: "New Write Packed", - group: "wp", - fn: () => { - nbf.writePacked(dataRecord, DT); - }, -}); -Deno.bench({ - name: "Old Write", - group: "w", - fn: () => { - obf.write(dataRecord, DT); - }, -}); -Deno.bench({ - name: "New Write", - group: "w", - fn: () => { - nbf.write(dataRecord, DT); - }, -}); -//#endregion diff --git a/src/compound/tuple_bench.ts b/src/compound/tuple_bench.ts deleted file mode 100644 index f6dd9a3..0000000 --- a/src/compound/tuple_bench.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Tuple as OTuple } from "https://raw.githubusercontent.com/denosaurs/byte_type/796f19a5d0e4368b3910aa1e13fac70d59a7221d/mod.ts"; -import { Tuple, u32, u8 } from "../mod.ts"; - -const record = [u32, u8]; - -// @ts-ignore: -const oTuple = new OTuple(record); -const nTuple = new Tuple(record); - -const data = [32, 8]; -const AB = new ArrayBuffer(256); -const DT = new DataView(AB); - -Deno.bench("nop", () => {}); - -//#region READ BENCHMARKS -Deno.bench({ - name: "Old Read Packed", - group: "rp", - fn: () => { - oTuple.readPacked(DT); - }, -}); -Deno.bench({ - name: "New Read Packed", - group: "rp", - fn: () => { - nTuple.readPacked(DT); - }, -}); -Deno.bench({ - name: "Old Read", - group: "r", - fn: () => { - oTuple.read(DT); - }, -}); -Deno.bench({ - name: "New Read", - group: "r", - fn: () => { - nTuple.read(DT); - }, -}); -//#endregion -//#region WRITE BENCHMARKS -Deno.bench({ - name: "Old Write Packed", - group: "wp", - fn: () => { - oTuple.writePacked(data, DT); - }, -}); -Deno.bench({ - name: "New Write Packed", - group: "wp", - fn: () => { - nTuple.writePacked(data, DT); - }, -}); -Deno.bench({ - name: "Old Write", - group: "w", - fn: () => { - oTuple.write(data, DT); - }, -}); -Deno.bench({ - name: "New Write", - group: "w", - fn: () => { - nTuple.write(data, DT); - }, -}); -//#endregion From f837caf4a08e6f86992c7955bb187ae47f90e821 Mon Sep 17 00:00:00 2001 From: Skye Date: Tue, 5 Nov 2024 15:29:29 +0100 Subject: [PATCH 9/9] remove range check --- src/array/array_buffer.ts | 4 ---- src/array/typed_array.ts | 4 ---- src/bitflags/bitflags16.ts | 4 ---- src/bitflags/bitflags32.ts | 4 ---- src/bitflags/bitflags64.ts | 4 ---- src/bitflags/bitflags8.ts | 4 ---- src/primitives/bool.ts | 6 +---- src/primitives/f32.ts | 2 -- src/primitives/f64.ts | 2 -- src/primitives/i16.ts | 2 -- src/primitives/i32.ts | 2 -- src/primitives/i64.ts | 2 -- src/primitives/i8.ts | 2 -- src/primitives/u16.ts | 2 -- src/primitives/u32.ts | 2 -- src/primitives/u64.ts | 2 -- src/primitives/u8.ts | 2 -- src/string/fixed_length.ts | 4 ---- src/types/sized.ts | 7 ------ src/varint/i32_leb128_test.ts | 45 +++++++++++++++++++++++++++++++++++ 20 files changed, 46 insertions(+), 60 deletions(-) diff --git a/src/array/array_buffer.ts b/src/array/array_buffer.ts index 87b9cc9..acc93fe 100644 --- a/src/array/array_buffer.ts +++ b/src/array/array_buffer.ts @@ -9,8 +9,6 @@ export class ArrayBufferType extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): ArrayBuffer { - super.rangeCheck(dt.byteLength, options.byteOffset); - const resultAB = new ArrayBuffer(this.byteSize); const resultView = new Uint8Array(resultAB); @@ -32,8 +30,6 @@ export class ArrayBufferType extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - const view = new Uint8Array( dt.buffer, dt.byteOffset + options.byteOffset, diff --git a/src/array/typed_array.ts b/src/array/typed_array.ts index 0ef1579..5150996 100644 --- a/src/array/typed_array.ts +++ b/src/array/typed_array.ts @@ -39,8 +39,6 @@ export class TypedArray extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): T { - super.rangeCheck(dt.byteLength, options.byteOffset); - const value = new this.arrayConstructor( dt.buffer, dt.byteOffset + options.byteOffset, @@ -56,8 +54,6 @@ export class TypedArray extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - const view = new this.arrayConstructor( dt.buffer, dt.byteOffset + options.byteOffset, diff --git a/src/bitflags/bitflags16.ts b/src/bitflags/bitflags16.ts index 369a61c..8955762 100644 --- a/src/bitflags/bitflags16.ts +++ b/src/bitflags/bitflags16.ts @@ -13,8 +13,6 @@ export class BitFlags16< } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): O { - super.rangeCheck(dt.byteLength, options.byteOffset); - const returnObject: Record = {}; const byteBag = dt.getUint16(options.byteOffset); @@ -32,8 +30,6 @@ export class BitFlags16< dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - let flags = 0; for (const { 0: key, 1: flagValue } of this.#recordEntries) { diff --git a/src/bitflags/bitflags32.ts b/src/bitflags/bitflags32.ts index c66fffc..e0a5e5c 100644 --- a/src/bitflags/bitflags32.ts +++ b/src/bitflags/bitflags32.ts @@ -13,8 +13,6 @@ export class BitFlags32< } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): O { - super.rangeCheck(dt.byteLength, options.byteOffset); - const returnObject: Record = {}; const byteBag = dt.getUint32(options.byteOffset); @@ -32,8 +30,6 @@ export class BitFlags32< dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - let flags = 0; for (const { 0: key, 1: flagValue } of this.#recordEntries) { diff --git a/src/bitflags/bitflags64.ts b/src/bitflags/bitflags64.ts index 08db206..6b5f742 100644 --- a/src/bitflags/bitflags64.ts +++ b/src/bitflags/bitflags64.ts @@ -13,8 +13,6 @@ export class BitFlags64< } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): O { - super.rangeCheck(dt.byteLength, options.byteOffset); - const returnObject: Record = {}; const byteBag = dt.getBigUint64(options.byteOffset); @@ -32,8 +30,6 @@ export class BitFlags64< dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - let flags = 0n; for (const { 0: key, 1: flagValue } of this.#recordEntries) { diff --git a/src/bitflags/bitflags8.ts b/src/bitflags/bitflags8.ts index 6d90b05..a083392 100644 --- a/src/bitflags/bitflags8.ts +++ b/src/bitflags/bitflags8.ts @@ -13,8 +13,6 @@ export class BitFlags8< } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): O { - super.rangeCheck(dt.byteLength, options.byteOffset); - const returnObject: Record = {}; const byteBag = dt.getUint8(options.byteOffset); @@ -32,8 +30,6 @@ export class BitFlags8< dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - let flags = 0; for (const { 0: key, 1: flagValue } of this.#recordEntries) { diff --git a/src/primitives/bool.ts b/src/primitives/bool.ts index c7b5e03..1e16f00 100644 --- a/src/primitives/bool.ts +++ b/src/primitives/bool.ts @@ -6,9 +6,7 @@ export class Bool extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): boolean { - super.rangeCheck(dt.byteLength, options.byteOffset); - - const value = Boolean(dt.getInt8(options.byteOffset)); + const value = !!dt.getInt8(options.byteOffset); super.incrementOffset(options); return value; } @@ -18,8 +16,6 @@ export class Bool extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - dt.setInt8(options.byteOffset, Number(value)); super.incrementOffset(options); } diff --git a/src/primitives/f32.ts b/src/primitives/f32.ts index 1ffc008..ff8d61c 100644 --- a/src/primitives/f32.ts +++ b/src/primitives/f32.ts @@ -7,7 +7,6 @@ export class F32 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getFloat32(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class F32 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setFloat32(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/f64.ts b/src/primitives/f64.ts index 1fa1695..9f1075c 100644 --- a/src/primitives/f64.ts +++ b/src/primitives/f64.ts @@ -7,7 +7,6 @@ export class F64 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getFloat64(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class F64 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setFloat64(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/i16.ts b/src/primitives/i16.ts index b43f563..481008c 100644 --- a/src/primitives/i16.ts +++ b/src/primitives/i16.ts @@ -7,7 +7,6 @@ export class I16 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getInt16(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class I16 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setInt16(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/i32.ts b/src/primitives/i32.ts index d56adb4..12fdfd7 100644 --- a/src/primitives/i32.ts +++ b/src/primitives/i32.ts @@ -7,7 +7,6 @@ export class I32 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getInt32(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class I32 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setInt32(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/i64.ts b/src/primitives/i64.ts index 513d267..eb66fcd 100644 --- a/src/primitives/i64.ts +++ b/src/primitives/i64.ts @@ -7,7 +7,6 @@ export class I64 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): bigint { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getBigInt64(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class I64 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setBigInt64(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/i8.ts b/src/primitives/i8.ts index 635951a..1783811 100644 --- a/src/primitives/i8.ts +++ b/src/primitives/i8.ts @@ -6,7 +6,6 @@ export class I8 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getInt8(options.byteOffset); super.incrementOffset(options); return value; @@ -17,7 +16,6 @@ export class I8 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setInt8(options.byteOffset, value); super.incrementOffset(options); } diff --git a/src/primitives/u16.ts b/src/primitives/u16.ts index 32ac527..d5c3547 100644 --- a/src/primitives/u16.ts +++ b/src/primitives/u16.ts @@ -7,7 +7,6 @@ export class U16 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getUint16(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class U16 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setUint16(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/u32.ts b/src/primitives/u32.ts index 32016af..75b1207 100644 --- a/src/primitives/u32.ts +++ b/src/primitives/u32.ts @@ -7,7 +7,6 @@ export class U32 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getUint32(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class U32 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setUint32(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/u64.ts b/src/primitives/u64.ts index f7bf151..490a251 100644 --- a/src/primitives/u64.ts +++ b/src/primitives/u64.ts @@ -7,7 +7,6 @@ export class U64 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): bigint { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getBigUint64(options.byteOffset, this.littleEndian); super.incrementOffset(options); return value; @@ -18,7 +17,6 @@ export class U64 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setBigUint64(options.byteOffset, value, this.littleEndian); super.incrementOffset(options); } diff --git a/src/primitives/u8.ts b/src/primitives/u8.ts index 63156e7..160d694 100644 --- a/src/primitives/u8.ts +++ b/src/primitives/u8.ts @@ -6,7 +6,6 @@ export class U8 extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): number { - super.rangeCheck(dt.byteLength, options.byteOffset); const value = dt.getUint8(options.byteOffset); super.incrementOffset(options); return value; @@ -17,7 +16,6 @@ export class U8 extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); dt.setUint8(options.byteOffset, value); super.incrementOffset(options); } diff --git a/src/string/fixed_length.ts b/src/string/fixed_length.ts index a4f79ba..7cc9960 100644 --- a/src/string/fixed_length.ts +++ b/src/string/fixed_length.ts @@ -7,8 +7,6 @@ export class FixedLengthString extends SizedType { } readPacked(dt: DataView, options: Options = { byteOffset: 0 }): string { - super.rangeCheck(dt.byteLength, options.byteOffset); - const view = new Uint8Array( dt.buffer, dt.byteOffset + options.byteOffset, @@ -25,8 +23,6 @@ export class FixedLengthString extends SizedType { dt: DataView, options: Options = { byteOffset: 0 }, ): void { - super.rangeCheck(dt.byteLength, options.byteOffset); - const view = new Uint8Array( dt.buffer, dt.byteOffset + options.byteOffset, diff --git a/src/types/sized.ts b/src/types/sized.ts index 1d2aafe..5fc8c14 100644 --- a/src/types/sized.ts +++ b/src/types/sized.ts @@ -20,11 +20,4 @@ export abstract class SizedType extends UnsizedType implements Sized { protected override incrementOffset(options: Options): void { super.incrementOffset(options, this.byteSize); } - - /** Allows you to check upfront if you will go out of bound */ - protected rangeCheck(byteLength: number, offset: number): void { - if (this.byteSize > (byteLength - offset)) { - throw new RangeError("Out of bound"); - } - } } diff --git a/src/varint/i32_leb128_test.ts b/src/varint/i32_leb128_test.ts index 5dde195..a62d779 100644 --- a/src/varint/i32_leb128_test.ts +++ b/src/varint/i32_leb128_test.ts @@ -78,3 +78,48 @@ Deno.test("i32leb128", async ({ step }) => { }); }); }); + +Deno.test("i32leb128", async ({ step }) => { + await step("read", async ({ step }) => { + await step("positive", () => { + let data = Uint8Array.of(127); + let result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, 127); + + data = Uint8Array.of(128, 1); + result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, 128); + + data = Uint8Array.of(221, 199, 1); + result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, 25565); + + data = Uint8Array.of(255, 255, 255, 255, 7); + result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, 2147483647); + }); + + await step("negative", () => { + let data = Uint8Array.of(255, 255, 255, 255, 15); + let result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, -1); + + data = Uint8Array.of(128, 128, 128, 128, 8); + result = i32leb128.readPacked2(new DataView(data.buffer)); + assertEquals(result, -2147483648); + }); + + await step("bad", () => { + const data = Uint8Array.of(255, 255, 255, 255, 255, 15); + assertThrows(() => i32leb128.readPacked2(new DataView(data.buffer))); + }); + + await step("i32 max", () => { + const data = Uint8Array.of(255, 255, 255, 255, 7); + assertEquals( + i32leb128.readPacked2(new DataView(data.buffer)), + 2147483647, + ); + }); + }); +});