diff --git a/jsoniter.go b/jsoniter.go index 92f5a2f..1f0e8a6 100644 --- a/jsoniter.go +++ b/jsoniter.go @@ -89,6 +89,7 @@ func (iter *Iterator) skipWhitespaces() { } func (iter *Iterator) nextToken() byte { + // a variation of skip whitespaces, returning the next non-whitespace token for { for i := iter.head; i < iter.tail; i++ { c := iter.buf[i] @@ -353,24 +354,6 @@ func (iter *Iterator) findStringEnd() (int, bool) { return -1, true // end with \ } - -func (iter *Iterator) skipUntilBreak() { - // true, false, null, number - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\r', '\t', ',', '}', ']': - iter.head = i - return - } - } - if (!iter.loadMore()) { - return - } - } -} - func (iter *Iterator) ReadStringAsBytes() (ret []byte) { c := iter.readByte() if c == 'n' { @@ -804,64 +787,71 @@ func (iter *Iterator) skipString() { } func (iter *Iterator) skipArray() { - c := iter.nextToken() - if c == ']' { - return - } else { - iter.unreadByte() - } + level := 1 for { - if iter.Error != nil { - return + 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 + return + } + } } - iter.Skip() - c = iter.nextToken() - switch c { - case ',': - iter.skipWhitespaces() - continue - case ']': - return - default: - iter.ReportError("skipArray", "expects , or ]") + if (!iter.loadMore()) { return } } } func (iter *Iterator) skipObject() { - c := iter.nextToken() - if c == '}' { - return // end of object - } else { - iter.unreadByte() - } + level := 1 for { - c = iter.nextToken() - if c != '"' { - iter.ReportError("skipObject", `expects "`) + 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 + return + } + } + } + if (!iter.loadMore()) { return } - iter.skipString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("skipObject", `expects :`) - return + } +} + +func (iter *Iterator) skipUntilBreak() { + // true, false, null, number + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\r', '\t', ',', '}', ']': + iter.head = i + return + } } - iter.skipWhitespaces() - if iter.Error != nil { - return - } - iter.Skip() - c = iter.nextToken() - switch c { - case ',': - iter.skipWhitespaces() - continue - case '}': - return // end of object - default: - iter.ReportError("skipObject", "expects , or }") + if (!iter.loadMore()) { return } } diff --git a/jsoniter_find_end_test.go b/jsoniter_find_end_test.go index a7e328a..9e04bfb 100644 --- a/jsoniter_find_end_test.go +++ b/jsoniter_find_end_test.go @@ -136,3 +136,35 @@ func Test_skip_string(t *testing.T) { t.Fatal(iter.head) } } + +func Test_skip_object(t *testing.T) { + iter := ParseString(`}`) + iter.skipObject() + if iter.head != 1 { + t.Fatal(iter.head) + } + iter = ParseString(`a}`) + iter.skipObject() + if iter.head != 2 { + t.Fatal(iter.head) + } + iter = ParseString(`{}}a`) + iter.skipObject() + if iter.head != 3 { + t.Fatal(iter.head) + } + reader := &StagedReader{ + r1: `{`, + r2: `}}a`, + } + iter = Parse(reader, 4096) + iter.skipObject() + if iter.head != 2 { + t.Fatal(iter.head) + } + iter = ParseString(`"}"}a`) + iter.skipObject() + if iter.head != 4 { + t.Fatal(iter.head) + } +} diff --git a/jsoniter_skip_test.go b/jsoniter_skip_test.go index 4070cc2..8a32c22 100644 --- a/jsoniter_skip_test.go +++ b/jsoniter_skip_test.go @@ -66,26 +66,6 @@ func Test_skip_empty_array(t *testing.T) { } } -func Test_skip_object(t *testing.T) { - iter := ParseString(`[ {"a" : {"b": "c"}, "d": 102 }, "b"]`) - iter.ReadArray() - iter.Skip() - iter.ReadArray() - if iter.ReadString() != "b" { - t.FailNow() - } -} - -func Test_skip_empty_object(t *testing.T) { - iter := ParseString(`[ { }, "b"]`) - iter.ReadArray() - iter.Skip() - iter.ReadArray() - if iter.ReadString() != "b" { - t.FailNow() - } -} - func Test_skip_nested(t *testing.T) { iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`) iter.ReadArray()