Skip to content

Add owned substring views#13

Closed
charliermarsh wants to merge 3 commits into
charlie/codspeed-benchmarksfrom
charlie/substring-view
Closed

Add owned substring views#13
charliermarsh wants to merge 3 commits into
charlie/codspeed-benchmarksfrom
charlie/substring-view

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Jul 6, 2026

Copy link
Copy Markdown
Member

Materializing many substrings currently requires one LeanString allocation and copy per selected range. Add a separate LeanSubstring companion that shallow-clones a LeanString owner and stores a validated u32 byte offset and length. The view is 24 bytes on 64-bit targets, leaves LeanString itself unchanged, and performs checked UTF-8 slicing without caching an interior pointer.

Expose borrowed and consuming constructors, with the consuming form returning the original owner when validation fails. The view implements the usual string borrowing, comparison, ordering, hashing, formatting, and dereference traits against its selected text. A full-owner view converts back to LeanString without allocating; partial conversion copies only the selection, returns the original view alongside an allocation error, and compact lets callers explicitly release a disproportionately large backing owner.

For 9,895 tokens selected from a 1 MiB corpus, building views from an existing LeanString took 36.0 µs versus 174.3 µs for materialized strings, a 4.84x improvement, and reduced incremental allocations from 9,896 to one with 82.5% fewer requested bytes. Including the initial owner copy still took 49.3 µs, a 3.53x improvement, but narrowed the requested-byte saving to 5.1%. Hashing and clone/drop were neutral to slightly faster, while scanning was 12% slower and sorting was 72.5% slower because each element is larger and repeatedly validates its range.

This is a draft because the type is valuable for tokenization and build-heavy workflows but is not a general LeanString replacement. A tiny view can pin an arbitrarily large owner until compacted, collections pay 50% more handle storage, and the u32 fields cannot describe starts or lengths beyond 4 GiB. We should decide whether that narrow public abstraction is worth exposing as-is or whether the stronger long-term design is a collection-level owner with compact per-element descriptors and cached comparison prefixes.

This branch includes the benchmark foundation from #15 and adds a substring_view target over the same 1 MiB corpus. It covers materialized strings versus existing-owner and owner-constructing views across build, scan, hash, clone/drop, sort, and tiny-retention workloads. Both CodSpeed simulation and memory discovery pass. The view-specific cases are new benchmark names, so the first run records their absolute baseline; the paired materialized cases make their CPU and allocation tradeoffs visible in the same report.

@charliermarsh charliermarsh force-pushed the charlie/substring-view branch 3 times, most recently from cd0b59e to 1b92d63 Compare July 7, 2026 12:36
@codspeed-hq

codspeed-hq Bot commented Jul 7, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 10.45%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 143 untouched benchmarks
🆕 26 new benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation lean_shared_first[0] 500 ns 558.3 ns -10.45%
🆕 Memory hash_allocated N/A 0 B N/A
🆕 Memory hash_views N/A 0 B N/A
🆕 Memory scan_allocated N/A 0 B N/A
🆕 Memory scan_views N/A 0 B N/A
🆕 Memory allocated_lean_strings N/A 1.3 MB N/A
🆕 Memory views_existing_owner N/A 231.9 KB N/A
🆕 Memory views_from_str N/A 1.2 MB N/A
🆕 Memory clone_drop_allocated N/A 154.6 KB N/A
🆕 Memory clone_drop_views N/A 231.9 KB N/A
🆕 Memory sort_allocated N/A 0 B N/A
🆕 Memory sort_views N/A 0 B N/A
🆕 Memory substring/retain_tiny/allocated N/A 0 B N/A
🆕 Memory substring/retain_tiny/view N/A 0 B N/A
🆕 Simulation hash_allocated N/A 1.9 ms N/A
🆕 Simulation hash_views N/A 1.9 ms N/A
🆕 Simulation scan_allocated N/A 546.1 µs N/A
🆕 Simulation scan_views N/A 492.2 µs N/A
🆕 Simulation allocated_lean_strings N/A 3.2 ms N/A
🆕 Simulation views_existing_owner N/A 706.8 µs N/A
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression with the CodSpeed MCP and your agent.


Comparing charlie/substring-view (84ac442) with charlie/codspeed-benchmarks (da4b003)

Open in CodSpeed

@charliermarsh charliermarsh changed the base branch from main to charlie/codspeed-benchmarks July 7, 2026 12:43
@charliermarsh charliermarsh force-pushed the charlie/substring-view branch from 1b92d63 to e275dc6 Compare July 7, 2026 12:44
@charliermarsh charliermarsh force-pushed the charlie/codspeed-benchmarks branch from fb1d268 to da4b003 Compare July 7, 2026 17:01
@charliermarsh charliermarsh force-pushed the charlie/substring-view branch from 771feae to 84ac442 Compare July 7, 2026 17:06
@charliermarsh

Copy link
Copy Markdown
Member Author

Closing this experiment. View construction is fast and allocation-light, but 24-byte handles, retained owners, and slower scan/sort behavior make this a poor core string type. A collection-level owner with compact range descriptors is the more promising direction.

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