From: Chris Duncan Date: Sat, 4 Jul 2026 06:15:21 +0000 (-0700) Subject: Replace built-in toString with faster bespoke implementation. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=4dc4a9bac42bb8d3b87a55e62fb50e93dac12c04;p=libnemo.git Replace built-in toString with faster bespoke implementation. --- diff --git a/src/lib/account/index.ts b/src/lib/account/index.ts index ef12304..2247b9a 100644 --- a/src/lib/account/index.ts +++ b/src/lib/account/index.ts @@ -4,7 +4,7 @@ import { derive as nano25519_derive } from 'nano25519/sync' import { Block } from '../block' import { ACCOUNT_KEY_BYTE_LENGTH, ACCOUNT_KEY_HEX_LENGTH } from '../constants' -import { bytes, hex } from '../convert' +import { bytes, dec, hex } from '../convert' import { Rpc } from '../rpc' import { Address } from './address' import { _refresh } from './refresh' @@ -133,19 +133,19 @@ export class Account { return { publicKey: this.publicKey, address: this.address, - confirmed_balance: this.confirmed_balance?.toString(), - confirmed_height: this.confirmed_height?.toString(), + confirmed_balance: this.confirmed_balance == null ? null : dec.toString(this.confirmed_balance), + confirmed_height: this.confirmed_height == null ? null : dec.toString(this.confirmed_height), confirmed_frontier: this.confirmed_frontier, - confirmed_receivable: this.confirmed_receivable?.toString(), + confirmed_receivable: this.confirmed_receivable == null ? null : dec.toString(this.confirmed_receivable), confirmed_representative: this.confirmed_representative?.address, - balance: this.balance?.toString(), + balance: this.balance == null ? null : dec.toString(this.balance), block_count: this.block_count, frontier: this.frontier, open_block: this.open_block, - receivable: this.receivable?.toString(), + receivable: this.receivable == null ? null : dec.toString(this.receivable), representative: this.representative?.address, representative_block: this.representative_block, - weight: this.weight?.toString(), + weight: this.weight == null ? null : dec.toString(this.weight), } } diff --git a/src/lib/block/index.ts b/src/lib/block/index.ts index 9f348a2..c76dc86 100644 --- a/src/lib/block/index.ts +++ b/src/lib/block/index.ts @@ -133,7 +133,7 @@ export class Block { "account": this.account.address, "previous": bytes.toHex(this.previous), "representative": this.representative.address ?? '', - "balance": this.balance.toString(), + "balance": dec.toString(this.balance), "link": bytes.toHex(this.link), "signature": this.signature ?? '', "work": this.work ?? '' diff --git a/src/lib/convert/dec.ts b/src/lib/convert/dec.ts index 7124498..32e3ce1 100644 --- a/src/lib/convert/dec.ts +++ b/src/lib/convert/dec.ts @@ -44,21 +44,50 @@ export const dec = Object.freeze({ if (decimal == null) { throw new TypeError(`Failed to convert '${decimal}' from decimal to hex`) } - if (typeof padding !== 'number' || padding < 1 || padding > 0x1fffffffe) { + if (typeof padding !== 'number' || padding < 1 || padding > 0xffffffff) { throw new TypeError('Invalid padding') } let int = BigInt(decimal) if (int < 0n) { throw new TypeError('Decimal must be non-negative') } - let hex: string = '' + let str: string = '' while (int > 0n) { - hex = HEXCHAR[Number(int & 15n)] + hex + str = HEXCHAR[Number(int & 15n)] + str int >>= 4n } - while (hex.length < padding) { - hex = '0' + hex + while (str.length < padding) { + str = '0' + str + } + return str + }, + + /** + * Convert a non-negative decimal integer to a decimal string. + * + * @param {(bigint|number)} decimal - Integer to convert + * @param {number} [padding=1] - Minimum length of the resulting string padded as necessary with starting zeroes + * @returns {string} Hexadecimal string representation of the input decimal + */ + toString (decimal: bigint | number | null, padding: number = 1): string { + if (decimal == undefined) { + throw new TypeError(`Failed to convert '${decimal}' from decimal to string`) + } + if (typeof padding !== 'number' || padding < 1 || padding > 0xffffffff) { + throw new TypeError('Invalid padding') + } + let int = BigInt(decimal) + if (int < 0n) { + throw new TypeError('Decimal must be non-negative') + } + let str: string = '' + while (int > 0n) { + str = HEXCHAR[Number(int % 10n)] + str + int /= 10n + } + while (str.length < padding) { + str = '0' + str } - return hex + return str }, }) diff --git a/src/lib/tools.ts b/src/lib/tools.ts index 0f4f90b..b15143c 100644 --- a/src/lib/tools.ts +++ b/src/lib/tools.ts @@ -5,7 +5,7 @@ import { sign as nano25519_sign, verify as nano25519_verify } from 'nano25519/sy import { Account } from './account' import { Block } from './block' import { MAX_SUPPLY, UNITS } from './constants' -import { bytes, hex, utf8 } from './convert' +import { bytes, dec, hex, utf8 } from './convert' import { Rpc } from './rpc' import { Wallet } from './wallet' @@ -62,7 +62,7 @@ export class Tools { let [i, f] = typeof amount === 'string' ? amount.split('.') - : amount.toString().split('.') + : dec.toString(amount).split('.') i = i.replace(/^0*/g, '') f = f?.replace(/0*$/g, '') @@ -89,8 +89,7 @@ export class Tools { // convert to desired denomination const outUnit = UNITS[outputUnit] - i = int.toString() - while (i.length < 40) i = '0' + i + i = dec.toString(int, 40) f = i.slice(40 - outUnit).replace(/0*$/g, '') i = i.slice(0, 40 - outUnit).replace(/^0*/g, '') const output = `${i === '' ? '0' : i}${f === '' ? '' : '.'}${f}` diff --git a/src/lib/vault/index.ts b/src/lib/vault/index.ts index a57c709..ece6295 100644 --- a/src/lib/vault/index.ts +++ b/src/lib/vault/index.ts @@ -2,6 +2,7 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { Worker as NodeWorker } from 'node:worker_threads' +import { dec } from '../convert' import { Data } from '../database' type TaskData = { @@ -52,7 +53,7 @@ export class Vault { stderr: false, stdout: false }) - this.#url = this.#worker.threadId.toString() + this.#url = dec.toString(this.#worker.threadId) this.#worker.on('message', listener) } } diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index 1d111f7..6c242c4 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -4,6 +4,7 @@ import { derive as nano25519_derive, sign as nano25519_sign } from 'nano25519/sync' import { parentPort, threadId } from 'node:worker_threads' import { BIP44_COIN_NANO } from '../constants' +import { dec } from '../convert' import { Bip39, Bip44, Blake2b, WalletAesGcm } from '../crypto' import { WalletType } from '../wallet' import { parseAction, parseData, parseIv, parseKeySalt, parseType } from './parsers' @@ -31,7 +32,7 @@ const listener = (event: MessageEvent): void => { const { url, id } = data if (typeof id !== 'string') return BROWSER: if (url !== location.href) return - NODE: if (url !== threadId.toString()) return + NODE: if (url !== dec.toString(threadId)) return NODE: if (parentPort == null) setTimeout(() => listener(event), 0) const action = parseAction(data) const keySalt = parseKeySalt(action, data) @@ -383,7 +384,7 @@ async function _autolock (): Promise { const { isLocked } = await lock() const id = 'autolock' BROWSER: self.postMessage({ url: location.href, id, isLocked }) - NODE: parentPort?.postMessage({ data: { url: threadId.toString(), id, isLocked } }) + NODE: parentPort?.postMessage({ data: { url: dec.toString(threadId), id, isLocked } }) } const _index = new DataView(new ArrayBuffer(4))