Commit 8ef6d6a8 authored by Sven Taute's avatar Sven Taute Committed by Ian Lance Taylor

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: default avatarIan Lance Taylor <iant@golang.org>
parent 4dc11ae2
......@@ -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
}
......
......@@ -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)))
......
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