From 67e38154bd4eb5eb60223a727cdb5684ae3cc820 Mon Sep 17 00:00:00 2001 From: Josh Baker Date: Wed, 24 Aug 2016 12:12:07 -0700 Subject: [PATCH] sped up map[string]interface{} unmarshalling --- gjson.go | 71 ++++++++++++++++++++++++++++++++------------------- gjson_test.go | 27 ++++++++++++++++++++ 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/gjson.go b/gjson.go index 2e16394..e6cc523 100644 --- a/gjson.go +++ b/gjson.go @@ -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 @@ -187,21 +208,34 @@ func (t Result) arrayOrMap(vc byte) ([]Result, map[string]Result, byte) { if count%2 == 0 { key = value } else { - o[key.Str] = value + if valueize { + oi[key.Str] = value.Value() + } else { + o[key.Str] = value + } } count++ } else { - a = append(a, value) + 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: diff --git a/gjson_test.go b/gjson_test.go index 38e2677..401a43f 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -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++ {