Skip to content

Commit 2c4d26b

Browse files
committed
DPL: use C++26 extension to expand packs where available
O(1) in both CPU and time rather than O(N) when compiling the pack expansion. Removes the limit to 100 elements in a struct. Requires XCode 26.4
1 parent 2a2edee commit 2c4d26b

3 files changed

Lines changed: 93 additions & 70 deletions

File tree

Framework/Core/include/Framework/AnalysisTask.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ struct AnalysisDataProcessorBuilder {
317317
groupingTable.setPointerReconstructor(pointerReconstructor);
318318
}
319319
#endif
320-
constexpr const int numElements = nested_brace_constructible_size<false, std::decay_t<Task>>() / 10;
320+
constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<Task>>();
321321

322322
// set filtered tables for partitions with grouping
323323
homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& element) {
@@ -546,7 +546,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args)
546546
newOrigin.runtimeInit(newOriginStr.c_str(), std::min(newOriginStr.size(), 4UL));
547547
}
548548

549-
constexpr const int numElements = nested_brace_constructible_size<false, std::decay_t<T>>() / 10;
549+
constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<T>>();
550550

551551
/// make sure options and configurables are set before expression infos are created
552552
homogeneous_apply_refs_sized<numElements>([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get());

Framework/Core/include/Framework/TableBuilder.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,23 @@ constexpr auto tuple_to_pack(std::tuple<ARGS...>&&)
558558

559559
/// Helper function to convert a brace-initialisable struct to
560560
/// a tuple.
561+
#ifdef DPL_STRUCTURED_BINDING_PACKS
562+
#ifdef __clang__
563+
#pragma clang diagnostic push
564+
#pragma clang diagnostic ignored "-Wc++26-extensions"
565+
#endif
566+
template <class T>
567+
auto constexpr to_tuple(T&& object) noexcept
568+
{
569+
auto&& [... members] = object;
570+
return std::make_tuple(members...);
571+
}
572+
#ifdef __clang__
573+
#pragma clang diagnostic pop
574+
#endif
575+
576+
#else // DPL_STRUCTURED_BINDING_PACKS
577+
561578
template <class T>
562579
auto constexpr to_tuple(T&& object) noexcept
563580
{
@@ -579,6 +596,8 @@ auto constexpr to_tuple(T&& object) noexcept
579596
}
580597
}
581598

