From d25ccbb1803f137cc5e9bf15fa060ae67c5be7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=A3=B0?= Date: Wed, 3 Jul 2024 17:23:28 +0800 Subject: [PATCH] feat: use TextDecoder to decode buffer (#1699) ## What does this PR do? Use the browser builtin decode utils: TextDecoder https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder This can improve a lot of performance. see the diff of the benchmark. and the original implementation will cause many `minor gc` in javascript, the longer the string, the longer the GC time. ## Related issues ## Does this PR introduce any user-facing change? - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark ![CleanShot 2024-06-25 at 17 04 45@2x](https://github.com/apache/fury/assets/13938334/29517aa9-563f-46ba-9aec-563d49c8db9a) --- .../packages/fury/lib/platformBuffer.ts | 25 ++++++------------ platform-buffer.jpg | Bin 0 -> 37116 bytes 2 files changed, 8 insertions(+), 17 deletions(-) create mode 100644 platform-buffer.jpg diff --git a/javascript/packages/fury/lib/platformBuffer.ts b/javascript/packages/fury/lib/platformBuffer.ts index b28df55bb9..e3a0978d62 100644 --- a/javascript/packages/fury/lib/platformBuffer.ts +++ b/javascript/packages/fury/lib/platformBuffer.ts @@ -19,6 +19,9 @@ import { hasBuffer } from "./util"; +let utf8Encoder: TextEncoder | null; +let textDecoder: TextDecoder | null; + export type SupportedEncodings = "latin1" | "utf8"; export interface PlatformBuffer extends Uint8Array { @@ -96,22 +99,12 @@ export class BrowserBuffer extends Uint8Array implements PlatformBuffer { if (end - start < 1) { return ""; } - let str = ""; - for (let i = start; i < end;) { - const t = this[i++]; - if (t <= 0x7F) { - str += String.fromCharCode(t); - } else if (t >= 0xC0 && t < 0xE0) { - str += String.fromCharCode((t & 0x1F) << 6 | this[i++] & 0x3F); - } else if (t >= 0xE0 && t < 0xF0) { - str += String.fromCharCode((t & 0xF) << 12 | (this[i++] & 0x3F) << 6 | this[i++] & 0x3F); - } else if (t >= 0xF0) { - const t2 = ((t & 7) << 18 | (this[i++] & 0x3F) << 12 | (this[i++] & 0x3F) << 6 | this[i++] & 0x3F) - 0x10000; - str += String.fromCharCode(0xD800 + (t2 >> 10)); - str += String.fromCharCode(0xDC00 + (t2 & 0x3FF)); - } + + if (!textDecoder) { + textDecoder = new TextDecoder("utf-8"); } - return str; + + return textDecoder.decode(this.subarray(start, end)); } copy(target: Uint8Array, targetStart?: number, sourceStart?: number, sourceEnd?: number) { @@ -153,8 +146,6 @@ export const alloc = (hasBuffer ? Buffer.allocUnsafe : BrowserBuffer.alloc) as u export const strByteLength = hasBuffer ? Buffer.byteLength : BrowserBuffer.byteLength; -let utf8Encoder: TextEncoder | null; - export const fromString = hasBuffer ? (str: string) => Buffer.from(str) as unknown as PlatformBuffer diff --git a/platform-buffer.jpg b/platform-buffer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0b69b4241bceb172aff55d1a8e733a58507911c8 GIT binary patch literal 37116 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 literal 0 HcmV?d00001