| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | import ( |
| | "bytes" |
| | "fmt" |
| | "io" |
| | "testing" |
| |
|
| | "encoding/json/internal/jsontest" |
| | "encoding/json/jsontext" |
| | ) |
| |
|
| | func TestIntern(t *testing.T) { |
| | var sc stringCache |
| | const alphabet = "abcdefghijklmnopqrstuvwxyz" |
| | for i := range len(alphabet) + 1 { |
| | want := alphabet[i:] |
| | if got := makeString(&sc, []byte(want)); got != want { |
| | t.Fatalf("make = %v, want %v", got, want) |
| | } |
| | } |
| | for i := range 1000 { |
| | want := fmt.Sprintf("test%b", i) |
| | if got := makeString(&sc, []byte(want)); got != want { |
| | t.Fatalf("make = %v, want %v", got, want) |
| | } |
| | } |
| | } |
| |
|
| | var sink string |
| |
|
| | func BenchmarkIntern(b *testing.B) { |
| | datasetStrings := func(name string) (out [][]byte) { |
| | var data []byte |
| | for _, ts := range jsontest.Data { |
| | if ts.Name == name { |
| | data = ts.Data() |
| | } |
| | } |
| | dec := jsontext.NewDecoder(bytes.NewReader(data)) |
| | for { |
| | k, n := dec.StackIndex(dec.StackDepth()) |
| | isObjectName := k == '{' && n%2 == 0 |
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | if err == io.EOF { |
| | break |
| | } |
| | b.Fatalf("ReadToken error: %v", err) |
| | } |
| | if tok.Kind() == '"' && !isObjectName { |
| | out = append(out, []byte(tok.String())) |
| | } |
| | } |
| | return out |
| | } |
| |
|
| | tests := []struct { |
| | label string |
| | data [][]byte |
| | }{ |
| | |
| | {"Best", func() (out [][]byte) { |
| | for range 1000 { |
| | out = append(out, []byte("hello, world!")) |
| | } |
| | return out |
| | }()}, |
| |
|
| | |
| | |
| | |
| | {"Repeat", func() (out [][]byte) { |
| | for range 100 { |
| | for _, s := range []string{"first_name", "last_name", "age", "address", "street_address", "city", "state", "postal_code", "phone_numbers", "gender"} { |
| | out = append(out, []byte(s)) |
| | } |
| | } |
| | return out |
| | }()}, |
| |
|
| | |
| | {"Synthea", datasetStrings("SyntheaFhir")}, |
| |
|
| | |
| | {"Twitter", datasetStrings("TwitterStatus")}, |
| |
|
| | |
| | |
| | {"Worst", func() (out [][]byte) { |
| | for i := range 1000 { |
| | out = append(out, []byte(fmt.Sprintf("%016x", i))) |
| | } |
| | return out |
| | }()}, |
| | } |
| |
|
| | for _, tt := range tests { |
| | b.Run(tt.label, func(b *testing.B) { |
| | |
| | |
| | b.Run("Alloc", func(b *testing.B) { |
| | b.ReportAllocs() |
| | for range b.N { |
| | for _, b := range tt.data { |
| | sink = string(b) |
| | } |
| | } |
| | }) |
| | |
| | |
| | |
| | b.Run("Cache", func(b *testing.B) { |
| | b.ReportAllocs() |
| | for range b.N { |
| | var sc stringCache |
| | for _, b := range tt.data { |
| | sink = makeString(&sc, b) |
| | } |
| | } |
| | }) |
| | |
| | |
| | b.Run("GoMap", func(b *testing.B) { |
| | b.ReportAllocs() |
| | for range b.N { |
| | m := make(map[string]string) |
| | for _, b := range tt.data { |
| | s, ok := m[string(b)] |
| | if !ok { |
| | s = string(b) |
| | m[s] = s |
| | } |
| | sink = s |
| | } |
| | } |
| | }) |
| | }) |
| | } |
| | } |
| |
|