599+
#endif // DPL_STRUCTURED_BINDING_PACKS
600+
582601
template <typename... ARGS>
583602
constexpr auto makeHolderTypes()
584603
{

Framework/Foundation/include/Framework/StructToTuple.h

Lines changed: 72 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
#include <Framework/Traits.h>
1515
#include <array>
1616

17+
// Structured binding packs (P1061) are C++26, but clang implements them as an
18+
// extension in every language mode and advertises them via the feature test
19+
// macro, so we can use them while still compiling as C++20.
20+
#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 202411L
21+
#define DPL_STRUCTURED_BINDING_PACKS 1
22+
#endif
23+
24+
#ifndef DPL_STRUCTURED_BINDING_PACKS
1725
namespace
1826
{
1927
template <class T, typename... Args>
@@ -24,9 +32,11 @@ template <class T, typename... Args>
2432
std::false_type
2533
brace_test(...);
2634
} // namespace
35+
#endif
2736

2837
namespace o2::framework
2938
{
39+
#ifndef DPL_STRUCTURED_BINDING_PACKS
3040
struct any_type {
3141
template <class T>
3242
constexpr operator T(); // non explicit
@@ -35,19 +45,67 @@ struct any_type {
3545
template <class T, typename... Args>
3646
struct is_braces_constructible : decltype(brace_test<T, Args...>(0)) {
3747
};
48+
#endif
3849

39-
#define DPL_REPEAT_0(x)
40-
#define DPL_REPEAT_1(x) x
41-
#define DPL_REPEAT_2(x) x, x
42-
#define DPL_REPEAT_3(x) x, x, x
43-
#define DPL_REPEAT_4(x) x, x, x, x
44-
#define DPL_REPEAT_5(x) x, x, x, x, x
45-
#define DPL_REPEAT_6(x) x, x, x, x, x, x
46-
#define DPL_REPEAT_7(x) x, x, x, x, x, x, x
47-
#define DPL_REPEAT_8(x) x, x, x, x, x, x, x, x
48-
#define DPL_REPEAT_9(x) x, x, x, x, x, x, x, x, x
49-
#define DPL_REPEAT_10(x) x, x, x, x, x, x, x, x, x, x
50-
#define DPL_REPEAT(x, d, u) DPL_REPEAT_##d(DPL_REPEAT_10(x)), DPL_REPEAT_##u(x)
50+
struct UniversalType {
51+
template <typename T>
52+
operator T()
53+
{
54+
}
55+
};
56+
57+
template <typename T>
58+
consteval auto brace_constructible_size(auto... Members)
59+
{
60+
if constexpr (requires { T{Members...}; } == false) {
61+
static_assert(sizeof...(Members) != 0, "You need to make sure that you have implicit constructors or that you call the explicit constructor correctly.");
62+
return sizeof...(Members) - 1;
63+
} else {
64+
return brace_constructible_size<T>(Members..., UniversalType{});
65+
}
66+
}
67+
68+
template <bool B, typename T>
69+
consteval int nested_brace_constructible_size()
70+
{
71+
using type = std::decay_t<T>;
72+
constexpr int nesting = B ? 1 : 0;
73+
return brace_constructible_size<type>() - nesting;
74+
}
75+
76+
/// The size to be passed to homogeneous_apply_refs_sized for T. Structured
77+
/// binding packs do not need to know how many members T has, so we can skip
78+
/// counting them altogether.
79+
template <bool B, typename T>
80+
consteval int homogeneous_apply_refs_size()
81+
{
82+
#ifdef DPL_STRUCTURED_BINDING_PACKS
83+
return 0;
84+
#else
85+
return nested_brace_constructible_size<B, T>() / 10;
86+
#endif
87+
}
88+
89+
#ifdef DPL_STRUCTURED_BINDING_PACKS
90+
#ifdef __clang__
91+
#pragma clang diagnostic push
92+
#pragma clang diagnostic ignored "-Wc++26-extensions"
93+
#endif
94+
template <bool B = false, class T, int D = 0, typename L>
95+
constexpr auto homogeneous_apply_refs(L l, T&& object)
96+
{
97+
auto&& [... members] = object;
98+
if constexpr (sizeof...(members) == 0) {
99+
return std::array<bool, 0>();
100+
} else {
101+
return std::array{l(members)...};
102+
}
103+
}
104+
#ifdef __clang__
105+
#pragma clang diagnostic pop
106+
#endif
107+
108+
#else // DPL_STRUCTURED_BINDING_PACKS
51109

52110
#define DPL_ENUM_0(pre, post)
53111
#define DPL_ENUM_1(pre, post) pre##0##post
@@ -97,54 +155,6 @@ struct is_braces_constructible : decltype(brace_test<T, Args...>(0)) {
97155

98156
#define DPL_FENUM(f, pre, post, d, u) DPL_FENUM_##d##0(f, pre, post), DPL_FENUM_##u(f, pre##d, post)
99157

100-
#define DPL_10_As DPL_REPEAT_10(A)
101-
#define DPL_20_As DPL_10_As, DPL_10_As
102-
#define DPL_30_As DPL_20_As, DPL_10_As
103-
#define DPL_40_As DPL_30_As, DPL_10_As
104-
#define DPL_50_As DPL_40_As, DPL_10_As
105-
#define DPL_60_As DPL_50_As, DPL_10_As
106-
#define DPL_70_As DPL_60_As, DPL_10_As
107-
#define DPL_80_As DPL_70_As, DPL_10_As
108-
#define DPL_90_As DPL_80_As, DPL_10_As
109-
#define DPL_100_As DPL_90_As, DPL_10_As
110-
111-
#define DPL_0_9(pre, po) pre##0##po, pre##1##po, pre##2##po, pre##3##po, pre##4##po, pre##5##po, pre##6##po, pre##7##po, pre##8##po, pre##9##po
112-
113-
#define BRACE_CONSTRUCTIBLE_ENTRY_LOW(u) \
114-
constexpr(is_braces_constructible<type, DPL_REPEAT_##u(A)>{}) \
115-
{ \
116-
return u; \
117-
}
118-
#define BRACE_CONSTRUCTIBLE_ENTRY(d, u) \
119-
constexpr(is_braces_constructible<type, DPL_REPEAT(A, d, u)>{}) \
120-
{ \
121-
return d##u; \
122-
}
123-
124-
#define BRACE_CONSTRUCTIBLE_ENTRY_TENS(d) \
125-
constexpr(is_braces_constructible<type, DPL_##d##0_As>{}) \
126-
{ \
127-
return d##0; \
128-
}
129-
130-
struct UniversalType {
131-
template <typename T>
132-
operator T()
133-
{
134-
}
135-
};
136-
137-
template <typename T>
138-
consteval auto brace_constructible_size(auto... Members)
139-
{
140-
if constexpr (requires { T{Members...}; } == false) {
141-
static_assert(sizeof...(Members) != 0, "You need to make sure that you have implicit constructors or that you call the explicit constructor correctly.");
142-
return sizeof...(Members) - 1;
143-
} else {
144-
return brace_constructible_size<T>(Members..., UniversalType{});
145-
}
146-
}
147-
148158
#define DPL_HOMOGENEOUS_APPLY_ENTRY_LOW(u) \
149159
constexpr(numElements == u) \
150160
{ \
@@ -166,14 +176,6 @@ consteval auto brace_constructible_size(auto... Members)
166176
return std::array<decltype(l(p0)), d##0>{DPL_FENUM_##d##0(l, p, )}; \
167177
}
168178

169-
template <bool B, typename T>
170-
consteval int nested_brace_constructible_size()
171-
{
172-
using type = std::decay_t<T>;
173-
constexpr int nesting = B ? 1 : 0;
174-
return brace_constructible_size<type>() - nesting;
175-
}
176-
177179
template <bool B = false, class T, int D = nested_brace_constructible_size<B, T>() / 10, typename L>
178180
requires(D == 9)
179181
constexpr auto homogeneous_apply_refs(L l, T&& object)
@@ -373,6 +375,8 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
373375
// clang-format on
374376
}
375377

378+
#endif // DPL_STRUCTURED_BINDING_PACKS
379+
376380
template <int D, typename T, typename L>
377381
constexpr auto homogeneous_apply_refs_sized(L l, T&& object)
378382
{

0 commit comments

Comments
 (0)