github.com/dgraph-io/simdjson-go@v0.3.0/parse_json_amd64_test.go (about)

     1  //+build !noasm
     2  //+build !appengine
     3  //+build gc
     4  
     5  /*
     6   * MinIO Cloud Storage, (C) 2020 MinIO, Inc.
     7   *
     8   * Licensed under the Apache License, Version 2.0 (the "License");
     9   * you may not use this file except in compliance with the License.
    10   * You may obtain a copy of the License at
    11   *
    12   *     http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing, software
    15   * distributed under the License is distributed on an "AS IS" BASIS,
    16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17   * See the License for the specific language governing permissions and
    18   * limitations under the License.
    19   */
    20  
    21  package simdjson
    22  
    23  import (
    24  	"bytes"
    25  	"errors"
    26  	"fmt"
    27  	"io"
    28  	"math"
    29  	"runtime"
    30  	"strconv"
    31  	"strings"
    32  	"testing"
    33  )
    34  
    35  func TestDemoNdjson(t *testing.T) {
    36  
    37  	pj := internalParsedJson{}
    38  
    39  	if err := pj.parseMessageNdjson([]byte(demo_ndjson)); err != nil {
    40  		t.Errorf("TestDemoNdjson: got: %v want: nil", err)
    41  	}
    42  
    43  	verifyDemoNdjson(pj, t, 0)
    44  }
    45  
    46  func TestNdjsonEmptyLines(t *testing.T) {
    47  
    48  	ndjson_emptylines := []string{`{"zero":"emptylines"}
    49  {"c":"d"}`,
    50  		`{"single":"emptyline"}
    51  
    52  {"c":"d"}`,
    53  		`{"dual":"emptylines"}
    54  
    55  
    56  {"c":"d"}`,
    57  		`{"triple":"emptylines"}
    58  
    59  
    60  
    61  {"c":"d"}`}
    62  
    63  	pj := internalParsedJson{}
    64  
    65  	for _, json := range ndjson_emptylines {
    66  		if err := pj.parseMessageNdjson([]byte(json)); err != nil {
    67  			t.Errorf("TestNdjsonEmptyLine: got: %v want: nil", err)
    68  		}
    69  	}
    70  }
    71  
    72  func BenchmarkNdjsonStage2(b *testing.B) {
    73  	ndjson := loadFile("testdata/parking-citations-1M.json.zst")
    74  	pj := internalParsedJson{}
    75  
    76  	b.SetBytes(int64(len(ndjson)))
    77  	b.ReportAllocs()
    78  	b.ResetTimer()
    79  	for i := 0; i < b.N; i++ {
    80  		err := pj.parseMessageNdjson(ndjson)
    81  		if err != nil {
    82  			panic(err)
    83  		}
    84  	}
    85  }
    86  
    87  func BenchmarkNdjsonStage1(b *testing.B) {
    88  
    89  	ndjson := loadFile("testdata/parking-citations-1M.json.zst")
    90  
    91  	pj := internalParsedJson{}
    92  
    93  	b.SetBytes(int64(len(ndjson)))
    94  	b.ReportAllocs()
    95  	b.ResetTimer()
    96  
    97  	for i := 0; i < b.N; i++ {
    98  		// Create new channel (large enough so we won't block)
    99  		pj.indexChans = make(chan indexChan, 128*10240)
   100  		findStructuralIndices([]byte(ndjson), &pj)
   101  	}
   102  }
   103  
   104  func BenchmarkNdjsonColdCountStar(b *testing.B) {
   105  
   106  	ndjson := loadFile("testdata/parking-citations-1M.json.zst")
   107  
   108  	b.SetBytes(int64(len(ndjson)))
   109  	b.ReportAllocs()
   110  	// Allocate stuff
   111  	pj := internalParsedJson{}
   112  
   113  	b.ResetTimer()
   114  
   115  	for i := 0; i < b.N; i++ {
   116  		pj.parseMessageNdjson(ndjson)
   117  		count_raw_tape(pj.Tape)
   118  	}
   119  }
   120  
   121  func BenchmarkNdjsonColdCountStarWithWhere(b *testing.B) {
   122  	ndjson := loadFile("testdata/parking-citations-1M.json.zst")
   123  	const want = 110349
   124  	runtime.GC()
   125  	pj := internalParsedJson{}
   126  
   127  	b.Run("iter", func(b *testing.B) {
   128  		b.SetBytes(int64(len(ndjson)))
   129  		b.ReportAllocs()
   130  
   131  		for i := 0; i < b.N; i++ {
   132  			err := pj.parseMessageNdjson(ndjson)
   133  			if err != nil {
   134  				b.Fatal(err)
   135  			}
   136  			got := countWhere("Make", "HOND", pj.ParsedJson)
   137  			if got != want {
   138  				b.Fatal(got, "!=", want)
   139  			}
   140  		}
   141  	})
   142  	b.Run("chan", func(b *testing.B) {
   143  		b.SetBytes(int64(len(ndjson)))
   144  		b.ReportAllocs()
   145  
   146  		for i := 0; i < b.N; i++ {
   147  			// Temp values.
   148  			obj := &Object{}
   149  			elem := &Element{}
   150  			var tmp Iter
   151  			var nFound int
   152  			reuse := make(chan *ParsedJson, 1000)
   153  			res := make(chan Stream, 10)
   154  
   155  			ParseNDStream(bytes.NewBuffer(ndjson), res, reuse)
   156  			for got := range res {
   157  				if got.Error != nil {
   158  					if got.Error == io.EOF {
   159  						break
   160  					}
   161  					b.Fatal(got.Error)
   162  				}
   163  
   164  				all := got.Value.Iter()
   165  				// NDJSON is a separated by root objects.
   166  				for all.Advance() == TypeRoot {
   167  					// Read inside root.
   168  					t, i, err := all.Root(&tmp)
   169  					if t != TypeObject {
   170  						b.Log("got type", t.String())
   171  						continue
   172  					}
   173  
   174  					// Prepare object.
   175  					obj, err = i.Object(obj)
   176  					if err != nil {
   177  						b.Log("got err", err)
   178  						continue
   179  					}
   180  
   181  					// Find Make key.
   182  					elem = obj.FindKey("Make", elem)
   183  					if elem.Type != TypeString {
   184  						b.Log("got type", err)
   185  						continue
   186  					}
   187  					asB, err := elem.Iter.StringBytes()
   188  					if err != nil {
   189  						b.Log("got err", err)
   190  						continue
   191  					}
   192  					if bytes.Equal(asB, []byte("HOND")) {
   193  						nFound++
   194  					}
   195  				}
   196  				reuse <- got.Value
   197  			}
   198  			if nFound != want {
   199  				b.Fatal(nFound, "!=", want)
   200  			}
   201  		}
   202  	})
   203  
   204  }
   205  
   206  func TestParseNumber(t *testing.T) {
   207  	testCases := []struct {
   208  		input     string
   209  		wantTag   Tag
   210  		expectedD float64
   211  		expectedI int64
   212  		expectedU uint64
   213  		flags     FloatFlags
   214  	}{
   215  		{input: "1", wantTag: TagInteger, expectedI: 1},
   216  		{input: "-1", wantTag: TagInteger, expectedI: -1},
   217  		{input: "10000000000000000000", wantTag: TagUint, expectedU: 10000000000000000000},
   218  		{input: "10000000000000000001", wantTag: TagUint, expectedU: 10000000000000000001},
   219  		// math.MinInt64 - 1
   220  		{input: "-9223372036854775809", wantTag: TagFloat, expectedD: -9.223372036854776e+18, flags: FloatOverflowedInteger.Flags()},
   221  		{input: "-10000000000000000000", wantTag: TagFloat, expectedD: -10000000000000000000, flags: FloatOverflowedInteger.Flags()},
   222  		{input: "100000000000000000000", wantTag: TagFloat, expectedD: 100000000000000000000, flags: FloatOverflowedInteger.Flags()},
   223  		// math.MaxUint64 +1
   224  		{input: "18446744073709551616", wantTag: TagFloat, expectedD: 1.8446744073709552e+19, flags: FloatOverflowedInteger.Flags()},
   225  		{input: "1.0", wantTag: TagFloat, expectedD: 1.0},
   226  		{input: "1234567890", wantTag: TagInteger, expectedI: 1234567890},
   227  		{input: "9876.543210", wantTag: TagFloat, expectedD: 9876.543210},
   228  		{input: "0.123456789e-12", wantTag: TagFloat, expectedD: 1.23456789e-13},
   229  		{input: "1.234567890E+34", wantTag: TagFloat, expectedD: 1.234567890e+34},
   230  		{input: "23456789012E66", wantTag: TagFloat, expectedD: 23456789012e66},
   231  		{input: "-9876.543210", wantTag: TagFloat, expectedD: -9876.543210},
   232  		{input: "-65.619720000000029", wantTag: TagFloat, expectedD: -65.61972000000003},
   233  	}
   234  
   235  	for _, tc := range testCases {
   236  		tag, val, flags, _ := parseNumber([]byte(fmt.Sprintf(`%s:`, tc.input)))
   237  		if tag != tc.wantTag {
   238  			t.Errorf("TestParseNumber: got: %v want: %v", tag, tc.wantTag)
   239  		}
   240  		switch tag {
   241  		case TagFloat:
   242  			got := math.Float64frombits(val)
   243  			if !closeEnough(got, tc.expectedD) {
   244  				t.Errorf("TestParseNumber: got: %g want: %g", got, tc.expectedD)
   245  			}
   246  		case TagInteger:
   247  			if tc.expectedI != int64(val) {
   248  				t.Errorf("TestParseNumber: got: %d want: %d", int64(val), tc.expectedI)
   249  			}
   250  		case TagUint:
   251  			if tc.expectedU != val {
   252  				t.Errorf("TestParseNumber: got: %d want: %d", val, tc.expectedU)
   253  			}
   254  		}
   255  		if flags != uint64(tc.flags) {
   256  			t.Errorf("TestParseNumber flags; got: %d want: %d", flags, tc.flags)
   257  		}
   258  	}
   259  }
   260  
   261  // The following code is borrowed from Golang (https://golang.org/src/strconv/atoi_test.go)
   262  
   263  type parseInt64Test struct {
   264  	in  string
   265  	out int64
   266  	tag Tag
   267  }
   268  
   269  var parseInt64Tests = []parseInt64Test{
   270  	{"", 0, TagEnd},
   271  	{"0", 0, TagInteger},
   272  	{"-0", 0, TagInteger},
   273  	{"1", 1, TagInteger},
   274  	{"-1", -1, TagInteger},
   275  	{"12345", 12345, TagInteger},
   276  	{"-12345", -12345, TagInteger},
   277  	{"012345", 0, TagEnd},
   278  	{"-012345", 0, TagEnd},
   279  	{"98765432100", 98765432100, TagInteger},
   280  	{"-98765432100", -98765432100, TagInteger},
   281  	{"9223372036854775807", 1<<63 - 1, TagInteger},
   282  	{"-9223372036854775807", -(1<<63 - 1), TagInteger},
   283  	{"9223372036854775808", 1<<63 - 1, TagUint},
   284  	{"-9223372036854775808", -1 << 63, TagInteger},
   285  	{"9223372036854775809", 1<<63 - 1, TagUint},
   286  	{"-9223372036854775809", -1 << 63, TagFloat},
   287  	{"-1_2_3_4_5", 0, TagEnd}, // base=10 so no underscores allowed
   288  	{"-_12345", 0, TagEnd},
   289  	{"_12345", 0, TagEnd},
   290  	{"1__2345", 0, TagEnd},
   291  	{"12345_", 0, TagEnd},
   292  
   293  	// zero (originate from atof tests below, but returned as int for simdjson)
   294  	{"0e0", 0, TagFloat},
   295  	{"-0e0", 0, TagFloat},
   296  	{"0e-0", 0, TagFloat},
   297  	{"-0e-0", 0, TagFloat},
   298  	{"0e+0", 0, TagFloat},
   299  	{"-0e+0", 0, TagFloat},
   300  }
   301  
   302  func TestParseInt64(t *testing.T) {
   303  	for i := range parseInt64Tests {
   304  		test := &parseInt64Tests[i]
   305  		t.Run(test.in, func(t *testing.T) {
   306  
   307  			tag, val, _, _ := parseNumber([]byte(fmt.Sprintf(`%s:`, test.in)))
   308  			if tag != test.tag {
   309  				// Ignore intentionally bad syntactical errors
   310  				t.Errorf("TestParseInt64: got: %v want: %v", tag, test.tag)
   311  				return // skip testing the rest for this test case
   312  			}
   313  			if tag == TagInteger && int64(val) != test.out {
   314  				// Ignore intentionally wrong conversions
   315  				t.Errorf("TestParseInt64: got value: %v want: %v", int64(val), test.out)
   316  			}
   317  		})
   318  
   319  	}
   320  }
   321  
   322  // The following code is borrowed from Golang (https://golang.org/src/strconv/atof_test.go)
   323  
   324  type atofTest struct {
   325  	in  string
   326  	out string
   327  	err error
   328  }
   329  
   330  var atoftests = []atofTest{
   331  	{"", "0", strconv.ErrSyntax}, /* fails for simdjson */
   332  	{"1", "1", nil},              /* parsed as int for simdjson */
   333  	{"+1", "1", nil},             /* parsed as int for simdjson */
   334  
   335  	{"1x", "0", strconv.ErrSyntax},
   336  	{"1.1.", "0", strconv.ErrSyntax},
   337  	{"1e23", "1e+23", nil},
   338  	{"1E23", "1e+23", nil},
   339  	{"100000000000000000000000", "1e+23", nil}, /* parsed as int for simdjson */
   340  	{"1e-100", "1e-100", nil},
   341  	{"123456700", "123456700", nil},                             /* parsed as int for simdjson */
   342  	{"99999999999999974834176", "9.999999999999997e+22", nil},   /* parsed as int for simdjson */
   343  	{"100000000000000000000001", "1.0000000000000001e+23", nil}, /* parsed as int for simdjson */
   344  	{"100000000000000008388608", "1.0000000000000001e+23", nil}, /* parsed as int for simdjson */
   345  	{"100000000000000016777215", "1.0000000000000001e+23", nil}, /* parsed as int for simdjson */
   346  	{"100000000000000016777216", "1.0000000000000003e+23", nil}, /* parsed as int for simdjson */
   347  	{"-1", "-1", nil},                                           /* parsed as int for simdjson */
   348  	{"-0.1", "-0.1", nil},
   349  	{"-0", "0", nil}, /* parsed as int for simdjson */
   350  	{"1e-20", "1e-20", nil},
   351  	{"625e-3", "0.625", nil},
   352  
   353  	// zeros (several test cases for zero have been moved up because they are detected as ints)
   354  	{"+0e0", "0", nil},
   355  	{"+0e-0", "0", nil},
   356  	{"+0e+0", "0", nil},
   357  	{"0e+01234567890123456789", "0", nil},
   358  	{"0.00e-01234567890123456789", "0", nil},
   359  	{"-0e+01234567890123456789", "-0", nil},
   360  	{"-0.00e-01234567890123456789", "-0", nil},
   361  
   362  	{"0e291", "0", nil},   // issue 15364
   363  	{"0e292", "0", nil},   // issue 15364
   364  	{"0e347", "0", nil},   // issue 15364
   365  	{"0e348", "0", nil},   // issue 15364
   366  	{"-0e291", "-0", nil}, /* returns "0" */
   367  	{"-0e292", "-0", nil}, /* returns "0" */
   368  	{"-0e347", "-0", nil}, /* returns "0" */
   369  	{"-0e348", "-0", nil}, /* returns "0" */
   370  
   371  	// NaNs
   372  	{"nan", "NaN", errors.New("invalid json")},
   373  	{"NaN", "NaN", errors.New("invalid json")},
   374  	{"NAN", "NaN", errors.New("invalid json")},
   375  
   376  	// Infs
   377  	{"inf", "+Inf", errors.New("invalid json")},
   378  	{"-Inf", "-Inf", errors.New("invalid json")},
   379  	{"+INF", "+Inf", errors.New("invalid json")},
   380  	{"-Infinity", "-Inf", errors.New("invalid json")},
   381  	{"+INFINITY", "+Inf", errors.New("invalid json")},
   382  	{"Infinity", "+Inf", errors.New("invalid json")},
   383  
   384  	// largest float64
   385  	{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
   386  	{"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
   387  
   388  	// next float64 - too large
   389  	{"1.7976931348623159e308", "+Inf", strconv.ErrRange},
   390  	{"-1.7976931348623159e308", "-Inf", strconv.ErrRange},
   391  
   392  	{"1.7976931348623158e308", "1.7976931348623157e+308", nil},
   393  	{"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
   394  
   395  	// borderline - too large
   396  	{"1.797693134862315808e308", "+Inf", strconv.ErrRange},
   397  	{"-1.797693134862315808e308", "-Inf", strconv.ErrRange},
   398  
   399  	// a little too large
   400  	{"1e308", "1e+308", nil},
   401  	{"2e308", "+Inf", strconv.ErrRange},
   402  	{"1e309", "+Inf", strconv.ErrRange},
   403  
   404  	// way too large
   405  	{"1e310", "+Inf", strconv.ErrRange},
   406  	{"-1e310", "-Inf", strconv.ErrRange},
   407  	{"1e400", "+Inf", strconv.ErrRange},
   408  	{"-1e400", "-Inf", strconv.ErrRange},
   409  	{"1e400000", "+Inf", strconv.ErrRange},
   410  	{"-1e400000", "-Inf", strconv.ErrRange},
   411  
   412  	// denormalized
   413  	{"1e-305", "1e-305", nil},
   414  	{"1e-306", "1e-306", nil},
   415  	{"1e-307", "1e-307", nil},
   416  	{"1e-308", "1e-308", nil},
   417  	{"1e-309", "1e-309", nil},
   418  	{"1e-310", "1e-310", nil},
   419  	{"1e-322", "1e-322", nil},
   420  	// smallest denormal
   421  	{"5e-324", "5e-324", nil},
   422  	{"4e-324", "5e-324", nil},
   423  	{"3e-324", "5e-324", nil},
   424  	// too small
   425  	{"2e-324", "0", nil},
   426  	// way too small
   427  	{"1e-350", "0", nil},
   428  	{"1e-400000", "0", nil},
   429  
   430  	// try to overflow exponent
   431  	{"1e-4294967296", "0", nil},
   432  	{"1e+4294967296", "+Inf", strconv.ErrRange},
   433  	{"1e-18446744073709551616", "0", nil},
   434  	{"1e+18446744073709551616", "+Inf", strconv.ErrRange},
   435  
   436  	// Parse errors
   437  	{"1e", "0", strconv.ErrSyntax},
   438  	{"1e-", "0", strconv.ErrSyntax},
   439  	{".e-1", "0", strconv.ErrSyntax},
   440  
   441  	// https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
   442  	{"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
   443  	// https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
   444  	{"2.2250738585072011e-308", "2.225073858507201e-308", nil},
   445  
   446  	// A very large number (initially wrongly parsed by the fast algorithm).
   447  	{"4.630813248087435e+307", "4.630813248087435e+307", nil},
   448  
   449  	// A different kind of very large number.
   450  	{"22.222222222222222", "22.22222222222222", nil},
   451  	{"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil},
   452  
   453  	// Exactly halfway between 1 and math.Nextafter(1, 2).
   454  	// Round to even (down).
   455  	{"1.00000000000000011102230246251565404236316680908203125", "1", nil},
   456  	// Slightly lower; still round down.
   457  	{"1.00000000000000011102230246251565404236316680908203124", "1", nil},
   458  	// Slightly higher; round up.
   459  	{"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil},
   460  	// Slightly higher, but you have to read all the way to the end.
   461  	{"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil},
   462  
   463  	// Halfway between x := math.Nextafter(1, 2) and math.Nextafter(x, 2)
   464  	// Round to even (up).
   465  	{"1.00000000000000033306690738754696212708950042724609375", "1.0000000000000004", nil},
   466  
   467  	// Underscores.
   468  	{"1_23.50_0_0e+1_2", "1.235e+14", strconv.ErrSyntax},
   469  	{"-_123.5e+12", "0", strconv.ErrSyntax},
   470  	{"+_123.5e+12", "0", strconv.ErrSyntax},
   471  	{"_123.5e+12", "0", strconv.ErrSyntax},
   472  	{"1__23.5e+12", "0", strconv.ErrSyntax},
   473  	{"123_.5e+12", "0", strconv.ErrSyntax},
   474  	{"123._5e+12", "0", strconv.ErrSyntax},
   475  	{"123.5_e+12", "0", strconv.ErrSyntax},
   476  	{"123.5__0e+12", "0", strconv.ErrSyntax},
   477  	{"123.5e_+12", "0", strconv.ErrSyntax},
   478  	{"123.5e+_12", "0", strconv.ErrSyntax},
   479  	{"123.5e_-12", "0", strconv.ErrSyntax},
   480  	{"123.5e-_12", "0", strconv.ErrSyntax},
   481  	{"123.5e+1__2", "0", strconv.ErrSyntax},
   482  	{"123.5e+12_", "0", strconv.ErrSyntax},
   483  }
   484  
   485  func TestParseFloat64(t *testing.T) {
   486  
   487  	for i := 0; i < len(atoftests); i++ {
   488  		test := &atoftests[i]
   489  		t.Run(test.in, func(t *testing.T) {
   490  			tag, val, _, _ := parseNumber([]byte(fmt.Sprintf(`%s:`, test.in)))
   491  			switch tag {
   492  			case TagEnd:
   493  				if test.err == nil {
   494  					t.Errorf("TestParseFloat64: got error, none")
   495  				}
   496  			case TagFloat:
   497  				got := math.Float64frombits(val)
   498  				outs := strconv.FormatFloat(got, 'g', -1, 64)
   499  				if outs != test.out {
   500  					t.Errorf("TestParseFloat64: got: %v want: %v", outs, test.out)
   501  				}
   502  			case TagInteger:
   503  				got := int64(val)
   504  				outs := fmt.Sprint(got)
   505  				if outs != test.out {
   506  					t.Errorf("TestParseFloat64: got: %v want: %v", outs, test.out)
   507  				}
   508  			case TagUint:
   509  				got := val
   510  				outs := fmt.Sprint(got)
   511  				if outs != test.out {
   512  					t.Errorf("TestParseFloat64: got: %v want: %v", outs, test.out)
   513  				}
   514  			default:
   515  			}
   516  		})
   517  	}
   518  }
   519  
   520  func TestParseString(t *testing.T) {
   521  
   522  	for _, tt := range tests {
   523  		t.Run(tt.name, func(t *testing.T) {
   524  			// enclose test string in quotes (as validated by stage 1)
   525  			buf := []byte(fmt.Sprintf(`"%s"`, tt.str))
   526  			dest := make([]byte, 0, len(buf)+32 /* safety margin as parseString writes full AVX2 words */)
   527  
   528  			success := parseStringSimd(buf, &dest)
   529  
   530  			if success != tt.success {
   531  				t.Errorf("TestParseString() got = %v, want %v", success, tt.success)
   532  			}
   533  			if success {
   534  				size := len(dest)
   535  				if size != len(tt.want) {
   536  					t.Errorf("TestParseString() got = %d, want %d", size, len(tt.want))
   537  				}
   538  				if bytes.Compare(dest[:size], tt.want) != 0 {
   539  					t.Errorf("TestParseString() got = %v, want %v", dest[:size], tt.want)
   540  				}
   541  			}
   542  		})
   543  	}
   544  }
   545  
   546  func TestParseStringValidateOnly(t *testing.T) {
   547  
   548  	for _, tt := range tests {
   549  		t.Run(tt.name, func(t *testing.T) {
   550  			// enclose test string in quotes (as validated by stage 1)
   551  			buf := []byte(fmt.Sprintf(`"%s"`, tt.str))
   552  
   553  			dst_length := uint64(0)
   554  			need_copy := false
   555  			l := uint64(len(buf))
   556  			success := parseStringSimdValidateOnly(buf, &l, &dst_length, &need_copy)
   557  
   558  			if success != tt.success {
   559  				t.Errorf("TestParseString() got = %v, want %v", success, tt.success)
   560  			}
   561  			if success && !need_copy {
   562  				if dst_length != uint64(len(tt.want)) {
   563  					t.Errorf("TestParseString() got = %d, want %d", dst_length, len(tt.want))
   564  				}
   565  			}
   566  		})
   567  	}
   568  }
   569  
   570  func TestParseStringValidateOnlyBeyondBuffer(t *testing.T) {
   571  
   572  	t.Skip()
   573  
   574  	buf := []byte(fmt.Sprintf(`"%s`, "   "))
   575  
   576  	dst_length := uint64(0)
   577  	need_copy := false
   578  	l := uint64(len(buf)) + 32
   579  	success := parseStringSimdValidateOnly(buf, &l, &dst_length, &need_copy)
   580  	if !success {
   581  		t.Errorf("TestParseStringValidateOnlyBeyondBuffer() got = %v, want %v", success, false)
   582  	}
   583  }
   584  
   585  // Benchmarking code for integers
   586  
   587  func BenchmarkParseNumber(b *testing.B) {
   588  	b.Run("Pos", func(b *testing.B) {
   589  		benchmarkParseNumber(b, 1)
   590  	})
   591  	b.Run("Neg", func(b *testing.B) {
   592  		benchmarkParseNumber(b, -1)
   593  	})
   594  }
   595  
   596  func benchmarkParseNumber(b *testing.B, neg int) {
   597  	cases := []benchCase{
   598  		{"63bit", 1<<63 - 1},
   599  	}
   600  	for _, cs := range cases {
   601  		b.Run(cs.name, func(b *testing.B) {
   602  			s := fmt.Sprintf("%d", cs.num*int64(neg))
   603  			s = fmt.Sprintf(`%s:`, s) // append delimiter
   604  			for i := 0; i < b.N; i++ {
   605  				parseNumber([]byte(s))
   606  			}
   607  		})
   608  	}
   609  }
   610  
   611  func BenchmarkParseNumberFloat(b *testing.B) {
   612  	for i := 0; i < b.N; i++ {
   613  		parseNumber([]byte("339.7784:"))
   614  	}
   615  }
   616  
   617  func BenchmarkParseAtof64FloatGolang(b *testing.B) {
   618  	for i := 0; i < b.N; i++ {
   619  		strconv.ParseFloat("339.7784", 64)
   620  	}
   621  }
   622  
   623  func BenchmarkParseNumberFloatExp(b *testing.B) {
   624  	for i := 0; i < b.N; i++ {
   625  		parseNumber([]byte("-5.09e75:"))
   626  	}
   627  }
   628  
   629  func BenchmarkParseNumberBig(b *testing.B) {
   630  	for i := 0; i < b.N; i++ {
   631  		parseNumber([]byte("123456789123456789123456789:"))
   632  	}
   633  }
   634  
   635  func BenchmarkParseNumberRandomBits(b *testing.B) {
   636  	initAtof()
   637  	for i := 0; i < b.N; i++ {
   638  		parseNumber([]byte(benchmarksRandomBitsSimd[i%1024]))
   639  	}
   640  }
   641  
   642  func BenchmarkParseNumberRandomFloats(b *testing.B) {
   643  	initAtof()
   644  	for i := 0; i < b.N; i++ {
   645  		parseNumber([]byte(benchmarksRandomNormalSimd[i%1024]))
   646  	}
   647  }
   648  
   649  func TestVerifyTape(t *testing.T) {
   650  	// FIXME: Does not have tapes any more.
   651  	for _, tt := range testCases {
   652  
   653  		t.Run(tt.name, func(t *testing.T) {
   654  			ref := loadCompressed(t, tt.name)
   655  
   656  			pj := internalParsedJson{}
   657  			if err := pj.parseMessage(ref); err != nil {
   658  				t.Errorf("parseMessage failed: %v\n", err)
   659  				return
   660  			}
   661  
   662  			//ctape := bytesToUint64(cbuf)
   663  
   664  			//testCTapeCtoGoTapeCompare(t, ctape, csbuf, pj)
   665  		})
   666  	}
   667  }