Skip to content

Commit c79d490

Browse files
author
Brian Vaughn
committed
Switched UTF string encoding approach to handle multibyte characters
Also removed LRU cache since the caching approach seems to slow things down overall, based on benchmarking.
1 parent 8464d69 commit c79d490

File tree

2 files changed

+31
-48
lines changed

2 files changed

+31
-48
lines changed

packages/react-devtools-shared/src/__tests__/setupEnv.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,3 @@ global.process.env.DARK_MODE_DIMMED_LOG_COLOR = DARK_MODE_DIMMED_LOG_COLOR;
2424
global.process.env.LIGHT_MODE_DIMMED_WARNING_COLOR = LIGHT_MODE_DIMMED_WARNING_COLOR;
2525
global.process.env.LIGHT_MODE_DIMMED_ERROR_COLOR = LIGHT_MODE_DIMMED_ERROR_COLOR;
2626
global.process.env.LIGHT_MODE_DIMMED_LOG_COLOR = LIGHT_MODE_DIMMED_LOG_COLOR;
27-
28-
global.TextEncoder = require('util').TextEncoder;
29-
global.TextDecoder = require('util').TextDecoder;

packages/react-devtools-shared/src/utils.js

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
* @flow
88
*/
99

10-
import LRU from 'lru-cache';
1110
import {
1211
isElement,
1312
typeOf,
@@ -50,19 +49,9 @@ import {localStorageGetItem, localStorageSetItem} from './storage';
5049
import {meta} from './hydration';
5150

5251
import type {ComponentFilter, ElementType} from './types';
53-
import type {LRUCache} from 'react-devtools-shared/src/types';
5452

5553
const cachedDisplayNames: WeakMap<Function, string> = new WeakMap();
5654

57-
// On large trees, encoding takes significant time.
58-
// Try to reuse the already encoded strings.
59-
const encodedStringCache: LRUCache<
60-
string,
61-
Array<number> | Uint8Array,
62-
> = new LRU({
63-
max: 1000,
64-
});
65-
6655
export function alphaSortKeys(
6756
a: string | number | Symbol,
6857
b: string | number | Symbol,
@@ -128,47 +117,44 @@ export function getUID(): number {
128117
return ++uidCounter;
129118
}
130119

131-
const isTextEncoderSupported =
132-
typeof TextDecoder === 'function' && typeof TextEncoder === 'function';
133-
134120
export function utfDecodeString(array: Array<number>): string {
135-
if (isTextEncoderSupported) {
136-
// Handles multi-byte characters; use if available.
137-
return new TextDecoder().decode(new Uint8Array(array));
138-
} else {
139-
// Avoid spreading the array (e.g. String.fromCodePoint(...array))
140-
// Functions arguments are first placed on the stack before the function is called
141-
// which throws a RangeError for large arrays.
142-
// See github.com/facebook/react/issues/22293
143-
let string = '';
144-
for (let i = 0; i < array.length; i++) {
145-
const char = array[i];
146-
string += String.fromCodePoint(char);
147-
}
148-
return string;
121+
// Avoid spreading the array (e.g. String.fromCodePoint(...array))
122+
// Functions arguments are first placed on the stack before the function is called
123+
// which throws a RangeError for large arrays.
124+
// See github.com/facebook/react/issues/22293
125+
let string = '';
126+
for (let i = 0; i < array.length; i++) {
127+
const char = array[i];
128+
string += String.fromCodePoint(char);
149129
}
130+
return string;
150131
}
151132

152-
export function utfEncodeString(string: string): Array<number> | Uint8Array {
153-
const cached = encodedStringCache.get(string);
154-
if (cached !== undefined) {
155-
return cached;
156-
}
133+
function surrogatePairToCodePoint(
134+
charCode1: number,
135+
charCode2: number,
136+
): number {
137+
return ((charCode1 & 0x3ff) << 10) + (charCode2 & 0x3ff) + 0x10000;
138+
}
157139

158-
let encoded;
159-
if (isTextEncoderSupported) {
160-
// Handles multi-byte characters; use if available.
161-
encoded = new TextEncoder().encode(string);
162-
} else {
163-
encoded = new Array(string.length);
164-
for (let i = 0; i < string.length; i++) {
165-
encoded[i] = string.codePointAt(i);
140+
// Credit for this encoding approach goes to Tim Down:
141+
// https://stackoverflow.com/questions/4877326/how-can-i-tell-if-a-string-contains-multibyte-characters-in-javascript
142+
export function utfEncodeString(string: string): Array<number> {
143+
const codePoints = [];
144+
let i = 0;
145+
let charCode;
146+
while (i < string.length) {
147+
charCode = string.charCodeAt(i);
148+
if ((charCode & 0xf800) === 0xd800) {
149+
codePoints.push(
150+
surrogatePairToCodePoint(charCode, string.charCodeAt(++i)),
151+
);
152+
} else {
153+
codePoints.push(charCode);
166154
}
155+
++i;
167156
}
168-
169-
encodedStringCache.set(string, encoded);
170-
171-
return encoded;
157+
return codePoints;
172158
}
173159

174160
export function printOperationsArray(operations: Array<number>) {

0 commit comments

Comments
 (0)