This is both simpler and more performant.
The need for fmt.fmtC to manually check for utf8.MaxRune
is subtle to avoid overflow when converting uint64 to rune,
so a test case was added to exercise this edge case.
Change-Id: I0f2e6cce91dcd4cc6b88190c29807ca1c58e999d
Reviewed-on: https://go-review.googlesource.com/c/go/+/412335
Auto-Submit: Joseph Tsai <joetsai@digital-static.net>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
{"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect.
{"%3c", '⌘', " ⌘"},
{"%-3c", '⌘', "⌘ "},
+ {"%c", uint64(0x100000000), "\ufffd"},
// Runes that are not printable.
{"%c", '\U00000e00', "\u0e00"},
{"%c", '\U0010ffff', "\U0010ffff"},
// fmtC formats an integer as a Unicode character.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmtC(c uint64) {
+ // Explicitly check whether c exceeds utf8.MaxRune since the conversion
+ // of a uint64 to a rune may lose precision that indicates an overflow.
r := rune(c)
if c > utf8.MaxRune {
r = utf8.RuneError
}
buf := f.intbuf[:0]
- w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
- f.pad(buf[:w])
+ f.pad(utf8.AppendRune(buf, r))
}
// fmtQc formats an integer as a single-quoted, escaped Go character constant.
}
func (bp *buffer) writeRune(r rune) {
- if r < utf8.RuneSelf {
- *bp = append(*bp, byte(r))
- return
- }
-
- b := *bp
- n := len(b)
- for n+utf8.UTFMax > cap(b) {
- b = append(b, 0)
- }
- w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
- *bp = b[:n+w]
+ *bp = utf8.AppendRune(*bp, r)
}
// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.