Skip to content

⚡ Make deep-copying of blocks and fields cheap - #613

Closed
MiWeiss wants to merge 1 commit into
mainfrom
perf/cheap-block-deepcopy
Closed

⚡ Make deep-copying of blocks and fields cheap#613
MiWeiss wants to merge 1 commit into
mainfrom
perf/cheap-block-deepcopy

Conversation

@MiWeiss

@MiWeiss MiWeiss commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Problem: BlockMiddleware.transform_block deep-copies every block unless allow_inplace_modification is set (the default for the unparse stack). With the generic copy.deepcopy (~140 calls per entry) this is ~85% of a write_string profile on a real-world .bib.

Fix: Block and Field get a __deepcopy__ backed by one attribute-aware helper: immutable primitives are shared, plain lists/dicts and nested blocks/fields are copied directly, everything else goes through copy.deepcopy. Semantics unchanged: independent copies, memo honoured (shared references and cycles preserved), subclasses and custom __deepcopy__ overrides supported. No middleware change.

Benchmark (write_string(lib), min of 3, single core; copy.deepcopy(entry) per entry):

corpus entries write main write PR deepcopy main deepcopy PR
crypto.bib (41 MB) 90,587 5.73 s 3.57 s 33.7 µs 11.1 µs
anthology.bib (91 MB) 131,040 9.44 s 6.04 s 35.8 µs 12.1 µs

Tests: new deepcopy tests for every block type, nested values, memo sharing, cycles, subclasses, and a write round-trip; 2751 passed, 12 skipped.

🤖 Generated with Claude Code

`BlockMiddleware.transform_block` deep-copies every block unless
`allow_inplace_modification` is set, which is the default for the
unparse stack. With the generic `copy.deepcopy` this dominated
`write_string`/`write_file` (~85% of a profile on a real-world .bib).

Implement `__deepcopy__` for `Block` and `Field` via a shared,
attribute-aware helper: immutable primitives are shared, plain lists
and dicts and nested blocks/fields are copied directly, anything else
is delegated to `copy.deepcopy`. Semantics are unchanged (independent
copies, memo honoured, cycles and shared references preserved,
subclasses and custom `__deepcopy__` overrides supported).

Per-entry deepcopy drops from ~34us to ~11us; `write_string` on a
41 MB / 91 MB .bib from 5.7s / 9.4s to 3.6s / 6.0s.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@MiWeiss MiWeiss closed this Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant