Skip to content

Commit 969384a

Browse files
committed
reuse buffer for sort keys, pre-setup union parser of multi-wildcards
1 parent 19de581 commit 969384a

25 files changed

+218
-136
lines changed

buffer_container.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package jsonpath
2+
3+
import (
4+
"sort"
5+
"sync"
6+
)
7+
8+
type bufferContainer struct {
9+
result []interface{}
10+
sortKeys *sort.StringSlice
11+
}
12+
13+
var bufferContainerSortSliceSyncPool = &sync.Pool{
14+
New: func() interface{} { return new(sort.StringSlice) },
15+
}
16+
17+
func (b *bufferContainer) expandSortSlice(length int) {
18+
if b.sortKeys == nil {
19+
b.sortKeys = bufferContainerSortSliceSyncPool.Get().(*sort.StringSlice)
20+
}
21+
if cap(*b.sortKeys) < length {
22+
*b.sortKeys = make(sort.StringSlice, length)
23+
}
24+
*b.sortKeys = (*b.sortKeys)[:length]
25+
}
26+
27+
func (b *bufferContainer) putSortSlice() {
28+
if b.sortKeys != nil {
29+
bufferContainerSortSliceSyncPool.Put(b.sortKeys)
30+
}
31+
}

jsonpath.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ func Parse(jsonPath string, config ...Config) (f func(src interface{}) ([]interf
5555

5656
root := parser.jsonPathParser.root
5757
return func(src interface{}) ([]interface{}, error) {
58-
var result []interface{}
58+
container := bufferContainer{}
59+
60+
defer func() {
61+
container.putSortSlice()
62+
}()
63+
64+
err := root.retrieve(src, src, &container)
65+
return container.result, err
5966

60-
err := root.retrieve(src, src, &result)
61-
return result, err
6267
}, nil
6368
}

jsonpath_parser.go

+49-2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ func (p *jsonPathParser) setNodeChain() {
9595
for _, singleIdentifier := range multiIdentifier.identifiers {
9696
singleIdentifier.setNext(nextNode)
9797
}
98+
if multiIdentifier.isAllWildcard {
99+
multiIdentifier.unionQualifier.setNext(nextNode)
100+
}
98101
}
99102

100103
last.setNext(nextNode)
@@ -112,6 +115,12 @@ func (p *jsonPathParser) setConnectedText(targetNode syntaxNode) {
112115
childText = targetNode.getNext().getConnectedText()
113116
}
114117
targetNode.setConnectedText(targetNode.getText() + childText)
118+
119+
if multiIdentifier, ok := targetNode.(*syntaxChildMultiIdentifier); ok {
120+
if multiIdentifier.isAllWildcard {
121+
multiIdentifier.unionQualifier.setConnectedText(targetNode.getConnectedText())
122+
}
123+
}
115124
}
116125

