Skip to content

Commit 6fd6d9d

Browse files
committed
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<chars...>.
1 parent a6674c4 commit 6fd6d9d

3 files changed

Lines changed: 42 additions & 39 deletions

File tree

‎Framework/Core/include/Framework/HistogramRegistry.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ class HistogramRegistry
129129
// HistogramName class providing the associated hash and a first guess for the index in the registry
130130
struct HistName {
131131
// ctor for histogram names that are already hashed at compile time via HIST("myHistName")
132-
template <char... chars>
133-
constexpr HistName(const ConstStr<chars...>& hashedHistName);
132+
template <FixedString S>
133+
constexpr HistName(const ConstStr<S>& hashedHistName);
134134
char const* const str{};
135135
const uint32_t hash{};
136136
const uint32_t idx{};
@@ -386,8 +386,8 @@ int HistFiller::getBaseElementSize(T* ptr)
386386
//--------------------------------------------------------------------------------------------------
387387
//--------------------------------------------------------------------------------------------------
388388

389-
template <char... chars>
390-
constexpr HistogramRegistry::HistName::HistName(const ConstStr<chars...>& hashedHistName)
389+
template <FixedString S>
390+
constexpr HistogramRegistry::HistName::HistName(const ConstStr<S>& hashedHistName)
391391
: str(hashedHistName.str),
392392
hash(hashedHistName.hash),
393393
idx(hash & REGISTRY_BITMASK)

‎Framework/Core/include/Framework/StringHelpers.h‎

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,32 @@ consteval uint32_t compile_time_hash_from_literal(const char (&str)[N])
122122
return crc32(str, N - 2) ^ 0xFFFFFFFF;
123123
}
124124

125-
template <char... chars>
125+
/// A string usable as a template argument, so that a compile-time string is
126+
/// one type per distinct text rather than one type per character.
127+
template <std::size_t N>
128+
struct FixedString {
129+
char str[N]{};
130+
constexpr FixedString(std::string_view s)
131+
{
132+
for (std::size_t i = 0; i + 1 < N; ++i) {
133+
str[i] = s[i];
134+
}
135+
}
136+
constexpr FixedString(const char (&s)[N]) : FixedString(std::string_view{s, N - 1}) {}
137+
};
138+
139+
template <FixedString S>
126140
struct ConstStr {
127-
static constexpr char str[] = {chars..., '\0'};
128-
static constexpr uint32_t hash = compile_time_hash_from_literal(str);
141+
static constexpr char const* str = S.str;
142+
static constexpr uint32_t hash = compile_time_hash_from_literal(S.str);
129143
};
130144

131145
template <typename>
132146
struct is_const_str : std::false_type {
133147
};
134148

135-
template <char... chars>
136-
struct is_const_str<ConstStr<chars...>> : std::true_type {
149+
template <FixedString S>
150+
struct is_const_str<ConstStr<S>> : std::true_type {
137151
};
138152

139153
template <typename T>
@@ -142,27 +156,27 @@ consteval bool is_const_str_v(T)
142156
return is_const_str<T>::value;
143157
}
144158

145-
template <char... chars1, char... chars2>
146-
constexpr auto operator+(const ConstStr<chars1...>&, const ConstStr<chars2...>&)
159+
template <std::size_t N1, std::size_t N2>
160+
consteval FixedString<N1 + N2 - 1> concatenate(const FixedString<N1>& lhs, const FixedString<N2>& rhs)
147161
{
148-
return ConstStr<chars1..., chars2...>{};
162+
char str[N1 + N2 - 1]{};
163+
for (std::size_t i = 0; i + 1 < N1; ++i) {
164+
str[i] = lhs.str[i];
165+
}
166+
for (std::size_t i = 0; i + 1 < N2; ++i) {
167+
str[N1 - 1 + i] = rhs.str[i];
168+
}
169+
return FixedString<N1 + N2 - 1>(std::string_view{str, N1 + N2 - 2});
149170
}
150171

151-
namespace const_str_details
172+
template <FixedString S1, FixedString S2>
173+
constexpr auto operator+(const ConstStr<S1>&, const ConstStr<S2>&)
152174
{
153-
154-
template <typename T, std::size_t... Is>
155-
constexpr auto as_chars_impl(std::index_sequence<Is...>)
156-
{
157-
return ConstStr<T::str()[Is]...>{};
175+
return ConstStr<concatenate(S1, S2)>{};
158176
}
159177

160-
template <typename T>
161-
constexpr auto as_chars()
178+
namespace const_str_details
162179
{
163-
return as_chars_impl<T>(
164-
std::make_index_sequence<T::size() - 1>{});
165-
}
166180

167181
template <int N>
168182
constexpr auto get_str(const char (&str)[N])
@@ -187,19 +201,7 @@ constexpr auto get_size(const std::string_view& str)
187201
}
188202
} // namespace const_str_details
189203

190-
#define CONST_STR(literal) \
191-
[] { \
192-
struct literal_to_chars { \
193-
static constexpr decltype(auto) str() \
194-
{ \
195-
return const_str_details::get_str(literal); \
196-
} \
197-
static constexpr decltype(auto) size() \
198-
{ \
199-
return const_str_details::get_size(literal); \
200-
} \
201-
}; \
202-
return const_str_details::as_chars<literal_to_chars>(); \
203-
}()
204+
#define CONST_STR(literal) \
205+
ConstStr<FixedString<const_str_details::get_size(literal)>(literal)> {}
204206

205207
#endif // O2_FRAMEWORK_STRINGHELPERS_H

‎Framework/Core/test/test_StringHelpers.cxx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ TEST_CASE("StringHelpersConstStr")
4242

4343
auto myConstStr = CONST_STR("helloWorld");
4444
printString(myConstStr);
45-
static_assert(std::same_as<decltype(myConstStr), ConstStr<'h', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'>>);
45+
static_assert(std::same_as<decltype(myConstStr), ConstStr<"helloWorld">>);
4646
static_assert(myConstStr.hash == (uint32_t)942280617);
4747
REQUIRE(myConstStr.hash == compile_time_hash("helloWorld"));
4848

@@ -52,7 +52,8 @@ TEST_CASE("StringHelpersConstStr")
5252

5353
auto myConstStr2 = CONST_STR("hello") + CONST_STR("Universe");
5454
printString(myConstStr2);
55-
static_assert(std::same_as<decltype(myConstStr2), ConstStr<'h', 'e', 'l', 'l', 'o', 'U', 'n', 'i', 'v', 'e', 'r', 's', 'e'>>);
55+
static_assert(std::same_as<decltype(myConstStr2), ConstStr<"helloUniverse">>);
56+
static_assert((CONST_STR("a/") + CONST_STR("b/") + CONST_STR("c")).hash == compile_time_hash("a/b/c"));
5657

5758
enum ParticleSpecies {
5859
kPion,

0 commit comments

Comments
 (0)