1
0
mirror of https://github.com/json-iterator/go.git synced 2025-01-20 18:48:32 +02:00

#61 read any reuse skip impl

This commit is contained in:
Tao Wen 2017-06-18 17:00:28 +08:00
parent 54dbcda64d
commit 1ec246d16b
3 changed files with 51 additions and 124 deletions

View File

@ -167,137 +167,45 @@ func (iter *Iterator) readAny() Any {
return iter.readObjectAny()
case '[':
return iter.readArrayAny()
case '-':
return iter.readNumberAny(false)
default:
return iter.readNumberAny(c)
return iter.readNumberAny(true)
}
}
func (iter *Iterator) readNumberAny(firstByte byte) Any {
dotFound := false
lazyBuf := make([]byte, 1, 8)
lazyBuf[0] = firstByte
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '.' {
dotFound = true
continue
}
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
iter.head = i
if dotFound {
return &float64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
if firstByte == '-' {
return &int64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
return &uint64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.head = iter.tail
if dotFound {
return &float64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
if firstByte == '-' {
return &int64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
return &uint64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
}
}
func (iter *Iterator) readNumberAny(positive bool) Any {
iter.startCapture(iter.head - 1)
dotFound := iter.skipNumberAndTellDotFoundOrNot()
lazyBuf := iter.stopCapture()
if dotFound {
return &float64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
if positive {
return &uint64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
} else {
return &int64LazyAny{baseAny{}, iter.cfg, lazyBuf, nil, 0}
}
}
}
func (iter *Iterator) readStringAny() Any {
lazyBuf := make([]byte, 1, 8)
lazyBuf[0] = '"'
for {
end, escaped := iter.findStringEnd()
if end == -1 {
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("readStringAny", "incomplete string")
return &invalidAny{}
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
lazyBuf = append(lazyBuf, iter.buf[iter.head:end]...)
iter.head = end
return &stringLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, ""}
}
}
iter.startCapture(iter.head - 1)
iter.skipString()
lazyBuf := iter.stopCapture()
return &stringLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, ""}
}
func (iter *Iterator) readObjectAny() Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '{'
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete object")
return &invalidAny{}
}
}
iter.startCapture(iter.head - 1)
iter.skipObject()
lazyBuf := iter.stopCapture()
return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, nil, lazyBuf}
}
func (iter *Iterator) readArrayAny() Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '['
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipArray", "incomplete array")
return &invalidAny{}
}
}
iter.startCapture(iter.head - 1)
iter.skipArray()
lazyBuf := iter.stopCapture()
return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil, nil, lazyBuf}
}

View File

@ -210,6 +210,7 @@ func (iter *Iterator) readByte() (ret byte) {
func (iter *Iterator) loadMore() bool {
if iter.reader == nil {
if iter.Error == nil {
iter.head = iter.tail
iter.Error = io.EOF
}
return false

View File

@ -30,7 +30,7 @@ func (iter *Iterator) ReadBool() (ret bool) {
}
func (iter *Iterator) SkipAndReturnBytes() []byte {
iter.startCapture()
iter.startCapture(iter.head)
iter.Skip()
return iter.stopCapture()
}
@ -40,11 +40,11 @@ type captureBuffer struct {
captured []byte
}
func (iter *Iterator) startCapture() {
func (iter *Iterator) startCapture(captureStartedAt int) {
if iter.captured != nil {
panic("already in capture mode")
}
iter.captureStartedAt = iter.head
iter.captureStartedAt = captureStartedAt
iter.captured = make([]byte, 0, 32)
}
@ -75,7 +75,7 @@ func (iter *Iterator) Skip() {
case 'f':
iter.skipFixedBytes(4) // false
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.skipUntilBreak()
iter.skipNumber()
case '[':
iter.skipArray()
case '{':
@ -209,8 +209,7 @@ func (iter *Iterator) skipObject() {
}
}
func (iter *Iterator) skipUntilBreak() {
// true, false, null, number
func (iter *Iterator) skipNumber() {
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
@ -226,6 +225,25 @@ func (iter *Iterator) skipUntilBreak() {
}
}
func (iter *Iterator) skipNumberAndTellDotFoundOrNot() bool {
dotFound := false
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
iter.head = i
return dotFound
case '.':
dotFound = true
}
}
if !iter.loadMore() {
return dotFound
}
}
}
func (iter *Iterator) skipFixedBytes(n int) {
iter.head += n
if iter.head >= iter.tail {