forked from mirror/gjson
added stack frame. faster
This commit is contained in:
parent
f4afb106da
commit
a4005bcf0f
|
@ -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).
|
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
|
BenchmarkJSONUnmarshalMap-8 600000 10738 ns/op 3176 B/op 69 allocs/op
|
||||||
BenchmarkJSONUnmarshalStruct-8 600000 11635 ns/op 1960 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
|
BenchmarkJSONDecoder-8 300000 17193 ns/op 4864 B/op 184 allocs/op
|
||||||
|
|
100
gjson.go
100
gjson.go
|
@ -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.
|
// Get searches json for the specified path.
|
||||||
// A path is in dot syntax, such as "name.last" or "age".
|
// 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.
|
// 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"
|
// "c?ildren.0" >> "Sara"
|
||||||
//
|
//
|
||||||
func Get(json string, path string) Result {
|
func Get(json string, path string) Result {
|
||||||
var i, s, depth int
|
var s int
|
||||||
var squashed string
|
|
||||||
var key string
|
|
||||||
var stype byte
|
|
||||||
var count int
|
|
||||||
var wild bool
|
var wild bool
|
||||||
var matched bool
|
var parts = make([]part, 0, 4)
|
||||||
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)
|
|
||||||
|
|
||||||
// do nothing when no path specified
|
// do nothing when no path specified
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return Result{} // nothing
|
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
|
depth = 1
|
||||||
|
|
||||||
// look for first delimiter
|
// look for first delimiter
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
if json[i] > ' ' {
|
if json[i] > ' ' {
|
||||||
if json[i] == '{' {
|
if json[i] == '{' {
|
||||||
stype = '{'
|
f.stype = '{'
|
||||||
} else if json[i] == '[' {
|
} else if json[i] == '[' {
|
||||||
stype = '['
|
f.stype = '['
|
||||||
} else {
|
} else {
|
||||||
// not a valid type
|
// not a valid type
|
||||||
return Result{}
|
return Result{}
|
||||||
|
@ -135,30 +157,13 @@ func Get(json string, path string) Result {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stypes = append(stypes, stype)
|
stack = append(stack, f)
|
||||||
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)
|
|
||||||
|
|
||||||
// search for key
|
// search for key
|
||||||
read_key:
|
read_key:
|
||||||
if stype == '[' {
|
if f.stype == '[' {
|
||||||
key = strconv.FormatInt(int64(count), 10)
|
f.key = strconv.FormatInt(int64(f.count), 10)
|
||||||
count++
|
f.count++
|
||||||
} else {
|
} else {
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
if json[i] == '"' {
|
if json[i] == '"' {
|
||||||
|
@ -169,7 +174,7 @@ read_key:
|
||||||
s = i
|
s = i
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
if json[i] == '"' {
|
if json[i] == '"' {
|
||||||
key = json[s:i]
|
f.key = json[s:i]
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -193,7 +198,7 @@ read_key:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
key = unescape(json[s:i])
|
f.key = unescape(json[s:i])
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -206,11 +211,11 @@ read_key:
|
||||||
|
|
||||||
// we have a brand new key.
|
// we have a brand new key.
|
||||||
// is it the key that we are looking for?
|
// is it the key that we are looking for?
|
||||||
if wilds[depth-1] {
|
if parts[depth-1].wild {
|
||||||
// it's a wildcard path element
|
// it's a wildcard path element
|
||||||
matched = wildcardMatch(key, parts[depth-1])
|
matched = wildcardMatch(f.key, parts[depth-1].key)
|
||||||
} else {
|
} else {
|
||||||
matched = parts[depth-1] == key
|
matched = parts[depth-1].key == f.key
|
||||||
}
|
}
|
||||||
|
|
||||||
// read to the value token
|
// read to the value token
|
||||||
|
@ -377,10 +382,8 @@ proc_val:
|
||||||
// can only deep search objects
|
// can only deep search objects
|
||||||
// return Result{}
|
// return Result{}
|
||||||
} else {
|
} else {
|
||||||
stype = vc
|
f.stype = vc
|
||||||
keys = append(keys, key)
|
stack = append(stack, f)
|
||||||
stypes = append(stypes, stype)
|
|
||||||
counts = append(counts, count)
|
|
||||||
depth++
|
depth++
|
||||||
goto read_key
|
goto read_key
|
||||||
}
|
}
|
||||||
|
@ -416,19 +419,16 @@ proc_val:
|
||||||
for ; i < len(json); i++ {
|
for ; i < len(json); i++ {
|
||||||
switch json[i] {
|
switch json[i] {
|
||||||
case '}', ']':
|
case '}', ']':
|
||||||
if parts[depth-1] == "#" {
|
if parts[depth-1].key == "#" {
|
||||||
return Result{Type: Number, Num: float64(count)}
|
return Result{Type: Number, Num: float64(f.count)}
|
||||||
}
|
}
|
||||||
// step the stack back
|
// step the stack back
|
||||||
depth--
|
depth--
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
return Result{}
|
return Result{}
|
||||||
}
|
}
|
||||||
keys = keys[:len(keys)-1]
|
stack = stack[:len(stack)-1]
|
||||||
stypes = stypes[:len(stypes)-1]
|
f = stack[len(stack)-1]
|
||||||
counts = counts[:len(counts)-1]
|
|
||||||
stype = stypes[len(stypes)-1]
|
|
||||||
count = counts[len(counts)-1]
|
|
||||||
case ',':
|
case ',':
|
||||||
i++
|
i++
|
||||||
goto read_key
|
goto read_key
|
||||||
|
|
Loading…
Reference in New Issue