Add owned substring views#13
Conversation
cd0b59e to
1b92d63
Compare
Merging this PR will degrade performance by 10.45%
|
| 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)
1b92d63 to
e275dc6
Compare
fb1d268 to
da4b003
Compare
771feae to
84ac442
Compare
|
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. |
Materializing many substrings currently requires one
LeanStringallocation and copy per selected range. Add a separateLeanSubstringcompanion that shallow-clones aLeanStringowner and stores a validatedu32byte offset and length. The view is 24 bytes on 64-bit targets, leavesLeanStringitself 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
LeanStringwithout allocating; partial conversion copies only the selection, returns the original view alongside an allocation error, andcompactlets callers explicitly release a disproportionately large backing owner.For 9,895 tokens selected from a 1 MiB corpus, building views from an existing
LeanStringtook 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
LeanStringreplacement. A tiny view can pin an arbitrarily large owner until compacted, collections pay 50% more handle storage, and theu32fields 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_viewtarget 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.