mirror of
https://github.com/minio/minio.git
synced 2025-05-23 02:21:51 -04:00
Upgrade gjson to bring in new performance improvements (#6106)
This commit is contained in:
parent
360f3f9335
commit
d7ced9a8b5
132
vendor/github.com/tidwall/gjson/README.md
generated
vendored
132
vendor/github.com/tidwall/gjson/README.md
generated
vendored
@ -3,15 +3,19 @@
|
|||||||
src="logo.png"
|
src="logo.png"
|
||||||
width="240" height="78" border="0" alt="GJSON">
|
width="240" height="78" border="0" alt="GJSON">
|
||||||
<br>
|
<br>
|
||||||
<a href="https://travis-ci.org/tidwall/gjson"><img src="https://img.shields.io/travis/tidwall/gjson.svg?style=flat-square" alt="Build Status"></a><!--
|
<a href="https://travis-ci.org/tidwall/gjson"><img src="https://img.shields.io/travis/tidwall/gjson.svg?style=flat-square" alt="Build Status"></a>
|
||||||
<a href="http://gocover.io/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/coverage-97%25-brightgreen.svg?style=flat-square" alt="Code Coverage"></a>
|
|
||||||
-->
|
|
||||||
<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
||||||
|
<a href="http://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">get a json value quickly</a></p>
|
|
||||||
|
|
||||||
GJSON is a Go package that provides a [very fast](#performance) and simple way to get a value from a json document. The purpose for this library it to give efficient json indexing for the [BuntDB](https://github.com/tidwall/buntdb) project.
|
|
||||||
|
<p align="center">get json values quickly</a></p>
|
||||||
|
|
||||||
|
GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document.
|
||||||
|
It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [parsing json lines](#json-lines).
|
||||||
|
|
||||||
|
Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool.
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
===============
|
===============
|
||||||
@ -27,7 +31,7 @@ $ go get -u github.com/tidwall/gjson
|
|||||||
This will retrieve the library.
|
This will retrieve the library.
|
||||||
|
|
||||||
## Get a value
|
## Get a value
|
||||||
Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". This function expects that the json is well-formed and validates. Invalid json will not panic, but it may return back unexpected results. When the value is found it's returned immediately.
|
Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@ -55,7 +59,7 @@ A path is a series of keys separated by a dot.
|
|||||||
A key may contain special wildcard characters '\*' and '?'.
|
A key may contain special wildcard characters '\*' and '?'.
|
||||||
To access an array value use the index as the key.
|
To access an array value use the index as the key.
|
||||||
To get the number of elements in an array or to access a child path, use the '#' character.
|
To get the number of elements in an array or to access a child path, use the '#' character.
|
||||||
The dot and wildcard characters can be escaped with '\'.
|
The dot and wildcard characters can be escaped with '\\'.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -93,6 +97,36 @@ friends.#[age>45]#.last >> ["Craig","Murphy"]
|
|||||||
friends.#[first%"D*"].last >> "Murphy"
|
friends.#[first%"D*"].last >> "Murphy"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## JSON Lines
|
||||||
|
|
||||||
|
There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"name": "Gilbert", "age": 61}
|
||||||
|
{"name": "Alexa", "age": 34}
|
||||||
|
{"name": "May", "age": 57}
|
||||||
|
{"name": "Deloise", "age": 44}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
..# >> 4
|
||||||
|
..1 >> {"name": "Alexa", "age": 34}
|
||||||
|
..3 >> {"name": "Deloise", "age": 44}
|
||||||
|
..#.name >> ["Gilbert","Alexa","May","Deloise"]
|
||||||
|
..#[name="May"].age >> 57
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ForEachLines` function will iterate through JSON lines.
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.ForEachLine(json, func(line gjson.Result) bool{
|
||||||
|
println(line.String())
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Result Type
|
## Result Type
|
||||||
|
|
||||||
GJSON supports the json types `string`, `number`, `bool`, and `null`.
|
GJSON supports the json types `string`, `number`, `bool`, and `null`.
|
||||||
@ -120,12 +154,14 @@ result.Index // index of raw value in original json, zero means index unknown
|
|||||||
There are a variety of handy functions that work on a result:
|
There are a variety of handy functions that work on a result:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
result.Exists() bool
|
||||||
result.Value() interface{}
|
result.Value() interface{}
|
||||||
result.Int() int64
|
result.Int() int64
|
||||||
result.Uint() uint64
|
result.Uint() uint64
|
||||||
result.Float() float64
|
result.Float() float64
|
||||||
result.String() string
|
result.String() string
|
||||||
result.Bool() bool
|
result.Bool() bool
|
||||||
|
result.Time() time.Time
|
||||||
result.Array() []gjson.Result
|
result.Array() []gjson.Result
|
||||||
result.Map() map[string]gjson.Result
|
result.Map() map[string]gjson.Result
|
||||||
result.Get(path string) Result
|
result.Get(path string) Result
|
||||||
@ -135,8 +171,6 @@ result.Less(token Result, caseSensitive bool) bool
|
|||||||
|
|
||||||
The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
|
The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The `result.Array()` function returns back an array of values.
|
The `result.Array()` function returns back an array of values.
|
||||||
If the result represents a non-existent value, then an empty array will be returned.
|
If the result represents a non-existent value, then an empty array will be returned.
|
||||||
If the result is not a JSON array, the return value will be an array containing one result.
|
If the result is not a JSON array, the return value will be an array containing one result.
|
||||||
@ -150,6 +184,15 @@ array >> []interface{}
|
|||||||
object >> map[string]interface{}
|
object >> map[string]interface{}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 64-bit integers
|
||||||
|
|
||||||
|
The `result.Int()` and `result.Uint()` calls are capable of reading all 64 bits, allowing for large JSON integers.
|
||||||
|
|
||||||
|
```go
|
||||||
|
result.Int() int64 // -9223372036854775808 to 9223372036854775807
|
||||||
|
result.Uint() int64 // 0 to 18446744073709551615
|
||||||
|
```
|
||||||
|
|
||||||
## Get nested array values
|
## Get nested array values
|
||||||
|
|
||||||
Suppose you want all the last names from the following json:
|
Suppose you want all the last names from the following json:
|
||||||
@ -168,14 +211,14 @@ Suppose you want all the last names from the following json:
|
|||||||
"lastName": "Harold",
|
"lastName": "Harold",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You would use the path "programmers.#.lastName" like such:
|
You would use the path "programmers.#.lastName" like such:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
result := gjson.Get(json, "programmers.#.lastName")
|
result := gjson.Get(json, "programmers.#.lastName")
|
||||||
for _,name := range result.Array() {
|
for _, name := range result.Array() {
|
||||||
println(name.String())
|
println(name.String())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -196,7 +239,7 @@ Returning `false` from an iterator will stop iteration.
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
result := gjson.Get(json, "programmers")
|
result := gjson.Get(json, "programmers")
|
||||||
result.ForEach(func(key, value gjson.Result) bool{
|
result.ForEach(func(key, value gjson.Result) bool {
|
||||||
println(value.String())
|
println(value.String())
|
||||||
return true // keep iterating
|
return true // keep iterating
|
||||||
})
|
})
|
||||||
@ -227,18 +270,31 @@ if !value.Exists() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Or as one step
|
// Or as one step
|
||||||
if gjson.Get(json, "name.last").Exists(){
|
if gjson.Get(json, "name.last").Exists() {
|
||||||
println("has a last name")
|
println("has a last name")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Validate JSON
|
||||||
|
|
||||||
|
The `Get*` and `Parse*` functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results.
|
||||||
|
|
||||||
|
If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON.
|
||||||
|
|
||||||
|
```go
|
||||||
|
if !gjson.Valid(json) {
|
||||||
|
return errors.New("invalid json")
|
||||||
|
}
|
||||||
|
value := gjson.Get(json, "name.last")
|
||||||
|
```
|
||||||
|
|
||||||
## Unmarshal to a map
|
## Unmarshal to a map
|
||||||
|
|
||||||
To unmarshal to a `map[string]interface{}`:
|
To unmarshal to a `map[string]interface{}`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
m, ok := gjson.Parse(json).Value().(map[string]interface{})
|
m, ok := gjson.Parse(json).Value().(map[string]interface{})
|
||||||
if !ok{
|
if !ok {
|
||||||
// not a map
|
// not a map
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -269,7 +325,7 @@ This is a best-effort no allocation sub slice of the original json. This method
|
|||||||
|
|
||||||
## Get multiple values at once
|
## Get multiple values at once
|
||||||
|
|
||||||
The `GetMany` function can be used to get multiple values at the same time, and is optimized to scan over a JSON payload once.
|
The `GetMany` function can be used to get multiple values at the same time.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
results := gjson.GetMany(json, "name.first", "name.last", "age")
|
results := gjson.GetMany(json, "name.first", "name.last", "age")
|
||||||
@ -282,28 +338,18 @@ The return value is a `[]Result`, which will always contain exactly the same num
|
|||||||
Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
|
Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
|
||||||
[ffjson](https://github.com/pquerna/ffjson),
|
[ffjson](https://github.com/pquerna/ffjson),
|
||||||
[EasyJSON](https://github.com/mailru/easyjson),
|
[EasyJSON](https://github.com/mailru/easyjson),
|
||||||
and [jsonparser](https://github.com/buger/jsonparser)
|
[jsonparser](https://github.com/buger/jsonparser),
|
||||||
|
and [json-iterator](https://github.com/json-iterator/go)
|
||||||
|
|
||||||
```
|
```
|
||||||
BenchmarkGJSONGet-8 15000000 333 ns/op 0 B/op 0 allocs/op
|
BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op
|
||||||
BenchmarkGJSONUnmarshalMap-8 900000 4188 ns/op 1920 B/op 26 allocs/op
|
BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op
|
||||||
BenchmarkJSONUnmarshalMap-8 600000 8908 ns/op 3048 B/op 69 allocs/op
|
BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op
|
||||||
BenchmarkJSONUnmarshalStruct-8 600000 9026 ns/op 1832 B/op 69 allocs/op
|
BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op
|
||||||
BenchmarkJSONDecoder-8 300000 14339 ns/op 4224 B/op 184 allocs/op
|
BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op
|
||||||
BenchmarkFFJSONLexer-8 1500000 3156 ns/op 896 B/op 8 allocs/op
|
BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op
|
||||||
BenchmarkEasyJSONLexer-8 3000000 938 ns/op 613 B/op 6 allocs/op
|
BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op
|
||||||
BenchmarkJSONParserGet-8 3000000 442 ns/op 21 B/op 0 allocs/op
|
BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op
|
||||||
```
|
|
||||||
|
|
||||||
Benchmarks for the `GetMany` function:
|
|
||||||
|
|
||||||
```
|
|
||||||
BenchmarkGJSONGetMany4Paths-8 4000000 319 ns/op 112 B/op 0 allocs/op
|
|
||||||
BenchmarkGJSONGetMany8Paths-8 8000000 218 ns/op 56 B/op 0 allocs/op
|
|
||||||
BenchmarkGJSONGetMany16Paths-8 16000000 160 ns/op 56 B/op 0 allocs/op
|
|
||||||
BenchmarkGJSONGetMany32Paths-8 32000000 130 ns/op 64 B/op 0 allocs/op
|
|
||||||
BenchmarkGJSONGetMany64Paths-8 64000000 117 ns/op 64 B/op 0 allocs/op
|
|
||||||
BenchmarkGJSONGetMany128Paths-8 128000000 109 ns/op 64 B/op 0 allocs/op
|
|
||||||
```
|
```
|
||||||
|
|
||||||
JSON document used:
|
JSON document used:
|
||||||
@ -344,22 +390,8 @@ widget.image.hOffset
|
|||||||
widget.text.onMouseUp
|
widget.text.onMouseUp
|
||||||
```
|
```
|
||||||
|
|
||||||
For the `GetMany` benchmarks these paths are used:
|
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be be found [here](https://github.com/tidwall/gjson-benchmarks).*
|
||||||
|
|
||||||
```
|
|
||||||
widget.window.name
|
|
||||||
widget.image.hOffset
|
|
||||||
widget.text.onMouseUp
|
|
||||||
widget.window.title
|
|
||||||
widget.image.alignment
|
|
||||||
widget.text.style
|
|
||||||
widget.window.height
|
|
||||||
widget.image.src
|
|
||||||
widget.text.data
|
|
||||||
widget.text.size
|
|
||||||
```
|
|
||||||
|
|
||||||
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.*
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
||||||
|
1091
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
1091
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
File diff suppressed because it is too large
Load Diff
10
vendor/github.com/tidwall/gjson/gjson_gae.go
generated
vendored
Normal file
10
vendor/github.com/tidwall/gjson/gjson_gae.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//+build appengine
|
||||||
|
|
||||||
|
package gjson
|
||||||
|
|
||||||
|
func getBytes(json []byte, path string) Result {
|
||||||
|
return Get(string(json), path)
|
||||||
|
}
|
||||||
|
func fillIndex(json string, c *parseContext) {
|
||||||
|
// noop. Use zero for the Index value.
|
||||||
|
}
|
73
vendor/github.com/tidwall/gjson/gjson_ngae.go
generated
vendored
Normal file
73
vendor/github.com/tidwall/gjson/gjson_ngae.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//+build !appengine
|
||||||
|
|
||||||
|
package gjson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getBytes casts the input json bytes to a string and safely returns the
|
||||||
|
// results as uniquely allocated data. This operation is intended to minimize
|
||||||
|
// copies and allocations for the large json string->[]byte.
|
||||||
|
func getBytes(json []byte, path string) Result {
|
||||||
|
var result Result
|
||||||
|
if json != nil {
|
||||||
|
// unsafe cast to string
|
||||||
|
result = Get(*(*string)(unsafe.Pointer(&json)), path)
|
||||||
|
result = fromBytesGet(result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromBytesGet(result Result) Result {
|
||||||
|
// safely get the string headers
|
||||||
|
rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
|
||||||
|
strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
|
||||||
|
// create byte slice headers
|
||||||
|
rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
|
||||||
|
strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
|
||||||
|
if strh.Data == 0 {
|
||||||
|
// str is nil
|
||||||
|
if rawh.Data == 0 {
|
||||||
|
// raw is nil
|
||||||
|
result.Raw = ""
|
||||||
|
} else {
|
||||||
|
// raw has data, safely copy the slice header to a string
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
}
|
||||||
|
result.Str = ""
|
||||||
|
} else if rawh.Data == 0 {
|
||||||
|
// raw is nil
|
||||||
|
result.Raw = ""
|
||||||
|
// str has data, safely copy the slice header to a string
|
||||||
|
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
||||||
|
} else if strh.Data >= rawh.Data &&
|
||||||
|
int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
|
||||||
|
// Str is a substring of Raw.
|
||||||
|
start := int(strh.Data - rawh.Data)
|
||||||
|
// safely copy the raw slice header
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
// substring the raw
|
||||||
|
result.Str = result.Raw[start : start+strh.Len]
|
||||||
|
} else {
|
||||||
|
// safely copy both the raw and str slice headers to strings
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillIndex finds the position of Raw data and assigns it to the Index field
|
||||||
|
// of the resulting value. If the position cannot be found then Index zero is
|
||||||
|
// used instead.
|
||||||
|
func fillIndex(json string, c *parseContext) {
|
||||||
|
if len(c.value.Raw) > 0 && !c.calcd {
|
||||||
|
jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
|
||||||
|
rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
|
||||||
|
c.value.Index = int(rhdr.Data - jhdr.Data)
|
||||||
|
if c.value.Index < 0 || c.value.Index >= len(json) {
|
||||||
|
c.value.Index = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -689,10 +689,10 @@
|
|||||||
"revisionTime": "2016-03-11T21:55:03Z"
|
"revisionTime": "2016-03-11T21:55:03Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "k/Xh0p5L7+tBCXAL2dOCwUf9J3Y=",
|
"checksumSHA1": "d+4iuDj/qQ+2LiWEbQ+AWjxEJOc=",
|
||||||
"path": "github.com/tidwall/gjson",
|
"path": "github.com/tidwall/gjson",
|
||||||
"revision": "09d1c5c5bc64e094394dfe2150220d906c55ac37",
|
"revision": "f123b340873a0084cb27267eddd8ff615115fbff",
|
||||||
"revisionTime": "2017-02-05T16:10:42Z"
|
"revisionTime": "2018-06-21T18:09:58Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "qmePMXEDYGwkAfT9QvtMC58JN/E=",
|
"checksumSHA1": "qmePMXEDYGwkAfT9QvtMC58JN/E=",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user