From 515c5c76ba914d8e2ad6698fc525c6f47fa5cf93 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 9 Jan 2025 10:42:45 +0100 Subject: [PATCH] refactor inputsFromArgs; update concepts --- Framework/Core/include/Framework/ASoA.h | 4 +- .../Core/include/Framework/AnalysisTask.h | 124 +++++++++++------- .../Core/include/Framework/Configurable.h | 4 + 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 7b0b69ec8941f..8eb2b6f2392d9 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1009,7 +1009,7 @@ template -concept is_table = framework::specialization_of_template || framework::base_of_template; +concept is_table = framework::specialization_of_template> || framework::base_of_template>; /// Similar to a pair but not a pair, to avoid /// exposing the second type everywhere. @@ -1232,7 +1232,7 @@ struct ArrowHelpers { //! Helper to check if a type T is an iterator template -concept is_iterator = framework::base_of_template || framework::specialization_of_template; +concept is_iterator = framework::base_of_template> || framework::specialization_of_template>; template concept with_originals = requires { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index cf0bba20e74ea..807c99114f189 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -140,46 +140,82 @@ struct AnalysisDataProcessorBuilder { DataSpecUtils::updateInputList(inputs, InputSpec{o2::aod::label(), o2::aod::origin(), aod::description(o2::aod::signature()), R.version, Lifetime::Timeframe, inputMetadata}); } - template - static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos, std::vector& bk, std::vector& bku) requires(std::is_lvalue_reference_v&&...) + /// helpers to append expression information for a single argument + template + requires(!soa::is_filtered_table>) + static void addExpression(int, uint32_t, std::vector&) { - // update grouping cache - if constexpr (soa::is_iterator>>>) { - addGroupingCandidates(bk, bku); - } + } - // populate input list and expression infos - int ai = -1; - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); - ([&name, &value, &eInfos, &inputs, &hash, &ai]() mutable { + template + static void addExpression(int ai, uint32_t hash, std::vector& eInfos) + { + auto fields = soa::createFieldsFromColumns(typename std::decay_t::persistent_columns_t{}); + eInfos.emplace_back(ai, hash, std::decay_t::hashes(), std::make_shared(fields)); + } + + template + static void addExpression(int ai, uint32_t hash, std::vector& eInfos) + { + addExpression::parent_t>(ai, hash, eInfos); + } + + /// helpers to append InputSpec for a single argument + template + static void addInput(const char* name, bool value, std::vector& inputs) + { + [&name, &value, &inputs] refs, size_t... Is>(std::index_sequence) mutable { + (addOriginalRef(name, value, inputs), ...); + }.template operator()::originals>(std::make_index_sequence::originals.size()>()); + } + + template + static void addInput(const char* name, bool value, std::vector& inputs) + { + addInput::parent_t>(name, value, inputs); + } + + /// helper to append the inputs and expression information for normalized arguments + template + static void addInputsAndExpressions(uint32_t hash, const char* name, bool value, std::vector& inputs, std::vector& eInfos) + { + int ai = 0; + addExpression>(ai, hash, eInfos); + addInput>(name, value, inputs); + + ([&ai, &hash, &eInfos, &name, &value, &inputs]() mutable { ++ai; - using T = std::decay_t; - if constexpr (is_enumeration) { - std::vector inputMetadata; - // FIXME: for the moment we do not support begin, end and step. - DataSpecUtils::updateInputList(inputs, InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata}); - } else { - // populate expression infos - if constexpr (soa::is_filtered_table) { - auto fields = soa::createFieldsFromColumns(typename T::persistent_columns_t{}); - eInfos.emplace_back(ai, hash, T::hashes(), std::make_shared(fields)); - } else if constexpr (soa::is_filtered_iterator) { - auto fields = soa::createFieldsFromColumns(typename T::parent_t::persistent_columns_t{}); - eInfos.emplace_back(ai, hash, T::parent_t::hashes(), std::make_shared(fields)); - } - // add inputs from the originals - auto adder = [&name, &value, &inputs] refs, size_t... Is>(std::index_sequence) mutable { - (addOriginalRef(name, value, inputs), ...); - }; - if constexpr (soa::is_table || soa::is_filtered_table) { - adder.template operator()(std::make_index_sequence()); - } else if constexpr (soa::is_iterator || soa::is_filtered_iterator) { - adder.template operator()(std::make_index_sequence()); - } - } - return true; - }() && - ...); + using T = std::decay_t; + addExpression(ai, hash, eInfos); + addInput(name, value, inputs); + }(), ...); + } + + /// helper to parse the process arguments + /// 1. enumeration (must be a sole argument) + template + static void inputsFromArgs(R (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&, std::vector&, std::vector&) + { + std::vector inputMetadata; + // FIXME: for the moment we do not support begin, end and step. + DataSpecUtils::updateInputList(inputs, InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata}); + } + + /// 2. grouping case - 1st argument is an iterator + template + static void inputsFromArgs(R (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos, std::vector& bk, std::vector& bku) requires(std::is_lvalue_reference_v && (std::is_lvalue_reference_v&&...)) + { + addGroupingCandidates(bk, bku); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + addInputsAndExpressions::parent_t, Args...>(hash, name, value, inputs, eInfos); + } + + /// 3. generic case + template + static void inputsFromArgs(R (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos, std::vector&, std::vector&) requires(std::is_lvalue_reference_v && (std::is_lvalue_reference_v&&...)) + { + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + addInputsAndExpressions(hash, name, value, inputs, eInfos); } template @@ -498,19 +534,19 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) homogeneous_apply_refs([&inputs](auto& x) { return ConditionManager>::appendCondition(inputs, x); }, *task.get()); /// parse process functions defined by corresponding configurables - if constexpr (requires { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, bindingsKeys, bindingsKeysUnsorted); }) { + if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, bindingsKeys, bindingsKeysUnsorted); } homogeneous_apply_refs( - [name = name_str, &expressionInfos, &inputs, &bindingsKeys, &bindingsKeysUnsorted](auto& x) { - using D = std::decay_t; - if constexpr (base_of_template) { + overloaded { + [name = name_str, &expressionInfos, &inputs, &bindingsKeys, &bindingsKeysUnsorted](framework::is_process_configurable auto& x) mutable { // this pushes (argumentIndex,processHash,schemaPtr,nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators AnalysisDataProcessorBuilder::inputsFromArgs(x.process, (name + "/" + x.name).c_str(), x.value, inputs, expressionInfos, bindingsKeys, bindingsKeysUnsorted); return true; - } - return false; - }, + }, + [](auto&){ + return false; + }}, *task.get()); // add preslice declarations to slicing cache definition diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index f1167adb5ebdd..88e50cf3c7c26 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -11,6 +11,7 @@ #ifndef O2_FRAMEWORK_CONFIGURABLE_H_ #define O2_FRAMEWORK_CONFIGURABLE_H_ #include "Framework/ConfigurableKinds.h" +#include "Framework/Traits.h" #include #include namespace o2::framework @@ -95,6 +96,9 @@ struct ProcessConfigurable : Configurable { (As...); }; +template +concept is_process_configurable = base_of_template; + #define PROCESS_SWITCH(_Class_, _Name_, _Help_, _Default_) \ decltype(ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}) do##_Name_ = ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}; #define PROCESS_SWITCH_FULL(_Class_, _Method_, _Name_, _Help_, _Default_) \