From 4c91a5cb162f1b0b195a336acf0c218821019477 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 8 Aug 2024 22:13:55 -0400 Subject: [PATCH] Add polyfill --- package.json | 3 +-- src/bigint-polyfill/polyfill.ts | 13 ++++++++++ src/bigint-polyfill/pure.ts | 42 +++++++++++++++++++++++++++++++++ src/declare.d.ts | 2 -- src/index.ts | 1 + src/twoBitFile.ts | 7 ++++-- 6 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/bigint-polyfill/polyfill.ts create mode 100644 src/bigint-polyfill/pure.ts delete mode 100644 src/declare.d.ts diff --git a/package.json b/package.json index 970cf30..b22e2ac 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,7 @@ "biojs" ], "dependencies": { - "generic-filehandle": "^3.0.0", - "long": "^4.0.0" + "generic-filehandle": "^3.0.0" }, "devDependencies": { "@types/jest": "^29.2.4", diff --git a/src/bigint-polyfill/polyfill.ts b/src/bigint-polyfill/polyfill.ts new file mode 100644 index 0000000..b8e20a2 --- /dev/null +++ b/src/bigint-polyfill/polyfill.ts @@ -0,0 +1,13 @@ +import { getBigInt64, getBigUint64 } from './pure' + +if (!('getBigInt64' in DataView)) { + DataView.prototype.getBigInt64 = function (byteOffset, littleEndian) { + return getBigInt64(this, byteOffset, littleEndian) + } +} + +if (!('getBigUint64' in DataView)) { + DataView.prototype.getBigUint64 = function (byteOffset, littleEndian) { + return getBigUint64(this, byteOffset, littleEndian) + } +} diff --git a/src/bigint-polyfill/pure.ts b/src/bigint-polyfill/pure.ts new file mode 100644 index 0000000..bdb9500 --- /dev/null +++ b/src/bigint-polyfill/pure.ts @@ -0,0 +1,42 @@ +const BigInt32 = BigInt(32) + +export function getBigInt64( + dataView: DataView, + byteOffset: number, + littleEndian: boolean | undefined, +): bigint { + const littleEndianMask = Number(!!littleEndian) + const bigEndianMask = Number(!littleEndian) + + return ( + (BigInt( + dataView.getInt32(byteOffset, littleEndian) * bigEndianMask + + dataView.getInt32(byteOffset + 4, littleEndian) * littleEndianMask, + ) << + BigInt32) | + BigInt( + dataView.getUint32(byteOffset, littleEndian) * littleEndianMask + + dataView.getUint32(byteOffset + 4, littleEndian) * bigEndianMask, + ) + ) +} + +export function getBigUint64( + dataView: DataView, + byteOffset: number, + littleEndian: boolean | undefined, +): bigint { + const a = dataView.getUint32(byteOffset, littleEndian) + const b = dataView.getUint32(byteOffset + 4, littleEndian) + + const littleEndianMask = Number(!!littleEndian) + const bigEndianMask = Number(!littleEndian) + + // This branch-less optimization is 77x faster than normal ternary operator. + // and only 3% slower than native implementation + // https://jsbench.me/p8kyhg1eqv/1 + return ( + (BigInt(a * bigEndianMask + b * littleEndianMask) << BigInt32) | + BigInt(a * littleEndianMask + b * bigEndianMask) + ) +} diff --git a/src/declare.d.ts b/src/declare.d.ts deleted file mode 100644 index 963111e..0000000 --- a/src/declare.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module '@gmod/binary-parser' -declare module 'long' diff --git a/src/index.ts b/src/index.ts index 9c1abfc..03973f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,2 @@ +import './bigint-polyfill/polyfill' export { default as TwoBitFile } from './twoBitFile' diff --git a/src/twoBitFile.ts b/src/twoBitFile.ts index ed36541..bfb17d5 100644 --- a/src/twoBitFile.ts +++ b/src/twoBitFile.ts @@ -1,4 +1,3 @@ -import Long from 'long' import { LocalFile, GenericFilehandle } from 'generic-filehandle' const TWOBIT_MAGIC = 0x1a412743 @@ -316,7 +315,11 @@ export default class TwoBitFile { * @param {number} [regionEnd] optional 0-based half-open end of the sequence region to fetch. defaults to end of the sequence * @returns {Promise} for a string of sequence bases */ - async getSequence(seqName: string, regionStart = 0, regionEnd = Number.POSITIVE_INFINITY) { + async getSequence( + seqName: string, + regionStart = 0, + regionEnd = Number.POSITIVE_INFINITY, + ) { const index = await this.getIndex() const offset = index[seqName] if (!offset) {