117126
func (p *jsonPathParser) updateRootValueGroup() {
@@ -150,6 +159,12 @@ func (p *jsonPathParser) deleteRootIdentifier(targetNode syntaxNode) syntaxNode
150159
func (p *jsonPathParser) setLastNodeText(text string) {
151160
node := p.params[len(p.params)-1].(syntaxNode)
152161
node.setText(text)
162+
163+
if multiIdentifier, ok := node.(*syntaxChildMultiIdentifier); ok {
164+
if multiIdentifier.isAllWildcard {
165+
multiIdentifier.unionQualifier.setText(text)
166+
}
167+
}
153168
}
154169

155170
func (p *jsonPathParser) updateAccessorMode(checkNode syntaxNode, mode bool) {
@@ -220,11 +235,27 @@ func (p *jsonPathParser) pushChildMultiIdentifier(
220235

221236
if multiIdentifier, ok := node.(*syntaxChildMultiIdentifier); ok {
222237
multiIdentifier.identifiers = append(multiIdentifier.identifiers, appendNode)
238+
239+
_, isWildcard := appendNode.(*syntaxChildWildcardIdentifier)
240+
multiIdentifier.isAllWildcard = multiIdentifier.isAllWildcard && isWildcard
241+
242+
if multiIdentifier.isAllWildcard {
243+
multiIdentifier.unionQualifier.subscripts = append(
244+
multiIdentifier.unionQualifier.subscripts,
245+
&syntaxWildcardSubscript{},
246+
)
247+
} else {
248+
multiIdentifier.unionQualifier = syntaxUnionQualifier{}
249+
}
250+
223251
p.push(multiIdentifier)
224252
return
225253
}
226254

227-
p.push(&syntaxChildMultiIdentifier{
255+
_, isNodeWildcard := node.(*syntaxChildWildcardIdentifier)
256+
_, isAppendNodeWildcard := appendNode.(*syntaxChildWildcardIdentifier)
257+
258+
identifier := syntaxChildMultiIdentifier{
228259
syntaxBasicNode: &syntaxBasicNode{
229260
valueGroup: true,
230261
accessorMode: p.accessorMode,
@@ -233,7 +264,23 @@ func (p *jsonPathParser) pushChildMultiIdentifier(
233264
node,
234265
appendNode,
235266
},
236-
})
267+
isAllWildcard: isNodeWildcard && isAppendNodeWildcard,
268+
}
269+
270+
if identifier.isAllWildcard {
271+
identifier.unionQualifier = syntaxUnionQualifier{
272+
syntaxBasicNode: &syntaxBasicNode{
273+
valueGroup: true,
274+
accessorMode: p.accessorMode,
275+
},
276+
subscripts: []syntaxSubscript{
277+
&syntaxWildcardSubscript{},
278+
&syntaxWildcardSubscript{},
279+
},
280+
}
281+
}
282+
283+
p.push(&identifier)
237284
}
238285

239286
func (p *jsonPathParser) pushChildWildcardIdentifier() {

syntax_basic_compare_parameter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ type syntaxBasicCompareParameter struct {
66
}
77

88
func (p *syntaxBasicCompareParameter) compute(
9-
root interface{}, currentList []interface{}) []interface{} {
9+
root interface{}, currentList []interface{}, container *bufferContainer) []interface{} {
1010

1111
if _, ok := p.param.(*syntaxQueryParamRoot); ok {
1212
currentList = []interface{}{root}
1313
}
1414

15-
return p.param.compute(root, currentList)
15+
return p.param.compute(root, currentList, container)
1616
}

syntax_basic_compare_query.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ type syntaxBasicCompareQuery struct {
77
}
88

99
func (q *syntaxBasicCompareQuery) compute(
10-
root interface{}, currentList []interface{}) []interface{} {
10+
root interface{}, currentList []interface{}, container *bufferContainer) []interface{} {
1111

12-
leftValues := q.leftParam.compute(root, currentList)
12+
leftValues := q.leftParam.compute(root, currentList, container)
1313
q.comparator.typeCast(leftValues)
1414

15-
rightValues := q.rightParam.compute(root, currentList)
15+
rightValues := q.rightParam.compute(root, currentList, container)
1616
q.comparator.typeCast(rightValues)
1717

1818
var leftPartialFound bool

syntax_basic_node.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -45,57 +45,57 @@ func (i *syntaxBasicNode) getNext() syntaxNode {
4545
}
4646

4747
func (i *syntaxBasicNode) retrieveAnyValueNext(
48-
root interface{}, nextSrc interface{}, result *[]interface{}) error {
48+
root interface{}, nextSrc interface{}, container *bufferContainer) error {
4949

5050
if i.next != nil {
51-
return i.next.retrieve(root, nextSrc, result)
51+
return i.next.retrieve(root, nextSrc, container)
5252
}
5353

5454
if i.accessorMode {
55-
*result = append(*result, Accessor{
55+
container.result = append(container.result, Accessor{
5656
Get: func() interface{} { return nextSrc },
5757
Set: nil,
5858
})
5959
} else {
60-
*result = append(*result, nextSrc)
60+
container.result = append(container.result, nextSrc)
6161
}
6262

6363
return nil
6464
}
6565

6666
func (i *syntaxBasicNode) retrieveMapNext(
67-
root interface{}, currentMap map[string]interface{}, key string, result *[]interface{}) error {
67+
root interface{}, currentMap map[string]interface{}, key string, container *bufferContainer) error {
6868

6969
if i.next != nil {
70-
return i.next.retrieve(root, currentMap[key], result)
70+
return i.next.retrieve(root, currentMap[key], container)
7171
}
7272

7373
if i.accessorMode {
74-
*result = append(*result, Accessor{
74+
container.result = append(container.result, Accessor{
7575
Get: func() interface{} { return currentMap[key] },
7676
Set: func(value interface{}) { currentMap[key] = value },
7777
})
7878
} else {
79-
*result = append(*result, currentMap[key])
79+
container.result = append(container.result, currentMap[key])
8080
}
8181

8282
return nil
8383
}
8484

8585
func (i *syntaxBasicNode) retrieveListNext(
86-
root interface{}, currentList []interface{}, index int, result *[]interface{}) error {
86+
root interface{}, currentList []interface{}, index int, container *bufferContainer) error {
8787

8888
if i.next != nil {
89-
return i.next.retrieve(root, currentList[index], result)
89+
return i.next.retrieve(root, currentList[index], container)
9090
}
9191

9292
if i.accessorMode {
93-
*result = append(*result, Accessor{
93+
container.result = append(container.result, Accessor{
9494
Get: func() interface{} { return currentList[index] },
9595
Set: func(value interface{}) { currentList[index] = value },
9696
})
9797
} else {
98-
*result = append(*result, currentList[index])
98+
container.result = append(container.result, currentList[index])
9999
}
100100

101101
return nil

syntax_if_node.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package jsonpath
22

33
type syntaxNode interface {
4-
retrieve(root, current interface{}, result *[]interface{}) error
4+
retrieve(root, current interface{}, container *bufferContainer) error
55
setText(text string)
66
getText() string
77
setValueGroup()

syntax_if_query.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package jsonpath
22

33
type syntaxQuery interface {
4-
compute(root interface{}, currentList []interface{}) []interface{}
4+
compute(root interface{}, currentList []interface{}, container *bufferContainer) []interface{}
55
}

syntax_node_function_aggregate.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,29 @@ type syntaxAggregateFunction struct {
88
}
99

1010
func (f *syntaxAggregateFunction) retrieve(
11-
root, current interface{}, result *[]interface{}) error {
11+
root, current interface{}, container *bufferContainer) error {
1212

13-
var values []interface{}
13+
values := bufferContainer{
14+
sortKeys: container.sortKeys,
15+
}
1416

1517
if err := f.param.retrieve(root, current, &values); err != nil {
1618
return err
1719
}
1820

1921
if !f.param.isValueGroup() {
20-
if arrayParam, ok := values[0].([]interface{}); ok {
21-
values = arrayParam
22+
if arrayParam, ok := values.result[0].([]interface{}); ok {
23+
values.result = arrayParam
2224
}
2325
}
2426

25-
filteredValue, err := f.function(values)
27+
filteredValue, err := f.function(values.result)
2628
if err != nil {
2729
return ErrorFunctionFailed{
2830
function: f.text,
2931
err: err,
3032
}
3133
}
3234

33-
return f.retrieveAnyValueNext(root, filteredValue, result)
35+
return f.retrieveAnyValueNext(root, filteredValue, container)
3436
}

syntax_node_function_filter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type syntaxFilterFunction struct {
77
}
88

99
func (f *syntaxFilterFunction) retrieve(
10-
root, current interface{}, result *[]interface{}) error {
10+
root, current interface{}, container *bufferContainer) error {
1111

1212
filteredValue, err := f.function(current)
1313
if err != nil {
@@ -17,5 +17,5 @@ func (f *syntaxFilterFunction) retrieve(
1717
}
1818
}
1919

20-
return f.retrieveAnyValueNext(root, filteredValue, result)
20+
return f.retrieveAnyValueNext(root, filteredValue, container)
2121
}

syntax_node_identifier_child_multi.go

+10-26
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,20 @@ import "reflect"
55
type syntaxChildMultiIdentifier struct {
66
*syntaxBasicNode
77

8-
identifiers []syntaxNode
8+
identifiers []syntaxNode
9+
isAllWildcard bool
10+
unionQualifier syntaxUnionQualifier
911
}
1012

1113
func (i *syntaxChildMultiIdentifier) retrieve(
12-
root, current interface{}, result *[]interface{}) error {
14+
root, current interface{}, container *bufferContainer) error {
1315

1416
if _, ok := current.([]interface{}); ok {
15-
wildcardSubscripts := make([]syntaxSubscript, 0, len(i.identifiers))
16-
isAllWildcard := true
17-
for _, identifier := range i.identifiers {
18-
if _, ok := identifier.(*syntaxChildWildcardIdentifier); !ok {
19-
isAllWildcard = false
20-
break
21-
}
22-
wildcardSubscripts = append(wildcardSubscripts, &syntaxWildcardSubscript{})
23-
}
24-
if len(i.identifiers) > 0 && isAllWildcard {
17+
if i.isAllWildcard {
2518
// If the "current" variable points to the array structure
2619
// and only wildcards are specified for qualifier,
2720
// then switch to syntaxUnionQualifier.
28-
unionQualifier := syntaxUnionQualifier{
29-
syntaxBasicNode: &syntaxBasicNode{
30-
text: i.text,
31-
next: i.next,
32-
valueGroup: true,
33-
accessorMode: i.accessorMode,
34-
},
35-
subscripts: wildcardSubscripts,
36-
}
37-
return unionQualifier.retrieve(root, current, result)
21+
return i.unionQualifier.retrieve(root, current, container)
3822
}
3923
}
4024

@@ -53,9 +37,9 @@ func (i *syntaxChildMultiIdentifier) retrieve(
5337

5438
childErrorMap := make(map[error]struct{}, 1)
5539

56-
lastError := i.retrieveMap(root, srcMap, result, childErrorMap)
40+
lastError := i.retrieveMap(root, srcMap, container, childErrorMap)
5741

58-
if len(*result) == 0 {
42+
if len(container.result) == 0 {
5943
switch len(childErrorMap) {
6044
case 0:
6145
return ErrorMemberNotExist{path: i.text}
@@ -70,7 +54,7 @@ func (i *syntaxChildMultiIdentifier) retrieve(
7054
}
7155

7256
func (i *syntaxChildMultiIdentifier) retrieveMap(
73-
root interface{}, srcMap map[string]interface{}, result *[]interface{},
57+
root interface{}, srcMap map[string]interface{}, container *bufferContainer,
7458
childErrorMap map[error]struct{}) error {
7559

7660
var lastError error
@@ -87,7 +71,7 @@ func (i *syntaxChildMultiIdentifier) retrieveMap(
8771
}
8872

8973
if found {
90-
if err := identifier.retrieve(root, srcMap, result); err != nil {
74+
if err := identifier.retrieve(root, srcMap, container); err != nil {
9175
childErrorMap[err] = struct{}{}
9276
lastError = err
9377
continue

syntax_node_identifier_child_single.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type syntaxChildSingleIdentifier struct {
99
}
1010

1111
func (i *syntaxChildSingleIdentifier) retrieve(
12-
root, current interface{}, result *[]interface{}) error {
12+
root, current interface{}, container *bufferContainer) error {
1313

1414
srcMap, ok := current.(map[string]interface{})
1515
if !ok {
@@ -28,5 +28,5 @@ func (i *syntaxChildSingleIdentifier) retrieve(
2828
return ErrorMemberNotExist{path: i.text}
2929
}
3030

31-
return i.retrieveMapNext(root, srcMap, i.identifier, result)
31+
return i.retrieveMapNext(root, srcMap, i.identifier, container)
3232
}

0 commit comments

Comments
 (0)