aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/base64/base64.go
diff options
context:
space:
mode:
authorJosselin Costanzi <josselin@costanzi.fr>2017-01-07 14:12:57 +0100
committerBrad Fitzpatrick <bradfitz@golang.org>2017-04-24 22:40:23 +0000
commit31c96fc2276b54f844bb5a83f2b4f817f956d976 (patch)
treee38029cf449f2c2a3a17707a562f4418d4aef73e /src/encoding/base64/base64.go
parentd9b1f9e85ee097ebc95c5904cee921ba7be4f732 (diff)
downloadgo-31c96fc2276b54f844bb5a83f2b4f817f956d976.tar.xz
encoding/base64: Optimize DecodeString
Optimize DecodeString for the common case where most of the input isn't a newline or a padding character. Also add some testcases found when fuzzing this implementation against upstream. Change Decode benchmark to run with different input sizes. name old time/op new time/op delta DecodeString/2-4 71.5ns ± 4% 70.0ns ± 6% ~ (p=0.246 n=5+5) DecodeString/4-4 112ns ±25% 91ns ± 2% ~ (p=0.056 n=5+5) DecodeString/8-4 136ns ± 5% 126ns ± 5% -7.33% (p=0.016 n=5+5) DecodeString/64-4 872ns ±29% 652ns ±21% -25.23% (p=0.032 n=5+5) DecodeString/8192-4 90.9µs ±21% 61.0µs ±13% -32.87% (p=0.008 n=5+5) name old speed new speed delta DecodeString/2-4 56.0MB/s ± 4% 57.2MB/s ± 6% ~ (p=0.310 n=5+5) DecodeString/4-4 73.4MB/s ±23% 87.7MB/s ± 2% ~ (p=0.056 n=5+5) DecodeString/8-4 87.8MB/s ± 5% 94.8MB/s ± 5% +7.98% (p=0.016 n=5+5) DecodeString/64-4 103MB/s ±24% 136MB/s ±19% +32.63% (p=0.032 n=5+5) DecodeString/8192-4 122MB/s ±19% 180MB/s ±11% +47.75% (p=0.008 n=5+5) Improves #19636 Change-Id: I39667f4fb682a12b3137946d017ad999553c5780 Reviewed-on: https://go-review.googlesource.com/34950 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/encoding/base64/base64.go')
-rw-r--r--src/encoding/base64/base64.go45
1 files changed, 24 insertions, 21 deletions
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index 5a384315f9..b208f9e4d8 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -273,44 +273,50 @@ func (e CorruptInputError) Error() string {
// indicates if end-of-message padding or a partial quantum was encountered
// and thus any additional data is an error.
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- var inIdx int
si := 0
- // skip over newlines
- for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
- si++
- }
-
for si < len(src) && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
dinc, dlen := 3, 4
- for j := range dbuf {
+ for j := 0; j < len(dbuf); j++ {
if len(src) == si {
- if enc.padChar != NoPadding || j < 2 {
+ switch {
+ case j == 0:
+ return n, false, nil
+ case j == 1, enc.padChar != NoPadding:
return n, false, CorruptInputError(si - j)
}
dinc, dlen, end = j-1, j, true
break
}
in := src[si]
- inIdx = si
si++
- // skip over newlines
- for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
- si++
+
+ out := enc.decodeMap[in]
+ if out != 0xFF {
+ dbuf[j] = out
+ continue
}
+ if in == '\n' || in == '\r' {
+ j--
+ continue
+ }
if rune(in) == enc.padChar {
// We've reached the end and there's padding
switch j {
case 0, 1:
// incorrect padding
- return n, false, CorruptInputError(inIdx)
+ return n, false, CorruptInputError(si - 1)
case 2:
// "==" is expected, the first "=" is already consumed.
+ // skip over newlines
+ for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+ si++
+ }
if si == len(src) {
// not enough padding
return n, false, CorruptInputError(len(src))
@@ -321,10 +327,10 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
}
si++
- // skip over newlines
- for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
- si++
- }
+ }
+ // skip over newlines
+ for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+ si++
}
if si < len(src) {
// trailing garbage
@@ -333,10 +339,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
dinc, dlen, end = 3, j, true
break
}
- dbuf[j] = enc.decodeMap[in]
- if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(inIdx)
- }
+ return n, false, CorruptInputError(si - 1)
}
// Convert 4x 6bit source bytes into 3 bytes