From d0c9b40964f1951d2684545f1a6df64be899d26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Nu=C3=9F?= Date: Wed, 9 Sep 2015 21:10:43 +0200 Subject: [PATCH] mime: Remove an allocation in word decoding. This fixes a TODO in (*WordDecoder).Decode by replacing a call to strings.Split with simple prefix/suffix checking and some custom slicing. Benchmark results: benchmark old ns/op new ns/op delta BenchmarkQEncodeWord-8 740 693 -6.35% BenchmarkQDecodeWord-8 1291 727 -43.69% BenchmarkQDecodeHeader-8 1194 767 -35.76% benchmark old allocs new allocs delta BenchmarkQEncodeWord-8 1 1 +0.00% BenchmarkQDecodeWord-8 3 2 -33.33% BenchmarkQDecodeHeader-8 3 2 -33.33% benchmark old bytes new bytes delta BenchmarkQEncodeWord-8 48 48 +0.00% BenchmarkQDecodeWord-8 128 48 -62.50% BenchmarkQDecodeHeader-8 128 48 -62.50% Change-Id: I2d6844c75ec2e2b79be2e49b7fc4ca320b7e84e5 Reviewed-on: https://go-review.googlesource.com/14432 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/mime/encodedword.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go index 3b414dd5c4b..db4b5f4510b 100644 --- a/src/mime/encodedword.go +++ b/src/mime/encodedword.go @@ -194,12 +194,24 @@ type WordDecoder struct { // Decode decodes an RFC 2047 encoded-word. func (d *WordDecoder) Decode(word string) (string, error) { - fields := strings.Split(word, "?") // TODO: remove allocation? - if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 { + if !strings.HasPrefix(word, "=?") || !strings.HasSuffix(word, "?=") || strings.Count(word, "?") != 4 { + return "", errInvalidWord + } + word = word[2 : len(word)-2] + + // split delimits the first 2 fields + split := strings.IndexByte(word, '?') + // the field after split must only be one byte + if word[split+2] != '?' { return "", errInvalidWord } - content, err := decode(fields[2][0], fields[3]) + // split word "UTF-8?q?ascii" into "UTF-8", 'q', and "ascii" + charset := word[:split] + encoding := word[split+1] + text := word[split+3:] + + content, err := decode(encoding, text) if err != nil { return "", err } @@ -207,7 +219,7 @@ func (d *WordDecoder) Decode(word string) (string, error) { buf := getBuffer() defer putBuffer(buf) - if err := d.convert(buf, fields[1], content); err != nil { + if err := d.convert(buf, charset, content); err != nil { return "", err }