First benchmark!
~/s/g/p/g/benchmark$ go test -bench=. goos: linux goarch: amd64 pkg: github.com/pelletier/go-toml/v2/benchmark cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz BenchmarkUnmarshalSimple/v2-8 1607115 742.0 ns/op BenchmarkUnmarshalSimple/v1-8 307977 3915 ns/op BenchmarkUnmarshalSimple/bs-8 516754 2330 ns/op BenchmarkReferenceFile/v2-8 9604 129158 ns/op 111422 B/op 1381 allocs/op BenchmarkReferenceFile/v1-8 4521 263808 ns/op 130566 B/op 2649 allocs/op BenchmarkReferenceFile/bs-8 4070 296271 ns/op 80784 B/op 1729 allocs/op PASS ok github.com/pelletier/go-toml/v2/benchmark 8.139s
This commit is contained in:
@@ -0,0 +1,244 @@
|
|||||||
|
################################################################################
|
||||||
|
## Comment
|
||||||
|
|
||||||
|
# Speak your mind with the hash symbol. They go from the symbol to the end of
|
||||||
|
# the line.
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Table
|
||||||
|
|
||||||
|
# Tables (also known as hash tables or dictionaries) are collections of
|
||||||
|
# key/value pairs. They appear in square brackets on a line by themselves.
|
||||||
|
|
||||||
|
[table]
|
||||||
|
|
||||||
|
key = "value" # Yeah, you can do this.
|
||||||
|
|
||||||
|
# Nested tables are denoted by table names with dots in them. Name your tables
|
||||||
|
# whatever crap you please, just don't use #, ., [ or ].
|
||||||
|
|
||||||
|
[table.subtable]
|
||||||
|
|
||||||
|
key = "another value"
|
||||||
|
|
||||||
|
# You don't need to specify all the super-tables if you don't want to. TOML
|
||||||
|
# knows how to do it for you.
|
||||||
|
|
||||||
|
# [x] you
|
||||||
|
# [x.y] don't
|
||||||
|
# [x.y.z] need these
|
||||||
|
[x.y.z.w] # for this to work
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Inline Table
|
||||||
|
|
||||||
|
# Inline tables provide a more compact syntax for expressing tables. They are
|
||||||
|
# especially useful for grouped data that can otherwise quickly become verbose.
|
||||||
|
# Inline tables are enclosed in curly braces `{` and `}`. No newlines are
|
||||||
|
# allowed between the curly braces unless they are valid within a value.
|
||||||
|
|
||||||
|
[table.inline]
|
||||||
|
|
||||||
|
name = { first = "Tom", last = "Preston-Werner" }
|
||||||
|
point = { x = 1, y = 2 }
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## String
|
||||||
|
|
||||||
|
# There are four ways to express strings: basic, multi-line basic, literal, and
|
||||||
|
# multi-line literal. All strings must contain only valid UTF-8 characters.
|
||||||
|
|
||||||
|
[string.basic]
|
||||||
|
|
||||||
|
basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
|
||||||
|
|
||||||
|
[string.multiline]
|
||||||
|
|
||||||
|
# The following strings are byte-for-byte equivalent:
|
||||||
|
key1 = "One\nTwo"
|
||||||
|
key2 = """One\nTwo"""
|
||||||
|
key3 = """
|
||||||
|
One
|
||||||
|
Two"""
|
||||||
|
|
||||||
|
[string.multiline.continued]
|
||||||
|
|
||||||
|
# The following strings are byte-for-byte equivalent:
|
||||||
|
key1 = "The quick brown fox jumps over the lazy dog."
|
||||||
|
|
||||||
|
key2 = """
|
||||||
|
The quick brown \
|
||||||
|
|
||||||
|
|
||||||
|
fox jumps over \
|
||||||
|
the lazy dog."""
|
||||||
|
|
||||||
|
key3 = """\
|
||||||
|
The quick brown \
|
||||||
|
fox jumps over \
|
||||||
|
the lazy dog.\
|
||||||
|
"""
|
||||||
|
|
||||||
|
[string.literal]
|
||||||
|
|
||||||
|
# What you see is what you get.
|
||||||
|
winpath = 'C:\Users\nodejs\templates'
|
||||||
|
winpath2 = '\\ServerX\admin$\system32\'
|
||||||
|
quoted = 'Tom "Dubs" Preston-Werner'
|
||||||
|
regex = '<\i\c*\s*>'
|
||||||
|
|
||||||
|
|
||||||
|
[string.literal.multiline]
|
||||||
|
|
||||||
|
regex2 = '''I [dw]on't need \d{2} apples'''
|
||||||
|
lines = '''
|
||||||
|
The first newline is
|
||||||
|
trimmed in raw strings.
|
||||||
|
All other whitespace
|
||||||
|
is preserved.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Integer
|
||||||
|
|
||||||
|
# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
|
||||||
|
# Negative numbers are prefixed with a minus sign.
|
||||||
|
|
||||||
|
[integer]
|
||||||
|
|
||||||
|
key1 = +99
|
||||||
|
key2 = 42
|
||||||
|
key3 = 0
|
||||||
|
key4 = -17
|
||||||
|
|
||||||
|
[integer.underscores]
|
||||||
|
|
||||||
|
# For large numbers, you may use underscores to enhance readability. Each
|
||||||
|
# underscore must be surrounded by at least one digit.
|
||||||
|
key1 = 1_000
|
||||||
|
key2 = 5_349_221
|
||||||
|
key3 = 1_2_3_4_5 # valid but inadvisable
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Float
|
||||||
|
|
||||||
|
# A float consists of an integer part (which may be prefixed with a plus or
|
||||||
|
# minus sign) followed by a fractional part and/or an exponent part.
|
||||||
|
|
||||||
|
[float.fractional]
|
||||||
|
|
||||||
|
key1 = +1.0
|
||||||
|
key2 = 3.1415
|
||||||
|
key3 = -0.01
|
||||||
|
|
||||||
|
[float.exponent]
|
||||||
|
|
||||||
|
key1 = 5e+22
|
||||||
|
key2 = 1e6
|
||||||
|
key3 = -2E-2
|
||||||
|
|
||||||
|
[float.both]
|
||||||
|
|
||||||
|
key = 6.626e-34
|
||||||
|
|
||||||
|
[float.underscores]
|
||||||
|
|
||||||
|
key1 = 9_224_617.445_991_228_313
|
||||||
|
key2 = 1e1_00
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Boolean
|
||||||
|
|
||||||
|
# Booleans are just the tokens you're used to. Always lowercase.
|
||||||
|
|
||||||
|
[boolean]
|
||||||
|
|
||||||
|
True = true
|
||||||
|
False = false
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Datetime
|
||||||
|
|
||||||
|
# Datetimes are RFC 3339 dates.
|
||||||
|
|
||||||
|
[datetime]
|
||||||
|
|
||||||
|
key1 = 1979-05-27T07:32:00Z
|
||||||
|
key2 = 1979-05-27T00:32:00-07:00
|
||||||
|
key3 = 1979-05-27T00:32:00.999999-07:00
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Array
|
||||||
|
|
||||||
|
# Arrays are square brackets with other primitives inside. Whitespace is
|
||||||
|
# ignored. Elements are separated by commas. Data types may not be mixed.
|
||||||
|
|
||||||
|
[array]
|
||||||
|
|
||||||
|
key1 = [ 1, 2, 3 ]
|
||||||
|
key2 = [ "red", "yellow", "green" ]
|
||||||
|
key3 = [ [ 1, 2 ], [3, 4, 5] ]
|
||||||
|
#key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
|
||||||
|
|
||||||
|
# Arrays can also be multiline. So in addition to ignoring whitespace, arrays
|
||||||
|
# also ignore newlines between the brackets. Terminating commas are ok before
|
||||||
|
# the closing bracket.
|
||||||
|
|
||||||
|
key5 = [
|
||||||
|
1, 2, 3
|
||||||
|
]
|
||||||
|
key6 = [
|
||||||
|
1,
|
||||||
|
2, # this is ok
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Array of Tables
|
||||||
|
|
||||||
|
# These can be expressed by using a table name in double brackets. Each table
|
||||||
|
# with the same double bracketed name will be an element in the array. The
|
||||||
|
# tables are inserted in the order encountered.
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
|
||||||
|
name = "Hammer"
|
||||||
|
sku = 738594937
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
|
||||||
|
name = "Nail"
|
||||||
|
sku = 284758393
|
||||||
|
color = "gray"
|
||||||
|
|
||||||
|
|
||||||
|
# You can create nested arrays of tables as well.
|
||||||
|
|
||||||
|
[[fruit]]
|
||||||
|
name = "apple"
|
||||||
|
|
||||||
|
[fruit.physical]
|
||||||
|
color = "red"
|
||||||
|
shape = "round"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "red delicious"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "granny smith"
|
||||||
|
|
||||||
|
[[fruit]]
|
||||||
|
name = "banana"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "plantain"
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
package benchmark_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tomlbs "github.com/BurntSushi/toml"
|
||||||
|
tomlv1 "github.com/pelletier/go-toml-v1"
|
||||||
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type runner struct {
|
||||||
|
name string
|
||||||
|
unmarshal func([]byte, interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var runners = []runner{
|
||||||
|
{"v2", toml.Unmarshal},
|
||||||
|
{"v1", tomlv1.Unmarshal},
|
||||||
|
{"bs", tomlbs.Unmarshal},
|
||||||
|
}
|
||||||
|
|
||||||
|
func bench(b *testing.B, f func(r runner, b *testing.B)) {
|
||||||
|
for _, r := range runners {
|
||||||
|
b.Run(r.name, func(b *testing.B) {
|
||||||
|
f(r, b)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalSimple(b *testing.B) {
|
||||||
|
bench(b, func(r runner, b *testing.B) {
|
||||||
|
d := struct {
|
||||||
|
A string
|
||||||
|
}{}
|
||||||
|
doc := []byte(`A = "hello"`)
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := r.unmarshal(doc, &d)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type benchmarkDoc struct {
|
||||||
|
Table struct {
|
||||||
|
Key string
|
||||||
|
Subtable struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
Inline struct {
|
||||||
|
Name struct {
|
||||||
|
First string
|
||||||
|
Last string
|
||||||
|
}
|
||||||
|
Point struct {
|
||||||
|
X int64
|
||||||
|
U int64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String struct {
|
||||||
|
Basic struct {
|
||||||
|
Basic string
|
||||||
|
}
|
||||||
|
Multiline struct {
|
||||||
|
Key1 string
|
||||||
|
Key2 string
|
||||||
|
Key3 string
|
||||||
|
Continued struct {
|
||||||
|
Key1 string
|
||||||
|
Key2 string
|
||||||
|
Key3 string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Literal struct {
|
||||||
|
Winpath string
|
||||||
|
Winpath2 string
|
||||||
|
Quoted string
|
||||||
|
Regex string
|
||||||
|
Multiline struct {
|
||||||
|
Regex2 string
|
||||||
|
Lines string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Integer struct {
|
||||||
|
Key1 int64
|
||||||
|
Key2 int64
|
||||||
|
Key3 int64
|
||||||
|
Key4 int64
|
||||||
|
Underscores struct {
|
||||||
|
Key1 int64
|
||||||
|
Key2 int64
|
||||||
|
Key3 int64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Float struct {
|
||||||
|
Fractional struct {
|
||||||
|
Key1 float64
|
||||||
|
Key2 float64
|
||||||
|
Key3 float64
|
||||||
|
}
|
||||||
|
Exponent struct {
|
||||||
|
Key1 float64
|
||||||
|
Key2 float64
|
||||||
|
Key3 float64
|
||||||
|
}
|
||||||
|
Both struct {
|
||||||
|
Key float64
|
||||||
|
}
|
||||||
|
Underscores struct {
|
||||||
|
Key1 float64
|
||||||
|
Key2 float64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Boolean struct {
|
||||||
|
True bool
|
||||||
|
False bool
|
||||||
|
}
|
||||||
|
Datetime struct {
|
||||||
|
Key1 time.Time
|
||||||
|
Key2 time.Time
|
||||||
|
Key3 time.Time
|
||||||
|
}
|
||||||
|
Array struct {
|
||||||
|
Key1 []int64
|
||||||
|
Key2 []string
|
||||||
|
Key3 [][]int64
|
||||||
|
// TODO: Key4 not supported by go-toml's Unmarshal
|
||||||
|
Key5 []int64
|
||||||
|
Key6 []int64
|
||||||
|
}
|
||||||
|
Products []struct {
|
||||||
|
Name string
|
||||||
|
Sku int64
|
||||||
|
Color string
|
||||||
|
}
|
||||||
|
Fruit []struct {
|
||||||
|
Name string
|
||||||
|
Physical struct {
|
||||||
|
Color string
|
||||||
|
Shape string
|
||||||
|
Variety []struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkReferenceFile(b *testing.B) {
|
||||||
|
bench(b, func(r runner, b *testing.B) {
|
||||||
|
bytes, err := ioutil.ReadFile("benchmark.toml")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
d := benchmarkDoc{}
|
||||||
|
err := r.unmarshal(bytes, &d)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReferenceFile(t *testing.T) {
|
||||||
|
bytes, err := ioutil.ReadFile("benchmark.toml")
|
||||||
|
require.NoError(t, err)
|
||||||
|
d := benchmarkDoc{}
|
||||||
|
err = toml.Unmarshal(bytes, &d)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
module github.com/pelletier/go-toml/v2/benchmark
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
replace github.com/pelletier/go-toml/v2 => ../
|
||||||
|
|
||||||
|
replace github.com/pelletier/go-toml-v1 => /home/thomas/src/github.com/pelletier/go-toml-v1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/BurntSushi/toml v0.3.1
|
||||||
|
github.com/pelletier/go-toml v1.8.1 // indirect
|
||||||
|
github.com/pelletier/go-toml-v1 v0.0.0-00010101000000-000000000000
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.0-00010101000000-000000000000
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
|
)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
|
||||||
|
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||||
|
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/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
module github.com/pelletier/go-toml/v2
|
module github.com/pelletier/go-toml/v2
|
||||||
|
|
||||||
go 1.14
|
go 1.15
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.7.0
|
require github.com/stretchr/testify v1.7.0
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
|
|||||||
switch b[i] {
|
switch b[i] {
|
||||||
case '\'':
|
case '\'':
|
||||||
if scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
|
if scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
|
||||||
return b[:i+3], b[:i+3], nil
|
return b[:i+3], b[i+3:], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user