perf(encode): emit in place, pool the buffer and cache interface flags
Test / test (push) Successful in 1m33s

Grouped emission walks the entries slice in three passes instead of copying them into per-kind slices, error paths render their key path only when an error names it, inline tables are measured once because a measuring encoder no longer nests another measurement, clean string runs are written in one write, and date-times render through the single-buffer path. The output buffer comes from a sync.Pool and returns to it within a 1 MiB retention cap, the output handed to the caller as a copy; repeated marshals keep the live heap flat, verified over 500 runs. The encoder resolves Marshaler and the text interfaces through the same per-type flag cache and hint the decoder uses, and docs/ARCHITECTURE.md now lists the caches and the pool as the library's shared state.

Representative document: 177 to 141 allocations, 12 230 to 6170 bytes per operation; long document: 97 175 to 63 660 allocations, 6.97 to 2.79 MB per operation, about 7.8 to about 3.4 ms.
This commit is contained in:
2026-09-20 22:15:38 +02:00
parent 9874464213
commit 2ae487e117
4 changed files with 337 additions and 118 deletions
+11
View File
@@ -92,6 +92,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
document (9792 ns against 11 147 ns) with 24 percent fewer allocations
(167 against 220); interface lookups resolve through a cached per-type
flag set instead of boxing every value into an interface to ask.
- `Marshal` runs at the 1.1.0 speed while emitting the new TOML 1.1 output
form, at half the bytes per operation (6170 against 11 348 on the
representative document), and writes through a pooled output buffer with
a 1 MiB retention cap; repeated marshals keep the live heap flat.
- Two benchmarks measure the shapes that drove the work:
`BenchmarkStrictDecodeLong` and `BenchmarkMarshalLong` run the 2000-entry
document at about 3.8 ms and 3.4 ms per call, at 63 772 and 63 660
allocations.
### Fixed
@@ -99,6 +107,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
as `type Name string`, panicked instead of storing the value, because a
value of the predeclared type is not assignable to a defined type and the
decoder assigned it without a conversion.
- A top-level value the encoder could not normalise reported its path with
a leading dot, `interpres: .port: ...`; the message now reads
`interpres: port: ...`, the shape `EncodeError.Path` already used.
## [1.1.0] - 2026-09-18