Skip to content

Commit 4a3e8af

Browse files
authored
opt: support NoCopyRawMessage (#708)
1 parent b1872c1 commit 4a3e8af

File tree

2 files changed

+216
-21
lines changed

2 files changed

+216
-21
lines changed

decode_test.go

+173-21
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,28 @@
2020
package sonic
2121

2222
import (
23-
`bytes`
24-
`encoding`
25-
`encoding/json`
26-
`errors`
27-
`fmt`
28-
`image`
29-
`math`
30-
`math/big`
31-
`math/rand`
32-
`net`
33-
`reflect`
34-
`strconv`
35-
`strings`
36-
`testing`
37-
`time`
38-
`unsafe`
39-
40-
`github.com/bytedance/sonic/decoder`
41-
`github.com/bytedance/sonic/internal/native/types`
42-
`github.com/davecgh/go-spew/spew`
43-
`github.com/stretchr/testify/assert`
23+
"bytes"
24+
"encoding"
25+
"encoding/json"
26+
"errors"
27+
"fmt"
28+
"image"
29+
"math"
30+
"math/big"
31+
"math/rand"
32+
"net"
33+
"reflect"
34+
"runtime"
35+
"strconv"
36+
"strings"
37+
"testing"
38+
"time"
39+
"unsafe"
40+
41+
"github.com/bytedance/sonic/decoder"
42+
"github.com/bytedance/sonic/internal/native/types"
43+
"github.com/davecgh/go-spew/spew"
44+
"github.com/stretchr/testify/assert"
4445
)
4546

4647
type T struct {
@@ -2815,3 +2816,154 @@ func TestUseNumber(t *testing.T) {
28152816
}
28162817
}
28172818
}
2819+
2820+
2821+
func BenchmarkDecoderRawMessage(b *testing.B) {
2822+
data := ` {
2823+
"coordinates": null,
2824+
"favorited": false,
2825+
"truncated": false,
2826+
"created_at": "Mon Sep 24 03:35:21 +0000 2012",
2827+
"id_str": "250075927172759552",
2828+
"entities": {
2829+
"urls": [
2830+
2831+
],
2832+
"hashtags": [
2833+
{
2834+
"text": "freebandnames",
2835+
"indices": [
2836+
20,
2837+
34
2838+
]
2839+
}
2840+
],
2841+
"user_mentions": [
2842+
2843+
]
2844+
},
2845+
"in_reply_to_user_id_str": null,
2846+
"contributors": null,
2847+
"text": "Aggressive Ponytail #freebandnames",
2848+
"metadata": {
2849+
"iso_language_code": "en",
2850+
"result_type": "recent"
2851+
},
2852+
"retweet_count": 0,
2853+
"in_reply_to_status_id_str": null,
2854+
"id": 250075927172759552,
2855+
"geo": null,
2856+
"retweeted": false,
2857+
"in_reply_to_user_id": null,
2858+
"place": null,
2859+
"user": {
2860+
"profile_sidebar_fill_color": "DDEEF6",
2861+
"profile_sidebar_border_color": "C0DEED",
2862+
"profile_background_tile": false,
2863+
"name": "Sean Cummings",
2864+
"profile_image_url": "https://a0.twimg.com/profile_images/2359746665/1v6zfgqo8g0d3mk7ii5s_normal.jpeg",
2865+
"created_at": "Mon Apr 26 06:01:55 +0000 2010",
2866+
"location": "LA, CA",
2867+
"follow_request_sent": null,
2868+
"profile_link_color": "0084B4",
2869+
"is_translator": false,
2870+
"id_str": "137238150",
2871+
"entities": {
2872+
"url": {
2873+
"urls": [
2874+
{
2875+
"expanded_url": null,
2876+
"url": "",
2877+
"indices": [
2878+
0,
2879+
0
2880+
]
2881+
}
2882+
]
2883+
},
2884+
"description": {
2885+
"urls": [
2886+
2887+
]
2888+
}
2889+
},
2890+
"default_profile": true,
2891+
"contributors_enabled": false,
2892+
"favourites_count": 0,
2893+
"url": null,
2894+
"profile_image_url_https": "https://si0.twimg.com/profile_images/2359746665/1v6zfgqo8g0d3mk7ii5s_normal.jpeg",
2895+
"utc_offset": -28800,
2896+
"id": 137238150,
2897+
"profile_use_background_image": true,
2898+
"listed_count": 2,
2899+
"profile_text_color": "333333",
2900+
"lang": "en",
2901+
"followers_count": 70,
2902+
"protected": false,
2903+
"notifications": null,
2904+
"profile_background_image_url_https": "https://si0.twimg.com/images/themes/theme1/bg.png",
2905+
"profile_background_color": "C0DEED",
2906+
"verified": false,
2907+
"geo_enabled": true,
2908+
"time_zone": "Pacific Time (US & Canada)",
2909+
"description": "Born 330 Live 310",
2910+
"default_profile_image": false,
2911+
"profile_background_image_url": "https://a0.twimg.com/images/themes/theme1/bg.png",
2912+
"statuses_count": 579,
2913+
"friends_count": 110,
2914+
"following": null,
2915+
"show_all_inline_media": false,
2916+
"screen_name": "sean_cummings"
2917+
},
2918+
"in_reply_to_screen_name": null,
2919+
"source": "<a href=\"//itunes.apple.com/us/app/twitter/id409789998?mt=12%5C%22\" rel=\"\\\"nofollow\\\"\">Twitter for Mac</a>",
2920+
"in_reply_to_status_id": null
2921+
}`
2922+
2923+
bench := func(b *testing.B, run func(b *testing.B) ) {
2924+
b.ResetTimer()
2925+
b.ReportAllocs()
2926+
b.SetBytes(int64(len(data)))
2927+
for i := 0; i < b.N; i++ {
2928+
run(b)
2929+
}
2930+
runtime.GC()
2931+
}
2932+
2933+
b.Run("StdRawMessage", func(b *testing.B) {
2934+
bench(b, func(b *testing.B) {
2935+
var obj map[string]json.RawMessage
2936+
dc := decoder.NewDecoder(data)
2937+
dc.SetOptions(decoder.OptionUseNumber)
2938+
if err := dc.Decode(&obj); err!= nil {
2939+
b.Fatal(err.Error())
2940+
}
2941+
_ = obj
2942+
})
2943+
})
2944+
2945+
b.Run("NocopyRawMessage", func(b *testing.B) {
2946+
bench(b, func(b *testing.B) {
2947+
var obj map[string]NoCopyRawMessage
2948+
dc := decoder.NewDecoder(data)
2949+
dc.SetOptions(decoder.OptionUseNumber)
2950+
if err := dc.Decode(&obj); err!= nil {
2951+
b.Fatal(err.Error())
2952+
}
2953+
_ = obj
2954+
})
2955+
})
2956+
2957+
2958+
b.Run("NocopyRawMessageWithoutValidation", func(b *testing.B) {
2959+
bench(b, func(b *testing.B) {
2960+
var obj map[string]NoCopyRawMessage
2961+
dc := decoder.NewDecoder(data)
2962+
dc.SetOptions(decoder.OptionNoValidateJSON | decoder.OptionUseNumber)
2963+
if err := dc.Decode(&obj); err!= nil {
2964+
b.Fatal(err.Error())
2965+
}
2966+
_ = obj
2967+
})
2968+
})
2969+
}

rawmessage.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2024 ByteDance Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package sonic
18+
19+
import (
20+
"errors"
21+
)
22+
23+
// NoCopyRawMessage is a NOCOPY raw encoded JSON value.
24+
// It implements [Marshaler] and [Unmarshaler] and can
25+
// be used to delay JSON decoding or precompute a JSON encoding.
26+
type NoCopyRawMessage []byte
27+
28+
// MarshalJSON returns m as the JSON encoding of m.
29+
func (m NoCopyRawMessage) MarshalJSON() ([]byte, error) {
30+
if m == nil {
31+
return []byte("null"), nil
32+
}
33+
return m, nil
34+
}
35+
36+
// UnmarshalJSON sets *m to a reference of data. NoCopy here!!!
37+
func (m *NoCopyRawMessage) UnmarshalJSON(data []byte) error {
38+
if m == nil {
39+
return errors.New("sonic.NoCopyRawMessage: UnmarshalJSON on nil pointer")
40+
}
41+
*m = data
42+
return nil
43+
}

0 commit comments

Comments
 (0)