Repository navigation
static_variant: look up type positions without a recursive template chain - #6
Conversation
…hain impl::position<X, Ts...> and impl::type_info<Ts...> recursed over the type pack, so every lookup instantiated a chain of N classes over a shrinking pack and the duplicate check instantiated O(N^2) of them. For the 107-alternative `operation` variant that was ~10k class instantiations in every TU that touched it. Both are now a single constexpr function over a pack expansion. Dispatch (storage_ops) is unchanged: a function-pointer table was measured 15% slower to compile with 3x the object size, because each per-type thunk gets the visitor body inlined into it. Measured with clang -O3 on operations.cpp: 8.4 s -> 6.7 s, object byte-identical. database.cpp: unchanged (80.3 s vs 80.2 s), object byte-identical. All 107 operations round-trip through raw and JSON with the same digest as before.
|
Independent sanity check from the consumer side (viz-cpp-node), no changes requested — two facts and one nit. 1. Semantics are preserved (measured, not eyeballed). I extracted the old recursive 2. One behavioural divergence, and it is unreachable. For 3. Build-time effect on GCC, not just Apple clang. On a TU that queries Nit: the new comment says "the 111-alternative The companion |
What
impl::position<X, Ts...>,impl::type_info<Ts...>and the type-list helpers instatic_variant.hppwere recursive class templates: for a variant of N alternatives,tag<T>for each T instantiated an O(N) chain, so a TU that touches every alternative (anything that serializesgraphene::protocol::operation, N = 107) paid O(N²) class-template instantiations in the frontend.They are now C++14
constexprfunctions over a pack-expandedbool/intarray (index_of,no_reference_types,no_duplicates,max_size).positionandtype_infokeep their names and members, so no caller changes.What did not change
storage_opsdispatch (the if-chain over the shrinking pack) is untouched. A jump-table/visit-array version was tried first: it made per-type thunks inline every visitor body, tripledoperations.oand sloweddatabase.cppby ~15%. The if-chain is what the optimizer handles best; only the lookup recursion was expensive.operations.obuilt with and without this patch is byte-identical. A round-trip digest over every operation alternative (raw pack/unpack + variant to/from JSON) is identical before and after.tag<T>::valuenumbering,count(),which()semantics.Numbers (Apple clang 17, -O2, M1)
libraries/protocol/ops.cpplibraries/chain/database.cppThe win is confined to TUs that enumerate all alternatives; most of the chain's build is backend-bound and unaffected.
Checks
static_assertcheck oftag,no_duplicates,no_reference_types,max_sizecompiles with Apple clang 17 and GCC 13 (-std=c++14 -Wall -Wextra).makewith this submodule, 13/13 fast ctest,consensus_sim_testsincluding a newoperation_variantsuite that round-trips all 107 alternatives (companion PR in viz-cpp-node).