Commit e0ff4e6d authored by Daniel Martí's avatar Daniel Martí

encoding/pem: skip whitespace work on most inputs

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: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 06c86e0f
...@@ -50,14 +50,22 @@ func getLine(data []byte) (line, rest []byte) { ...@@ -50,14 +50,22 @@ func getLine(data []byte) (line, rest []byte) {
return bytes.TrimRight(data[0:i], " \t"), data[j:] return bytes.TrimRight(data[0:i], " \t"), data[j:]
} }
// removeWhitespace returns a copy of its input with all spaces, tab and // removeSpacesAndTabs returns a copy of its input with all spaces and tabs
// newline characters removed. // removed, if there were any. Otherwise, the input is returned unchanged.
func removeWhitespace(data []byte) []byte { //
// 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)) result := make([]byte, len(data))
n := 0 n := 0
for _, b := range data { for _, b := range data {
if b == ' ' || b == '\t' || b == '\r' || b == '\n' { if b == ' ' || b == '\t' {
continue continue
} }
result[n] = b result[n] = b
...@@ -155,7 +163,7 @@ func Decode(data []byte) (p *Block, rest []byte) { ...@@ -155,7 +163,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
return decodeError(data, rest) return decodeError(data, rest)
} }
base64Data := removeWhitespace(rest[:endIndex]) base64Data := removeSpacesAndTabs(rest[:endIndex])
p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
if err != nil { if err != nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment