63 lines
No EOL
3.6 KiB
Markdown
63 lines
No EOL
3.6 KiB
Markdown
# Universal Lenient Base64 Decoder
|
|
|
|
This is a modified version of the standard base64 decoder from `encoding/base64`. Key differences:
|
|
|
|
- Accepts both Standard and URL-safe encoding, no need to specify it explicitly.
|
|
- Works for both padded and raw inputs.
|
|
- The input can be a `string` or a `[]byte`, no allocation or copy is performed for either.
|
|
|
|
The goal was to create a decoder compatible with the one used in nodejs (and possibly elsewhere too). Unfortunately
|
|
the standard package does not expose enough API to do this efficiently, and trying all 4 possible variants
|
|
(standard/url, padded/raw) seemed wasteful.
|
|
|
|
Because there is no need to convert the input from `string` to `[]byte`, decoding strings (specially long ones)
|
|
is more efficient than with the standard library. Below is the comparison between `BenchmarkDecodeBase64Std`
|
|
and `BenchmarkDecodeBase64` on go1.21.3:
|
|
|
|
```
|
|
goos: linux
|
|
goarch: amd64
|
|
pkg: base64dec
|
|
cpu: Intel(R) Core(TM) i7-2600S CPU @ 2.80GHz
|
|
│ old.txt │ new.txt │
|
|
│ sec/op │ sec/op vs base │
|
|
DecodeBase64/2-8 28.85n ± 3% 22.95n ± 2% -20.45% (p=0.000 n=10)
|
|
DecodeBase64/4-8 48.05n ± 0% 41.41n ± 1% -13.83% (p=0.000 n=10)
|
|
DecodeBase64/8-8 38.31n ± 2% 29.55n ± 1% -22.89% (p=0.000 n=10)
|
|
DecodeBase64/64-8 406.7n ± 5% 113.0n ± 2% -72.20% (p=0.000 n=10)
|
|
DecodeBase64/8192-8 31.670µ ± 10% 9.995µ ± 2% -68.44% (p=0.000 n=10)
|
|
geomean 232.8n 126.0n -45.89%
|
|
|
|
│ old.txt │ new.txt │
|
|
│ B/s │ B/s vs base │
|
|
DecodeBase64/2-8 132.2Mi ± 3% 166.2Mi ± 2% +25.70% (p=0.000 n=10)
|
|
DecodeBase64/4-8 158.8Mi ± 0% 184.2Mi ± 1% +16.04% (p=0.000 n=10)
|
|
DecodeBase64/8-8 298.7Mi ± 2% 387.3Mi ± 1% +29.67% (p=0.000 n=10)
|
|
DecodeBase64/64-8 206.4Mi ± 5% 742.4Mi ± 2% +259.71% (p=0.000 n=10)
|
|
DecodeBase64/8192-8 329.0Mi ± 11% 1042.4Mi ± 2% +216.87% (p=0.000 n=10)
|
|
geomean 211.8Mi 391.4Mi +84.81%
|
|
|
|
│ old.txt │ new.txt │
|
|
│ B/op │ B/op vs base │
|
|
DecodeBase64/2-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/4-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/8-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/64-8 96.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10)
|
|
DecodeBase64/8192-8 12.00Ki ± 0% 0.00Ki ± 0% -100.00% (p=0.000 n=10)
|
|
geomean ² ? ² ³
|
|
¹ all samples are equal
|
|
² summaries must be >0 to compute geomean
|
|
³ ratios must be >0 to compute geomean
|
|
|
|
│ old.txt │ new.txt │
|
|
│ allocs/op │ allocs/op vs base │
|
|
DecodeBase64/2-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/4-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/8-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
|
|
DecodeBase64/64-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
|
DecodeBase64/8192-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
|
geomean ² ? ² ³
|
|
¹ all samples are equal
|
|
² summaries must be >0 to compute geomean
|
|
³ ratios must be >0 to compute geomean
|
|
``` |