From 6fd6d9d615a5b8aec6a5022f2b61aebd9854a168 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 4 Nov 2026 13:38:53 +0100 Subject: [PATCH] Framework: key HIST() names by a fixed-string template argument HIST()/CONST_STR() created, at every call site, a lambda, a local struct, an index_sequence expansion over the characters and a ConstStr<'a','b',...> type. They now produce ConstStr<"ab">: one type per distinct name, the hash still a static member computed once per name, and concatenation still at the type level, so names passed as function parameters keep working. Hashes are unchanged. 2,000 distinct names (a quarter concatenated with a directory) in a template instantiated twice, -O2: clang 21 3.76 s -> 1.90 s and 591 -> 238 MB peak; GCC 16 6.41 s -> 3.04 s and 602 -> 366 MB. Object size +6%. Needs AliceO2Group/O2Physics#18584, which updates the helpers that spelled out ConstStr. --- .../include/Framework/HistogramRegistry.h | 8 +-- .../Core/include/Framework/StringHelpers.h | 68 ++++++++++--------- Framework/Core/test/test_StringHelpers.cxx | 5 +- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index a09a9988fb576..9725fa3f15cbc 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -129,8 +129,8 @@ class HistogramRegistry // HistogramName class providing the associated hash and a first guess for the index in the registry struct HistName { // ctor for histogram names that are already hashed at compile time via HIST("myHistName") - template - constexpr HistName(const ConstStr& hashedHistName); + template + constexpr HistName(const ConstStr& hashedHistName); char const* const str{}; const uint32_t hash{}; const uint32_t idx{}; @@ -386,8 +386,8 @@ int HistFiller::getBaseElementSize(T* ptr) //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- -template -constexpr HistogramRegistry::HistName::HistName(const ConstStr& hashedHistName) +template +constexpr HistogramRegistry::HistName::HistName(const ConstStr& hashedHistName) : str(hashedHistName.str), hash(hashedHistName.hash), idx(hash & REGISTRY_BITMASK) diff --git a/Framework/Core/include/Framework/StringHelpers.h b/Framework/Core/include/Framework/StringHelpers.h index a2ee758435efc..2485705fd3062 100644 --- a/Framework/Core/include/Framework/StringHelpers.h +++ b/Framework/Core/include/Framework/StringHelpers.h @@ -122,18 +122,32 @@ consteval uint32_t compile_time_hash_from_literal(const char (&str)[N]) return crc32(str, N - 2) ^ 0xFFFFFFFF; } -template +/// A string usable as a template argument, so that a compile-time string is +/// one type per distinct text rather than one type per character. +template +struct FixedString { + char str[N]{}; + constexpr FixedString(std::string_view s) + { + for (std::size_t i = 0; i + 1 < N; ++i) { + str[i] = s[i]; + } + } + constexpr FixedString(const char (&s)[N]) : FixedString(std::string_view{s, N - 1}) {} +}; + +template struct ConstStr { - static constexpr char str[] = {chars..., '\0'}; - static constexpr uint32_t hash = compile_time_hash_from_literal(str); + static constexpr char const* str = S.str; + static constexpr uint32_t hash = compile_time_hash_from_literal(S.str); }; template struct is_const_str : std::false_type { }; -template -struct is_const_str> : std::true_type { +template +struct is_const_str> : std::true_type { }; template @@ -142,27 +156,27 @@ consteval bool is_const_str_v(T) return is_const_str::value; } -template -constexpr auto operator+(const ConstStr&, const ConstStr&) +template +consteval FixedString concatenate(const FixedString& lhs, const FixedString& rhs) { - return ConstStr{}; + char str[N1 + N2 - 1]{}; + for (std::size_t i = 0; i + 1 < N1; ++i) { + str[i] = lhs.str[i]; + } + for (std::size_t i = 0; i + 1 < N2; ++i) { + str[N1 - 1 + i] = rhs.str[i]; + } + return FixedString(std::string_view{str, N1 + N2 - 2}); } -namespace const_str_details +template +constexpr auto operator+(const ConstStr&, const ConstStr&) { - -template -constexpr auto as_chars_impl(std::index_sequence) -{ - return ConstStr{}; + return ConstStr{}; } -template -constexpr auto as_chars() +namespace const_str_details { - return as_chars_impl( - std::make_index_sequence{}); -} template constexpr auto get_str(const char (&str)[N]) @@ -187,19 +201,7 @@ constexpr auto get_size(const std::string_view& str) } } // namespace const_str_details -#define CONST_STR(literal) \ - [] { \ - struct literal_to_chars { \ - static constexpr decltype(auto) str() \ - { \ - return const_str_details::get_str(literal); \ - } \ - static constexpr decltype(auto) size() \ - { \ - return const_str_details::get_size(literal); \ - } \ - }; \ - return const_str_details::as_chars(); \ - }() +#define CONST_STR(literal) \ + ConstStr(literal)> {} #endif // O2_FRAMEWORK_STRINGHELPERS_H diff --git a/Framework/Core/test/test_StringHelpers.cxx b/Framework/Core/test/test_StringHelpers.cxx index 96abe20b814a9..57e6e0ddbe5e5 100644 --- a/Framework/Core/test/test_StringHelpers.cxx +++ b/Framework/Core/test/test_StringHelpers.cxx @@ -42,7 +42,7 @@ TEST_CASE("StringHelpersConstStr") auto myConstStr = CONST_STR("helloWorld"); printString(myConstStr); - static_assert(std::same_as>); + static_assert(std::same_as>); static_assert(myConstStr.hash == (uint32_t)942280617); REQUIRE(myConstStr.hash == compile_time_hash("helloWorld")); @@ -52,7 +52,8 @@ TEST_CASE("StringHelpersConstStr") auto myConstStr2 = CONST_STR("hello") + CONST_STR("Universe"); printString(myConstStr2); - static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert((CONST_STR("a/") + CONST_STR("b/") + CONST_STR("c")).hash == compile_time_hash("a/b/c")); enum ParticleSpecies { kPion,