Commit 6a4d2313 authored by Kirill Smelkov's avatar Kirill Smelkov

X xfmt/py: Speedup

it is annoying to see this function high in fstail profiles taking up to 10%

name       old time/op    new time/op    delta
PyQuote-4    1.33µs ± 1%    0.98µs ± 0%  -26.77%  (p=0.008 n=5+5)

name       old alloc/op   new alloc/op   delta
PyQuote-4     0.00B          0.00B          ~     (all equal)

name       old allocs/op  new allocs/op  delta
PyQuote-4      0.00           0.00          ~     (all equal)
parent 72bc3bf4
...@@ -31,56 +31,67 @@ func AppendQuotePyBytes(buf, b []byte) []byte { ...@@ -31,56 +31,67 @@ func AppendQuotePyBytes(buf, b []byte) []byte {
// smartquotes: choose ' or " as quoting character // smartquotes: choose ' or " as quoting character
// https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L947 // https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L947
quote := byte('\'') quote := byte('\'')
noquote := byte('"')
if bytes.ContainsRune(b, '\'') && !bytes.ContainsRune(b, '"') { if bytes.ContainsRune(b, '\'') && !bytes.ContainsRune(b, '"') {
quote, noquote = noquote, quote quote = '"'
} }
buf = append(buf, quote) buf = append(buf, quote)
for len(b) > 0 { for len(b) > 0 {
r, size := utf8.DecodeRune(b) c := b[0]
switch {
switch r { // fast path - ASCII only - trying to avoid UTF-8 decoding
case utf8.RuneError: case c < utf8.RuneSelf:
buf = append(buf, '\\', 'x', hexdigits[b[0]>>4], hexdigits[b[0]&0xf]) switch c {
case '\\', rune(quote): case '\\', quote:
buf = append(buf, '\\', byte(r)) buf = append(buf, '\\', c)
case rune(noquote):
buf = append(buf, noquote) // NOTE python converts to \<letter> only \t \n \r (not e.g. \v)
// https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L963
// NOTE python converts to \<letter> only \t \n \r (not e.g. \v) case '\t':
// https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L963 buf = append(buf, `\t`...)
case '\t': case '\n':
buf = append(buf, `\t`...) buf = append(buf, `\n`...)
case '\n': case '\r':
buf = append(buf, `\n`...) buf = append(buf, `\r`...)
case '\r':
buf = append(buf, `\r`...) default:
if c < ' ' || c == '\x7f' /* the only non-printable ASCII character > space */ {
// we already converted to \<letter> what python represents as such above
// everything else goes in numeric byte escapes
buf = append(buf, '\\', 'x', hexdigits[c>>4], hexdigits[c&0xf])
} else {
// printable ASCII
buf = append(buf, c)
}
}
default: b = b[1:]
switch {
case r < ' ':
// we already converted to \<letter> what python represents as such above
buf = append(buf, '\\', 'x', hexdigits[b[0]>>4], hexdigits[b[0]&0xf])
case r < utf8.RuneSelf /* RuneSelf itself is not printable */ - 1: // slow path - full UTF-8 decoding
// we already escaped all < RuneSelf runes default:
buf = append(buf, byte(r)) r, size := utf8.DecodeRune(b)
case strconv.IsPrint(r): switch r {
// printable utf-8 characters go as is case utf8.RuneError:
buf = append(buf, b[:size]...) buf = append(buf, '\\', 'x', hexdigits[c>>4], hexdigits[c&0xf])
default: default:
// everything else goes in numeric byte escapes switch {
for i := 0; i < size; i++ { case strconv.IsPrint(r):
buf = append(buf, '\\', 'x', hexdigits[b[i]>>4], hexdigits[b[i]&0xf]) // printable utf-8 characters go as is
buf = append(buf, b[:size]...)
default:
// everything else goes in numeric byte escapes
for i := 0; i < size; i++ {
buf = append(buf, '\\', 'x', hexdigits[b[i]>>4], hexdigits[b[i]&0xf])
}
} }
} }
}
b = b[size:] b = b[size:]
}
} }
buf = append(buf, quote) buf = append(buf, quote)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment