Skip to content

Commit

Permalink
Merge pull request #221 from goccy/feature/refactor-validator
Browse files Browse the repository at this point in the history
Refactor validator
  • Loading branch information
goccy committed May 9, 2021
2 parents bfd9846 + ec7aec5 commit 835c00e
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 261 deletions.
16 changes: 13 additions & 3 deletions .github/workflows/go.yml
Expand Up @@ -39,10 +39,20 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: checkout
- name: checkout ( feature )
uses: actions/checkout@v2
- name: run benchmark ( feature )
run: cd benchmarks && go test -bench GoJson | tee $HOME/new.txt
- name: install benchcmp
run: go get -u golang.org/x/tools/cmd/benchcmp
- name: checkout ( master )
uses: actions/checkout@v2
- name: run benchmark
run: cd benchmarks && go test -bench .
with:
ref: master
- name: run benchmark ( master )
run: cd benchmarks && go test -bench GoJson | tee $HOME/old.txt
- name: compare benchmark results
run: benchcmp $HOME/old.txt $HOME/new.txt
coverage:
name: Coverage
runs-on: ubuntu-latest
Expand Down
21 changes: 6 additions & 15 deletions decode_array.go
Expand Up @@ -95,24 +95,14 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
return 0, errExceededMaxDepth(buf[cursor], cursor)
}

buflen := int64(len(buf))
for ; cursor < buflen; cursor++ {
for {
switch buf[cursor] {
case ' ', '\n', '\t', '\r':
cursor++
continue
case 'n':
buflen := int64(len(buf))
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
return cursor, nil
Expand Down Expand Up @@ -149,7 +139,8 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
return 0, errInvalidCharacter(buf[cursor], "array", cursor)
}
}
default:
return 0, errUnexpectedEndOfJSON("array", cursor)
}
}
return 0, errUnexpectedEndOfJSON("array", cursor)
}
43 changes: 6 additions & 37 deletions decode_bool.go
Expand Up @@ -47,56 +47,25 @@ ERROR:
}

func (d *boolDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buflen := int64(len(buf))
cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] {
case 't':
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("bool(true)", cursor)
}
if buf[cursor+1] != 'r' {
return 0, errInvalidCharacter(buf[cursor+1], "bool(true)", cursor)
}
if buf[cursor+2] != 'u' {
return 0, errInvalidCharacter(buf[cursor+2], "bool(true)", cursor)
}
if buf[cursor+3] != 'e' {
return 0, errInvalidCharacter(buf[cursor+3], "bool(true)", cursor)
if err := validateTrue(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**bool)(unsafe.Pointer(&p)) = true
return cursor, nil
case 'f':
if cursor+4 >= buflen {
return 0, errUnexpectedEndOfJSON("bool(false)", cursor)
}
if buf[cursor+1] != 'a' {
return 0, errInvalidCharacter(buf[cursor+1], "bool(false)", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "bool(false)", cursor)
}
if buf[cursor+3] != 's' {
return 0, errInvalidCharacter(buf[cursor+3], "bool(false)", cursor)
}
if buf[cursor+4] != 'e' {
return 0, errInvalidCharacter(buf[cursor+4], "bool(false)", cursor)
if err := validateFalse(buf, cursor); err != nil {
return 0, err
}
cursor += 5
**(**bool)(unsafe.Pointer(&p)) = false
return cursor, nil
case 'n':
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
return cursor, nil
Expand Down
4 changes: 1 addition & 3 deletions decode_bytes.go
Expand Up @@ -166,9 +166,7 @@ func (d *bytesDecoder) decodeBinary(buf []byte, cursor, depth int64, p unsafe.Po
cursor += 4
return nil, cursor, nil
default:
goto ERROR
return nil, 0, errNotAtBeginningOfValue(cursor)
}
}
ERROR:
return nil, 0, errNotAtBeginningOfValue(cursor)
}
66 changes: 39 additions & 27 deletions decode_context.go
Expand Up @@ -153,37 +153,14 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) {
}
return cursor, nil
case 't':
buflen := int64(len(buf))
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+1] != 'r' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+2] != 'u' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+3] != 'e' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
if err := validateTrue(buf, cursor); err != nil {
return 0, err
}
cursor += 4
return cursor, nil
case 'f':
buflen := int64(len(buf))
if cursor+4 >= buflen {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+1] != 'a' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+3] != 's' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+4] != 'e' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
if err := validateFalse(buf, cursor); err != nil {
return 0, err
}
cursor += 5
return cursor, nil
Expand All @@ -199,6 +176,41 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) {
}
}

