mirror of
				https://github.com/minio/minio.git
				synced 2025-10-29 15:55:00 -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"  | ||||
|     width="240" height="78" border="0" alt="GJSON"> | ||||
| <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="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://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://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 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 | ||||
| =============== | ||||
| @ -27,7 +31,7 @@ $ go get -u github.com/tidwall/gjson | ||||
| This will retrieve the library. | ||||
| 
 | ||||
| ## 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 | ||||
| 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 '?'. | ||||
| 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. | ||||
| The dot and wildcard characters can be escaped with '\'. | ||||
| The dot and wildcard characters can be escaped with '\\'. | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| @ -93,6 +97,36 @@ friends.#[age>45]#.last            >> ["Craig","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 | ||||
| 
 | ||||
| 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: | ||||
| 
 | ||||
| ```go | ||||
| result.Exists() bool | ||||
| result.Value() interface{} | ||||
| result.Int() int64 | ||||
| result.Uint() uint64 | ||||
| result.Float() float64 | ||||
| result.String() string | ||||
| result.Bool() bool | ||||
| result.Time() time.Time | ||||
| result.Array() []gjson.Result | ||||
| result.Map() map[string]gjson.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.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 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{} | ||||
| ``` | ||||
| 
 | ||||
| ### 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 | ||||
| 
 | ||||
| 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",  | ||||
|     } | ||||
|   ] | ||||
| }` | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| You would use the path "programmers.#.lastName" like such: | ||||
| 
 | ||||
| ```go | ||||
| result := gjson.Get(json, "programmers.#.lastName") | ||||
| for _,name := range result.Array() { | ||||
| for _, name := range result.Array() { | ||||
| 	println(name.String()) | ||||
| } | ||||
| ``` | ||||
| @ -196,7 +239,7 @@ Returning `false` from an iterator will stop iteration. | ||||
| 
 | ||||
| ```go | ||||
| result := gjson.Get(json, "programmers") | ||||
| result.ForEach(func(key, value gjson.Result) bool{ | ||||
| result.ForEach(func(key, value gjson.Result) bool { | ||||
| 	println(value.String())  | ||||
| 	return true // keep iterating | ||||
| }) | ||||
| @ -227,18 +270,31 @@ if !value.Exists() { | ||||
| } | ||||
| 
 | ||||
| // Or as one step | ||||
| if gjson.Get(json, "name.last").Exists(){ | ||||
| if gjson.Get(json, "name.last").Exists() { | ||||
| 	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 | ||||
| 
 | ||||
| To unmarshal to a `map[string]interface{}`: | ||||
| 
 | ||||
| ```go | ||||
| m, ok := gjson.Parse(json).Value().(map[string]interface{}) | ||||
| if !ok{ | ||||
| if !ok { | ||||
| 	// 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 | ||||
| 
 | ||||
| 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 | ||||
| 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/),  | ||||
| [ffjson](https://github.com/pquerna/ffjson),  | ||||
| [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 | ||||
| BenchmarkGJSONUnmarshalMap-8     	  900000	      4188 ns/op	    1920 B/op	      26 allocs/op | ||||
| BenchmarkJSONUnmarshalMap-8      	  600000	      8908 ns/op	    3048 B/op	      69 allocs/op | ||||
| BenchmarkJSONUnmarshalStruct-8   	  600000	      9026 ns/op	    1832 B/op	      69 allocs/op | ||||
| BenchmarkJSONDecoder-8           	  300000	     14339 ns/op	    4224 B/op	     184 allocs/op | ||||
| BenchmarkFFJSONLexer-8           	 1500000	      3156 ns/op	     896 B/op	       8 allocs/op | ||||
| BenchmarkEasyJSONLexer-8         	 3000000	       938 ns/op	     613 B/op	       6 allocs/op | ||||
| BenchmarkJSONParserGet-8         	 3000000	       442 ns/op	      21 B/op	       0 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 | ||||
| BenchmarkGJSONGet-8                  3000000        372 ns/op          0 B/op         0 allocs/op | ||||
| BenchmarkGJSONUnmarshalMap-8          900000       4154 ns/op       1920 B/op        26 allocs/op | ||||
| BenchmarkJSONUnmarshalMap-8           600000       9019 ns/op       3048 B/op        69 allocs/op | ||||
| BenchmarkJSONDecoder-8                300000      14120 ns/op       4224 B/op       184 allocs/op | ||||
| BenchmarkFFJSONLexer-8               1500000       3111 ns/op        896 B/op         8 allocs/op | ||||
| BenchmarkEasyJSONLexer-8             3000000        887 ns/op        613 B/op         6 allocs/op | ||||
| BenchmarkJSONParserGet-8             3000000        499 ns/op         21 B/op         0 allocs/op | ||||
| BenchmarkJSONIterator-8              3000000        812 ns/op        544 B/op         9 allocs/op | ||||
| ``` | ||||
| 
 | ||||
| JSON document used: | ||||
| @ -344,22 +390,8 @@ widget.image.hOffset | ||||
| 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 | ||||
| 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" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "k/Xh0p5L7+tBCXAL2dOCwUf9J3Y=", | ||||
| 			"checksumSHA1": "d+4iuDj/qQ+2LiWEbQ+AWjxEJOc=", | ||||
| 			"path": "github.com/tidwall/gjson", | ||||
| 			"revision": "09d1c5c5bc64e094394dfe2150220d906c55ac37", | ||||
| 			"revisionTime": "2017-02-05T16:10:42Z" | ||||
| 			"revision": "f123b340873a0084cb27267eddd8ff615115fbff", | ||||
| 			"revisionTime": "2018-06-21T18:09:58Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "qmePMXEDYGwkAfT9QvtMC58JN/E=", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user