diff options
author | Richard Viney <richard.viney@gmail.com> | 2024-06-21 17:01:37 +1200 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2024-06-21 10:49:14 +0100 |
commit | 6a6d5adf356993031ab2e79012e436dd2567a2f9 (patch) | |
tree | a1da55c581271e0160b47e3be35211f456719099 /src/gleam_stdlib.mjs | |
parent | ddd52834c46a9e8c608cbdc347a71b9ceeb361df (diff) | |
download | gleam_stdlib-6a6d5adf356993031ab2e79012e436dd2567a2f9.tar.gz gleam_stdlib-6a6d5adf356993031ab2e79012e436dd2567a2f9.zip |
Base64 encoding optimisations. Fix encoding of large bit arrays on JS.
This native JS implementation is 13-14x faster in simple benchmarks.
Diffstat (limited to 'src/gleam_stdlib.mjs')
-rw-r--r-- | src/gleam_stdlib.mjs | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs index a837e1d..c4111f9 100644 --- a/src/gleam_stdlib.mjs +++ b/src/gleam_stdlib.mjs @@ -504,10 +504,47 @@ export function parse_query(query) { } } -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64 -export function encode64(bit_array) { - const binString = String.fromCodePoint(...bit_array.buffer); - return btoa(binString); +const b64EncodeLookup = [ + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, +]; + +let b64TextDecoder; + +// Implementation based on https://github.com/mitschabaude/fast-base64/blob/main/js.js +export function encode64(bit_array, padding) { + b64TextDecoder ??= new TextDecoder(); + + const bytes = bit_array.buffer; + + const m = bytes.length; + const k = m % 3; + const n = Math.floor(m / 3) * 4 + (k && k + 1); + const N = Math.ceil(m / 3) * 4; + const encoded = new Uint8Array(N); + + for (let i = 0, j = 0; j < m; i += 4, j += 3) { + const y = (bytes[j] << 16) + (bytes[j + 1] << 8) + (bytes[j + 2] | 0); + encoded[i] = b64EncodeLookup[y >> 18]; + encoded[i + 1] = b64EncodeLookup[(y >> 12) & 0x3f]; + encoded[i + 2] = b64EncodeLookup[(y >> 6) & 0x3f]; + encoded[i + 3] = b64EncodeLookup[y & 0x3f]; + } + + let base64 = b64TextDecoder.decode(new Uint8Array(encoded.buffer, 0, n)); + + if (padding) { + if (k === 1) { + base64 += "=="; + } + else if (k === 2) { + base64 += "="; + } + } + + return base64; } // From https://developer.mozilla.org/en-US/docs/Glossary/Base64 |