summaryrefslogtreecommitdiff
path: root/src/fmt/format.go
diff options
context:
space:
mode:
authorMartin Möhrmann <martisch@uos.de>2016-02-27 19:47:43 +0100
committerRob Pike <r@golang.org>2016-03-03 08:25:28 +0000
commit033e3e106e6132b530759bf97f7b359b9897ae25 (patch)
treea528b270ada5720bd5d5c3629f291f996e65b069 /src/fmt/format.go
parent71d13a8c01706c0196a843116d403fe8eb446130 (diff)
downloadgo-git-033e3e106e6132b530759bf97f7b359b9897ae25.tar.gz
fmt: optimize %x and %X formatting for byte slices and strings
No extra buffering is needed to save the encoding since the left padding can be computed and written out before the encoding is generated. Add extra tests to both string and byte slice formatting. name old time/op new time/op delta SprintfHexString-2 410ns ± 3% 194ns ± 3% -52.60% (p=0.000 n=20+19) SprintfHexBytes-2 431ns ± 3% 202ns ± 2% -53.13% (p=0.000 n=18+20) Change-Id: Ibca4316427c89f834e4faee61614493c7eedb42b Reviewed-on: https://go-review.googlesource.com/20097 Run-TryBot: Rob Pike <r@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rob Pike <r@golang.org>
Diffstat (limited to 'src/fmt/format.go')
-rw-r--r--src/fmt/format.go82
1 files changed, 58 insertions, 24 deletions
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 302f82441d..0388d4764c 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -14,8 +14,8 @@ const (
// Hex can add 0x and we handle it specially.
nByte = 65
- ldigits = "0123456789abcdef"
- udigits = "0123456789ABCDEF"
+ ldigits = "0123456789abcdefx"
+ udigits = "0123456789ABCDEFX"
)
const (
@@ -236,8 +236,9 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = '0'
}
case 16:
+ // Add a leading 0x or 0X.
i--
- buf[i] = 'x' + digits[10] - 'a'
+ buf[i] = digits[16]
i--
buf[i] = '0'
}
@@ -302,44 +303,77 @@ func (f *fmt) fmt_s(s string) {
// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
- n := len(b)
+ length := len(b)
if b == nil {
- n = len(s)
+ // No byte slice present. Assume string s should be encoded.
+ length = len(s)
+ }
+ // Set length to not process more bytes than the precision demands.
+ if f.precPresent && f.prec < length {
+ length = f.prec
+ }
+ // Compute width of the encoding taking into account the f.sharp and f.space flag.
+ width := 2 * length
+ if width > 0 {
+ if f.space {
+ // Each element encoded by two hexadecimals will get a leading 0x or 0X.
+ if f.sharp {
+ width *= 2
+ }
+ // Elements will be separated by a space.
+ width += length - 1
+ } else if f.sharp {
+ // Only a leading 0x or 0X will be added for the whole string.
+ width += 2
+ }
+ } else { // The byte slice or string that should be encoded is empty.
+ if f.widPresent {
+ f.writePadding(f.wid)
+ }
+ return
+ }
+ // Handle padding to the left.
+ if f.widPresent && f.wid > width && !f.minus {
+ f.writePadding(f.wid - width)
+ }
+ // Write the encoding directly into the output buffer.
+ buf := *f.buf
+ if f.sharp {
+ // Add leading 0x or 0X.
+ buf = append(buf, '0', digits[16])
}
- x := digits[10] - 'a' + 'x'
- // TODO: Avoid buffer by pre-padding.
- var buf []byte
- for i := 0; i < n; i++ {
- if i > 0 && f.space {
+ var c byte
+ for i := 0; i < length; i++ {
+ if f.space && i > 0 {
+ // Separate elements with a space.
buf = append(buf, ' ')
+ if f.sharp {
+ // Add leading 0x or 0X for each element.
+ buf = append(buf, '0', digits[16])
+ }
}
- if f.sharp && (f.space || i == 0) {
- buf = append(buf, '0', x)
- }
- var c byte
- if b == nil {
- c = s[i]
+ if b != nil {
+ c = b[i] // Take a byte from the input byte slice.
} else {
- c = b[i]
+ c = s[i] // Take a byte from the input string.
}
+ // Encode each byte as two hexadecimal digits.
buf = append(buf, digits[c>>4], digits[c&0xF])
}
- f.pad(buf)
+ *f.buf = buf
+ // Handle padding to the right.
+ if f.widPresent && f.wid > width && f.minus {
+ f.writePadding(f.wid - width)
+ }
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s, digits string) {
- if f.precPresent && f.prec < len(s) {
- s = s[:f.prec]
- }
f.fmt_sbx(s, nil, digits)
}
// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_bx(b []byte, digits string) {
- if f.precPresent && f.prec < len(b) {
- b = b[:f.prec]
- }
f.fmt_sbx("", b, digits)
}