FrameConfig: optional sizing hint for large messages - #2
Merged
Conversation
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.
FrameConfig: optional sizing hint for large messages
Problem
HybridMessageMap::SMALL_CAPACITY(128) has always been a fixed threshold: below it, parameters live in a flatstd::vector; above it, the container migrates totsl::robin_map. For messages known in advance to hold far more than 128 parameters, this migration costs more than necessary — the vector fills up, gets copied into a freshly created map, and that map is reserved for onlySMALL_CAPACITYslots regardless of the final size, so it keeps rehashing as more parameters are added past 128.What changed
FrameConfig(Structures.hpp) — a small opt-in struct with a single field,initial_reserve. Default (0) reproduces today's behavior exactly.HybridMessageMapgains aFrameConfig-aware constructor. Ifinitial_reserve > SMALL_CAPACITY, the container skips vector mode entirely and starts directly in map mode, with the hash map reserved for the real expected size instead ofSMALL_CAPACITY.clear()now preserves the hint. Previouslyclear()unconditionally reset the container to vector mode, which meant aFrameConfighint was only honored once — anyMessageFramereused in aadd()/serialize()/clear()loop lost the benefit on the very next cycle.clear()now re-primes storage using the original config instead of forgetting it, with a fallback to lazy vector mode onbad_allocsoclear()'snoexceptcontract still holds.MessageFramegains a matching constructor overload and a trailingFrameConfigparameter (with a default), so all existing call sites are unaffected. Note: the templated constructor is no longernoexcept, since a largeinitial_reservecan throwstd::bad_allocduring construction.SMALL_CAPACITYitself is untouched and stays a compile-time constant —FrameConfigonly controls initial storage mode/capacity, not the vector→map switching threshold. (This is deliberate: the threshold is used inunpack(), where a receiver has no access to the sender's config, and changing it to a runtime value would mean serialize/deserialize round-trips could behave differently per instance.)Testing
tests/test_hybrid_map.cpp: newFrameConfigHintsgroup — verifies (indirectly, viaiterate()order, sinceis_vector_modeis private) that a largeinitial_reserveputs the container in map mode immediately even well belowSMALL_CAPACITY, that this survivesclear(), and that the no-hint default path is unchanged (still resets to vector mode onclear()).benchmarks/benchmark.cpp: new--reserve Nflag, forwarded toFrameConfig::initial_reserve, printed in the results output.Docs
## Sizing hint via FrameConfig (optional)section, placed after## 🚀 Key featuressoSMALL_CAPACITY/ vector→map switching are already introduced by the time it's referenced.🎯 Optional sizing hintbullet in Key features.clear()section updated to describe hint-preserving behavior.--reservehint).examples/extended_usage.cpp— new example covering API nuances not shown inbasic_usage.cpp:add()/set()/update()contracts,FlatKey/_flatfast path,VALUE()type deduction,tryGet*()on a type mismatch, copy vs move semantics, the vector→map transition,FrameConfigusage (including hint-survives-clear()), header mutation after construction, multiple attachments, anddeserialize()error handling on malformed input. Wired intoCMakeLists.txtas a second example target.Backward compatibility
Fully additive.
FrameConfig{}(default) reproduces existing behavior bit-for-bit; nothing changes for code that doesn't touch the new constructor overloads. The one visible API change is the loss ofnoexceptonMessageFrame's templated constructor — flagged above since it's the only non-additive part of this change.