]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/pem: skip whitespace work on most inputs
authorDaniel Martí <mvdan@mvdan.cc>
Mon, 31 Dec 2018 18:48:21 +0000 (19:48 +0100)
committerDaniel Martí <mvdan@mvdan.cc>
Sat, 2 Mar 2019 20:43:08 +0000 (20:43 +0000)
encoding/base64 already skips \r and \n when decoding, so this package
must only deal with spaces and tabs. Those aren't nearly as common, so
we can add a fast path with bytes.ContainsAny to skip the costly alloc
and filtering code.

name      old time/op    new time/op    delta
Decode-8     279µs ± 0%     259µs ± 1%   -7.07%  (p=0.002 n=6+6)

name      old speed      new speed      delta
Decode-8   319MB/s ± 0%   343MB/s ± 1%   +7.61%  (p=0.002 n=6+6)

name      old alloc/op   new alloc/op   delta
Decode-8     164kB ± 0%      74kB ± 0%  -54.90%  (p=0.002 n=6+6)

name      old allocs/op  new allocs/op  delta
Decode-8      12.0 ± 0%      11.0 ± 0%   -8.33%  (p=0.002 n=6+6)

Change-Id: Idfca8700c52f46eb70a4a7e0d2db3bf0124e4699
Reviewed-on: https://go-review.googlesource.com/c/155964
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/encoding/pem/pem.go

index 35058c306bc75be8fc1c46b38656dcef2440edad..a7272da5ad3a81575c3930fd405aafb824375004 100644 (file)
@@ -50,14 +50,22 @@ func getLine(data []byte) (line, rest []byte) {
        return bytes.TrimRight(data[0:i], " \t"), data[j:]
 }
 
-// removeWhitespace returns a copy of its input with all spaces, tab and
-// newline characters removed.
-func removeWhitespace(data []byte) []byte {
+// removeSpacesAndTabs returns a copy of its input with all spaces and tabs
+// removed, if there were any. Otherwise, the input is returned unchanged.
+//
+// The base64 decoder already skips newline characters, so we don't need to
+// filter them out here.
+func removeSpacesAndTabs(data []byte) []byte {
+       if !bytes.ContainsAny(data, " \t") {
+               // Fast path; most base64 data within PEM contains newlines, but
+               // no spaces nor tabs. Skip the extra alloc and work.
+               return data
+       }
        result := make([]byte, len(data))
        n := 0
 
        for _, b := range data {
-               if b == ' ' || b == '\t' || b == '\r' || b == '\n' {
+               if b == ' ' || b == '\t' {
                        continue
                }
                result[n] = b
@@ -155,7 +163,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
                return decodeError(data, rest)
        }
 
-       base64Data := removeWhitespace(rest[:endIndex])
+       base64Data := removeSpacesAndTabs(rest[:endIndex])
        p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
        n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
        if err != nil {