Skip to content

Commit

Permalink
feat: speed up escaped string decoding
Browse files Browse the repository at this point in the history
name                            old time/op    new time/op    delta
Decoder_escapedChar/Unicode-12    18.7ns ± 3%    12.6ns ± 1%  -32.81%  (p=0.000 n=15+13)
Decoder_escapedChar/Newline-12    7.80ns ± 0%    3.75ns ± 0%  -51.94%  (p=0.000 n=14+14)
  • Loading branch information
tdakkota committed Jan 18, 2022
1 parent 32b1f5d commit fdf89f0
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 58 deletions.
14 changes: 0 additions & 14 deletions dec.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,9 @@ const (
Object
)

var hexDigits []byte
var types []Type

func init() {
hexDigits = make([]byte, 256)
for i := 0; i < len(hexDigits); i++ {
hexDigits[i] = 255
}
for i := '0'; i <= '9'; i++ {
hexDigits[i] = byte(i - '0')
}
for i := 'a'; i <= 'f'; i++ {
hexDigits[i] = byte((i - 'a') + 10)
}
for i := 'A'; i <= 'F'; i++ {
hexDigits[i] = byte((i - 'A') + 10)
}
types = make([]Type, 256)
for i := range types {
types[i] = Invalid
Expand Down
30 changes: 18 additions & 12 deletions dec_skip.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,19 +240,26 @@ stateExp:

var (
escapedStrSet = [256]byte{
'"': 1, '\\': 1, '/': 1, 'b': 1, 'f': 1, 'n': 1, 'r': 1, 't': 1,
'u': 2,
'"': '"',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'u': 'u',
}
hexSet = [256]byte{
'0': 1, '1': 1, '2': 1, '3': 1,
'4': 1, '5': 1, '6': 1, '7': 1,
'8': 1, '9': 1,
'0': 0x0 + 1, '1': 0x1 + 1, '2': 0x2 + 1, '3': 0x3 + 1,
'4': 0x4 + 1, '5': 0x5 + 1, '6': 0x6 + 1, '7': 0x7 + 1,
'8': 0x8 + 1, '9': 0x9 + 1,

'A': 1, 'B': 1, 'C': 1, 'D': 1,
'E': 1, 'F': 1,
'A': 0xA + 1, 'B': 0xB + 1, 'C': 0xC + 1, 'D': 0xD + 1,
'E': 0xE + 1, 'F': 0xF + 1,

'a': 1, 'b': 1, 'c': 1, 'd': 1,
'e': 1, 'f': 1,
'a': 0xa + 1, 'b': 0xb + 1, 'c': 0xc + 1, 'd': 0xd + 1,
'e': 0xe + 1, 'f': 0xf + 1,
}
)

Expand Down Expand Up @@ -348,8 +355,7 @@ readTok:
return err
}
switch escapedStrSet[v] {
case 1:
case 2:
case 'u':
for i := 0; i < 4; i++ {
h, err := d.byte()
if err != nil {
Expand All @@ -359,7 +365,7 @@ readTok:
return badToken(h)
}
}
default:
case 0:
return badToken(v)
}
case c < ' ':
Expand Down
44 changes: 12 additions & 32 deletions dec_str.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func (d *Decoder) Str() (string, error) {
}

func (d *Decoder) escapedChar(v value, c byte) (value, error) {
switch c {
switch val := escapedStrSet[c]; val {
case 'u':
r1, err := d.readU4()
if err != nil {
Expand Down Expand Up @@ -294,45 +294,25 @@ func (d *Decoder) escapedChar(v value, c byte) (value, error) {
} else {
v = v.rune(r1)
}
case '"':
v = v.rune('"')
case '\\':
v = v.rune('\\')
case '/':
v = v.rune('/')
case 'b':
v = v.rune('\b')
case 'f':
v = v.rune('\f')
case 'n':
v = v.rune('\n')
case 'r':
v = v.rune('\r')
case 't':
v = v.rune('\t')
default:
v.buf = append(v.buf, val)
case 0:
return v, errors.Wrap(badToken(c), "bad escape: %w")
}
return v, nil
}

func (d *Decoder) readU4() (rune, error) {
var v rune
for i := 0; i < 4; i++ {
c, err := d.byte()
if err != nil {
return 0, err
}
switch {
case c >= '0' && c <= '9':
v = v*16 + rune(c-'0')
case c >= 'a' && c <= 'f':
v = v*16 + rune(c-'a'+10)
case c >= 'A' && c <= 'F':
v = v*16 + rune(c-'A'+10)
default:
func (d *Decoder) readU4() (v rune, err error) {
var b [4]byte
if err = d.readExact4(&b); err != nil {
return 0, err
}
for _, c := range b {
val := hexSet[c]
if val == 0 {
return 0, badToken(c)
}
v = v*16 + rune(val-1)
}
return v, nil
}
Expand Down

0 comments on commit fdf89f0

Please sign in to comment.