diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index bfd67a03ecbc1..d99d33dcb4068 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -315,6 +315,25 @@ struct AnalysisDataProcessorBuilder { (std::get(dest).bindInternalIndicesTo(&std::get(src)), ...); } + /// The members that binding a process function's arguments can affect. + struct BindableMembers { + template + constexpr auto operator()(M& member) const + { + if constexpr (is_partition || is_combinations_generator) { + return std::tuple{member}; + } else { + return std::tuple<>{}; + } + } + }; + + template + static void forEachRef(Members& members, L&& l) + { + std::apply([&l](auto&... member) { (l(member), ...); }, members); + } + template static void invokeProcess(Task& task, InputRecord& inputs, R matchers, PointerReconstructor const& pointerReconstructor, void (Task::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"}) { @@ -326,23 +345,22 @@ struct AnalysisDataProcessorBuilder { } constexpr const int numElements = homogeneous_apply_refs_size>(); + auto bindable = apply_refs_tuple_cat_sized(BindableMembers{}, task); // set filtered tables for partitions with grouping - homogeneous_apply_refs_sized([&groupingTable](auto& element) { + forEachRef(bindable, [&groupingTable](auto& element) { analysis_task_parsers::setPartition(element, groupingTable); analysis_task_parsers::bindInternalIndicesPartition(element, &groupingTable); return true; - }, - task); + }); if constexpr (sizeof...(Associated) == 0) { // single argument to process - homogeneous_apply_refs_sized([&groupingTable](auto& element) { + forEachRef(bindable, [&groupingTable](auto& element) { analysis_task_parsers::bindExternalIndicesPartition(element, &groupingTable); analysis_task_parsers::setGroupedCombination(element, groupingTable); return true; - }, - task); + }); if constexpr (soa::is_iterator) { for (auto& element : groupingTable) { std::invoke(processingFunction, task, *element); @@ -355,13 +373,12 @@ struct AnalysisDataProcessorBuilder { auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, matchers, processingFunction, infos); // pre-bind self indices std::apply( - [&task](auto&... t) mutable { - (homogeneous_apply_refs_sized( - [&t](auto& p) { - analysis_task_parsers::bindInternalIndicesPartition(p, &t); - return true; - }, - task), + [&bindable](auto&... t) mutable { + (forEachRef(bindable, + [&t](auto& p) { + analysis_task_parsers::bindInternalIndicesPartition(p, &t); + return true; + }), ...); }, associatedTables); @@ -370,14 +387,13 @@ struct AnalysisDataProcessorBuilder { }, associatedTables); - auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable { + auto binder = [&bindable, &groupingTable, &associatedTables](auto& x) mutable { x.bindExternalIndices(&groupingTable, &std::get>(associatedTables)...); - homogeneous_apply_refs_sized([&x](auto& t) mutable { + forEachRef(bindable, [&x](auto& t) mutable { analysis_task_parsers::setPartition(t, x); analysis_task_parsers::bindExternalIndicesPartition(t, &x); return true; - }, - task); + }); }; groupingTable.bindExternalIndices(&std::get>(associatedTables)...); @@ -389,11 +405,10 @@ struct AnalysisDataProcessorBuilder { associatedTables); // GroupedCombinations bound separately, as they should be set once for all associated tables - homogeneous_apply_refs_sized([&groupingTable, &associatedTables](auto& t) { + forEachRef(bindable, [&groupingTable, &associatedTables](auto& t) { analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables); return true; - }, - task); + }); overwriteInternalIndices(associatedTables, associatedTables); if constexpr (soa::is_iterator) { auto slicer = GroupSlicer(groupingTable, associatedTables, slices, newOrigin); @@ -412,11 +427,10 @@ struct AnalysisDataProcessorBuilder { associatedSlices); // bind partitions and grouping table - homogeneous_apply_refs_sized([&groupingTable](auto& x) { + forEachRef(bindable, [&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; - }, - task); + }); [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple...>& at) { std::invoke(processingFunction, task, g, std::get>(at)...); @@ -424,11 +438,10 @@ struct AnalysisDataProcessorBuilder { } } else { // bind partitions and grouping table - homogeneous_apply_refs_sized([&groupingTable](auto& x) { + forEachRef(bindable, [&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; - }, - task); + }); [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple...>& at) { std::invoke(processingFunction, task, g, std::get>(at)...); diff --git a/Framework/Foundation/include/Framework/StructToTuple.h b/Framework/Foundation/include/Framework/StructToTuple.h index e06df1bab984a..b02d964f44334 100644 --- a/Framework/Foundation/include/Framework/StructToTuple.h +++ b/Framework/Foundation/include/Framework/StructToTuple.h @@ -13,6 +13,7 @@ #include #include +#include // Structured binding packs (P1061) are C++26, but clang implements them as an // extension in every language mode and advertises them via the feature test @@ -91,11 +92,13 @@ consteval int homogeneous_apply_refs_size() #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++26-extensions" #endif -template +template constexpr auto homogeneous_apply_refs(L l, T&& object) { auto&& [... members] = object; - if constexpr (sizeof...(members) == 0) { + if constexpr (Cat) { + return std::tuple_cat(l(members)...); + } else if constexpr (sizeof...(members) == 0) { return std::array(); } else { return std::array{l(members)...}; @@ -155,28 +158,42 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) #define DPL_FENUM(f, pre, post, d, u) DPL_FENUM_##d##0(f, pre, post), DPL_FENUM_##u(f, pre##d, post) -#define DPL_HOMOGENEOUS_APPLY_ENTRY_LOW(u) \ - constexpr(numElements == u) \ - { \ - auto&& [DPL_ENUM_##u(p, )] = object; \ - return std::array{DPL_FENUM_##u(l, p, )}; \ +#define DPL_HOMOGENEOUS_APPLY_RESULT(n, ...) \ + if constexpr (Cat) { \ + return std::tuple_cat(__VA_ARGS__); \ + } else { \ + return std::array{__VA_ARGS__}; \ } -#define DPL_HOMOGENEOUS_APPLY_ENTRY(d, u) \ - constexpr(numElements == d##u) \ - { \ - auto&& [DPL_ENUM(p, , d, u)] = object; \ - return std::array{DPL_FENUM(l, p, , d, u)}; \ +#define DPL_HOMOGENEOUS_APPLY_EMPTY \ + if constexpr (Cat) { \ + return std::tuple<>(); \ + } else { \ + return std::array(); \ } -#define DPL_HOMOGENEOUS_APPLY_ENTRY_TENS(d) \ - constexpr(numElements == d##0) \ - { \ - auto&& [DPL_ENUM_##d##0(p, )] = object; \ - return std::array{DPL_FENUM_##d##0(l, p, )}; \ +#define DPL_HOMOGENEOUS_APPLY_ENTRY_LOW(u) \ + constexpr(numElements == u) \ + { \ + auto&& [DPL_ENUM_##u(p, )] = object; \ + DPL_HOMOGENEOUS_APPLY_RESULT(u, DPL_FENUM_##u(l, p, )) \ } -template () / 10, typename L> +#define DPL_HOMOGENEOUS_APPLY_ENTRY(d, u) \ + constexpr(numElements == d##u) \ + { \ + auto&& [DPL_ENUM(p, , d, u)] = object; \ + DPL_HOMOGENEOUS_APPLY_RESULT(d##u, DPL_FENUM(l, p, , d, u)) \ + } + +#define DPL_HOMOGENEOUS_APPLY_ENTRY_TENS(d) \ + constexpr(numElements == d##0) \ + { \ + auto&& [DPL_ENUM_##d##0(p, )] = object; \ + DPL_HOMOGENEOUS_APPLY_RESULT(d##0, DPL_FENUM_##d##0(l, p, )) \ + } + +template () / 10, typename L, bool Cat = false> requires(D == 9) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -192,11 +209,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (9, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (9, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (9) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 8) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -212,11 +229,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (8, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (8, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (8) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 7) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -232,11 +249,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (7, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (7, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (7) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 6) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -252,11 +269,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (6, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (6, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (6) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 5) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -272,11 +289,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (5, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (5, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (5) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 4) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -292,11 +309,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (4, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (4, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (4) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 3) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -312,11 +329,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (3, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (3, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (3) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 2) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -332,11 +349,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (2, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (2, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (2) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 1) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -352,11 +369,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY (1, 2) else if DPL_HOMOGENEOUS_APPLY_ENTRY (1, 1) else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (1) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } -template () / 10, typename L> +template () / 10, typename L, bool Cat = false> requires(D == 0) constexpr auto homogeneous_apply_refs(L l, T&& object) { @@ -371,7 +388,7 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (3) else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (2) else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (1) - else { return std::array(); } + else { DPL_HOMOGENEOUS_APPLY_EMPTY } // clang-format on } @@ -383,6 +400,15 @@ constexpr auto homogeneous_apply_refs_sized(L l, T&& object) return homogeneous_apply_refs(l, object); } +/// Like homogeneous_apply_refs_sized, but l returns a std::tuple for each +/// member and the results are concatenated: returning std::tuple or +/// std::tuple<>() selects members. The calls to l are unsequenced. +template +constexpr auto apply_refs_tuple_cat_sized(L l, T&& object) +{ + return homogeneous_apply_refs(l, object); +} + } // namespace o2::framework #endif // O2_FRAMEWORK_STRUCTTOTUPLE_H_