diff --git a/README.md b/README.md
index f5f173e..61cdd18 100644
--- a/README.md
+++ b/README.md
@@ -235,17 +235,17 @@ the AST level. See https://pkg.go.dev/github.com/pelletier/go-toml/v2/unstable.
Execution time speedup compared to other Go TOML libraries:
-
- | Benchmark | go-toml v1 | BurntSushi/toml |
-
-
- | Marshal/HugoFrontMatter-2 | 2.1x | 2.0x |
- | Marshal/ReferenceFile/map-2 | 1.9x | 2.0x |
- | Marshal/ReferenceFile/struct-2 | 2.3x | 2.5x |
- | Unmarshal/HugoFrontMatter-2 | 3.4x | 2.8x |
- | Unmarshal/ReferenceFile/map-2 | 3.0x | 3.0x |
- | Unmarshal/ReferenceFile/struct-2 | 4.9x | 5.1x |
-
+
+ | Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ | Marshal/HugoFrontMatter-2 | 2.1x | 2.0x |
+ | Marshal/ReferenceFile/map-2 | 2.0x | 2.0x |
+ | Marshal/ReferenceFile/struct-2 | 2.3x | 2.5x |
+ | Unmarshal/HugoFrontMatter-2 | 3.3x | 2.8x |
+ | Unmarshal/ReferenceFile/map-2 | 2.9x | 3.0x |
+ | Unmarshal/ReferenceFile/struct-2 | 4.8x | 5.0x |
+
See more
The table above has the results of the most common use-cases. The table below
@@ -253,22 +253,22 @@ contains the results of all benchmarks, including unrealistic ones. It is
provided for completeness.
-
- | Benchmark | go-toml v1 | BurntSushi/toml |
-
-
- | Marshal/SimpleDocument/map-2 | 2.0x | 2.9x |
- | Marshal/SimpleDocument/struct-2 | 2.5x | 3.5x |
- | Unmarshal/SimpleDocument/map-2 | 4.3x | 3.5x |
- | Unmarshal/SimpleDocument/struct-2 | 5.9x | 4.5x |
- | UnmarshalDataset/example-2 | 3.2x | 2.9x |
- | UnmarshalDataset/code-2 | 2.4x | 2.9x |
- | UnmarshalDataset/twitter-2 | 2.7x | 2.5x |
- | UnmarshalDataset/citm_catalog-2 | 2.1x | 2.1x |
- | UnmarshalDataset/canada-2 | 1.9x | 1.5x |
- | UnmarshalDataset/config-2 | 5.4x | 3.1x |
- | geomean | 2.9x | 2.8x |
-
+
+ | Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ | Marshal/SimpleDocument/map-2 | 2.0x | 2.9x |
+ | Marshal/SimpleDocument/struct-2 | 2.5x | 3.6x |
+ | Unmarshal/SimpleDocument/map-2 | 4.2x | 3.4x |
+ | Unmarshal/SimpleDocument/struct-2 | 5.9x | 4.4x |
+ | UnmarshalDataset/example-2 | 3.2x | 2.9x |
+ | UnmarshalDataset/code-2 | 2.4x | 2.8x |
+ | UnmarshalDataset/twitter-2 | 2.7x | 2.5x |
+ | UnmarshalDataset/citm_catalog-2 | 2.3x | 2.3x |
+ | UnmarshalDataset/canada-2 | 1.9x | 1.5x |
+ | UnmarshalDataset/config-2 | 5.4x | 3.0x |
+ | geomean | 2.9x | 2.8x |
+
This table can be generated with ./ci.sh benchmark -a -html.
diff --git a/marshaler.go b/marshaler.go
index 9ff3a75..ca462d4 100644
--- a/marshaler.go
+++ b/marshaler.go
@@ -704,15 +704,18 @@ func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte
for iter.Next() {
v := iter.Value()
- if isNil(v) {
- // For nil pointers, convert to zero value of the element type.
- // This allows round-trip marshaling of maps with nil pointer values.
- // For nil interfaces and nil maps, skip since we can't derive a type.
- if v.Kind() == reflect.Ptr {
+ // Handle nil values: convert nil pointers to zero value,
+ // skip nil interfaces and nil maps.
+ switch v.Kind() {
+ case reflect.Ptr:
+ if v.IsNil() {
v = reflect.Zero(v.Type().Elem())
- } else {
+ }
+ case reflect.Interface, reflect.Map:
+ if v.IsNil() {
continue
}
+ default:
}
k, err := enc.keyToString(iter.Key())
@@ -936,7 +939,7 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
if shouldOmitEmpty(kv.Options, kv.Value) {
continue
}
- if shouldOmitZero(kv.Options, kv.Value) {
+ if kv.Options.omitzero && shouldOmitZero(kv.Options, kv.Value) {
continue
}
hasNonEmptyKV = true
@@ -958,7 +961,7 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
if shouldOmitEmpty(table.Options, table.Value) {
continue
}
- if shouldOmitZero(table.Options, table.Value) {
+ if table.Options.omitzero && shouldOmitZero(table.Options, table.Value) {
continue
}
if first {
@@ -995,7 +998,7 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte
if shouldOmitEmpty(kv.Options, kv.Value) {
continue
}
- if shouldOmitZero(kv.Options, kv.Value) {
+ if kv.Options.omitzero && shouldOmitZero(kv.Options, kv.Value) {
continue
}
diff --git a/unstable/ast.go b/unstable/ast.go
index 34ef628..6b21592 100644
--- a/unstable/ast.go
+++ b/unstable/ast.go
@@ -28,12 +28,16 @@ func (c *Iterator) Next() bool {
if c.nodes == nil {
return false
}
+ nodes := *c.nodes
if !c.started {
c.started = true
- } else if c.idx >= 0 {
- c.idx = (*c.nodes)[c.idx].next
+ } else {
+ idx := c.idx
+ if idx >= 0 && int(idx) < len(nodes) {
+ c.idx = nodes[idx].next
+ }
}
- return c.idx >= 0 && int(c.idx) < len(*c.nodes)
+ return c.idx >= 0 && int(c.idx) < len(nodes)
}
// IsLast returns true if the current node of the iterator is the last
diff --git a/unstable/parser.go b/unstable/parser.go
index d97dc34..e7c68dc 100644
--- a/unstable/parser.go
+++ b/unstable/parser.go
@@ -363,9 +363,10 @@ func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
p.builder.Chain(valRef, key)
p.builder.AttachChild(ref, valRef)
- // Set Raw to span the entire key-value expression
- node := p.builder.NodeAt(ref)
- node.Raw = p.rangeOfToken(startB[:len(startB)-len(b)], b)
+ // Set Raw to span the entire key-value expression.
+ // Access the node directly in the slice to avoid the write barrier
+ // that NodeAt's nodes-pointer setup would trigger.
+ p.builder.tree.nodes[ref].Raw = p.rangeOfToken(startB[:len(startB)-len(b)], b)
return ref, b, err
}