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 { if t.Type != JSON {
return nil return nil
} }
a, _, _ := t.arrayOrMap('[') a, _, _, _, _ := t.arrayOrMap('[', false)
return a return a
} }
@ -109,7 +109,7 @@ func (t Result) Map() map[string]Result {
if t.Type != JSON { if t.Type != JSON {
return map[string]Result{} return map[string]Result{}
} }
_, o, _ := t.arrayOrMap('{') _, _, o, _, _ := t.arrayOrMap('{', false)
return o return o
} }
@ -119,9 +119,17 @@ func (t Result) Get(path string) Result {
return Get(t.Raw, path) return Get(t.Raw, path)
} }
func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) { func (t Result) arrayOrMap(vc byte, valueize bool) (
var a = []Result{} []Result,
var o = map[string]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 json = t.Raw
var i int var i int
var value Result 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++ { for ; i < len(json); i++ {
if json[i] <= ' ' { if json[i] <= ' ' {
continue continue
@ -187,21 +208,34 @@ func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) {
if count%2 == 0 { if count%2 == 0 {
key = value key = value
} else { } else {
o[key.Str] = value if valueize {
oi[key.Str] = value.Value()
} else {
o[key.Str] = value
}
} }
count++ count++
} else { } else {
a = append(a, value) if valueize {
ai = append(ai, value.Value())
} else {
a = append(a, value)
}
} }
} }
end: end:
return a, o, vc return a, ai, o, oi, vc
} }
// Parse parses the json and returns a result // Parse parses the json and returns a result
func Parse(json string) Result { func Parse(json string) Result {
var value Result var value Result
for i := 0; i < len(json); i++ { 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] <= ' ' { if json[i] <= ' ' {
continue continue
} }
@ -213,13 +247,6 @@ func Parse(json string) Result {
} else { } else {
return Result{} 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': case 'n':
value.Type = Null value.Type = Null
value.Raw = tolit(json[i:]) value.Raw = tolit(json[i:])
@ -390,19 +417,11 @@ func (t Result) Value() interface{} {
case Number: case Number:
return t.Num return t.Num
case JSON: case JSON:
a, o, vc := t.arrayOrMap(0) _, ai, _, oi, vc := t.arrayOrMap(0, true)
if vc == '{' { if vc == '{' {
var m = map[string]interface{}{} return oi
for k, v := range o {
m[k] = v.Value()
}
return m
} else if vc == '[' { } else if vc == '[' {
var m = make([]interface{}, 0, len(a)) return ai
for _, v := range a {
m = append(m, v.Value())
}
return m
} }
return nil return nil
case True: case True:

View File

@ -395,6 +395,33 @@ func BenchmarkGJSONGet(t *testing.B) {
t.N *= len(benchPaths) // because we are running against 3 paths 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) { func BenchmarkJSONUnmarshalMap(t *testing.B) {
t.ReportAllocs() t.ReportAllocs()
for i := 0; i < t.N; i++ { for i := 0; i < t.N; i++ {