From fe91118385ff05ad4d9e08a1977deb20388e9306 Mon Sep 17 00:00:00 2001 From: Jaco Date: Tue, 19 Jul 2022 08:45:11 +0200 Subject: [PATCH] Optimize packed WASM base64 decoding loop (#404) --- CHANGELOG.md | 7 +++++++ packages/wasm-util/src/base64.ts | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0d63281..e1ce0cd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## master + +Changes: + +- Optimize packed WASM base64 decoding loop + + ## 6.2.3 Jul 7, 2022 Changes: diff --git a/packages/wasm-util/src/base64.ts b/packages/wasm-util/src/base64.ts index a3a0270d..a0a546a1 100644 --- a/packages/wasm-util/src/base64.ts +++ b/packages/wasm-util/src/base64.ts @@ -1,11 +1,16 @@ // Copyright 2019-2022 @polkadot/wasm-util authors & contributors // SPDX-License-Identifier: Apache-2.0 +// Use an array for our indexer - this is faster than using map access. In +// this case we assume ASCII-only inputs, so we cannot overflow the array const chr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; -const map: Record = {}; +const map = new Array(256); +// We use charCodeAt for access here and in the decoder loop - this is faster +// on lookups (array + numbers) and also faster than accessing the specific +// character via data[i] for (let i = 0; i < chr.length; i++) { - map[chr[i]] = i; + map[chr.charCodeAt(i)] = i; } /** @@ -16,16 +21,18 @@ for (let i = 0; i < chr.length; i++) { * slightly slower, but it is platform independent. * * For our usage, since we have access to the static final size (where used), we - * decode to a specified output buffer. + * decode to a specified output buffer. This also means we have applied a number + * of optimizations based on this - checking out output position instead of chars. */ export function base64Decode (data: string, out: Uint8Array): Uint8Array { + const len = out.length; let byte = 0; let bits = 0; let pos = -1; - for (let i = 0; i < data.length && data[i] !== '='; i++) { + for (let i = 0; pos < len; i++) { // each character represents 6 bits - byte = (byte << 6) | map[data[i]]; + byte = (byte << 6) | map[data.charCodeAt(i)]; // each byte needs to contain 8 bits if ((bits += 6) >= 8) {