diff options
author | Sven Taute <sven.taute@gmail.com> | 2019-09-09 21:56:46 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2019-09-11 00:56:39 +0000 |
commit | 8ef6d6a8f24354ef167f9dca54ab64e1ea6579f0 (patch) | |
tree | d5d3b50be9e884effad5705435337544c4085df3 /src/encoding/base32 | |
parent | 4dc11ae26b3a092bbcd1b4d0ae8cdaeb1cf1cef9 (diff) | |
download | go-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.go | 47 | ||||
-rw-r--r-- | src/encoding/base32/base32_test.go | 18 |
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))) |