From ee369a1c831b1a4596e3abc1743e4ead42ffd570 Mon Sep 17 00:00:00 2001 From: teidesu Date: Fri, 21 May 2021 22:15:25 +0300 Subject: [PATCH] feat(core): int64 write optimization this optimization gives about 10x performance boost on systems that support BigInt, and about 2x on those that don't --- .../core/src/utils/binary/binary-reader.ts | 19 ++++++++++++++----- .../core/src/utils/binary/binary-writer.ts | 19 ++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/core/src/utils/binary/binary-reader.ts b/packages/core/src/utils/binary/binary-reader.ts index 35d22c16..dbdb9d9b 100644 --- a/packages/core/src/utils/binary/binary-reader.ts +++ b/packages/core/src/utils/binary/binary-reader.ts @@ -2,9 +2,11 @@ import bigInt, { BigInteger } from 'big-integer' import { inflate } from 'pako' import { typedArrayToBuffer } from '../buffer-utils' import readerMap, { ITlBinaryReader } from '@mtcute/tl/binary/reader' -import { ulongToLong } from '../bigint-utils' +import { bufferToBigInt, longToUlong, ulongToLong } from '../bigint-utils' import { tl } from '@mtcute/tl' +const isNativeBigIntAvailable = typeof BigInt !== 'undefined' && 'readBigInt64LE' in Buffer.prototype + export class BinaryReader implements ITlBinaryReader { data: Buffer pos = 0 @@ -33,12 +35,19 @@ export class BinaryReader implements ITlBinaryReader { } long(unsigned = false): BigInteger { - const lo = this.data.readUInt32LE(this.pos) - const hi = this.data.readUInt32LE(this.pos + 4) + let big: BigInteger + if (isNativeBigIntAvailable) { + const val = this.data.readBigInt64LE(this.pos) + big = bigInt(val) + + if (unsigned) big = longToUlong(big) + } else { + big = bufferToBigInt(this.data, this.pos, 8, true) + if (!unsigned) big = ulongToLong(big) + } + this.pos += 8 - let big = bigInt(hi).shiftLeft(32).or(lo) - if (!unsigned) big = ulongToLong(big) return big } diff --git a/packages/core/src/utils/binary/binary-writer.ts b/packages/core/src/utils/binary/binary-writer.ts index 21af5c9c..0db9d4d7 100644 --- a/packages/core/src/utils/binary/binary-writer.ts +++ b/packages/core/src/utils/binary/binary-writer.ts @@ -1,5 +1,5 @@ import { BigInteger } from 'big-integer' -import { longToUlong } from '../bigint-utils' +import { longToUlong, ulongToLong, writeBigInt } from '../bigint-utils' import writerMap, { ITlBinaryWriter, TlBinaryWriterFunction, @@ -11,6 +11,8 @@ type SerializableObject = { [key: string]: any } +const isNativeBigIntAvailable = typeof BigInt !== 'undefined' && 'writeBigInt64LE' in Buffer.prototype + export class SerializationCounter implements ITlBinaryWriter { count = 0 _objectMap = writerMap @@ -145,12 +147,15 @@ export class BinaryWriter implements ITlBinaryWriter { } long(val: BigInteger): void { - val = longToUlong(val) - const lo = val.and(0xffffffff).toJSNumber() - const hi = val.shiftRight(32).and(0xffffffff).toJSNumber() - - this.buffer.writeUInt32LE(lo, this.pos) - this.buffer.writeUInt32LE(hi, this.pos + 4) + if (isNativeBigIntAvailable) { + val = ulongToLong(val) + // if BigInt is supported, `BigInteger` is just a + // wrapper over native BigInt, stored in `value` + this.buffer.writeBigInt64LE((val as any).value, this.pos) + } else { + val = longToUlong(val) + writeBigInt(this.buffer, val, 8, this.pos, true) + } this.pos += 8 }