Skip to content

Commit 2615864

Browse files
perf(NODE-6126): improve Long.fromBigInt performance
1 parent 208f7e8 commit 2615864

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/long.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,20 @@ export class Long extends BSONValue {
243243
* @returns The corresponding Long value
244244
*/
245245
static fromBigInt(value: bigint, unsigned?: boolean): Long {
246-
return Long.fromString(value.toString(), unsigned);
246+
const byteStr = value.toString(16);
247+
const isNeg = byteStr[0] === '-';
248+
const startIndex = isNeg ? 1 : 0;
249+
const lowByteString =
250+
byteStr.length - startIndex > 8
251+
? byteStr.substring(byteStr.length - 8, byteStr.length)
252+
: isNeg
253+
? byteStr.slice(1)
254+
: byteStr;
255+
const highByteString =
256+
byteStr.length - startIndex > 8 ? byteStr.substring(startIndex, byteStr.length - 8) : 0;
257+
return isNeg
258+
? new Long(Number('0x' + lowByteString), Number('0x' + highByteString), unsigned).neg()
259+
: new Long(Number('0x' + lowByteString), Number('0x' + highByteString), unsigned);
247260
}
248261

249262
/**

test/node/long.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from 'chai';
22
import { Long, BSONError, __noBigInt__ } from '../register-bson';
3+
import { BSON_INT32_MAX, BSON_INT32_MIN } from '../../src/constants';
34

45
describe('Long', function () {
56
it('accepts strings in the constructor', function () {
@@ -164,6 +165,41 @@ describe('Long', function () {
164165
});
165166
});
166167

168+
describe('static fromBigInt()', function () {
169+
const inputs: [
170+
name: string,
171+
input: bigint,
172+
unsigned: boolean | undefined,
173+
expectedStr?: string
174+
][] = [
175+
['0', BigInt('0'), false, '0'],
176+
['-0 (bigint coerces this to 0)', BigInt('-0'), false, '0'],
177+
[
178+
'max unsigned input',
179+
BigInt(Long.MAX_UNSIGNED_VALUE.toString(10)),
180+
true,
181+
Long.MAX_UNSIGNED_VALUE.toString(10)
182+
],
183+
['max signed input', BigInt(Long.MAX_VALUE.toString(10)), false, Long.MAX_VALUE.toString(10)],
184+
['min signed input', BigInt(Long.MIN_VALUE.toString(10)), false, Long.MIN_VALUE.toString(10)],
185+
['negative greater than 32 bits', BigInt(-9228915101), false, '-9228915101'],
186+
['less than 32 bits', BigInt(245666), false, '245666'],
187+
['unsigned less than 32 bits', BigInt(245666), true, '245666'],
188+
['negative less than 32 bits', BigInt(-245666), false, '-245666'],
189+
['max int32', BigInt(BSON_INT32_MAX), false, BSON_INT32_MAX.toString(10)],
190+
['max int32 unsigned', BigInt(BSON_INT32_MAX), true, BSON_INT32_MAX.toString(10)],
191+
['min int32', BigInt(BSON_INT32_MIN), false, BSON_INT32_MIN.toString(10)]
192+
];
193+
194+
for (const [testName, num, unsigned, expectedStr] of inputs) {
195+
context(`when the input is ${testName}`, () => {
196+
it(`should return a Long representation of the input`, () => {
197+
expect(Long.fromBigInt(num, unsigned).toString(10)).to.equal(expectedStr);
198+
});
199+
});
200+
}
201+
});
202+
167203
describe('static fromString()', function () {
168204
const successInputs: [
169205
name: string,

0 commit comments

Comments
 (0)