github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/encoder/encoder_test.go (about)

     1  /*
     2   * Copyright 2021 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 encoder
    18  
    19  import (
    20  	"bytes"
    21  	"encoding"
    22  	"encoding/json"
    23  	"runtime"
    24  	"runtime/debug"
    25  	"strconv"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/goshafaq/sonic/internal/rt"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestMain(m *testing.M) {
    35  	go func() {
    36  		if !debugAsyncGC {
    37  			return
    38  		}
    39  		println("Begin GC looping...")
    40  		for {
    41  			runtime.GC()
    42  			debug.FreeOSMemory()
    43  		}
    44  		println("stop GC looping!")
    45  	}()
    46  	time.Sleep(time.Millisecond)
    47  	m.Run()
    48  }
    49  
    50  func TestGC(t *testing.T) {
    51  	if debugSyncGC {
    52  		return
    53  	}
    54  	out, err := Encode(_GenericValue, 0)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	n := len(out)
    59  	wg := &sync.WaitGroup{}
    60  	N := 10000
    61  	for i := 0; i < N; i++ {
    62  		wg.Add(1)
    63  		go func(wg *sync.WaitGroup, size int) {
    64  			defer wg.Done()
    65  			out, err := Encode(_GenericValue, 0)
    66  			if err != nil {
    67  				t.Fatal(err)
    68  			}
    69  			if len(out) != size {
    70  				t.Fatal(len(out), size)
    71  			}
    72  			runtime.GC()
    73  		}(wg, n)
    74  	}
    75  	wg.Wait()
    76  }
    77  
    78  type sample struct {
    79  	M  map[string]interface{}
    80  	S  []interface{}
    81  	A  [0]interface{}
    82  	MP *map[string]interface{}
    83  	SP *[]interface{}
    84  	AP *[0]interface{}
    85  }
    86  
    87  func TestOptionSliceOrMapNoNull(t *testing.T) {
    88  	obj := sample{}
    89  	out, err := Encode(obj, NoNullSliceOrMap)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	require.Equal(t, `{"M":{},"S":[],"A":[],"MP":null,"SP":null,"AP":null}`, string(out))
    94  
    95  	obj2 := sample{}
    96  	out, err = Encode(obj2, 0)
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	require.Equal(t, `{"M":null,"S":null,"A":[],"MP":null,"SP":null,"AP":null}`, string(out))
   101  }
   102  
   103  func BenchmarkOptionSliceOrMapNoNull(b *testing.B) {
   104  	b.Run("true", func(b *testing.B) {
   105  		obj := sample{}
   106  		_, err := Encode(obj, NoNullSliceOrMap)
   107  		if err != nil {
   108  			b.Fatal(err)
   109  		}
   110  		b.ResetTimer()
   111  		for i := 0; i < b.N; i++ {
   112  			_, _ = Encode(obj, NoNullSliceOrMap)
   113  		}
   114  	})
   115  
   116  	b.Run("false", func(b *testing.B) {
   117  		obj2 := sample{}
   118  		_, err := Encode(obj2, 0)
   119  		if err != nil {
   120  			b.Fatal(err)
   121  		}
   122  		for i := 0; i < b.N; i++ {
   123  			_, _ = Encode(obj2, 0)
   124  		}
   125  	})
   126  }
   127  
   128  func runEncoderTest(t *testing.T, fn func(string) string, exp string, arg string) {
   129  	require.Equal(t, exp, fn(arg))
   130  }
   131  
   132  func TestEncoder_String(t *testing.T) {
   133  	runEncoderTest(t, Quote, `""`, "")
   134  	runEncoderTest(t, Quote, `"hello, world"`, "hello, world")
   135  	runEncoderTest(t, Quote, `"hello啊啊啊aa"`, "hello啊啊啊aa")
   136  	runEncoderTest(t, Quote, `"hello\\\"world"`, "hello\\\"world")
   137  	runEncoderTest(t, Quote, `"hello\n\tworld"`, "hello\n\tworld")
   138  	runEncoderTest(t, Quote, `"hello\u0000\u0001world"`, "hello\x00\x01world")
   139  	runEncoderTest(t, Quote, `"hello\u0000\u0001world"`, "hello\x00\x01world")
   140  	runEncoderTest(t, Quote, `"Cartoonist, Illustrator, and T-Shirt connoisseur"`, "Cartoonist, Illustrator, and T-Shirt connoisseur")
   141  }
   142  
   143  type StringStruct struct {
   144  	X *int        `json:"x,string,omitempty"`
   145  	Y []int       `json:"y"`
   146  	Z json.Number `json:"z,string"`
   147  	W string      `json:"w,string"`
   148  }
   149  
   150  func TestEncoder_FieldStringize(t *testing.T) {
   151  	x := 12345
   152  	v := StringStruct{X: &x, Y: []int{1, 2, 3}, Z: "4567456", W: "asdf"}
   153  	r, e := Encode(v, 0)
   154  	require.NoError(t, e)
   155  	println(string(r))
   156  }
   157  
   158  func TestEncodeErrorAndScratchBuf(t *testing.T) {
   159  	var obj = map[string]interface{}{
   160  		"a": json.RawMessage(" [} "),
   161  	}
   162  	buf := make([]byte, 0, 10)
   163  	_ = EncodeInto(&buf, obj, 0)
   164  	if len(buf) < 0 || len(buf) > 10 {
   165  		println(buf)
   166  		t.Fatal()
   167  	}
   168  }
   169  
   170  type MarshalerImpl struct {
   171  	X int
   172  }
   173  
   174  func (self *MarshalerImpl) MarshalJSON() ([]byte, error) {
   175  	ret := []byte(strconv.Itoa(self.X))
   176  	return append(ret, "    "...), nil
   177  }
   178  
   179  type MarshalerStruct struct {
   180  	V MarshalerImpl
   181  }
   182  
   183  func TestEncoder_Marshaler(t *testing.T) {
   184  	v := MarshalerStruct{V: MarshalerImpl{X: 12345}}
   185  	ret, err := Encode(&v, 0)
   186  	require.NoError(t, err)
   187  	require.Equal(t, `{"V":12345    }`, string(ret))
   188  	ret, err = Encode(v, 0)
   189  	require.NoError(t, err)
   190  	require.Equal(t, `{"V":{"X":12345}}`, string(ret))
   191  
   192  	ret2, err2 := Encode(&v, 0)
   193  	require.NoError(t, err2)
   194  	require.Equal(t, `{"V":12345    }`, string(ret2))
   195  	ret3, err3 := Encode(v, CompactMarshaler)
   196  	require.NoError(t, err3)
   197  	require.Equal(t, `{"V":{"X":12345}}`, string(ret3))
   198  }
   199  
   200  type MarshalerErrorStruct struct {
   201  	V MarshalerImpl
   202  }
   203  
   204  func (self *MarshalerErrorStruct) MarshalJSON() ([]byte, error) {
   205  	return []byte(`[""] {`), nil
   206  }
   207  
   208  func TestMarshalerError(t *testing.T) {
   209  	v := MarshalerErrorStruct{}
   210  	ret, err := Encode(&v, 0)
   211  	require.EqualError(t, err, `invalid Marshaler output json syntax at 5: "[\"\"] {"`)
   212  	require.Equal(t, []byte(nil), ret)
   213  }
   214  
   215  type RawMessageStruct struct {
   216  	X json.RawMessage
   217  }
   218  
   219  func TestEncoder_RawMessage(t *testing.T) {
   220  	rms := RawMessageStruct{
   221  		X: json.RawMessage("123456    "),
   222  	}
   223  	ret, err := Encode(&rms, 0)
   224  	require.NoError(t, err)
   225  	require.Equal(t, `{"X":123456    }`, string(ret))
   226  
   227  	ret, err = Encode(&rms, CompactMarshaler)
   228  	require.NoError(t, err)
   229  	require.Equal(t, `{"X":123456}`, string(ret))
   230  }
   231  
   232  type TextMarshalerImpl struct {
   233  	X string
   234  }
   235  
   236  func (self *TextMarshalerImpl) MarshalText() ([]byte, error) {
   237  	return []byte(self.X), nil
   238  }
   239  
   240  type TextMarshalerImplV struct {
   241  	X string
   242  }
   243  
   244  func (self TextMarshalerImplV) MarshalText() ([]byte, error) {
   245  	return []byte(self.X), nil
   246  }
   247  
   248  type TextMarshalerStruct struct {
   249  	V TextMarshalerImpl
   250  }
   251  
   252  func TestEncoder_TextMarshaler(t *testing.T) {
   253  	v := TextMarshalerStruct{V: TextMarshalerImpl{X: (`{"a"}`)}}
   254  	ret, err := Encode(&v, 0)
   255  	require.NoError(t, err)
   256  	require.Equal(t, `{"V":"{\"a\"}"}`, string(ret))
   257  	ret, err = Encode(v, 0)
   258  	require.NoError(t, err)
   259  	require.Equal(t, `{"V":{"X":"{\"a\"}"}}`, string(ret))
   260  
   261  	ret2, err2 := Encode(&v, NoQuoteTextMarshaler)
   262  	require.NoError(t, err2)
   263  	require.Equal(t, `{"V":{"a"}}`, string(ret2))
   264  	ret3, err3 := Encode(v, NoQuoteTextMarshaler)
   265  	require.NoError(t, err3)
   266  	require.Equal(t, `{"V":{"X":"{\"a\"}"}}`, string(ret3))
   267  }
   268  
   269  func TestTextMarshalTextKey_SortKeys(t *testing.T) {
   270  	v := map[*TextMarshalerImpl]string{
   271  		{"b"}: "b",
   272  		{"c"}: "c",
   273  		{"a"}: "a",
   274  	}
   275  	ret, err := Encode(v, SortMapKeys)
   276  	require.NoError(t, err)
   277  	require.Equal(t, `{"a":"a","b":"b","c":"c"}`, string(ret))
   278  
   279  	v2 := map[TextMarshalerImplV]string{
   280  		{"b"}: "b",
   281  		{"c"}: "c",
   282  		{"a"}: "a",
   283  	}
   284  	ret, err = Encode(v2, SortMapKeys)
   285  	require.NoError(t, err)
   286  	require.Equal(t, `{"a":"a","b":"b","c":"c"}`, string(ret))
   287  
   288  	v3 := map[encoding.TextMarshaler]string{
   289  		TextMarshalerImplV{"b"}: "b",
   290  		&TextMarshalerImpl{"c"}: "c",
   291  		TextMarshalerImplV{"a"}: "a",
   292  	}
   293  	ret, err = Encode(v3, SortMapKeys)
   294  	require.NoError(t, err)
   295  	require.Equal(t, `{"a":"a","b":"b","c":"c"}`, string(ret))
   296  }
   297  
   298  func TestEncoder_Marshal_EscapeHTML(t *testing.T) {
   299  	v := map[string]TextMarshalerImpl{"&&": {"<>"}}
   300  	ret, err := Encode(v, EscapeHTML)
   301  	require.NoError(t, err)
   302  	require.Equal(t, `{"\u0026\u0026":{"X":"\u003c\u003e"}}`, string(ret))
   303  	ret, err = Encode(v, 0)
   304  	require.NoError(t, err)
   305  	require.Equal(t, `{"&&":{"X":"<>"}}`, string(ret))
   306  
   307  	// “ is \xe2\x80\x9c, and ” is \xe2\x80\x9d,
   308  	// similar as HTML escaped chars \u2028(\xe2\x80\xa8) and \u2029(\xe2\x80\xa9)
   309  	m := map[string]string{"test": "“123”"}
   310  	ret, err = Encode(m, EscapeHTML)
   311  	require.Equal(t, string(ret), `{"test":"“123”"}`)
   312  	require.NoError(t, err)
   313  
   314  	m = map[string]string{"K": "\u2028\u2028\xe2"}
   315  	ret, err = Encode(m, EscapeHTML)
   316  	require.Equal(t, string(ret), "{\"K\":\"\\u2028\\u2028\xe2\"}")
   317  	require.NoError(t, err)
   318  }
   319  
   320  func TestEncoder_EscapeHTML(t *testing.T) {
   321  	// test data from libfuzzer
   322  	test := []string{
   323  		"&&&&&&&&&&&&&&&&&&&&&&&\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
   324  		"{\"\"\u2028\x94\xe2\x00\x00\x00\x00\x00\x00\x00\x00\u2028\x80\u2028\x80\u2028\xe2\u2028\x8a\u2028⑀\xa8\x8a\xa8\xe2\u2028\xe2\u2028\xe2\u2028\xe2\u2000\x8d\xe2\u2028\xe2\u2028\xe2\xe2\xa8\"}",
   325  	}
   326  	for _, s := range test {
   327  		data := []byte(s)
   328  		sdst := HTMLEscape(nil, data)
   329  		var dst bytes.Buffer
   330  		json.HTMLEscape(&dst, data)
   331  		require.Equal(t, string(sdst), dst.String())
   332  	}
   333  }
   334  
   335  func TestEncoder_Marshal_EscapeHTML_LargeJson(t *testing.T) {
   336  	buf1, err1 := Encode(&_BindingValue, SortMapKeys|EscapeHTML)
   337  	require.NoError(t, err1)
   338  	buf2, err2 := json.Marshal(&_BindingValue)
   339  	require.NoError(t, err2)
   340  	require.Equal(t, buf1, buf2)
   341  }
   342  
   343  var _GenericValue interface{}
   344  var _BindingValue TwitterStruct
   345  
   346  func init() {
   347  	_ = json.Unmarshal([]byte(TwitterJson), &_GenericValue)
   348  	_ = json.Unmarshal([]byte(TwitterJson), &_BindingValue)
   349  }
   350  
   351  func TestEncoder_Generic(t *testing.T) {
   352  	v, e := Encode(_GenericValue, 0)
   353  	require.NoError(t, e)
   354  	println(string(v))
   355  }
   356  
   357  func TestEncoder_Binding(t *testing.T) {
   358  	v, e := Encode(_BindingValue, 0)
   359  	require.NoError(t, e)
   360  	println(string(v))
   361  }
   362  
   363  func TestEncoder_MapSortKey(t *testing.T) {
   364  	m := map[string]string{
   365  		"C": "third",
   366  		"D": "forth",
   367  		"A": "first",
   368  		"F": "sixth",
   369  		"E": "fifth",
   370  		"B": "second",
   371  	}
   372  	v, e := Encode(m, SortMapKeys)
   373  	require.NoError(t, e)
   374  	require.Equal(t, `{"A":"first","B":"second","C":"third","D":"forth","E":"fifth","F":"sixth"}`, string(v))
   375  }
   376  
   377  func BenchmarkEncoder_Generic_Sonic(b *testing.B) {
   378  	_, _ = Encode(_GenericValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   379  	b.SetBytes(int64(len(TwitterJson)))
   380  	b.ResetTimer()
   381  	for i := 0; i < b.N; i++ {
   382  		_, _ = Encode(_GenericValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   383  	}
   384  }
   385  
   386  func BenchmarkEncoder_Generic_Sonic_Fast(b *testing.B) {
   387  	_, _ = Encode(_GenericValue, 0)
   388  	b.SetBytes(int64(len(TwitterJson)))
   389  	b.ResetTimer()
   390  	for i := 0; i < b.N; i++ {
   391  		_, _ = Encode(_GenericValue, 0)
   392  	}
   393  }
   394  
   395  func BenchmarkEncoder_Generic_StdLib(b *testing.B) {
   396  	_, _ = json.Marshal(_GenericValue)
   397  	b.SetBytes(int64(len(TwitterJson)))
   398  	b.ResetTimer()
   399  	for i := 0; i < b.N; i++ {
   400  		_, _ = json.Marshal(_GenericValue)
   401  	}
   402  }
   403  
   404  func BenchmarkEncoder_Binding_Sonic(b *testing.B) {
   405  	_, _ = Encode(&_BindingValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   406  	b.SetBytes(int64(len(TwitterJson)))
   407  	b.ResetTimer()
   408  	for i := 0; i < b.N; i++ {
   409  		_, _ = Encode(&_BindingValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   410  	}
   411  }
   412  
   413  func BenchmarkEncoder_Binding_Sonic_Fast(b *testing.B) {
   414  	_, _ = Encode(&_BindingValue, NoQuoteTextMarshaler)
   415  	b.SetBytes(int64(len(TwitterJson)))
   416  	b.ResetTimer()
   417  	for i := 0; i < b.N; i++ {
   418  		_, _ = Encode(&_BindingValue, NoQuoteTextMarshaler)
   419  	}
   420  }
   421  
   422  func BenchmarkEncoder_Binding_StdLib(b *testing.B) {
   423  	_, _ = json.Marshal(&_BindingValue)
   424  	b.SetBytes(int64(len(TwitterJson)))
   425  	b.ResetTimer()
   426  	for i := 0; i < b.N; i++ {
   427  		_, _ = json.Marshal(&_BindingValue)
   428  	}
   429  }
   430  
   431  func BenchmarkEncoder_Parallel_Generic_Sonic(b *testing.B) {
   432  	_, _ = Encode(_GenericValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   433  	b.SetBytes(int64(len(TwitterJson)))
   434  	b.ResetTimer()
   435  	b.RunParallel(func(pb *testing.PB) {
   436  		for pb.Next() {
   437  			_, _ = Encode(_GenericValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   438  		}
   439  	})
   440  }
   441  
   442  func BenchmarkEncoder_Parallel_Generic_Sonic_Fast(b *testing.B) {
   443  	_, _ = Encode(_GenericValue, NoQuoteTextMarshaler)
   444  	b.SetBytes(int64(len(TwitterJson)))
   445  	b.ResetTimer()
   446  	b.RunParallel(func(pb *testing.PB) {
   447  		for pb.Next() {
   448  			_, _ = Encode(_GenericValue, NoQuoteTextMarshaler)
   449  		}
   450  	})
   451  }
   452  
   453  func BenchmarkEncoder_Parallel_Generic_StdLib(b *testing.B) {
   454  	_, _ = json.Marshal(_GenericValue)
   455  	b.SetBytes(int64(len(TwitterJson)))
   456  	b.ResetTimer()
   457  	b.RunParallel(func(pb *testing.PB) {
   458  		for pb.Next() {
   459  			_, _ = json.Marshal(_GenericValue)
   460  		}
   461  	})
   462  }
   463  
   464  func BenchmarkEncoder_Parallel_Binding_Sonic(b *testing.B) {
   465  	_, _ = Encode(&_BindingValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   466  	b.SetBytes(int64(len(TwitterJson)))
   467  	b.ResetTimer()
   468  	b.RunParallel(func(pb *testing.PB) {
   469  		for pb.Next() {
   470  			_, _ = Encode(&_BindingValue, SortMapKeys|EscapeHTML|CompactMarshaler)
   471  		}
   472  	})
   473  }
   474  
   475  func BenchmarkEncoder_Parallel_Binding_Sonic_Fast(b *testing.B) {
   476  	_, _ = Encode(&_BindingValue, NoQuoteTextMarshaler)
   477  	b.SetBytes(int64(len(TwitterJson)))
   478  	b.ResetTimer()
   479  	b.RunParallel(func(pb *testing.PB) {
   480  		for pb.Next() {
   481  			_, _ = Encode(&_BindingValue, NoQuoteTextMarshaler)
   482  		}
   483  	})
   484  }
   485  
   486  func BenchmarkEncoder_Parallel_Binding_StdLib(b *testing.B) {
   487  	_, _ = json.Marshal(&_BindingValue)
   488  	b.SetBytes(int64(len(TwitterJson)))
   489  	b.ResetTimer()
   490  	b.RunParallel(func(pb *testing.PB) {
   491  		for pb.Next() {
   492  			_, _ = json.Marshal(&_BindingValue)
   493  		}
   494  	})
   495  }
   496  
   497  func BenchmarkHTMLEscape_Sonic(b *testing.B) {
   498  	jsonByte := []byte(TwitterJson)
   499  	b.SetBytes(int64(len(TwitterJson)))
   500  	b.ResetTimer()
   501  	var buf []byte
   502  	for i := 0; i < b.N; i++ {
   503  		buf = HTMLEscape(nil, jsonByte)
   504  	}
   505  	_ = buf
   506  }
   507  
   508  func BenchmarkHTMLEscape_StdLib(b *testing.B) {
   509  	jsonByte := []byte(TwitterJson)
   510  	b.SetBytes(int64(len(TwitterJson)))
   511  	b.ResetTimer()
   512  	var buf []byte
   513  	for i := 0; i < b.N; i++ {
   514  		out := bytes.NewBuffer(make([]byte, 0, len(TwitterJson)*6/5))
   515  		json.HTMLEscape(out, jsonByte)
   516  		buf = out.Bytes()
   517  	}
   518  	_ = buf
   519  }
   520  
   521  func BenchmarkValidate_Sonic(b *testing.B) {
   522  	var data = rt.Str2Mem(TwitterJson)
   523  	ok, s := Valid(data)
   524  	if !ok {
   525  		b.Fatal(s)
   526  	}
   527  	b.SetBytes(int64(len(TwitterJson)))
   528  	b.ResetTimer()
   529  	for i := 0; i < b.N; i++ {
   530  		_, _ = Valid(data)
   531  	}
   532  }
   533  
   534  func BenchmarkValidate_Std(b *testing.B) {
   535  	var data = rt.Str2Mem(TwitterJson)
   536  	if !json.Valid(data) {
   537  		b.Fatal()
   538  	}
   539  	b.SetBytes(int64(len(TwitterJson)))
   540  	b.ResetTimer()
   541  	for i := 0; i < b.N; i++ {
   542  		_ = json.Valid(data)
   543  	}
   544  }
   545  
   546  func BenchmarkCompact_Std(b *testing.B) {
   547  	var data = rt.Str2Mem(TwitterJson)
   548  	var dst = bytes.NewBuffer(nil)
   549  	if err := json.Compact(dst, data); err != nil {
   550  		b.Fatal(err)
   551  	}
   552  	b.SetBytes(int64(len(TwitterJson)))
   553  	b.ResetTimer()
   554  	for i := 0; i < b.N; i++ {
   555  		dst.Reset()
   556  		_ = json.Compact(dst, data)
   557  	}
   558  }
   559  
   560  type f64Bench struct {
   561  	name  string
   562  	float float64
   563  }
   564  
   565  func BenchmarkEncode_Float64(b *testing.B) {
   566  	var bench = []f64Bench{
   567  		{"Zero", 0},
   568  		{"ShortDecimal", 1000},
   569  		{"Decimal", 33909},
   570  		{"Float", 339.7784},
   571  		{"Exp", -5.09e75},
   572  		{"NegExp", -5.11e-95},
   573  		{"LongExp", 1.234567890123456e-78},
   574  		{"Big", 123456789123456789123456789},
   575  	}
   576  	maxUint := "18446744073709551615"
   577  	for i := 1; i <= len(maxUint); i++ {
   578  		name := strconv.FormatInt(int64(i), 10) + "-Digs"
   579  		num, _ := strconv.ParseUint(string(maxUint[:i]), 10, 64)
   580  		bench = append(bench, f64Bench{name, float64(num)})
   581  	}
   582  	for _, c := range bench {
   583  		libs := []struct {
   584  			name string
   585  			test func(*testing.B)
   586  		}{{
   587  			name: "StdLib",
   588  			test: func(b *testing.B) {
   589  				_, _ = json.Marshal(c.float)
   590  				for i := 0; i < b.N; i++ {
   591  					_, _ = json.Marshal(c.float)
   592  				}
   593  			},
   594  		}, {
   595  			name: "Sonic",
   596  			test: func(b *testing.B) {
   597  				_, _ = Encode(c.float, 0)
   598  				for i := 0; i < b.N; i++ {
   599  					_, _ = Encode(c.float, 0)
   600  				}
   601  			},
   602  		}}
   603  		for _, lib := range libs {
   604  			name := lib.name + "_" + c.name
   605  			b.Run(name, lib.test)
   606  		}
   607  	}
   608  }
   609  
   610  type f32Bench struct {
   611  	name  string
   612  	float float32
   613  }
   614  
   615  func BenchmarkEncode_Float32(b *testing.B) {
   616  	var bench = []f32Bench{
   617  		{"Zero", 0},
   618  		{"ShortDecimal", 1000},
   619  		{"Decimal", 33909},
   620  		{"ExactFraction", 3.375},
   621  		{"Point", 339.7784},
   622  		{"Exp", -5.09e25},
   623  		{"NegExp", -5.11e-25},
   624  		{"Shortest", 1.234567e-8},
   625  	}
   626  
   627  	maxUint := "18446744073709551615"
   628  	for i := 1; i <= len(maxUint); i++ {
   629  		name := strconv.FormatInt(int64(i), 10) + "-Digs"
   630  		num, _ := strconv.ParseUint(string(maxUint[:i]), 10, 64)
   631  		bench = append(bench, f32Bench{name, float32(num)})
   632  	}
   633  	for _, c := range bench {
   634  		libs := []struct {
   635  			name string
   636  			test func(*testing.B)
   637  		}{{
   638  			name: "StdLib",
   639  			test: func(b *testing.B) {
   640  				_, _ = json.Marshal(c.float)
   641  				for i := 0; i < b.N; i++ {
   642  					_, _ = json.Marshal(c.float)
   643  				}
   644  			},
   645  		}, {
   646  			name: "Sonic",
   647  			test: func(b *testing.B) {
   648  				_, _ = Encode(c.float, 0)
   649  				for i := 0; i < b.N; i++ {
   650  					_, _ = Encode(c.float, 0)
   651  				}
   652  			},
   653  		}}
   654  		for _, lib := range libs {
   655  			name := lib.name + "_" + c.name
   656  			b.Run(name, lib.test)
   657  		}
   658  	}
   659  }