From b2920a9472b267e34cb6d97c295b247dc36d86e8 Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Mon, 26 Sep 2022 08:00:40 -0400 Subject: [PATCH 1/4] Switch json module to go-json. - Use strings.Replacer instead of strings.Replace --- gabs.go | 21 ++++++++++++++------- gabs_test.go | 5 ++++- go.mod | 4 ++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gabs.go b/gabs.go index 21d3371..8136b40 100644 --- a/gabs.go +++ b/gabs.go @@ -24,13 +24,14 @@ package gabs import ( "bytes" - "encoding/json" "errors" "fmt" "io" "io/ioutil" "strconv" "strings" + + "github.com/goccy/go-json" ) //------------------------------------------------------------------------------ @@ -76,6 +77,16 @@ var ( ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") ) +var ( + r1 *strings.Replacer + r2 *strings.Replacer +) + +func init() { + r1 = strings.NewReplacer("~1", "/", "~0", "~") + r2 = strings.NewReplacer("~1", ".", "~0", "~") +} + //------------------------------------------------------------------------------ // JSONPointerToSlice parses a JSON pointer path @@ -97,9 +108,7 @@ func JSONPointerToSlice(path string) ([]string, error) { } hierarchy := strings.Split(path, "/")[1:] for i, v := range hierarchy { - v = strings.Replace(v, "~1", "/", -1) - v = strings.Replace(v, "~0", "~", -1) - hierarchy[i] = v + hierarchy[i] = r1.Replace(v) } return hierarchy, nil } @@ -112,9 +121,7 @@ func JSONPointerToSlice(path string) ([]string, error) { func DotPathToSlice(path string) []string { hierarchy := strings.Split(path, ".") for i, v := range hierarchy { - v = strings.Replace(v, "~1", ".", -1) - v = strings.Replace(v, "~0", "~", -1) - hierarchy[i] = v + hierarchy[i] = r2.Replace(v) } return hierarchy } diff --git a/gabs_test.go b/gabs_test.go index b005dba..e2bd8aa 100644 --- a/gabs_test.go +++ b/gabs_test.go @@ -2,11 +2,12 @@ package gabs import ( "bytes" - "encoding/json" "fmt" "reflect" "strings" "testing" + + "github.com/goccy/go-json" ) func TestBasic(t *testing.T) { @@ -1573,6 +1574,7 @@ dynamic approach. */ func BenchmarkStatic(b *testing.B) { + b.ReportAllocs() for i := 0; i < b.N; i++ { var jsonObj jsonStructure json.Unmarshal(jsonContent, &jsonObj) @@ -1595,6 +1597,7 @@ func BenchmarkStatic(b *testing.B) { } func BenchmarkDynamic(b *testing.B) { + b.ReportAllocs() for i := 0; i < b.N; i++ { jsonObj, err := ParseJSON(jsonContent) if err != nil { diff --git a/go.mod b/go.mod index c3d7ca4..c04f7dc 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,5 @@ module github.com/Jeffail/gabs/v2 + +go 1.18 + +require github.com/goccy/go-json v0.9.11 From 3fc057cac162792048826d67d886233d14077d8b Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Sat, 14 Jan 2023 08:34:21 -0700 Subject: [PATCH 2/4] Remove go-json and use encoding/json --- gabs_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gabs_test.go b/gabs_test.go index e2bd8aa..d0c4b22 100644 --- a/gabs_test.go +++ b/gabs_test.go @@ -2,12 +2,11 @@ package gabs import ( "bytes" + "encoding/json" "fmt" "reflect" "strings" "testing" - - "github.com/goccy/go-json" ) func TestBasic(t *testing.T) { From ea8aaf5b9fc40ec41a9d9461b24ad5023a4133dc Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Sat, 14 Jan 2023 08:35:55 -0700 Subject: [PATCH 3/4] Remove go-json from gabs.go --- gabs.go | 3 +-- go.mod | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/gabs.go b/gabs.go index 8136b40..6ad4728 100644 --- a/gabs.go +++ b/gabs.go @@ -24,14 +24,13 @@ package gabs import ( "bytes" + "encoding/json" "errors" "fmt" "io" "io/ioutil" "strconv" "strings" - - "github.com/goccy/go-json" ) //------------------------------------------------------------------------------ diff --git a/go.mod b/go.mod index c04f7dc..e72d9e5 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ module github.com/Jeffail/gabs/v2 go 1.18 - -require github.com/goccy/go-json v0.9.11 From 52d7bb51e457e0e86265ab6c536935f6a63a2f35 Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Sat, 14 Jan 2023 11:03:11 -0700 Subject: [PATCH 4/4] Pre-allocate tmpArray in strictSearch --- gabs.go | 17 +++++++++++------ gabs_test.go | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/gabs.go b/gabs.go index 6ad4728..4ee3cdd 100644 --- a/gabs.go +++ b/gabs.go @@ -154,17 +154,22 @@ func (g *Container) searchStrict(allowWildcard bool, hierarchy ...string) (*Cont } } else if marray, ok := object.([]interface{}); ok { if allowWildcard && pathSeg == "*" { - tmpArray := []interface{}{} - for _, val := range marray { - if (target + 1) >= len(hierarchy) { - tmpArray = append(tmpArray, val) - } else if res := Wrap(val).Search(hierarchy[target+1:]...); res != nil { - tmpArray = append(tmpArray, res.Data()) + var tmpArray []interface{} + if (target + 1) >= len(hierarchy) { + tmpArray = marray + } else { + tmpArray = make([]interface{}, 0, len(marray)) + for _, val := range marray { + if res := Wrap(val).Search(hierarchy[target+1:]...); res != nil { + tmpArray = append(tmpArray, res.Data()) + } } } + if len(tmpArray) == 0 { return nil, nil } + return &Container{tmpArray}, nil } index, err := strconv.Atoi(pathSeg) diff --git a/gabs_test.go b/gabs_test.go index d0c4b22..78d52f0 100644 --- a/gabs_test.go +++ b/gabs_test.go @@ -1906,3 +1906,20 @@ func TestFlattenIncludeEmpty(t *testing.T) { } } } + +func BenchmarkWildcardSearch(b *testing.B) { + sample := []byte(`{"test":[{"value":10},{"value":20}]}`) + + val, err := ParseJSON(sample) + if err != nil { + b.Fatalf("Failed to parse: %v", err) + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + val.Search([]string{"test", "*"}...) + val.Search([]string{"test", "*", "value"}...) + } +}