Skip to content

FrameConfig: optional sizing hint for large messages - #2

Merged
stubcpp merged 5 commits into
masterfrom
frame_config_test
Aug 3, 2026
Merged

FrameConfig: optional sizing hint for large messages#2
stubcpp merged 5 commits into
masterfrom
frame_config_test

Conversation

@stubcpp

@stubcpp stubcpp commented Aug 3, 2026

Copy link
Copy Markdown
Owner

FrameConfig: optional sizing hint for large messages

Problem

HybridMessageMap::SMALL_CAPACITY (128) has always been a fixed threshold: below it, parameters live in a flat std::vector; above it, the container migrates to tsl::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 only SMALL_CAPACITY slots 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.
  • HybridMessageMap gains a FrameConfig-aware constructor. If initial_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 of SMALL_CAPACITY.
  • clear() now preserves the hint. Previously clear() unconditionally reset the container to vector mode, which meant a FrameConfig hint was only honored once — any MessageFrame reused in a add()/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 on bad_alloc so clear()'s noexcept contract still holds.
  • MessageFrame gains a matching constructor overload and a trailing FrameConfig parameter (with a default), so all existing call sites are unaffected. Note: the templated constructor is no longer noexcept, since a large initial_reserve can throw std::bad_alloc during construction.
  • SMALL_CAPACITY itself is untouched and stays a compile-time constant — FrameConfig only controls initial storage mode/capacity, not the vector→map switching threshold. (This is deliberate: the threshold is used in unpack(), 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: new FrameConfigHints group — verifies (indirectly, via iterate() order, since is_vector_mode is private) that a large initial_reserve puts the container in map mode immediately even well below SMALL_CAPACITY, that this survives clear(), and that the no-hint default path is unchanged (still resets to vector mode on clear()).
  • benchmarks/benchmark.cpp: new --reserve N flag, forwarded to FrameConfig::initial_reserve, printed in the results output.
  • Measuring added in Scenario D on the readme.md.

Docs

  • New ## Sizing hint via FrameConfig (optional) section, placed after ## 🚀 Key features so SMALL_CAPACITY / vector→map switching are already introduced by the time it's referenced.
  • New 🎯 Optional sizing hint bullet in Key features.
  • clear() section updated to describe hint-preserving behavior.
  • New Scenario D in Performance Benchmarks (large frame, with/without --reserve hint).
  • examples/extended_usage.cpp — new example covering API nuances not shown in basic_usage.cpp: add()/set()/update() contracts, FlatKey/_flat fast path, VALUE() type deduction, tryGet*() on a type mismatch, copy vs move semantics, the vector→map transition, FrameConfig usage (including hint-survives-clear()), header mutation after construction, multiple attachments, and deserialize() error handling on malformed input. Wired into CMakeLists.txt as 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 of noexcept on MessageFrame's templated constructor — flagged above since it's the only non-additive part of this change.

@stubcpp
stubcpp merged commit 301e492 into master Aug 3, 2026
2 checks passed
@stubcpp
stubcpp deleted the frame_config_test branch August 3, 2026 23:33
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