func validateTrue(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("true", cursor)
}
if buf[cursor+1] != 'r' {
return errInvalidCharacter(buf[cursor+1], "true", cursor)
}
if buf[cursor+2] != 'u' {
return errInvalidCharacter(buf[cursor+2], "true", cursor)
}
if buf[cursor+3] != 'e' {
return errInvalidCharacter(buf[cursor+3], "true", cursor)
}
return nil
}

func validateFalse(buf []byte, cursor int64) error {
if cursor+4 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("false", cursor)
}
if buf[cursor+1] != 'a' {
return errInvalidCharacter(buf[cursor+1], "false", cursor)
}
if buf[cursor+2] != 'l' {
return errInvalidCharacter(buf[cursor+2], "false", cursor)
}
if buf[cursor+3] != 's' {
return errInvalidCharacter(buf[cursor+3], "false", cursor)
}
if buf[cursor+4] != 'e' {
return errInvalidCharacter(buf[cursor+4], "false", cursor)
}
return nil
}

func validateNull(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("null", cursor)
Expand Down
25 changes: 6 additions & 19 deletions decode_float.go
Expand Up @@ -91,42 +91,29 @@ ERROR:
}

func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
buflen := int64(len(buf))
for ; cursor < buflen; cursor++ {
for {
switch buf[cursor] {
case ' ', '\n', '\t', '\r':
cursor++
continue
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
start := cursor
cursor++
for ; cursor < buflen; cursor++ {
if floatTable[buf[cursor]] {
continue
}
break
for floatTable[buf[cursor]] {
cursor++
}
num := buf[start:cursor]
return num, cursor, nil
case 'n':
if cursor+3 >= buflen {
return nil, 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return nil, 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return nil, 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return nil, 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return nil, 0, err
}
cursor += 4
return nil, cursor, nil
default:
return nil, 0, errUnexpectedEndOfJSON("float", cursor)
}
}
return nil, 0, errUnexpectedEndOfJSON("float", cursor)
}

func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
Expand Down
18 changes: 3 additions & 15 deletions decode_int.go
Expand Up @@ -154,26 +154,14 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error)
case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
start := cursor
cursor++
LOOP:
if numTable[char(b, cursor)] {
for numTable[char(b, cursor)] {
cursor++
goto LOOP
}
num := buf[start:cursor]
return num, cursor, nil
case 'n':
buflen := int64(len(buf))
if cursor+3 >= buflen {
return nil, 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return nil, 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return nil, 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return nil, 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return nil, 0, err
}
cursor += 4
return nil, cursor, nil
Expand Down
42 changes: 6 additions & 36 deletions decode_interface.go
Expand Up @@ -385,52 +385,22 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64,
**(**interface{})(unsafe.Pointer(&p)) = v
return cursor, nil
case 't':
if cursor+3 >= int64(len(buf)) {
return 0, errUnexpectedEndOfJSON("bool(true)", cursor)
}
if buf[cursor+1] != 'r' {
return 0, errInvalidCharacter(buf[cursor+1], "bool(true)", cursor)
}
if buf[cursor+2] != 'u' {
return 0, errInvalidCharacter(buf[cursor+2], "bool(true)", cursor)
}
if buf[cursor+3] != 'e' {
return 0, errInvalidCharacter(buf[cursor+3], "bool(true)", cursor)
if err := validateTrue(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**interface{})(unsafe.Pointer(&p)) = true
return cursor, nil
case 'f':
if cursor+4 >= int64(len(buf)) {
return 0, errUnexpectedEndOfJSON("bool(false)", cursor)
}
if buf[cursor+1] != 'a' {
return 0, errInvalidCharacter(buf[cursor+1], "bool(false)", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "bool(false)", cursor)
}
if buf[cursor+3] != 's' {
return 0, errInvalidCharacter(buf[cursor+3], "bool(false)", cursor)
}
if buf[cursor+4] != 'e' {
return 0, errInvalidCharacter(buf[cursor+4], "bool(false)", cursor)
if err := validateFalse(buf, cursor); err != nil {
return 0, err
}
cursor += 5
**(**interface{})(unsafe.Pointer(&p)) = false
return cursor, nil
case 'n':
if cursor+3 >= int64(len(buf)) {
return 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**interface{})(unsafe.Pointer(&p)) = nil
Expand Down
13 changes: 2 additions & 11 deletions decode_map.go
Expand Up @@ -102,17 +102,8 @@ func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (
}
switch buf[cursor] {
case 'n':
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return 0, errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return 0, errInvalidCharacter(buf[cursor+3], "null", cursor)
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
Expand Down

0 comments on commit 835c00e

Please sign in to comment.