Skip to content

Commit 8a02137

Browse files
committed
perf: improve bigint performance with strings
This reduces the overhead for typed arrays as well as having a faster check for cases where bigint is false.
1 parent 2027658 commit 8a02137

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
## Next
44

5+
- Added `'string'` as possible `bigint` option value. Bigint values are serialized as JSON strings using it.
6+
7+
```js
8+
import { configure } from 'safe-stable-stringify'
9+
10+
const stringify = configure({
11+
bigint: 'string'
12+
})
13+
14+
stringify([1n, 2, 3n, 4, 5n])
15+
// '["1",2,"3",4,"5"]'
16+
```
17+
518
- Fixed off by one error using the `maximumBreadth` option. It showed one entry to few being skipped.
619
- Added `safe` option to not fail in case a getter, `.toJSON()`, or a replacer throws an error.
720
Instead, a string as error message is replacing the object inspection. This allows to partially inspect such objects.

index.js

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function sort (array, comparator) {
5151
}
5252

5353
const typedArrayPrototypeGetSymbolToStringTag =
54+
// @ts-expect-error
5455
Object.getOwnPropertyDescriptor(
5556
Object.getPrototypeOf(
5657
Object.getPrototypeOf(
@@ -61,28 +62,29 @@ const typedArrayPrototypeGetSymbolToStringTag =
6162
).get
6263

6364
function isTypedArrayWithEntries (value) {
65+
// @ts-expect-error
6466
return typedArrayPrototypeGetSymbolToStringTag.call(value) !== undefined && value.length !== 0
6567
}
6668

69+
function wrapInQuotes (value) {
70+
return `"${value}"`
71+
}
72+
6773
function stringifyTypedArray (array, separator, maximumBreadth, bigint) {
6874
if (array.length < maximumBreadth) {
6975
maximumBreadth = array.length
7076
}
77+
const method = bigint === 'string' && array.length > 0 && typeof array[0] === 'bigint'
78+
? wrapInQuotes
79+
: String
7180
const whitespace = separator === ',' ? '' : ' '
72-
let res = `"0":${whitespace}${formatTypedArrayValue(array[0], bigint)}`
81+
let res = `"0":${whitespace}${method(array[0])}`
7382
for (let i = 1; i < maximumBreadth; i++) {
74-
res += `${separator}"${i}":${whitespace}${formatTypedArrayValue(array[i], bigint)}`
83+
res += `${separator}"${i}":${whitespace}${method(array[i])}`
7584
}
7685
return res
7786
}
7887

79-
function formatTypedArrayValue (value, bigint) {
80-
if (typeof value === 'bigint' && bigint === 'string') {
81-
return strEscape(String(value))
82-
}
83-
return String(value)
84-
}
85-
8688
function getCircularValueOption (options) {
8789
if (hasOwnProperty.call(options, 'circularValue')) {
8890
const circularValue = options.circularValue
@@ -353,10 +355,10 @@ function configure (options) {
353355
case 'undefined':
354356
return undefined
355357
case 'bigint':
356-
if (bigint === 'string') {
357-
return strEscape(String(value))
358-
}
359358
if (bigint) {
359+
if (bigint === 'string') {
360+
return `"${String(value)}"`
361+
}
360362
return String(value)
361363
}
362364
// fallthrough
@@ -445,10 +447,10 @@ function configure (options) {
445447
case 'undefined':
446448
return undefined
447449
case 'bigint':
448-
if (bigint === 'string') {
449-
return strEscape(String(value))
450-
}
451450
if (bigint) {
451+
if (bigint === 'string') {
452+
return `"${String(value)}"`
453+
}
452454
return String(value)
453455
}
454456
// fallthrough
@@ -558,10 +560,10 @@ function configure (options) {
558560
case 'undefined':
559561
return undefined
560562
case 'bigint':
561-
if (bigint === 'string') {
562-
return strEscape(String(value))
563-
}
564563
if (bigint) {
564+
if (bigint === 'string') {
565+
return `"${String(value)}"`
566+
}
565567
return String(value)
566568
}
567569
// fallthrough
@@ -662,10 +664,10 @@ function configure (options) {
662664
case 'undefined':
663665
return undefined
664666
case 'bigint':
665-
if (bigint === 'string') {
666-
return strEscape(String(value))
667-
}
668667
if (bigint) {
668+
if (bigint === 'string') {
669+
return `"${String(value)}"`
670+
}
669671
return String(value)
670672
}
671673
// fallthrough

0 commit comments

Comments
 (0)