Skip to content

Commit

Permalink
Reduce memory allocations in encoding operations
Browse files Browse the repository at this point in the history
Benchmarks:
```
name                 old time/op    new time/op    delta
ParseAllFramesISO-4     164µs ± 5%     164µs ± 2%     ~     (p=1.000 n=5+5)
WriteISO-4             7.89ms ±23%    7.33ms ± 7%   -7.11%  (p=0.690 n=5+5)

name                 old alloc/op   new alloc/op   delta
ParseAllFramesISO-4     264kB ± 0%     264kB ± 0%   -0.07%  (p=0.008 n=5+5)
WriteISO-4             8.62kB ± 0%    8.02kB ± 0%   -6.96%  (p=0.008 n=5+5)

name                 old allocs/op  new allocs/op  delta
ParseAllFramesISO-4      79.0 ± 0%      69.0 ± 0%  -12.66%  (p=0.008 n=5+5)
WriteISO-4               97.0 ± 0%      67.0 ± 0%  -30.93%  (p=0.008 n=5+5)
```
  • Loading branch information
n10v committed Apr 7, 2018
1 parent e4247ea commit 211759e
Showing 1 changed file with 43 additions and 23 deletions.
66 changes: 43 additions & 23 deletions encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@ func (e Encoding) String() string {
return e.Name
}

// xencodingWrapper is a convient wrapper for xencoding.Encoding.
type xencodingWrapper struct {
e xencoding.Encoding
decoder *xencoding.Decoder
encoder *xencoding.Encoder
}

func newXEncodingWrapper(e xencoding.Encoding) xencodingWrapper {
return xencodingWrapper{
e: e,
decoder: e.NewDecoder(),
encoder: e.NewEncoder(),
}
}

func (e *xencodingWrapper) Decoder() *xencoding.Decoder {
return e.decoder
}

func (e *xencodingWrapper) Encoder() *xencoding.Encoder {
return e.encoder
}

// Available encodings.
var (
// EncodingISO is ISO-8859-1 encoding.
Expand Down Expand Up @@ -52,6 +75,12 @@ var (
}

encodings = []Encoding{EncodingISO, EncodingUTF16, EncodingUTF16BE, EncodingUTF8}

xencodingISO = newXEncodingWrapper(charmap.ISO8859_1)
xencodingUTF16BEBOM = newXEncodingWrapper(unicode.UTF16(unicode.BigEndian, unicode.ExpectBOM))
xencodingUTF16LEBOM = newXEncodingWrapper(unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM))
xencodingUTF16BE = newXEncodingWrapper(unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM))
xencodingUTF8 = newXEncodingWrapper(unicode.UTF8)
)

// getEncoding returns Encoding in accordance with ID3v2 key.
Expand All @@ -69,7 +98,7 @@ func encodedSize(src string, enc Encoding) int {
}

toXEncoding := resolveXEncoding(nil, enc)
encoded, _ := toXEncoding.NewEncoder().String(src)
encoded, _ := toXEncoding.Encoder().String(src)
return len(encoded)
}

Expand All @@ -80,12 +109,11 @@ func decodeText(src []byte, from Encoding) string {
}

fromXEncoding := resolveXEncoding(src, from)
dst, err := fromXEncoding.NewDecoder().Bytes(src)
result, err := fromXEncoding.Decoder().Bytes(src)
if err != nil {
return string(src)
}

return string(dst)
return string(result)
}

// encodeWriteText encodes src from UTF-8 to "to" encoding and writes to bw.
Expand All @@ -96,34 +124,26 @@ func encodeWriteText(bw *bufWriter, src string, to Encoding) error {
}

toXEncoding := resolveXEncoding(nil, to)
encoded, err := toXEncoding.NewEncoder().String(src)
encoded, err := toXEncoding.Encoder().String(src)
if err != nil {
return err
}
bw.WriteString(encoded)
return nil
}

// resolveXEncoding returns golang.org/x/text/encoding encoding
// from src and encoding.
func resolveXEncoding(src []byte, encoding Encoding) xencoding.Encoding {
func resolveXEncoding(src []byte, encoding Encoding) xencodingWrapper {
switch encoding.Key {
case 0: // ISO-8859-1
return charmap.ISO8859_1
case 1: // UTF-16 With BOM
if len(src) < 2 {
return unicode.UTF16(unicode.BigEndian, unicode.ExpectBOM)
} else if src[0] == 0xFE && src[1] == 0xFF {
return unicode.UTF16(unicode.BigEndian, unicode.ExpectBOM)
} else if src[0] == 0xFF && src[1] == 0xFE {
return unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM)
case 0:
return xencodingISO
case 1:
if len(src) > 2 && src[0] == 0xFF && src[1] == 0xFE {
return xencodingUTF16LEBOM
}
return unicode.UTF16(unicode.BigEndian, unicode.ExpectBOM)
case 2: // UTF-16BE without BOM
return unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
case 3: // UTF-8
return unicode.UTF8
return xencodingUTF16BEBOM
case 2:
return xencodingUTF16BE
}

return unicode.UTF8
return xencodingUTF8
}

0 comments on commit 211759e

Please sign in to comment.