Skip to content

Commit 8ef6d6a

Browse files
sventianlancetaylor
authored andcommitted
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: f4be3cf GitHub-Pull-Request: #30376 Reviewed-on: https://go-review.googlesource.com/c/go/+/163598 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 4dc11ae commit 8ef6d6a

File tree

2 files changed

+41
-24
lines changed

2 files changed

+41
-24
lines changed

src/encoding/base32/base32.go

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
package base32
77

88
import (
9-
"bytes"
109
"io"
1110
"strconv"
12-
"strings"
1311
)
1412

1513
/*
@@ -62,13 +60,6 @@ var StdEncoding = NewEncoding(encodeStd)
6260
// It is typically used in DNS.
6361
var HexEncoding = NewEncoding(encodeHex)
6462

65-
var removeNewlinesMapper = func(r rune) rune {
66-
if r == '\r' || r == '\n' {
67-
return -1
68-
}
69-
return r
70-
}
71-
7263
// WithPadding creates a new encoding identical to enc except
7364
// with a specified padding character, or NoPadding to disable padding.
7465
// 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) {
372363
// number of bytes successfully written and CorruptInputError.
373364
// New line characters (\r and \n) are ignored.
374365
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
375-
src = bytes.Map(removeNewlinesMapper, src)
376-
n, _, err = enc.decode(dst, src)
366+
buf := make([]byte, len(src))
367+
l := stripNewlines(buf, src)
368+
n, _, err = enc.decode(dst, buf[:l])
377369
return
378370
}
379371

380372
// DecodeString returns the bytes represented by the base32 string s.
381373
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
382-
s = strings.Map(removeNewlinesMapper, s)
383-
dbuf := make([]byte, enc.DecodedLen(len(s)))
384-
n, _, err := enc.decode(dbuf, []byte(s))
385-
return dbuf[:n], err
374+
buf := []byte(s)
375+
l := stripNewlines(buf, buf)
376+
n, _, err := enc.decode(buf, buf[:l])
377+
return buf[:n], err
386378
}
387379

388380
type decoder struct {
@@ -497,18 +489,25 @@ type newlineFilteringReader struct {
497489
wrapped io.Reader
498490
}
499491

492+
// stripNewlines removes newline characters and returns the number
493+
// of non-newline characters copied to dst.
494+
func stripNewlines(dst, src []byte) int {
495+
offset := 0
496+
for _, b := range src {
497+
if b == '\r' || b == '\n' {
498+
continue
499+
}
500+
dst[offset] = b
501+
offset++
502+
}
503+
return offset
504+
}
505+
500506
func (r *newlineFilteringReader) Read(p []byte) (int, error) {
501507
n, err := r.wrapped.Read(p)
502508
for n > 0 {
503-
offset := 0
504-
for i, b := range p[0:n] {
505-
if b != '\r' && b != '\n' {
506-
if i != offset {
507-
p[offset] = b
508-
}
509-
offset++
510-
}
511-
}
509+
s := p[0:n]
510+
offset := stripNewlines(s, s)
512511
if err != nil || offset > 0 {
513512
return offset, err
514513
}

src/encoding/base32/base32_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,15 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
445445
}
446446
}
447447

448+
func BenchmarkEncode(b *testing.B) {
449+
data := make([]byte, 8192)
450+
buf := make([]byte, StdEncoding.EncodedLen(len(data)))
451+
b.SetBytes(int64(len(data)))
452+
for i := 0; i < b.N; i++ {
453+
StdEncoding.Encode(buf, data)
454+
}
455+
}
456+
448457
func BenchmarkEncodeToString(b *testing.B) {
449458
data := make([]byte, 8192)
450459
b.SetBytes(int64(len(data)))
@@ -453,6 +462,15 @@ func BenchmarkEncodeToString(b *testing.B) {
453462
}
454463
}
455464

465+
func BenchmarkDecode(b *testing.B) {
466+
data := make([]byte, StdEncoding.EncodedLen(8192))
467+
StdEncoding.Encode(data, make([]byte, 8192))
468+
buf := make([]byte, 8192)
469+
b.SetBytes(int64(len(data)))
470+
for i := 0; i < b.N; i++ {
471+
StdEncoding.Decode(buf, data)
472+
}
473+
}
456474
func BenchmarkDecodeString(b *testing.B) {
457475
data := StdEncoding.EncodeToString(make([]byte, 8192))
458476
b.SetBytes(int64(len(data)))

0 commit comments

Comments
 (0)