aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/base32
diff options
context:
space:
mode:
authorSven Taute <sven.taute@gmail.com>2019-09-09 21:56:46 +0000
committerIan Lance Taylor <iant@golang.org>2019-09-11 00:56:39 +0000
commit8ef6d6a8f24354ef167f9dca54ab64e1ea6579f0 (patch)
treed5d3b50be9e884effad5705435337544c4085df3 /src/encoding/base32
parent4dc11ae26b3a092bbcd1b4d0ae8cdaeb1cf1cef9 (diff)
downloadgo-8ef6d6a8f24354ef167f9dca54ab64e1ea6579f0.tar.gz
go-8ef6d6a8f24354ef167f9dca54ab64e1ea6579f0.zip
encoding/base32: increase performance and code reuse
Add benchmarks for the Encode/Decode functions operating on []byte and increase decoding performance by removing the calls to strings.Map/bytes.Map and reusing the newline filtering code that is used by NewDecoder. Cut allocations in half for DecodeString. Comparison using the new benchmarks: name old time/op new time/op delta Encode 16.7µs ± 1% 17.0µs ± 2% +2.25% (p=0.000 n=9+9) EncodeToString 21.1µs ± 1% 20.9µs ± 1% -0.96% (p=0.000 n=10+10) Decode 141µs ± 1% 54µs ± 1% -61.51% (p=0.000 n=10+10) DecodeString 81.4µs ± 0% 54.7µs ± 1% -32.79% (p=0.000 n=9+10) name old speed new speed delta Encode 492MB/s ± 1% 481MB/s ± 2% -2.19% (p=0.000 n=9+9) EncodeToString 389MB/s ± 1% 392MB/s ± 1% +0.97% (p=0.000 n=10+10) Decode 93.0MB/s ± 1% 241.6MB/s ± 1% +159.82% (p=0.000 n=10+10) DecodeString 161MB/s ± 0% 240MB/s ± 1% +48.78% (p=0.000 n=9+10) Change-Id: Id53633514a9e14ecd0389d52114b2b8ca64370cb GitHub-Last-Rev: f4be3cf55caf5b89d76d14b7f32422faff39e3c3 GitHub-Pull-Request: golang/go#30376 Reviewed-on: https://go-review.googlesource.com/c/go/+/163598 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/encoding/base32')
-rw-r--r--src/encoding/base32/base32.go47
-rw-r--r--src/encoding/base32/base32_test.go18
2 files changed, 41 insertions, 24 deletions
diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go
index 7b74c1ab2c..2f7d3637e5 100644
--- a/src/encoding/base32/base32.go
+++ b/src/encoding/base32/base32.go
@@ -6,10 +6,8 @@
package base32
import (
- "bytes"
"io"
"strconv"
- "strings"
)
/*
@@ -62,13 +60,6 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in DNS.
var HexEncoding = NewEncoding(encodeHex)
-var removeNewlinesMapper = func(r rune) rune {
- if r == '\r' || r == '\n' {
- return -1
- }
- return r
-}
-
// WithPadding creates a new encoding identical to enc except
// with a specified padding character, or NoPadding to disable padding.
// The padding character must not be '\r' or '\n', must not
@@ -372,17 +363,18 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
- src = bytes.Map(removeNewlinesMapper, src)
- n, _, err = enc.decode(dst, src)
+ buf := make([]byte, len(src))
+ l := stripNewlines(buf, src)
+ n, _, err = enc.decode(dst, buf[:l])
return
}
// DecodeString returns the bytes represented by the base32 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
- s = strings.Map(removeNewlinesMapper, s)
- dbuf := make([]byte, enc.DecodedLen(len(s)))
- n, _, err := enc.decode(dbuf, []byte(s))
- return dbuf[:n], err
+ buf := []byte(s)
+ l := stripNewlines(buf, buf)
+ n, _, err := enc.decode(buf, buf[:l])
+ return buf[:n], err
}
type decoder struct {
@@ -497,18 +489,25 @@ type newlineFilteringReader struct {
wrapped io.Reader
}
+// stripNewlines removes newline characters and returns the number
+// of non-newline characters copied to dst.
+func stripNewlines(dst, src []byte) int {
+ offset := 0
+ for _, b := range src {
+ if b == '\r' || b == '\n' {
+ continue
+ }
+ dst[offset] = b
+ offset++
+ }
+ return offset
+}
+
func (r *newlineFilteringReader) Read(p []byte) (int, error) {
n, err := r.wrapped.Read(p)
for n > 0 {
- offset := 0
- for i, b := range p[0:n] {
- if b != '\r' && b != '\n' {
- if i != offset {
- p[offset] = b
- }
- offset++
- }
- }
+ s := p[0:n]
+ offset := stripNewlines(s, s)
if err != nil || offset > 0 {
return offset, err
}
diff --git a/src/encoding/base32/base32_test.go b/src/encoding/base32/base32_test.go
index eb14f1eb26..0b611db0b2 100644
--- a/src/encoding/base32/base32_test.go
+++ b/src/encoding/base32/base32_test.go
@@ -445,6 +445,15 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
}
}
+func BenchmarkEncode(b *testing.B) {
+ data := make([]byte, 8192)
+ buf := make([]byte, StdEncoding.EncodedLen(len(data)))
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.Encode(buf, data)
+ }
+}
+
func BenchmarkEncodeToString(b *testing.B) {
data := make([]byte, 8192)
b.SetBytes(int64(len(data)))
@@ -453,6 +462,15 @@ func BenchmarkEncodeToString(b *testing.B) {
}
}
+func BenchmarkDecode(b *testing.B) {
+ data := make([]byte, StdEncoding.EncodedLen(8192))
+ StdEncoding.Encode(data, make([]byte, 8192))
+ buf := make([]byte, 8192)
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.Decode(buf, data)
+ }
+}
func BenchmarkDecodeString(b *testing.B) {
data := StdEncoding.EncodeToString(make([]byte, 8192))
b.SetBytes(int64(len(data)))