sped up map[string]interface{} unmarshalling

This commit is contained in:
Josh Baker 2016-08-24 12:12:07 -07:00
parent 0669befdc3
commit 67e38154bd
2 changed files with 72 additions and 26 deletions

View File

@ -100,7 +100,7 @@ func (t Result) Array() []Result {
if t.Type != JSON {
return nil
}
a, _, _ := t.arrayOrMap('[')
a, _, _, _, _ := t.arrayOrMap('[', false)
return a
}
@ -109,7 +109,7 @@ func (t Result) Map() map[string]Result {
if t.Type != JSON {
return map[string]Result{}
}
_, o, _ := t.arrayOrMap('{')
_, _, o, _, _ := t.arrayOrMap('{', false)
return o
}
@ -119,9 +119,17 @@ func (t Result) Get(path string) Result {
return Get(t.Raw, path)
}
func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) {
var a = []Result{}
var o = map[string]Result{}
func (t Result) arrayOrMap(vc byte, valueize bool) (
[]Result,
[]interface{},
map[string]Result,
map[string]interface{},
byte,
) {
var a []Result
var ai []interface{}
var o map[string]Result
var oi map[string]interface{}
var json = t.Raw
var i int
var value Result
@ -149,6 +157,19 @@ func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) {
}
}
}
if vc == '{' {
if valueize {
oi = make(map[string]interface{})
} else {
o = make(map[string]Result)
}
} else {
if valueize {
ai = make([]interface{}, 0)
} else {
a = make([]Result, 0)
}
}
for ; i < len(json); i++ {
if json[i] <= ' ' {
continue
@ -186,22 +207,35 @@ func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) {
if vc == '{' {
if count%2 == 0 {
key = value
} else {
if valueize {
oi[key.Str] = value.Value()
} else {
o[key.Str] = value
}
}
count++
} else {
if valueize {
ai = append(ai, value.Value())
} else {
a = append(a, value)
}
}
}
end:
return a, o, vc
return a, ai, o, oi, vc
}
// Parse parses the json and returns a result
func Parse(json string) Result {
var value Result
for i := 0; i < len(json); i++ {
if json[i] == '{' || json[i] == '[' {
value.Type = JSON
value.Raw = json[i:] // just take the entire raw
break
}
if json[i] <= ' ' {
continue
}
@ -213,13 +247,6 @@ func Parse(json string) Result {
} else {
return Result{}
}
case '{', '[':
value.Type = JSON
value.Raw = json[i:]
// we just trim the tail end
for value.Raw[len(value.Raw)-1] <= ' ' {
value.Raw = value.Raw[:len(value.Raw)-1]
}
case 'n':
value.Type = Null
value.Raw = tolit(json[i:])
@ -390,19 +417,11 @@ func (t Result) Value() interface{} {
case Number:
return t.Num
case JSON:
a, o, vc := t.arrayOrMap(0)
_, ai, _, oi, vc := t.arrayOrMap(0, true)
if vc == '{' {
var m = map[string]interface{}{}
for k, v := range o {
m[k] = v.Value()
}
return m
return oi
} else if vc == '[' {
var m = make([]interface{}, 0, len(a))
for _, v := range a {
m = append(m, v.Value())
}
return m
return ai
}
return nil
case True:

View File

@ -395,6 +395,33 @@ func BenchmarkGJSONGet(t *testing.B) {
t.N *= len(benchPaths) // because we are running against 3 paths
}
func BenchmarkGJSONUnmarshalMap(t *testing.B) {
t.ReportAllocs()
for i := 0; i < t.N; i++ {
for j := 0; j < len(benchPaths); j++ {
parts := strings.Split(benchPaths[j], ".")
m := Parse(exampleJSON).Value().(map[string]interface{})
var v interface{}
for len(parts) > 0 {
part := parts[0]
if len(parts) > 1 {
m = m[part].(map[string]interface{})
if m == nil {
t.Fatal("did not find the value")
}
} else {
v = m[part]
if v == nil {
t.Fatal("did not find the value")
}
}
parts = parts[1:]
}
}
}
t.N *= len(benchPaths) // because we are running against 3 paths
}
func BenchmarkJSONUnmarshalMap(t *testing.B) {
t.ReportAllocs()
for i := 0; i < t.N; i++ {