diff --git a/feature_any.go b/feature_any.go index 304fd40..8ca02c0 100644 --- a/feature_any.go +++ b/feature_any.go @@ -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} } diff --git a/feature_iter.go b/feature_iter.go index 6be4ef4..22398a6 100644 --- a/feature_iter.go +++ b/feature_iter.go @@ -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 diff --git a/feature_iter_skip.go b/feature_iter_skip.go index 01ab1a5..96f39be 100644 --- a/feature_iter_skip.go +++ b/feature_iter_skip.go @@ -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 {