diff --git a/README.md b/README.md index 4be3727..0bf92aa 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data). ## Requirement -- Go 1.15/1.16 +- Go 1.15/1.16/1.17 - Linux/darwin OS - Amd64 CPU with AVX instruction set @@ -13,65 +13,67 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JI - Fast, fast, fast! ## Benchmarks -For **all sizes** of json and **all cases** of usage, **Sonic performs best**. -- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers) -![small benchmarks](bench-small.png) -- [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635KB, 10000+ key, 6 layers) -![large benchmarks](bench-large.png) +For **all sizes** of json and **all scenarios** of usage, **Sonic performs best**. - [Medium](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13KB, 300+ key, 6 layers) - -**For medium data, Sonic's speed is `2.6x times` of [json-iterator's](https://github.com/json-iterator/go) in `decoding`, `2.5x times` in `encoding`,and `8.3x times` in `searching`.** - ```powershell +goversion: 1.17.1 goos: darwin goarch: amd64 cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz -BenchmarkEncoder_Generic_Sonic-16 100000 25547 ns/op 510.23 MB/s 13762 B/op 4 allocs/op -BenchmarkEncoder_Generic_JsonIter-16 100000 44526 ns/op 292.75 MB/s 13433 B/op 77 allocs/op -BenchmarkEncoder_Generic_StdLib-16 100000 134480 ns/op 96.93 MB/s 48177 B/op 827 allocs/op -BenchmarkEncoder_Binding_Sonic-16 100000 6658 ns/op 1957.74 MB/s 14156 B/op 4 allocs/op -BenchmarkEncoder_Binding_JsonIter-16 100000 21367 ns/op 610.05 MB/s 9487 B/op 2 allocs/op -BenchmarkEncoder_Binding_StdLib-16 100000 17558 ns/op 742.41 MB/s 9480 B/op 1 allocs/op -BenchmarkEncoder_Parallel_Generic_Sonic-16 100000 4562 ns/op 2857.18 MB/s 10957 B/op 4 allocs/op -BenchmarkEncoder_Parallel_Generic_JsonIter-16 100000 10943 ns/op 1191.21 MB/s 13449 B/op 77 allocs/op -BenchmarkEncoder_Parallel_Generic_StdLib-16 100000 52174 ns/op 249.84 MB/s 48218 B/op 827 allocs/op -BenchmarkEncoder_Parallel_Binding_Sonic-16 100000 1422 ns/op 9168.12 MB/s 11030 B/op 4 allocs/op -BenchmarkEncoder_Parallel_Binding_JsonIter-16 100000 4630 ns/op 2815.35 MB/s 9496 B/op 2 allocs/op -BenchmarkEncoder_Parallel_Binding_StdLib-16 100000 4977 ns/op 2619.08 MB/s 9488 B/op 1 allocs/op +BenchmarkEncoder_Generic_Sonic 25181 ns/op 517.65 MB/s 13035 B/op 4 allocs/op +BenchmarkEncoder_Generic_JsonIter 43765 ns/op 297.84 MB/s 13433 B/op 77 allocs/op +BenchmarkEncoder_Generic_StdLib 108776 ns/op 119.83 MB/s 49137 B/op 827 allocs/op +BenchmarkEncoder_Binding_Sonic 6282 ns/op 2075.01 MB/s 13765 B/op 4 allocs/op +BenchmarkEncoder_Binding_JsonIter 20740 ns/op 628.51 MB/s 9487 B/op 2 allocs/op +BenchmarkEncoder_Binding_StdLib 16661 ns/op 782.34 MB/s 9479 B/op 1 allocs/op +BenchmarkEncoder_Parallel_Generic_Sonic-16 4072 ns/op 3200.89 MB/s 11052 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Generic_JsonIter-16 11379 ns/op 1145.52 MB/s 13458 B/op 77 allocs/op +BenchmarkEncoder_Parallel_Generic_StdLib-16 50635 ns/op 257.43 MB/s 49183 B/op 827 allocs/op +BenchmarkEncoder_Parallel_Binding_Sonic-16 1304 ns/op 9994.64 MB/s 10925 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Binding_JsonIter-16 6072 ns/op 2146.76 MB/s 9505 B/op 2 allocs/op +BenchmarkEncoder_Parallel_Binding_StdLib-16 3510 ns/op 3713.89 MB/s 9481 B/op 1 allocs/op -BenchmarkDecoder_Generic_Sonic-16 100000 57247 ns/op 227.70 MB/s 49727 B/op 313 allocs/op -BenchmarkDecoder_Generic_StdLib-16 100000 139698 ns/op 93.31 MB/s 50898 B/op 772 allocs/op -BenchmarkDecoder_Generic_JsonIter-16 100000 101967 ns/op 127.84 MB/s 55787 B/op 1068 allocs/op -BenchmarkDecoder_Binding_Sonic-16 100000 28254 ns/op 461.35 MB/s 25062 B/op 34 allocs/op -BenchmarkDecoder_Binding_StdLib-16 100000 123779 ns/op 105.31 MB/s 10560 B/op 207 allocs/op -BenchmarkDecoder_Binding_JsonIter-16 100000 38253 ns/op 340.75 MB/s 14674 B/op 385 allocs/op -BenchmarkDecoder_Parallel_Generic_Sonic-16 100000 10171 ns/op 1281.59 MB/s 49458 B/op 313 allocs/op -BenchmarkDecoder_Parallel_Generic_StdLib-16 100000 54916 ns/op 237.36 MB/s 50907 B/op 772 allocs/op -BenchmarkDecoder_Parallel_Generic_JsonIter-16 100000 48286 ns/op 269.95 MB/s 55811 B/op 1068 allocs/op -BenchmarkDecoder_Parallel_Binding_Sonic-16 100000 5282 ns/op 2467.83 MB/s 24683 B/op 34 allocs/op -BenchmarkDecoder_Parallel_Binding_StdLib-16 100000 31875 ns/op 408.94 MB/s 10559 B/op 207 allocs/op -BenchmarkDecoder_Parallel_Binding_JsonIter-16 100000 13810 ns/op 943.90 MB/s 14679 B/op 385 allocs/op +BenchmarkDecoder_Generic_Sonic 53843 ns/op 242.09 MB/s 49779 B/op 313 allocs/op +BenchmarkDecoder_Generic_StdLib 130402 ns/op 99.96 MB/s 50868 B/op 772 allocs/op +BenchmarkDecoder_Generic_JsonIter 92810 ns/op 140.45 MB/s 55788 B/op 1068 allocs/op +BenchmarkDecoder_Binding_Sonic 29793 ns/op 437.52 MB/s 24778 B/op 34 allocs/op +BenchmarkDecoder_Binding_StdLib 121206 ns/op 107.54 MB/s 10576 B/op 208 allocs/op +BenchmarkDecoder_Binding_JsonIter 36099 ns/op 361.09 MB/s 14674 B/op 385 allocs/op +BenchmarkDecoder_Parallel_Generic_Sonic-16 10319 ns/op 1263.21 MB/s 49423 B/op 313 allocs/op +BenchmarkDecoder_Parallel_Generic_StdLib-16 58526 ns/op 222.72 MB/s 50875 B/op 772 allocs/op +BenchmarkDecoder_Parallel_Generic_JsonIter-16 60156 ns/op 216.69 MB/s 55812 B/op 1068 allocs/op +BenchmarkDecoder_Parallel_Binding_Sonic-16 7265 ns/op 1794.18 MB/s 24952 B/op 34 allocs/op +BenchmarkDecoder_Parallel_Binding_StdLib-16 44000 ns/op 296.25 MB/s 10575 B/op 208 allocs/op +BenchmarkDecoder_Parallel_Binding_JsonIter-16 21029 ns/op 619.86 MB/s 14678 B/op 385 allocs/op -BenchmarkSearchOne_Gjson-16 100000 8992 ns/op 1448.28 MB/s 0 B/op 0 allocs/op -BenchmarkSearchOne_Jsoniter-16 100000 58313 ns/op 223.33 MB/s 27936 B/op 647 allocs/op -BenchmarkSearchOne_Sonic-16 100000 10497 ns/op 1240.61 MB/s 29 B/op 1 allocs/op -BenchmarkSearchOne_Parallel_Gjson-16 100000 1046 ns/op 12449.59 MB/s 0 B/op 0 allocs/op -BenchmarkSearchOne_Parallel_Jsoniter-16 100000 16080 ns/op 809.88 MB/s 27942 B/op 647 allocs/op -BenchmarkSearchOne_Parallel_Sonic-16 100000 1435 ns/op 9074.18 MB/s 285 B/op 1 allocs/op +BenchmarkGetOne_Sonic 17070 ns/op 762.94 MB/s 29 B/op 1 allocs/op +BenchmarkGetOne_Gjson 19714 ns/op 660.59 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Jsoniter 99281 ns/op 131.17 MB/s 27936 B/op 647 allocs/op +BenchmarkSetOne_Sonic 23730 ns/op 548.80 MB/s 1883 B/op 17 allocs/op +BenchmarkSetOne_Sjson 57680 ns/op 225.78 MB/s 52180 B/op 9 allocs/op +BenchmarkSetOne_Jsoniter 104018 ns/op 125.20 MB/s 45859 B/op 964 allocs/op +BenchmarkGetOne_Parallel_Sonic-16 2010 ns/op 6479.41 MB/s 114 B/op 1 allocs/op +BenchmarkGetOne_Parallel_Gjson-16 1815 ns/op 7176.39 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Parallel_Jsoniter-16 23261 ns/op 559.86 MB/s 27942 B/op 647 allocs/op +BenchmarkSetOne_Parallel_Sonic-16 2007 ns/op 6487.78 MB/s 2202 B/op 17 allocs/op +BenchmarkSetOne_Parallel_Sjson-16 12422 ns/op 1048.40 MB/s 52180 B/op 9 allocs/op +BenchmarkSetOne_Parallel_Jsoniter-16 39204 ns/op 332.18 MB/s 45889 B/op 964 allocs/op ``` -More detail see [decoder/decoder_test.go](https://github.com/bytedance/sonic/blob/main/decoder/decoder_test.go), [encoder/encoder_test.go](https://github.com/bytedance/sonic/blob/main/encoder/encoder_test.go), [ast/search_test.go](https://github.com/bytedance/sonic/blob/main/ast/search_test.go), [ast/parser_test.go](https://github.com/bytedance/sonic/blob/main/ast/parser_test.go), [ast/node_test.go](https://github.com/bytedance/sonic/blob/main/ast/node_test.go) +- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers) +![small benchmarks](bench-small.jpg) +- [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635KB, 10000+ key, 6 layers) +![large benchmarks](bench-large.jpg) + +See [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) for benchmark codes. ## How it works -See [INTRODUCTION.md](INTRODUCTION.md) - -## Fuzzing -[sonic-fuzz](https://github.com/liuq19/sonic-fuzz) is the repository for fuzzing tests. If you find any bug, please report the issue to sonic. +See [INTRODUCTION.md](INTRODUCTION.md). ## Usage ### Marshal/Unmarshal -The behaviors are mostly consistent with encoding/json, except some uncommon escaping (see [issue4](https://github.com/bytedance/sonic/issues/4)) +Their behaviors are mostly consistent with `encoding/json`, except two escaping form (see [issue4](https://github.com/bytedance/sonic/issues/4)) that is **NOT** in conformity to [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). ```go import "github.com/bytedance/sonic" @@ -118,7 +120,6 @@ import "github.com/bytedance/sonic/encoder" m := map[string]interface{}{} v, err := encoder.Encode(m, encoder.SortMapKeys) ``` -**Caution**: sonic encode struct in order of its original field declaration, so if you want to sort a struct's keys like the map's, just rewrite your struct. ### Print Syntax Error ```go @@ -211,20 +212,23 @@ Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as import ( "reflect" "github.com/bytedance/sonic" -) - -func init() { - var v HugeStruct - err := sonic.Pretouch(reflect.TypeOf(v)) -} + "github.com/bytedance/sonic/option" + ) + + func init() { + var v HugeStruct + // For most large types (nesting depth <= 5) + err := sonic.Pretouch(reflect.TypeOf(v)) + // If the type is too deep nesting (nesting depth > 5), + // you can set compile recursive depth in Pretouch for better stability in JIT. + err := sonic.Pretouch(reflect.TypeOf(v), option.WithCompileRecursiveDepth(depth)) ``` -**CAUTION:** use the **STRUCT instead of its POINTER** to `Pretouch()`, otherwise it won't work when you pass the pointer to `Marshal()/Unmarshal()`! ### Pass string or []byte? -For alignment to encoding/json, we provide API to pass `[]byte` as argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when origin JSON is huge. Therefore, you can use `UnmarshalString`, `GetFromString` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. +For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when origin JSON is huge. Therefore, you can use `UnmarshalString` and `GetFromString` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. -### Better performance for generic deserializing -In most cases, `Unmarshal()` with schemalized data performs better than `ast.Loads()`/`node.Interface()` with generic data. But if you only have a schema for partial json, you can combine `Get()` and `Unmarshal()` together: +### Better performance for generic data +In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of schema for specific json, you can combine `Get()` and `Unmarshal()` together: ```go import "github.com/bytedance/sonic" @@ -232,14 +236,20 @@ node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") var user User // your partial schema... err = sonic.UnmarshalString(node.Raw(), &user) ``` -Even if you don't have any schema, Use `InterfaceUseNode()` as the container of generic values instead of `Map()` or `Interface()`: +Even if you don't have any schema, use `ast.Node` as the container of generic values instead of `map` or `interface`: ```go import "github.com/bytedance/sonic" -node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") -user := node.InterfaceUseNode() // use node.Interface() as little as possible +root, err := sonic.GetFromString(_TwitterJson) +user := root.GetByPath("statuses", 3, "user") // === root.Get("status").Index(3).Get("user") +err = user.Check() + +// err = user.LoadAll() // only call this when you want to use 'user' concurrently... +go someFunc(user) ``` -Why? -1. using `Interface()` means Sonic must parse all the underlying values, while in most cases you only need several of them; -2. `map[x]` is not efficient enough compared to `array[x]`, but `ast.Node` can use `Index()`, for either array or object node; -3. `map`'s performance degrades a lot once rehashing triggered, but `ast.Node` doesn't has this concern; \ No newline at end of file +Why? Because `ast.Node` stores its children using `array`: +- `Map`'s performance degrades a lot once rehashing triggered, but `ast.Node` doesn't have this concern; +- **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**. +- Using `Interface()`/`Map()` means Sonic must parse all the underlying values, while in most cases you don't need them all; + +**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, your can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}` \ No newline at end of file diff --git a/ast/node_test.go b/ast/node_test.go index f92a0cd..2d7aeb6 100644 --- a/ast/node_test.go +++ b/ast/node_test.go @@ -24,12 +24,9 @@ import ( `testing` `github.com/bytedance/sonic/internal/native/types` - jsoniter `github.com/json-iterator/go` `github.com/stretchr/testify/assert` ) -var parallelism = 4 - func TestLoadAll(t *testing.T) { e := Node{} err := e.Load() @@ -770,7 +767,6 @@ func TestNodeAdd(t *testing.T) { func BenchmarkLoadNode(b *testing.B) { b.Run("Interface()", func(b *testing.B) { - b.SetParallelism(parallelism) b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -785,7 +781,6 @@ func BenchmarkLoadNode(b *testing.B) { }) b.Run("LoadAll()", func(b *testing.B) { - b.SetParallelism(parallelism) b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -800,7 +795,6 @@ func BenchmarkLoadNode(b *testing.B) { }) b.Run("InterfaceUseNode()", func(b *testing.B) { - b.SetParallelism(parallelism) b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -815,7 +809,6 @@ func BenchmarkLoadNode(b *testing.B) { }) b.Run("Load()", func(b *testing.B) { - b.SetParallelism(parallelism) b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -836,7 +829,6 @@ func BenchmarkNodeGetByPath(b *testing.B) { b.Fatalf("decode failed: %v", derr.Error()) } _, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() - b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -846,14 +838,13 @@ func BenchmarkNodeGetByPath(b *testing.B) { }) } -func BenchmarkStructGetByPath_Jsoniter(b *testing.B) { +func BenchmarkStructGetByPath(b *testing.B) { var root = _TwitterStruct{} - err := jsoniter.Unmarshal([]byte(_TwitterJson), &root) + err := json.Unmarshal([]byte(_TwitterJson), &root) if err != nil { b.Fatalf("unmarshal failed: %v", err) } - b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { @@ -976,7 +967,6 @@ func BenchmarkNodeSet(b *testing.B) { node.Set("test4", NewNumber("4")) node.Set("test5", NewNumber("5")) n := NewNull() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node.Set("test3", n) @@ -996,7 +986,6 @@ func BenchmarkMapSet(b *testing.B) { node.Set("test5", NewNumber("5")) m, _ := node.Map() n := NewNull() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { m["test3"] = n @@ -1015,7 +1004,6 @@ func BenchmarkNodeSetByIndex(b *testing.B) { node.Add(NewNumber("4")) node.Add(NewNumber("5")) n := NewNull() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node.SetByIndex(2, n) @@ -1035,7 +1023,6 @@ func BenchmarkSliceSetByIndex(b *testing.B) { node.Add(NewNumber("5")) m, _ := node.Array() n := NewNull() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { m[2] = n @@ -1069,7 +1056,6 @@ func BenchmarkNodeUnset(b *testing.B) { node.Set("test3", NewNumber("3")) node.Set("test4", NewNumber("4")) node.Set("test5", NewNumber("5")) - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node.Unset("test3") @@ -1088,7 +1074,6 @@ func BenchmarkMapUnset(b *testing.B) { node.Set("test4", NewNumber("4")) node.Set("test5", NewNumber("5")) m, _ := node.Map() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { delete(m, "test3") @@ -1106,7 +1091,6 @@ func BenchmarkNodUnsetByIndex(b *testing.B) { node.Add(NewNumber("3")) node.Add(NewNumber("4")) node.Add(NewNumber("5")) - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node.UnsetByIndex(2) @@ -1125,7 +1109,6 @@ func BenchmarkSliceUnsetByIndex(b *testing.B) { node.Add(NewNumber("4")) node.Add(NewNumber("5")) m, _ := node.Array() - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { for i:=3; i<5; i++ { @@ -1136,7 +1119,6 @@ func BenchmarkSliceUnsetByIndex(b *testing.B) { func BenchmarkNodeAdd(b *testing.B) { n := NewObject([]Pair{{"test", NewNumber("1")}}) - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node := NewArray([]Node{}) @@ -1146,7 +1128,6 @@ func BenchmarkNodeAdd(b *testing.B) { func BenchmarkSliceAdd(b *testing.B) { n := NewObject([]Pair{{"test", NewNumber("1")}}) - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node := []Node{} @@ -1156,7 +1137,6 @@ func BenchmarkSliceAdd(b *testing.B) { func BenchmarkMapAdd(b *testing.B) { n := NewObject([]Pair{{"test", NewNumber("1")}}) - b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { node := map[string]Node{} diff --git a/ast/parser_test.go b/ast/parser_test.go index 2d5ddf9..9eb00b2 100644 --- a/ast/parser_test.go +++ b/ast/parser_test.go @@ -240,52 +240,95 @@ func TestParsehNotExist(t *testing.T) { } } -func BenchmarkParser_StdLib(b *testing.B) { - var bv = []byte(_TwitterJson) - b.SetBytes(int64(len(_TwitterJson))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - var out interface{} - _ = json.Unmarshal(bv, &out) - } -} - -func BenchmarkParser_JsonIter(b *testing.B) { - var bv = []byte(_TwitterJson) - b.SetBytes(int64(len(_TwitterJson))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - var out interface{} - _ = jsoniter.Unmarshal(bv, &out) - } -} - func BenchmarkParser_Sonic(b *testing.B) { - _, _, _ = Loads(_TwitterJson) + r, err := NewParser(_TwitterJson).Parse() + if err != 0 { + b.Fatal(err) + } + if err := r.LoadAll(); err != nil { + b.Fatal(err) + } b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() for i := 0; i < b.N; i++ { - _, _, _ = Loads(_TwitterJson) + r, _ = NewParser(_TwitterJson).Parse() + _ = r.LoadAll() } } -func BenchmarkParser_Parallel_StdLib(b *testing.B) { - var bv = []byte(_TwitterJson) +func BenchmarkParser_Gjson(b *testing.B) { + gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool { + if !value.Exists() { + b.Fatal(value.Index) + } + _ = value.Value() + return true + }) + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool { + if !value.Exists() { + b.Fatal(value.Index) + } + _ = value.Value() + return true + }) + } +} + +func BenchmarkParser_Jsoniter(b *testing.B) { + v := jsoniter.Get([]byte(_TwitterJson)).GetInterface() + if v == nil { + b.Fatal(v) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = jsoniter.Get([]byte(_TwitterJson)).GetInterface() + } +} + +func BenchmarkParser_Parallel_Sonic(b *testing.B) { + r, _ := NewParser(_TwitterJson).Parse() + if err := r.LoadAll(); err != nil { + b.Fatal(err) + } b.SetBytes(int64(len(_TwitterJson))) - b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - var out interface{} - _ = json.Unmarshal(bv, &out) + r, _ := NewParser(_TwitterJson).Parse() + _ = r.LoadAll() } }) } -func BenchmarkParser_Parallel_JsonIter(b *testing.B) { +func BenchmarkParser_Parallel_Gjson(b *testing.B) { + gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool { + if !value.Exists() { + b.Fatal(value.Index) + } + return true + }) + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool { + if !value.Exists() { + b.Fatal(value.Index) + } + _ = value.Value() + return true + }) + } + }) +} + +func BenchmarkParser_Parallel_Jsoniter(b *testing.B) { var bv = []byte(_TwitterJson) b.SetBytes(int64(len(_TwitterJson))) - b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { @@ -295,98 +338,215 @@ func BenchmarkParser_Parallel_JsonIter(b *testing.B) { }) } -func BenchmarkParser_Parallel_Sonic(b *testing.B) { - _, _, _ = Loads(_TwitterJson) +func BenchmarkParseOne_Sonic(b *testing.B) { + ast, _ := NewParser(_TwitterJson).Parse() + node, _ := ast.Get("statuses").Index(2).Get("id").Int64() + if node != 249289491129438208 { + b.Fail() + } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ast, _ := NewParser(_TwitterJson).Parse() + _, _ = ast.Get("statuses").Index(2).Get("id").Int64() + } +} + +func BenchmarkParseOne_Gjson(b *testing.B) { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.2.id") + v := node.Int() + if v != 249289491129438208 { + b.Fatal(node) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.2.id") + _ = node.Int() + } +} + +func BenchmarkParseOne_Jsoniter(b *testing.B) { + data := []byte(_TwitterJson) + ast := jsoniter.Get(data, "statuses", 2, "id") + node := ast.ToInt() + if node != 249289491129438208 { + b.Fail() + } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ast := jsoniter.Get(data, "statuses", 2, "id") + _ = ast.ToInt() + } +} + +func BenchmarkParseOne_Parallel_Sonic(b *testing.B) { + ast, _ := NewParser(_TwitterJson).Parse() + node, _ := ast.Get("statuses").Index(2).Get("id").Int64() + if node != 249289491129438208 { + b.Fail() + } b.SetBytes(int64(len(_TwitterJson))) - b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - _, _, _ = Loads(_TwitterJson) + ast, _ := NewParser(_TwitterJson).Parse() + _, _ = ast.Get("statuses").Index(2).Get("id").Int64() } }) } -func BenchmarkGetOne_Gjson(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) - for i := 0; i < b.N; i++ { - ast := gjson.Get(_TwitterJson, "statuses.2.id") - node := ast.Int() - if node != 249289491129438208 { - b.Fatal(node) - } +func BenchmarkParseOne_Parallel_Gjson(b *testing.B) { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.2.id") + v := node.Int() + if v != 249289491129438208 { + b.Fatal(node) } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.2.id") + _ = node.Int() + } + }) } -func BenchmarkGetOne_Jsoniter(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) +func BenchmarkParseOne_Parallel_Jsoniter(b *testing.B) { data := []byte(_TwitterJson) - for i := 0; i < b.N; i++ { - ast := jsoniter.Get(data, "statuses", 2, "id") - node := ast.ToInt() - if node != 249289491129438208 { - b.Fail() - } + ast := jsoniter.Get(data, "statuses", 2, "id") + node := ast.ToInt() + if node != 249289491129438208 { + b.Fail() } + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + data := []byte(_TwitterJson) + ast := jsoniter.Get(data, "statuses", 2, "id") + _ = ast.ToInt() + } + }) } -func BenchmarkGetOne_Sonic(b *testing.B) { +func BenchmarkParseSeven_Sonic(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() for i := 0; i < b.N; i++ { ast, _ := NewParser(_TwitterJson).Parse() - node, _ := ast.Get("statuses").Index(2).Get("id").Int64() - if node != 249289491129438208 { - b.Fail() - } - } -} - -func BenchmarkGetSeven_Gjson(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) - for i := 0; i < b.N; i++ { - ast := gjson.Get(_TwitterJson, "statuses.3.id") - ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.description") - ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.url.urls") - ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.url") - ast = gjson.Get(_TwitterJson, "statuses.3.user.created_at") - ast = gjson.Get(_TwitterJson, "statuses.3.user.name") - ast = gjson.Get(_TwitterJson, "statuses.3.text") - if ast.Value() == nil { - b.Fail() - } - } -} - -func BenchmarkGetSeven_Jsoniter(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) - data := []byte(_TwitterJson) - for i := 0; i < b.N; i++ { - ast := jsoniter.Get(data, "statuses", 3, "id") - ast = jsoniter.Get(data, "statuses", 3, "user", "entities","description") - ast = jsoniter.Get(data, "statuses", 3, "user", "entities","url","urls") - ast = jsoniter.Get(data, "statuses", 3, "user", "entities","url") - ast = jsoniter.Get(data, "statuses", 3, "user", "created_at") - ast = jsoniter.Get(data, "statuses", 3, "user", "name") - ast = jsoniter.Get(data, "statuses", 3, "text") - if ast == nil { - b.Fail() - } - } -} - -func BenchmarkGetSeven_SonicParser(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) - for i := 0; i < b.N; i++ { - ast, _ := NewParser(_TwitterJson).Parse() - node := ast.GetByPath( "statuses", 3, "id") + node := ast.GetByPath("statuses", 3, "id") node = ast.GetByPath("statuses", 3, "user", "entities","description") - node = ast.GetByPath("statuses", 3, "user", "entities","url","urls") + node = ast.GetByPath("statuses", 3, "user", "entities","url","urls") node = ast.GetByPath("statuses", 3, "user", "entities","url") node = ast.GetByPath("statuses", 3, "user", "created_at") node = ast.GetByPath("statuses", 3, "user", "name") node = ast.GetByPath("statuses", 3, "text") - if node == nil { + if node.Check() != nil { b.Fail() } } } + +func BenchmarkParseSeven_Gjson(b *testing.B) { + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.3.id") + node = ast.Get( "statuses.3.user.entities.description") + node = ast.Get( "statuses.3.user.entities.url.urls") + node = ast.Get( "statuses.3.user.entities.url") + node = ast.Get( "statuses.3.user.created_at") + node = ast.Get( "statuses.3.user.name") + node = ast.Get( "statuses.3.text") + if node.Value() == nil { + b.Fail() + } + } +} + +func BenchmarkParseSeven_Jsoniter(b *testing.B) { + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + data := []byte(_TwitterJson) + for i := 0; i < b.N; i++ { + ast := jsoniter.Get(data) + node := ast.Get("statuses", 3, "id") + node = ast.Get("statuses", 3, "user", "entities","description") + node = ast.Get("statuses", 3, "user", "entities","url","urls") + node = ast.Get("statuses", 3, "user", "entities","url") + node = ast.Get("statuses", 3, "user", "created_at") + node = ast.Get("statuses", 3, "user", "name") + node = ast.Get("statuses", 3, "text") + if node.LastError() != nil { + b.Fail() + } + } +} + +func BenchmarkParseSeven_Parallel_Sonic(b *testing.B) { + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + ast, _ := NewParser(_TwitterJson).Parse() + node := ast.GetByPath("statuses", 3, "id") + node = ast.GetByPath("statuses", 3, "user", "entities","description") + node = ast.GetByPath("statuses", 3, "user", "entities","url","urls") + node = ast.GetByPath("statuses", 3, "user", "entities","url") + node = ast.GetByPath("statuses", 3, "user", "created_at") + node = ast.GetByPath("statuses", 3, "user", "name") + node = ast.GetByPath("statuses", 3, "text") + if node.Check() != nil { + b.Fail() + } + } + }) +} + +func BenchmarkParseSeven_Parallel_Gjson(b *testing.B) { + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + ast := gjson.Parse(_TwitterJson) + node := ast.Get("statuses.3.id") + node = ast.Get( "statuses.3.user.entities.description") + node = ast.Get( "statuses.3.user.entities.url.urls") + node = ast.Get( "statuses.3.user.entities.url") + node = ast.Get( "statuses.3.user.created_at") + node = ast.Get( "statuses.3.user.name") + node = ast.Get( "statuses.3.text") + if node.Value() == nil { + b.Fail() + } + } + }) +} + +func BenchmarkParseSeven_Parallel_Jsoniter(b *testing.B) { + b.SetBytes(int64(len(_TwitterJson))) + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + data := []byte(_TwitterJson) + ast := jsoniter.Get(data) + node := ast.Get("statuses", 3, "id") + node = ast.Get("statuses", 3, "user", "entities","description") + node = ast.Get("statuses", 3, "user", "entities","url","urls") + node = ast.Get("statuses", 3, "user", "entities","url") + node = ast.Get("statuses", 3, "user", "created_at") + node = ast.Get("statuses", 3, "user", "name") + node = ast.Get("statuses", 3, "text") + if node.LastError() != nil { + b.Fail() + } + } + }) +} diff --git a/ast/search_test.go b/ast/search_test.go index 2d86d64..a2f8b2d 100644 --- a/ast/search_test.go +++ b/ast/search_test.go @@ -21,7 +21,11 @@ import ( `runtime` `runtime/debug` `sync` + `fmt` + `math` + `strconv` + `github.com/tidwall/sjson` jsoniter `github.com/json-iterator/go` `github.com/stretchr/testify/assert` `github.com/tidwall/gjson` @@ -190,7 +194,7 @@ func TestSearchNotExist(t *testing.T) { } } -func BenchmarkSearchOne_Gjson(b *testing.B) { +func BenchmarkGetOne_Gjson(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) for i := 0; i < b.N; i++ { ast := gjson.Get(_TwitterJson, "statuses.3.id") @@ -201,7 +205,7 @@ func BenchmarkSearchOne_Gjson(b *testing.B) { } } -func BenchmarkSearchOne_Jsoniter(b *testing.B) { +func BenchmarkGetOne_Jsoniter(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) data := []byte(_TwitterJson) for i := 0; i < b.N; i++ { @@ -213,7 +217,7 @@ func BenchmarkSearchOne_Jsoniter(b *testing.B) { } } -func BenchmarkSearchOne_Sonic(b *testing.B) { +func BenchmarkGetOne_Sonic(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) ast := NewSearcher(_TwitterJson) for i := 0; i < b.N; i++ { @@ -228,9 +232,8 @@ func BenchmarkSearchOne_Sonic(b *testing.B) { } } -func BenchmarkSearchOne_Parallel_Gjson(b *testing.B) { +func BenchmarkGetOne_Parallel_Gjson(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) - b.SetParallelism(parallelism) b.RunParallel(func(pb *testing.PB) { for pb.Next() { ast := gjson.Get(_TwitterJson, "statuses.3.id") @@ -242,10 +245,9 @@ func BenchmarkSearchOne_Parallel_Gjson(b *testing.B) { }) } -func BenchmarkSearchOne_Parallel_Jsoniter(b *testing.B) { +func BenchmarkGetOne_Parallel_Jsoniter(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) data := []byte(_TwitterJson) - b.SetParallelism(parallelism) b.RunParallel(func(pb *testing.PB) { for pb.Next() { ast := jsoniter.Get(data, "statuses", 3, "id") @@ -257,9 +259,8 @@ func BenchmarkSearchOne_Parallel_Jsoniter(b *testing.B) { }) } -func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) { +func BenchmarkGetOne_Parallel_Sonic(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) - b.SetParallelism(parallelism) b.RunParallel(func(pb *testing.PB) { ast := NewSearcher(_TwitterJson) for pb.Next() { @@ -274,3 +275,107 @@ func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) { } }) } + +func BenchmarkSetOne_Sonic(b *testing.B) { + node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + if err != nil { + b.Fatal(err) + } + n := NewNumber(strconv.Itoa(math.MaxInt32)) + _, err = node.Set("id", n) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + _, _ = node.Set("id", n) + } +} + +func BenchmarkSetOne_Sjson(b *testing.B) { + path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") + _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sjson.Set(_TwitterJson, path, math.MaxInt32) + } +} + +func BenchmarkSetOne_Jsoniter(b *testing.B) { + data := []byte(_TwitterJson) + node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + if !ok { + b.Fatal(node) + } + + b.SetBytes(int64(len(data))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + node["id"] = math.MaxInt32 + } +} + +func BenchmarkSetOne_Parallel_Sonic(b *testing.B) { + node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + if err != nil { + b.Fatal(err) + } + n := NewNumber(strconv.Itoa(math.MaxInt32)) + _, err = node.Set("id", n) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + _, _ = node.Set("id", n) + } + }) +} + +func BenchmarkSetOne_Parallel_Sjson(b *testing.B) { + path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") + _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + sjson.Set(_TwitterJson, path, math.MaxInt32) + } + }) +} + +func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) { + data := []byte(_TwitterJson) + node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + if !ok { + b.Fatal(node) + } + + b.SetBytes(int64(len(data))) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + node["id"] = math.MaxInt32 + } + }) +} \ No newline at end of file diff --git a/bench-large.jpg b/bench-large.jpg new file mode 100644 index 0000000..8be0111 Binary files /dev/null and b/bench-large.jpg differ diff --git a/bench-large.png b/bench-large.png deleted file mode 100644 index 2c5bdf0..0000000 Binary files a/bench-large.png and /dev/null differ diff --git a/bench-small.jpg b/bench-small.jpg new file mode 100644 index 0000000..705d555 Binary files /dev/null and b/bench-small.jpg differ diff --git a/bench-small.png b/bench-small.png deleted file mode 100644 index 5d76b0f..0000000 Binary files a/bench-small.png and /dev/null differ diff --git a/bench.sh b/bench.sh index 36b692b..f6c95db 100644 --- a/bench.sh +++ b/bench.sh @@ -10,11 +10,11 @@ cd $pwd/decoder go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkDecoder_Generic_Sonic|BenchmarkDecoder_Generic_StdLib|BenchmarkDecoder_Generic_JsonIter|BenchmarkDecoder_Generic_GoJson|BenchmarkDecoder_Binding_Sonic|BenchmarkDecoder_Binding_StdLib|BenchmarkDecoder_Binding_JsonIter|BenchmarkDecoder_Binding_GoJson|BenchmarkDecoder_Parallel_Generic_Sonic|BenchmarkDecoder_Parallel_Generic_StdLib|BenchmarkDecoder_Parallel_Generic_JsonIter|BenchmarkDecoder_Parallel_Generic_GoJson|BenchmarkDecoder_Parallel_Binding_Sonic|BenchmarkDecoder_Parallel_Binding_StdLib|BenchmarkDecoder_Parallel_Binding_JsonIter|BenchmarkDecoder_Parallel_Binding_GoJson)$" cd $pwd/ast -go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkSearchOne_Gjson|BenchmarkSearchOne_Jsoniter|BenchmarkSearchOne_Sonic|BenchmarkSearchOne_Parallel_Gjson|BenchmarkSearchOne_Parallel_Jsoniter|BenchmarkSearchOne_Parallel_Sonic)$" -go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_StdLib|BenchmarkParser_JsonIter|BenchmarkParser_Sonic|BenchmarkParser_Parallel_StdLib|BenchmarkParser_Parallel_JsonIter|BenchmarkParser_Parallel_Sonic|BenchmarkGetOne_Gjson|BenchmarkGetOne_Jsoniter|BenchmarkGetOne_Sonic|BenchmarkGetSeven_Gjson|BenchmarkGetSeven_Jsoniter|BenchmarkGetSeven_SonicParser)$" +go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkGetOne_Sonic|BenchmarkGetOne_Gjson|BenchmarkGetOne_Jsoniter|BenchmarkGetOne_Parallel_Sonic|BenchmarkGetOne_Parallel_Gjson|BenchmarkGetOne_Parallel_Jsoniter|BenchmarkSetOne_Sonic|BenchmarkSetOne_Sjson|BenchmarkSetOne_Jsoniter|BenchmarkSetOne_Parallel_Sonic|BenchmarkSetOne_Parallel_Sjson|BenchmarkSetOne_Parallel_Jsoniter)$" +go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_Sonic|BenchmarkParser_Gjson|BenchmarkParser_JsonIter|BenchmarkParser_Parallel_Sonic|BenchmarkParser_Parallel_Gjson|BenchmarkParser_Parallel_StdLib|BenchmarkParser_Parallel_JsonIter|BenchmarkParseOne_Sonic|BenchmarkParseOne_Gjson|BenchmarkParseOne_Jsoniter|BenchmarkParseOne_Parallel_Sonic|BenchmarkParseOne_Parallel_Gjson|BenchmarkParseOne_Parallel_Jsoniter|BenchmarkParseSeven_Sonic|BenchmarkParseSeven_Gjson|BenchmarkParseSeven_Jsoniter|BenchmarkParseSeven_Parallel_Sonic|BenchmarkParseSeven_Parallel_Gjson|BenchmarkParseSeven_Parallel_Jsoniter)$" go test -benchmem -run=^$ -benchtime=100000x -bench '^(BenchmarkEncodeRaw|BenchmarkEncodeSkip|BenchmarkEncodeLoad)$' -go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath_Jsoniter|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$" +go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$" unset SONIC_NO_ASYNC_GC cd $pwd \ No newline at end of file diff --git a/decoder/decoder.go b/decoder/decoder.go index 232e0ca..797174e 100644 --- a/decoder/decoder.go +++ b/decoder/decoder.go @@ -122,8 +122,6 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) { /* compile function */ compiler := newCompiler().apply(opts) - - /* compile function */ decoder := func(vt *rt.GoType) (interface{}, error) { if pp, err := compiler.compile(_vt); err != nil { return nil, err diff --git a/go.mod b/go.mod index 65ad1fb..30cc256 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/json-iterator/go v1.1.10 github.com/klauspost/cpuid/v2 v2.0.9 github.com/stretchr/testify v1.7.0 - github.com/tidwall/gjson v1.8.0 + github.com/tidwall/gjson v1.10.2 + github.com/tidwall/sjson v1.2.3 github.com/twitchyliquid64/golang-asm v0.15.1 ) diff --git a/go.sum b/go.sum index 1bca761..a501f40 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -github.com/chenzhuoyu/base64x v0.0.0-20210823082418-56861234f7ea/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -17,17 +16,18 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= -github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= -github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8= +github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=