Repository navigation
Write ISO 8211 records straight into their buffers and merge S-57 updates without list searches - #36
Merged
Merged
Conversation
…ates without list searches No public API changes. Writer: - Work out every record's layout first, then write each record directly into an exact-size buffer. This replaces appending to a List<byte> one byte at a time, formatting every number and the leader through strings, and copying the list into the result array. - The stream and file overloads write a 64 KB chunk of records at a time from a pooled buffer instead of building the whole output first. Every record is still checked before anything is written, so a document that can't be encoded leaves the stream untouched and creates no file, as before. - Layouts no longer keep each record's field lengths and positions, which are recomputed while writing. On the synthetic harbour cell, Write allocates 592 KB instead of 2.3 MB. On the synthetic Large cell, it takes 54 ms and allocates 28 MB, down from 85 ms and 69 MB; writing to a stream allocates 14 MB. The output is byte-identical on the synthetic cells and 20 real NOAA cells and updates, through every overload and with directory auto-sizing on. ApplyChanges: - Deleting a record no longer searches the list of records for its key, and inserting one no longer checks the list for it; a delete leaves the key behind, and building the output skips it. A base cell that repeats a record name, which is malformed, falls back to the list-based merge so its output can't change. - Three updates on the synthetic Large cell take 66 ms instead of 156 ms. A randomized test compares the merge with the list-based one, including repeated names, and real NOAA update chains give identical fingerprints. S57Document.GetFeatureRecord(S57RecordName) and GetVectorRecord loop instead of building a LINQ closure per call; neither this repository nor EncDotNet.S100 calls them, so they keep searching every record and point to S57Chart for indexed lookups. Budget tests skip, with a reason, when the libraries are Debug builds, whose allocations differ from the Release figures the budgets record, and a failure names the runtime the budgets were recorded on when the run used another. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YagvELyJKBANk61DyFGUNJ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR covers the smaller items left over from the performance review. It changes no public API.
Writer (
Iso8211DocumentWriter)How it writes now:
List<byte>one at a time, formatted every number and the leader as strings, and then copied the list into the result array.Stream and file overloads:
Smaller layouts: they no longer keep two
intarrays per record for field lengths and positions. Both values are recomputed while writing.mainWritetobyte[]Writeto a streamOutput is unchanged. It is byte-identical to
mainon:S57Document.ApplyChangesWhat changed:
Repeated record names: a base cell that repeats a record name is malformed. The old merge output such a record once per occurrence, and a delete removed only the first one. That case falls back to the old list-based merge, so its output can't change.
Result: applying three updates to the synthetic Large cell takes 66 ms instead of 156 ms. The allocation budget is unchanged.
How the output was checked:
main.GetFeatureRecord(S57RecordName)andGetVectorRecordThese now use plain loops instead of building a LINQ closure on every call. Neither this repository nor EncDotNet.S100 calls them, so an index isn't justified. They still search every record, and their docs now point to
S57Chartfor indexed lookups.Budget tests
maintoo. CI runs Release and is unaffected.global.jsonpin: I'd suggested one, but tests run on the newest 10.0 runtime installed regardless of the pinned SDK, so it wouldn't hold the runtime still.Iso8211DocumentWriterWriteis lowered to the new measured figure. No other budget changed.Standards alignment
iso8211)s57-enc)chart-viewer)Standard section references cited in code or docs:
No new references. The leader encoding still follows S-57 Part 3 Annex A.3, as already cited in
Iso8211RecordWriter.Tests
tests/:S57DocumentRecordMergeTests;dotnet test --configuration Releasepasses locally. Unit tests: 531 pass. Budget tests: 14 pass.Documentation
src/<project>/README.md. Not needed: no behaviour a reader would notice changed.docs/if user-facing behavior changed. Not needed, for the same reason.docfx docfx.json --warningsAsErrorspasses, if docs changedDependencies
Directory.Packages.props(not in the.csproj)gh-advisory-databasesecurity check run for any new dependency. Not applicable: no new dependencies.Breaking changes
None. Package validation against 0.7.0 reports no new differences for either package.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YagvELyJKBANk61DyFGUNJ
Generated by Claude Code