diff --git a/README.md b/README.md
index 521ed74..b2f3312 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@ Go library for the [TOML](https://toml.io/en/) format.
This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
-
## Development status
This is the upcoming major version of go-toml. It is currently in active
@@ -20,14 +19,12 @@ encouraged to try out this version.
[💬 Anything else](https://github.com/pelletier/go-toml/discussions)
-
## Documentation
Full API, examples, and implementation notes are available in the Go documentation.
[](https://pkg.go.dev/github.com/pelletier/go-toml/v2)
-
## Import
```go
@@ -44,7 +41,7 @@ standard library's `encoding/json`.
### Performance
While go-toml favors usability, it is written with performance in mind. Most
-operations should not be shockingly slow.
+operations should not be shockingly slow. See [benchmarks](#benchmarks).
### Strict mode
@@ -150,6 +147,43 @@ fmt.Println(string(b))
[marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal
+## Benchmarks
+
+Execution time speedup compared to other Go TOML libraries:
+
+
+
+ | Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ | HugoFrontMatter | 2.6x | 2.2x |
+ | ReferenceFile/map | 2.8x | 3.0x |
+ | ReferenceFile/struct | 5.4x | 6.2x |
+
+
+See more
+The table above has the results of the most common use-cases. The table
+below contains the results of all benchmarks, including unrealistic ones. is
+provided for completeness.
+
+
+
+ | Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ | UnmarshalSimple/map | 3.8x | 2.4x |
+ | UnmarshalSimple/struct | 5.4x | 3.1x |
+ | UnmarshalDataset/example | 2.8x | 2.0x |
+ | UnmarshalDataset/code | 1.8x | 2.2x |
+ | UnmarshalDataset/twitter | 2.5x | 1.8x |
+ | UnmarshalDataset/citm_catalog | 1.9x | 1.2x |
+ | UnmarshalDataset/config | 3.0x | 2.5x |
+ | [Geo mean] | 3.0x | 2.4x |
+
+
+This table can be generated with ./ci.sh benchmark -a -html.
+
+
## Migrating from v1
This section describes the differences between v1 and v2, with some pointers on
@@ -191,7 +225,7 @@ d := doc{
}
data := `
-[A]
+[A]
B = "After"
`
@@ -252,7 +286,6 @@ This method was not widely used, poorly defined, and added a lot of complexity.
A similar effect can be achieved by implementing the `encoding.TextUnmarshaler`
interface and use strings.
-
#### Support for `default` struct tag has been dropped
This feature adds complexity and a poorly defined API for an effect that can be
@@ -311,7 +344,6 @@ manually sort the fields alphabetically in the struct definition.
V1 automatically indents content of tables by default. V2 does not. However the
same behavior can be obtained using [`Encoder.SetIndentTables`][sit]. For example:
-
```go
data := map[string]interface{}{
"table": map[string]string{
@@ -333,15 +365,15 @@ fmt.Println("v2 Encoder:\n" + string(buf.Bytes()))
// Output:
// v1:
-//
+//
// [table]
// key = "value"
-//
+//
// v2:
// [table]
// key = 'value'
-//
-//
+//
+//
// v2 Encoder:
// [table]
// key = 'value'
diff --git a/ci.sh b/ci.sh
index d7e10cd..22cda0a 100755
--- a/ci.sh
+++ b/ci.sh
@@ -42,6 +42,9 @@ benchmark [OPTIONS...] [BRANCH]
-a Compare benchmarks of HEAD against go-toml v1 and
BurntSushi/toml.
+ -html When used with -a, emits the output as HTML, ready to be
+ embedded in the README.
+
coverage [OPTIONS...] [BRANCH]
Generates code coverage.
@@ -150,16 +153,78 @@ bench() {
fi
}
+fmktemp() {
+ if mktemp --version|grep GNU >/dev/null; then
+ mktemp --suffix=-$1;
+ else
+ mktemp -t $1;
+ fi
+}
+
+benchstathtml() {
+python3 - $1 <<'EOF'
+import sys
+
+lines = []
+stop = False
+
+with open(sys.argv[1]) as f:
+ for line in f.readlines():
+ line = line.strip()
+ if line == "":
+ stop = True
+ if not stop:
+ lines.append(line.split(','))
+
+results = []
+for line in reversed(lines[1:]):
+ v2 = float(line[1])
+ results.append([
+ line[0].replace("-32", ""),
+ "%.1fx" % (float(line[3])/v2), # v1
+ "%.1fx" % (float(line[5])/v2), # bs
+ ])
+# move geomean to the end
+results.append(results[0])
+del results[0]
+
+
+def printtable(data):
+ print("""
+
+
+ | Benchmark | go-toml v1 | BurntSushi/toml |
+
+ """)
+
+ for r in data:
+ print(" | {} | {} | {} |
".format(*r))
+
+ print("""
+
""")
+
+
+fold = 3
+printtable(results[:fold])
+print("See more
")
+print('The table above has the results of the most common use-cases. The table below contains the results of all benchmarks, including unrealistic ones. is provided for completeness.
')
+printtable(results[fold:])
+print('This table can be generated with ./ci.sh benchmark -a -html.
')
+print(" ")
+
+EOF
+}
+
benchmark() {
case "$1" in
-d)
shift
target="${1?Need to provide a target branch argument}"
- old=`mktemp --suffix=-${target}`
+ old=`fmktemp ${target}`
bench "${target}" "${old}"
- new=`mktemp --suffix=-HEAD`
+ new=`fmktemp HEAD`
bench HEAD "${new}"
benchstat "${old}" "${new}"
@@ -168,18 +233,24 @@ benchmark() {
-a)
shift
- v2stats=`mktemp -t go-toml-v2`
+ v2stats=`fmktemp go-toml-v2`
bench HEAD "${v2stats}" "github.com/pelletier/go-toml/v2"
- v1stats=`mktemp -t go-toml-v1`
+ v1stats=`fmktemp go-toml-v1`
bench HEAD "${v1stats}" "github.com/pelletier/go-toml"
- bsstats=`mktemp -t bs-toml`
+ bsstats=`fmktemp bs-toml`
bench HEAD "${bsstats}" "github.com/BurntSushi/toml"
cp "${v2stats}" go-toml-v2.txt
cp "${v1stats}" go-toml-v1.txt
cp "${bsstats}" bs-toml.txt
- benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt
+ if [ "$1" = "-html" ]; then
+ tmpcsv=`fmktemp csv`
+ benchstat -csv -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt > $tmpcsv
+ benchstathtml $tmpcsv
+ else
+ benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt
+ fi
rm -f go-toml-v2.txt go-toml-v1.txt bs-toml.txt
return $?