From 1f75cdd0238394b0fa80f1a786ddd6682b49b853 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 15 Feb 2021 18:40:59 +0900 Subject: [PATCH 1/5] Initialize buffer size each streaming decoding --- decode.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/decode.go b/decode.go index c235ff7..84ad4f0 100644 --- a/decode.go +++ b/decode.go @@ -150,6 +150,8 @@ func (d *Decoder) Decode(v interface{}) error { if err := dec.decodeStream(s, header.ptr); err != nil { return err } + s.reset() + s.bufSize = initBufSize return nil } From fa87dde0c32201370c06ec23ecbfb160b5674a2b Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 15 Feb 2021 18:45:22 +0900 Subject: [PATCH 2/5] Refactor skipValue --- decode_context.go | 147 ++++++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 58 deletions(-) diff --git a/decode_context.go b/decode_context.go index de02a37..a4ebaa5 100644 --- a/decode_context.go +++ b/decode_context.go @@ -1,6 +1,8 @@ package json -import "unsafe" +import ( + "unsafe" +) var ( isWhiteSpace = [256]bool{} @@ -26,69 +28,104 @@ LOOP: return cursor } -func skipValue(buf []byte, cursor int64) (int64, error) { - cursor = skipWhiteSpace(buf, cursor) - braceCount := 0 - bracketCount := 0 - buflen := int64(len(buf)) - start := cursor +func skipObject(buf []byte, cursor int64) (int64, error) { + braceCount := 1 for { switch buf[cursor] { - case nul: - if start == cursor { - return cursor, errUnexpectedEndOfJSON("value of object", cursor) - } - if braceCount == 0 && bracketCount == 0 { - return cursor, nil - } - return cursor, errUnexpectedEndOfJSON("value of object", cursor) case '{': braceCount++ - case '[': - bracketCount++ case '}': braceCount-- - if braceCount == -1 && bracketCount == 0 { - return cursor, nil - } - case ']': - bracketCount-- - if braceCount == 0 && bracketCount == -1 { - return cursor, nil - } - case ',': - if bracketCount == 0 && braceCount == 0 { - return cursor, nil + if braceCount == 0 { + return cursor + 1, nil } case '"': - cursor++ + for { + cursor++ + switch buf[cursor] { + case '"': + if buf[cursor-1] == '\\' { + continue + } + goto SWITCH_OUT + case nul: + return 0, errUnexpectedEndOfJSON("string of object", cursor) + } + } + case nul: + return 0, errUnexpectedEndOfJSON("object of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} - for ; cursor < buflen; cursor++ { - if buf[cursor] != '"' { - continue +func skipArray(buf []byte, cursor int64) (int64, error) { + bracketCount := 1 + for { + switch buf[cursor] { + case '[': + bracketCount++ + case ']': + bracketCount-- + if bracketCount == 0 { + return cursor + 1, nil + } + case '"': + for { + cursor++ + switch buf[cursor] { + case '"': + if buf[cursor-1] == '\\' { + continue + } + goto SWITCH_OUT + case nul: + return 0, errUnexpectedEndOfJSON("string of object", cursor) } - if buf[cursor-1] == '\\' { - continue - } - if bracketCount == 0 && braceCount == 0 { + } + case nul: + return 0, errUnexpectedEndOfJSON("array of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} + +func skipValue(buf []byte, cursor int64) (int64, error) { + for { + switch buf[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case '{': + return skipObject(buf, cursor+1) + case '[': + return skipArray(buf, cursor+1) + case '"': + for { + cursor++ + switch buf[cursor] { + case '"': + if buf[cursor-1] == '\\' { + continue + } return cursor + 1, nil + case nul: + return 0, errUnexpectedEndOfJSON("string of object", cursor) } - break } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - cursor++ - for ; cursor < buflen; cursor++ { - tk := int(buf[cursor]) - if (int('0') <= tk && tk <= int('9')) || tk == '.' || tk == 'e' || tk == 'E' { + for { + cursor++ + if floatTable[buf[cursor]] { continue } break } - if bracketCount == 0 && braceCount == 0 { - return cursor, nil - } - continue + return cursor, nil case 't': + buflen := int64(len(buf)) if cursor+3 >= buflen { return 0, errUnexpectedEndOfJSON("bool of object", cursor) } @@ -102,11 +139,9 @@ func skipValue(buf []byte, cursor int64) (int64, error) { return 0, errUnexpectedEndOfJSON("bool of object", cursor) } cursor += 4 - if bracketCount == 0 && braceCount == 0 { - return cursor, nil - } - continue + return cursor, nil case 'f': + buflen := int64(len(buf)) if cursor+4 >= buflen { return 0, errUnexpectedEndOfJSON("bool of object", cursor) } @@ -123,11 +158,9 @@ func skipValue(buf []byte, cursor int64) (int64, error) { return 0, errUnexpectedEndOfJSON("bool of object", cursor) } cursor += 5 - if bracketCount == 0 && braceCount == 0 { - return cursor, nil - } - continue + return cursor, nil case 'n': + buflen := int64(len(buf)) if cursor+3 >= buflen { return 0, errUnexpectedEndOfJSON("null", cursor) } @@ -141,11 +174,9 @@ func skipValue(buf []byte, cursor int64) (int64, error) { return 0, errUnexpectedEndOfJSON("null", cursor) } cursor += 4 - if bracketCount == 0 && braceCount == 0 { - return cursor, nil - } - continue + return cursor, nil + default: + return cursor, errUnexpectedEndOfJSON("null", cursor) } - cursor++ } } From 9053c385eabd38320e41d427ca58514abc0e5484 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 15 Feb 2021 18:45:41 +0900 Subject: [PATCH 3/5] Fix decoding of map type --- decode_map.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/decode_map.go b/decode_map.go index 8a26dd6..5d0f764 100644 --- a/decode_map.go +++ b/decode_map.go @@ -130,27 +130,24 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, cursor++ return cursor, nil } - for ; cursor < buflen; cursor++ { - var key interface{} - keyCursor, err := d.setKey(buf, cursor, &key) + for { + k := unsafe_New(d.keyType) + keyCursor, err := d.keyDecoder.decode(buf, cursor, k) if err != nil { return 0, err } cursor = keyCursor - cursor = skipWhiteSpace(buf, cursor) + cursor = skipWhiteSpace(buf, keyCursor) if buf[cursor] != ':' { return 0, errExpected("colon after object key", cursor) } cursor++ - if cursor >= buflen { - return 0, errUnexpectedEndOfJSON("map", cursor) - } - var value interface{} - valueCursor, err := d.setValue(buf, cursor, &value) + v := unsafe_New(d.valueType) + valueCursor, err := d.valueDecoder.decode(buf, cursor, v) if err != nil { return 0, err } - mapassign(d.mapType, mapValue, unsafe.Pointer(&key), unsafe.Pointer(&value)) + mapassign(d.mapType, mapValue, k, v) cursor = skipWhiteSpace(buf, valueCursor) if buf[cursor] == '}' { **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue @@ -160,6 +157,7 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, if buf[cursor] != ',' { return 0, errExpected("comma after object value", cursor) } + cursor++ } return cursor, nil } From 98824e9bd93d911839efcbe27f33e624f90b924f Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 15 Feb 2021 18:45:58 +0900 Subject: [PATCH 4/5] Fix decoding of struct type --- decode_struct.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/decode_struct.go b/decode_struct.go index bfd46d6..2ccb6dd 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -483,6 +483,7 @@ func (d *structDecoder) decodeStream(s *stream, p unsafe.Pointer) error { } } s.cursor++ + s.skipWhiteSpace() if s.char() == '}' { s.cursor++ return nil @@ -551,10 +552,12 @@ func (d *structDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int6 default: return 0, errNotAtBeginningOfValue(cursor) } - if buflen < 2 { - return 0, errUnexpectedEndOfJSON("object", cursor) - } cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return cursor, nil + } for { c, field, err := d.keyDecoder(d, buf, cursor) if err != nil { From 6575394cc0f034d7490739bbec5dcf38a5b21e8d Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 15 Feb 2021 18:54:12 +0900 Subject: [PATCH 5/5] Fix error by linter --- decode_map.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/decode_map.go b/decode_map.go index 5d0f764..0e87b1d 100644 --- a/decode_map.go +++ b/decode_map.go @@ -33,16 +33,6 @@ func makemap(*rtype, int) unsafe.Pointer //go:noescape func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) -func (d *mapDecoder) setKey(buf []byte, cursor int64, key interface{}) (int64, error) { - header := (*interfaceHeader)(unsafe.Pointer(&key)) - return d.keyDecoder.decode(buf, cursor, header.ptr) -} - -func (d *mapDecoder) setValue(buf []byte, cursor int64, key interface{}) (int64, error) { - header := (*interfaceHeader)(unsafe.Pointer(&key)) - return d.valueDecoder.decode(buf, cursor, header.ptr) -} - func (d *mapDecoder) decodeStream(s *stream, p unsafe.Pointer) error { s.skipWhiteSpace() switch s.char() { @@ -136,7 +126,6 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, if err != nil { return 0, err } - cursor = keyCursor cursor = skipWhiteSpace(buf, keyCursor) if buf[cursor] != ':' { return 0, errExpected("colon after object key", cursor) @@ -159,5 +148,4 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, } cursor++ } - return cursor, nil }