From 9e6e56d0346a97775ca8aca6463fe13ff1c8e73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20R=C3=ADos?= Date: Sun, 18 Jun 2023 13:15:06 +0200 Subject: [PATCH] feat: 128 bit types (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Elias Sjögreen --- types/primitive/i128.ts | 30 ++++++++++++++++++++++++++++++ types/primitive/i128_test.ts | 34 ++++++++++++++++++++++++++++++++++ types/primitive/u128.ts | 30 ++++++++++++++++++++++++++++++ types/primitive/u128_test.ts | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 types/primitive/i128.ts create mode 100644 types/primitive/i128_test.ts create mode 100644 types/primitive/u128.ts create mode 100644 types/primitive/u128_test.ts diff --git a/types/primitive/i128.ts b/types/primitive/i128.ts new file mode 100644 index 0000000..f81f8cd --- /dev/null +++ b/types/primitive/i128.ts @@ -0,0 +1,30 @@ +import { AlignedType } from "../types.ts"; +import { endianess } from "../../utils.ts"; + +export class I128 implements AlignedType { + byteLength = 16; + byteAlign = 16; + endian; + + constructor(endian: boolean = endianess) { + this.endian = endian; + } + + read(dataView: DataView, byteOffset = 0): bigint { + const hi = dataView.getBigInt64(byteOffset, this.endian); + const lo = dataView.getBigInt64(byteOffset + 8, this.endian); + return this.endian ? (lo << 64n) | hi : (hi << 64n) | lo; + } + + write(value: bigint, dataView: DataView, byteOffset = 0) { + const lo = value & 0xffffffffffffffffn; + const hi = value >> 64n; + dataView.setBigInt64(byteOffset, this.endian ? hi : lo, this.endian); + dataView.setBigInt64(byteOffset + 8, this.endian ? lo : hi, this.endian); + return dataView.buffer; + } +} + +export const i128 = new I128(); +export const i128le = new I128(true); +export const i128be = new I128(false); diff --git a/types/primitive/i128_test.ts b/types/primitive/i128_test.ts new file mode 100644 index 0000000..44cb05b --- /dev/null +++ b/types/primitive/i128_test.ts @@ -0,0 +1,34 @@ +import { i128be, i128le } from "./i128.ts"; +import { assertEquals } from "std/testing/asserts.ts"; + +Deno.test("i128", async ({ step }) => { + const buff = new ArrayBuffer(16); + const dt = new DataView(buff); + const value = 12n; + + await step("read", () => { + // Little endian + const lo = value & 0xffffffffffffffffn; + const hi = value >> 64n; + dt.setBigInt64(0, lo, true); + dt.setBigInt64(8, hi, true); + assertEquals(value, i128le.read(dt)); + // Big endian + dt.setBigInt64(0, hi, false); + dt.setBigInt64(8, lo, false); + assertEquals(value, i128be.read(dt)); + }); + + await step("write", () => { + // Little endian + i128le.write(value, dt); + let lo = dt.getBigInt64(0, true); + let hi = dt.getBigInt64(8, true); + assertEquals(value, (lo << 64n) | hi); + // Big endian + i128be.write(value, dt); + lo = dt.getBigInt64(8, false); + hi = dt.getBigInt64(0, false); + assertEquals(value, (lo << 64n) | hi); + }); +}); diff --git a/types/primitive/u128.ts b/types/primitive/u128.ts new file mode 100644 index 0000000..cb51ebe --- /dev/null +++ b/types/primitive/u128.ts @@ -0,0 +1,30 @@ +import { AlignedType } from "../types.ts"; +import { endianess } from "../../utils.ts"; + +export class U128 implements AlignedType { + byteLength = 16; + byteAlign = 16; + endian; + + constructor(endian: boolean = endianess) { + this.endian = endian; + } + + read(dataView: DataView, byteOffset = 0): bigint { + const hi = dataView.getBigUint64(byteOffset, this.endian); + const lo = dataView.getBigUint64(byteOffset + 8, this.endian); + return this.endian ? (lo << 64n) | hi : (hi << 64n) | lo; + } + + write(value: bigint, dataView: DataView, byteOffset = 0) { + const lo = value & 0xffffffffffffffffn; + const hi = value >> 64n; + dataView.setBigUint64(byteOffset, this.endian ? hi : lo, this.endian); + dataView.setBigUint64(byteOffset + 8, this.endian ? lo : hi, this.endian); + return dataView.buffer; + } +} + +export const u128 = new U128(); +export const u128le = new U128(true); +export const u128be = new U128(false); diff --git a/types/primitive/u128_test.ts b/types/primitive/u128_test.ts new file mode 100644 index 0000000..50d2c14 --- /dev/null +++ b/types/primitive/u128_test.ts @@ -0,0 +1,34 @@ +import { u128be, u128le } from "./u128.ts"; +import { assertEquals } from "std/testing/asserts.ts"; + +Deno.test("u128", async ({ step }) => { + const buff = new ArrayBuffer(16); + const dt = new DataView(buff); + const value = 12n; + + await step("read", () => { + // Little endian + const lo = value & 0xffffffffffffffffn; + const hi = value >> 64n; + dt.setBigUint64(0, lo, true); + dt.setBigUint64(8, hi, true); + assertEquals(value, u128le.read(dt)); + // Big endian + dt.setBigUint64(0, hi, false); + dt.setBigUint64(8, lo, false); + assertEquals(value, u128be.read(dt)); + }); + + await step("write", () => { + // Little endian + u128le.write(value, dt); + let lo = dt.getBigInt64(0, true); + let hi = dt.getBigInt64(8, true); + assertEquals(value, (lo << 64n) | hi); + // Big endian + u128be.write(value, dt); + lo = dt.getBigInt64(8, false); + hi = dt.getBigInt64(0, false); + assertEquals(value, (lo << 64n) | hi); + }); +});