added stack frame. faster

This commit is contained in:
Josh Baker 2016-08-11 10:39:38 -07:00
parent f4afb106da
commit a4005bcf0f
2 changed files with 51 additions and 51 deletions

View File

@ -103,7 +103,7 @@ result.Raw // holds the raw json
Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), [ffjson](https://github.com/pquerna/ffjson), and [EasyJSON](https://github.com/mailru/easyjson).
```
BenchmarkGJSONGet-8 3000000 477 ns/op 0 B/op 0 allocs/op
BenchmarkGJSONGet-8 3000000 440 ns/op 0 B/op 0 allocs/op
BenchmarkJSONUnmarshalMap-8 600000 10738 ns/op 3176 B/op 69 allocs/op
BenchmarkJSONUnmarshalStruct-8 600000 11635 ns/op 1960 B/op 69 allocs/op
BenchmarkJSONDecoder-8 300000 17193 ns/op 4864 B/op 184 allocs/op

100
gjson.go
View File

@ -76,6 +76,17 @@ func (t Result) Value() interface{} {
}
}
type part struct {
wild bool
key string
}
type frame struct {
key string
count int
stype byte
}
// Get searches json for the specified path.
// A path is in dot syntax, such as "name.last" or "age".
// This function expects that the json is well-formed, and does not validate.
@ -99,33 +110,44 @@ func (t Result) Value() interface{} {
// "c?ildren.0" >> "Sara"
//
func Get(json string, path string) Result {
var i, s, depth int
var squashed string
var key string
var stype byte
var count int
var s int
var wild bool
var matched bool
var parts = make([]string, 0, 4)
var wilds = make([]bool, 0, 4)
var keys = make([]string, 0, 4)
var stypes = make([]byte, 0, 4)
var counts = make([]int, 0, 4)
var parts = make([]part, 0, 4)
// do nothing when no path specified
if len(path) == 0 {
return Result{} // nothing
}
// parse the path. just split on the dot
for i := 0; i < len(path); i++ {
if path[i] == '.' {
parts = append(parts, part{wild: wild, key: path[s:i]})
if wild {
wild = false
}
s = i + 1
} else if path[i] == '*' || path[i] == '?' {
wild = true
}
}
parts = append(parts, part{wild: wild, key: path[s:]})
var i, depth int
var squashed string
var f frame
var matched bool
var stack = make([]frame, 0, 4)
depth = 1
// look for first delimiter
for ; i < len(json); i++ {
if json[i] > ' ' {
if json[i] == '{' {
stype = '{'
f.stype = '{'
} else if json[i] == '[' {
stype = '['
f.stype = '['
} else {
// not a valid type
return Result{}
@ -135,30 +157,13 @@ func Get(json string, path string) Result {
}
}
stypes = append(stypes, stype)
counts = append(counts, count)
// parse the path. just split on the dot
for i := 0; i < len(path); i++ {
if path[i] == '.' {
parts = append(parts, path[s:i])
wilds = append(wilds, wild)
if wild {
wild = false
}
s = i + 1
} else if path[i] == '*' || path[i] == '?' {
wild = true
}
}
parts = append(parts, path[s:])
wilds = append(wilds, wild)
stack = append(stack, f)
// search for key
read_key:
if stype == '[' {
key = strconv.FormatInt(int64(count), 10)
count++
if f.stype == '[' {
f.key = strconv.FormatInt(int64(f.count), 10)
f.count++
} else {
for ; i < len(json); i++ {
if json[i] == '"' {
@ -169,7 +174,7 @@ read_key:
s = i
for ; i < len(json); i++ {
if json[i] == '"' {
key = json[s:i]
f.key = json[s:i]
i++
break
}
@ -193,7 +198,7 @@ read_key:
break
}
}
key = unescape(json[s:i])
f.key = unescape(json[s:i])
i++
break
}
@ -206,11 +211,11 @@ read_key:
// we have a brand new key.
// is it the key that we are looking for?
if wilds[depth-1] {
if parts[depth-1].wild {
// it's a wildcard path element
matched = wildcardMatch(key, parts[depth-1])
matched = wildcardMatch(f.key, parts[depth-1].key)
} else {
matched = parts[depth-1] == key
matched = parts[depth-1].key == f.key
}
// read to the value token
@ -377,10 +382,8 @@ proc_val:
// can only deep search objects
// return Result{}
} else {
stype = vc
keys = append(keys, key)
stypes = append(stypes, stype)
counts = append(counts, count)
f.stype = vc
stack = append(stack, f)
depth++
goto read_key
}
@ -416,19 +419,16 @@ proc_val:
for ; i < len(json); i++ {
switch json[i] {
case '}', ']':
if parts[depth-1] == "#" {
return Result{Type: Number, Num: float64(count)}
if parts[depth-1].key == "#" {
return Result{Type: Number, Num: float64(f.count)}
}
// step the stack back
depth--
if depth == 0 {
return Result{}
}
keys = keys[:len(keys)-1]
stypes = stypes[:len(stypes)-1]
counts = counts[:len(counts)-1]
stype = stypes[len(stypes)-1]
count = counts[len(counts)-1]
stack = stack[:len(stack)-1]
f = stack[len(stack)-1]
case ',':
i++
goto read_key