diff --git a/.changesets/iwvpz.patch.md b/.changesets/iwvpz.patch.md new file mode 100644 index 0000000..4c939d6 --- /dev/null +++ b/.changesets/iwvpz.patch.md @@ -0,0 +1 @@ +Improve `base64.encode()` performance \ No newline at end of file diff --git a/src/encoding/base32.ts b/src/encoding/base32.ts index ec2daca..07b3fc2 100644 --- a/src/encoding/base32.ts +++ b/src/encoding/base32.ts @@ -33,18 +33,18 @@ export class Base32Encoding implements Encoding { } ): string { let result = ""; - let block = 0; + let buffer = 0; let shift = 0; for (let i = 0; i < data.length; i++) { - block = (block << 8) | data[i]!; + buffer = (buffer << 8) | data[i]!; shift += 8; while (shift >= 5) { shift -= 5; - result += this.alphabet[(block >> shift) & 0x1f]; + result += this.alphabet[(buffer >> shift) & 0x1f]; } } if (shift > 0) { - result += this.alphabet[(block << (5 - shift)) & 0x1f]; + result += this.alphabet[(buffer << (5 - shift)) & 0x1f]; } const includePadding = options?.includePadding ?? true; if (includePadding) { diff --git a/src/encoding/base64.ts b/src/encoding/base64.ts index 8b90fff..24accb1 100644 --- a/src/encoding/base64.ts +++ b/src/encoding/base64.ts @@ -33,23 +33,22 @@ export class Base64Encoding implements Encoding { } ): string { let result = ""; - const chunkCount = Math.ceil(data.length / 3); - for (let i = 0; i < chunkCount; i++) { - let buffer = data[i * 3]! << 16; - buffer += (data[i * 3 + 1] ?? 0) << 8; - buffer += data[i * 3 + 2] ?? 0; - for (let j = 0; j < 4; j++) { - const key = (buffer >> ((3 - j) * 6)) & 0x3f; - result += this.alphabet[key]; + let buffer = 0; + let shift = 0; + for (let i = 0; i < data.length; i++) { + buffer = (buffer << 8) | data[i]!; + shift += 8; + while (shift >= 6) { + shift += -6; + result += this.alphabet[(buffer >> shift) & 0x3f]; } } - let padCount = 0; - if (data.length % 3 !== 0) { - padCount = 4 - Math.ceil(((data.length % 3) * 4) / 3); + if (shift > 0) { + result += this.alphabet[(buffer << (6 - shift)) & 0x3f]; } - result = result.slice(0, result.length - padCount); const includePadding = options?.includePadding ?? true; if (includePadding) { + const padCount = (4 - (result.length % 4)) % 4; for (let i = 0; i < padCount; i++) { result += "="; }