Skip to content

Uses strings.Builder instead of []byte in iter.ReadString #526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/json-iterator/go

go 1.12
go 1.15

require (
github.com/davecgh/go-spew v1.1.1
Expand Down
54 changes: 28 additions & 26 deletions iter_str.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jsoniter

import (
"fmt"
"strings"
"unicode/utf16"
)

Expand Down Expand Up @@ -33,82 +34,83 @@ func (iter *Iterator) ReadString() (ret string) {
}

func (iter *Iterator) readStringSlowPath() (ret string) {
var str []byte
sb := &strings.Builder{}
var c byte
for iter.Error == nil {
c = iter.readByte()
if c == '"' {
return string(str)
return sb.String()
}
if c == '\\' {
c = iter.readByte()
str = iter.readEscapedChar(c, str)
iter.readEscapedChar(c, sb)
} else {
str = append(str, c)
sb.WriteByte(c)
}
}
iter.ReportError("readStringSlowPath", "unexpected end of input")
return
}

func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte {
func (iter *Iterator) readEscapedChar(c byte, sb *strings.Builder) {
switch c {
case 'u':
r := iter.readU4()
if utf16.IsSurrogate(r) {
c = iter.readByte()
if iter.Error != nil {
return nil
return
}
if c != '\\' {
iter.unreadByte()
str = appendRune(str, r)
return str
sb.WriteRune(r)
return
}
c = iter.readByte()
if iter.Error != nil {
return nil
return
}
if c != 'u' {
str = appendRune(str, r)
return iter.readEscapedChar(c, str)
sb.WriteRune(r)
iter.readEscapedChar(c, sb)
return
}
r2 := iter.readU4()
if iter.Error != nil {
return nil
return
}
combined := utf16.DecodeRune(r, r2)
if combined == '\uFFFD' {
str = appendRune(str, r)
str = appendRune(str, r2)
sb.WriteRune(r)
sb.WriteRune(r2)
} else {
str = appendRune(str, combined)
sb.WriteRune(combined)
}
} else {
str = appendRune(str, r)
sb.WriteRune(r)
}
case '"':
str = append(str, '"')
sb.WriteByte('"')
case '\\':
str = append(str, '\\')
sb.WriteByte('\\')
case '/':
str = append(str, '/')
sb.WriteByte('/')
case 'b':
str = append(str, '\b')
sb.WriteByte('\b')
case 'f':
str = append(str, '\f')
sb.WriteByte('\f')
case 'n':
str = append(str, '\n')
sb.WriteByte('\n')
case 'r':
str = append(str, '\r')
sb.WriteByte('\r')
case 't':
str = append(str, '\t')
sb.WriteByte('\t')
default:
iter.ReportError("readEscapedChar",
`invalid escape char after \`)
return nil
return
}
return str
return
}

// ReadStringAsSlice read string from iterator without copying into string form.
Expand Down
14 changes: 9 additions & 5 deletions type_tests/map_key_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build go1.15
// +build go1.16
// remove these tests temporarily until https://github.com/golang/go/issues/38105 and
// https://github.com/golang/go/issues/38940 is fixed

Expand Down Expand Up @@ -27,8 +27,10 @@ func (k *stringKeyType) UnmarshalText(text []byte) error {
return nil
}

var _ encoding.TextMarshaler = stringKeyType("")
var _ encoding.TextUnmarshaler = new(stringKeyType)
var (
_ encoding.TextMarshaler = stringKeyType("")
_ encoding.TextUnmarshaler = new(stringKeyType)
)

type structKeyType struct {
X string
Expand All @@ -43,5 +45,7 @@ func (k *structKeyType) UnmarshalText(text []byte) error {
return nil
}

var _ encoding.TextMarshaler = structKeyType{}
var _ encoding.TextUnmarshaler = &structKeyType{}
var (
_ encoding.TextMarshaler = structKeyType{}
_ encoding.TextUnmarshaler = &structKeyType{}
)