From dcf3a7b51c005a5aff8b1ca5d6eabef94b7165ab Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Fri, 7 Feb 2025 11:06:36 +0100 Subject: [PATCH 1/6] DPL Analysis: replace SFINAE with overloaded restricted templates --- .../Core/include/Framework/AnalysisHelpers.h | 32 + .../Core/include/Framework/AnalysisManagers.h | 884 ++++++++---------- .../Core/include/Framework/AnalysisTask.h | 85 +- Framework/Core/include/Framework/Condition.h | 10 + .../Core/include/Framework/Configurable.h | 11 +- .../Core/include/Framework/Expressions.h | 3 + .../include/Framework/GroupedCombinations.h | 17 + .../include/Framework/HistogramRegistry.h | 3 + Framework/Core/include/Framework/SliceCache.h | 5 +- 9 files changed, 505 insertions(+), 545 deletions(-) diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index bb7e5e14aaa75..eb091622312c4 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -190,6 +190,9 @@ template struct Produces : WritingCursor { }; +template +concept is_produces = requires (T t) { typename T::cursor_t; typename T::persistent_table_t; &T::cursor; }; + /// Use this to group together produces. Useful to separate them logically /// or simply to stay within the 100 elements per Task limit. /// Use as: @@ -201,6 +204,9 @@ struct Produces : WritingCursor { struct ProducesGroup { }; +template +concept is_produces_group = std::derived_from; + /// Helper template for table transformations template struct TableTransform { @@ -250,6 +256,7 @@ constexpr auto transformBase() template struct Spawns : decltype(transformBase()) { + using spawnable_t = T; using metadata = decltype(transformBase())::metadata; using extension_t = typename metadata::extension_table_t; using base_table_t = typename metadata::base_table_t; @@ -277,6 +284,12 @@ struct Spawns : decltype(transformBase()) { std::shared_ptr extension = nullptr; }; +template +concept is_spawns = requires(T t) { + typename T::metadata; + std::same_as; +}; + /// Policy to control index building /// Exclusive index: each entry in a row has a valid index /// Sparse index: values in a row can be (-1), index table is isomorphic (joinable) @@ -420,6 +433,7 @@ constexpr auto transformBase() template struct Builds : decltype(transformBase()) { + using buildable_t = T; using metadata = decltype(transformBase())::metadata; using IP = std::conditional_t, IndexBuilder>; using Key = metadata::Key; @@ -455,6 +469,13 @@ struct Builds : decltype(transformBase()) { } }; +template +concept is_builds = requires(T t) { + typename T::metadata; + typename T::Key; + std::same_as; +}; + /// This helper class allows you to declare things which will be created by a /// given analysis task. Currently wrapped objects are limited to be TNamed /// descendants. Objects will be written to a ROOT file at the end of the @@ -550,11 +571,15 @@ struct OutputObj { uint32_t mTaskHash; }; +template +concept is_outputobj = requires (T t) { &T::setObject; std::same_as>; }; + /// This helper allows you to fetch a Sevice from the context or /// by using some singleton. This hopefully will hide the Singleton and /// We will be able to retrieve it in a more thread safe manner later on. template struct Service { + using service_t = T; T* service; decltype(auto) operator->() const @@ -567,6 +592,9 @@ struct Service { } }; +template +concept is_service = requires (T t) { std::same_as; &T::operator->;}; + auto getTableFromFilter(soa::is_filtered_table auto const& table, soa::SelectionVector&& selection) { return std::make_unique>>(std::vector{table}, std::forward(selection)); @@ -581,6 +609,7 @@ void initializePartitionCaches(std::set const& hashes, std::shared_ptr template struct Partition { + using content_t = T; Partition(expressions::Node&& filter_) : filter{std::forward(filter_)} { } @@ -690,6 +719,9 @@ struct Partition { return mFiltered->size(); } }; + +template +concept is_partition = requires (T t) {&T::updatePlaceholders; std::same_as; std::same_as>>;}; } // namespace o2::framework namespace o2::soa diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 30ebf1799b227..24b64734d7a8e 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -31,547 +31,483 @@ namespace o2::framework { -template -struct GroupedCombinationManager { - template - static void setGroupedCombination(ANY&, TG&, T2s&...) - { - } -}; +namespace { +template +static inline auto extractOriginal(ProcessingContext& pc) +{ + return pc.inputs().get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable(); +} -template -struct GroupedCombinationManager> { - template - static void setGroupedCombination(GroupedCombinationsGenerator& comb, TG& grouping, std::tuple& associated) - { - static_assert(sizeof...(T2s) > 0, "There must be associated tables in process() for a correct pair"); - if constexpr (std::same_as) { - static_assert((framework::has_type(pack{}) && ...), "You didn't subscribed to all tables requested for mixing"); - comb.setTables(grouping, associated); - } - } -}; +template +static inline std::vector> extractOriginals(framework::pack, ProcessingContext& pc) +{ + return {extractOriginal(pc)...}; +} -template -struct PartitionManager { - template - static void setPartition(ANY&, T2s&...) - { - } +template refs> +static inline auto extractOriginals(ProcessingContext& pc) +{ + return [&](std::index_sequence) -> std::vector> { + return {pc.inputs().get(o2::aod::label())->asArrowTable()...}; + }(std::make_index_sequence()); +} +} - template - static void bindExternalIndices(ANY&, Ts*...) - { - } +namespace analysis_task_parsers { - template - static void bindInternalIndices(ANY&, E*) - { - } +/// Options handling +template +bool appendOption(std::vector&, O&) +{ + return false; +} - template - static void getBoundToExternalIndices(ANY&, Ts&...) - { - } +template +bool appendOption(std::vector& options, O& option) +{ + return ConfigurableHelpers::appendOption(options, option); +} - static void updatePlaceholders(ANY&, InitContext&) - { +template +bool appendOption(std::vector& options, O& optionGroup) +{ + if constexpr (requires { optionGroup.prefix; }) { + homogeneous_apply_refs([prefix = optionGroup.prefix](C& option) { // apend group prefix if set + if constexpr (requires { option.name; }) { + option.name.insert(0, 1, '.'); + option.name.insert(0, prefix); + } + return true; + }, + optionGroup); } + homogeneous_apply_refs([&options](auto& option) { return appendOption(options, option); }, optionGroup); + return true; +} - static bool newDataframe(ANY&) - { - return false; - } -}; +template +bool prepareOption(InitContext&, O&) +{ + return false; +} -template -struct PartitionManager> { - template - static void doSetPartition(Partition& partition, T2& table) - { - if constexpr (std::same_as) { - partition.bindTable(table); - } +template +bool prepareOption(InitContext& context, O& configurable) +{ + if constexpr (variant_trait_v != VariantType::Unknown) { + configurable.value = context.options().get(configurable.name.c_str()); + } else { + auto pt = context.options().get(configurable.name.c_str()); + configurable.value = RootConfigParamHelpers::as(pt); } + return true; +} - template - static void setPartition(Partition& partition, T2s&... tables) - { - (doSetPartition(partition, tables), ...); - } +template +bool prepareOption(InitContext& context, O& configurableGroup) +{ + homogeneous_apply_refs([&context](auto&& configurable) { return prepareOption(context, configurable); }, configurableGroup); + return true; +} - template - static void bindExternalIndices(Partition& partition, Ts*... tables) - { - partition.bindExternalIndices(tables...); - } +/// Conditions handling +template +bool appendCondition(std::vector&, C&) +{ + return false; +} - template - static void bindInternalIndices(Partition& partition, E* table) - { - if constexpr (o2::soa::is_binding_compatible_v>()) { - partition.bindInternalIndicesTo(table); - } - } +template +bool appendCondition(std::vector& inputs, C& condition) +{ + inputs.emplace_back(InputSpec{condition.path, "AODC", runtime_hash(condition.path.c_str()), Lifetime::Condition, ccdbParamSpec(condition.path)}); + return true; +} - static void updatePlaceholders(Partition& partition, InitContext& context) - { - partition.updatePlaceholders(context); - } +template +bool appendCondition(std::vector& inputs, C& conditionGroup) +{ + homogeneous_apply_refs([&inputs](auto& condition) { return appendCondition(inputs, condition); }, conditionGroup); + return true; +} - static bool newDataframe(Partition& partition) - { - partition.dataframeChanged = true; - return true; - } -}; +/// Table auto-creation handling +template +bool requestInputs(std::vector&, T const&) +{ + return false; +} -template -struct FilterManager { - static bool createExpressionTrees(ANY&, std::vector&) - { - return false; +template +bool requestInputs(std::vector& inputs, T const& spawns) +{ + auto base_specs = spawns.base_specs(); + for (auto base_spec : base_specs) { + base_spec.metadata.push_back(ConfigParamSpec{std::string{"control:spawn"}, VariantType::Bool, true, {"\"\""}}); + DataSpecUtils::updateInputList(inputs, std::forward(base_spec)); } + return true; +} - static bool updatePlaceholders(ANY&, InitContext&) - { - return false; +template +bool requestInputs(std::vector& inputs, T const& builds) +{ + auto base_specs = builds.base_specs(); + for (auto base_spec : base_specs) { + base_spec.metadata.push_back(ConfigParamSpec{std::string{"control:build"}, VariantType::Bool, true, {"\"\""}}); + DataSpecUtils::updateInputList(inputs, std::forward(base_spec)); } -}; + return true; +} -template <> -struct FilterManager { - static bool createExpressionTrees(expressions::Filter const& filter, std::vector& expressionInfos) - { - expressions::updateExpressionInfos(filter, expressionInfos); - return true; - } +template +bool newDataframeCondition(InputRecord&, C&) +{ + return false; +} - static bool updatePlaceholders(expressions::Filter& filter, InitContext& ctx) - { - expressions::updatePlaceholders(filter, ctx); - return true; - } -}; +template +bool newDataframeCondition(InputRecord& record, C& condition) +{ + condition.instance = (typename C::type*)record.get(condition.path).get(); + return true; +} -/// A manager which takes care of condition objects +template +bool newDataframeCondition(InputRecord& record, C& conditionGroup) +{ + homogeneous_apply_refs([&record](auto&& condition) { return newDataframeCondition(record, condition); }, conditionGroup); + return true; +} + +/// Outputs handling template -struct ConditionManager { - template - static bool appendCondition(std::vector& inputs, ANY& x) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&inputs](auto& y) { return ConditionManager>::appendCondition(inputs, y); }, x); - return true; - } else { - return false; - } - } +bool appendOutput(std::vector&, T&, uint32_t) +{ + return false; +} - template - static bool newDataframe(InputRecord& record, ANY& x) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&record](auto&& y) { return ConditionManager>::newDataframe(record, y); }, x); - return true; - } else { - return false; - } - } -}; +template +bool appendOutput(std::vector& outputs, T&, uint32_t) +{ + outputs.emplace_back(OutputForTable::spec()); + return true; +} -template -struct ConditionManager> { - static bool appendCondition(std::vector& inputs, Condition& what) - { - inputs.emplace_back(InputSpec{what.path, "AODC", runtime_hash(what.path.c_str()), Lifetime::Condition, ccdbParamSpec(what.path)}); - return true; - } - static bool newDataframe(InputRecord& inputs, Condition& what) - { - what.instance = (OBJ*)inputs.get(what.path).get(); - return true; - } -}; +template +bool appendOutput(std::vector& outputs, T& producesGroup, uint32_t hash) +{ + homogeneous_apply_refs([&outputs, hash](auto& produces) { return appendOutput(outputs, produces, hash); }, producesGroup); + return true; +} + +template +bool appendOutput(std::vector& outputs, T& hr, uint32_t hash) +{ + hr.setHash(hash); + outputs.emplace_back(hr.spec()); + return true; +} + +template +bool appendOutput(std::vector& outputs, T& obj, uint32_t hash) +{ + obj.setHash(hash); + outputs.emplace_back(obj.spec()); + return true; +} + +template +bool appendOutput(std::vector& outputs, T& spawns, uint32_t) +{ + outputs.emplace_back(spawns.spec()); + return true; +} + +template +bool appendOutput(std::vector& outputs, T& builds, uint32_t) +{ + outputs.emplace_back(builds.spec()); + return true; +} -/// SFINAE placeholder, also handles recursion in ProcessGroup template -struct OutputManager { - template - static bool appendOutput(std::vector& outputs, ANY& what, uint32_t v) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&outputs, v](auto& p) { return OutputManager>::appendOutput(outputs, p, v); }, what); - return true; - } - return false; - } +bool postRunOutput(EndOfStreamContext&, T&) +{ + return false; +} - template - static bool prepare(ProcessingContext& context, ANY& what) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&context](auto& p) { return OutputManager>::prepare(context, p); }, what); - return true; - } - return false; - } +template +bool postRunOutput(EndOfStreamContext& context, T& hr) +{ + auto& deviceSpec = context.services().get(); + context.outputs().snapshot(hr.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *(hr.getListOfHistograms())); + hr.clean(); + return true; +} - template - static bool postRun(EndOfStreamContext& context, ANY& what) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&context](auto& p) { return OutputManager>::postRun(context, p); }, what); - return true; - } - return true; - } +template +bool postRunOutput(EndOfStreamContext& context, T& obj) +{ + auto& deviceSpec = context.services().get(); + context.outputs().snapshot(obj.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *obj); + return true; +} - template - static bool finalize(ProcessingContext& context, ANY& what) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&context](auto& p) { return OutputManager>::finalize(context, p); }, what); - return true; - } - return true; - } -}; +template +bool prepareOutput(ProcessingContext&, T&) +{ + return false; +} -/// Produces specialization -template -struct OutputManager> { - static bool appendOutput(std::vector& outputs, Produces& /*what*/, uint32_t) - { - outputs.emplace_back(OutputForTable::persistent_table_t>::spec()); - return true; - } - static bool prepare(ProcessingContext& context, Produces& what) - { - what.resetCursor(std::move(context.outputs().make(OutputForTable::persistent_table_t>::ref()))); - return true; - } - static bool finalize(ProcessingContext&, Produces& what) - { - what.setLabel(o2::aod::label::persistent_table_t::ref>()); - what.release(); - return true; - } - static bool postRun(EndOfStreamContext&, Produces&) - { - return true; - } -}; +template +bool prepareOutput(ProcessingContext& context, T& produces) +{ + produces.resetCursor(std::move(context.outputs().make(OutputForTable::ref()))); + return true; +} -/// HistogramRegistry specialization -template <> -struct OutputManager { - static bool appendOutput(std::vector& outputs, HistogramRegistry& what, uint32_t hash) - { - what.setHash(hash); - outputs.emplace_back(what.spec()); - return true; - } - static bool prepare(ProcessingContext&, HistogramRegistry&) - { - return true; - } +template +bool prepareOutput(ProcessingContext& context, T& producesGroup) +{ + homogeneous_apply_refs([&context](auto& produces) { return prepareOutput(context, produces); }, producesGroup); + return true; +} - static bool finalize(ProcessingContext&, HistogramRegistry&) - { - return true; +template +bool prepareOutput(ProcessingContext& context, T& spawns) +{ + using metadata = o2::aod::MetadataTrait>::metadata; + auto originalTable = soa::ArrowHelpers::joinTables(extractOriginals(context)); + if (originalTable->schema()->fields().empty() == true) { + using base_table_t = typename T::base_table_t::table_t; + originalTable = makeEmptyTable(o2::aod::label()); } - static bool postRun(EndOfStreamContext& context, HistogramRegistry& what) - { - auto& deviceSpec = context.services().get(); - context.outputs().snapshot(what.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *(what.getListOfHistograms())); - what.clean(); - return true; - } -}; + spawns.extension = std::make_shared(o2::framework::spawner>(originalTable, o2::aod::label())); + spawns.table = std::make_shared(soa::ArrowHelpers::joinTables({spawns.extension->asArrowTable(), originalTable})); + return true; +} + +template +bool prepareOuput(ProcessingContext& context, T& builds) +{ + using metadata = o2::aod::MetadataTrait>::metadata; + return builds.template build(builds.pack(), extractOriginals(context)); +} -/// OutputObj specialization template -struct OutputManager> { - static bool appendOutput(std::vector& outputs, OutputObj& what, uint32_t hash) - { - what.setHash(hash); - outputs.emplace_back(what.spec()); - return true; - } - static bool prepare(ProcessingContext&, OutputObj&) - { - return true; - } +bool finalizeOutput(ProcessingContext&, T&) +{ + return false; +} - static bool finalize(ProcessingContext&, OutputObj&) - { - return true; - } +template +bool finalizeOutput(ProcessingContext&, T& produces) +{ + produces.setLabel(o2::aod::label()); + produces.release(); + return true; +} - static bool postRun(EndOfStreamContext& context, OutputObj& what) - { - auto& deviceSpec = context.services().get(); - context.outputs().snapshot(what.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *what); - return true; - } -}; +template +bool finalizeOutput(ProcessingContext& context, T& producesGroup) +{ + homogeneous_apply_refs([&context](auto& produces) { return finalizeOutput(context, produces); }, producesGroup); + return true; +} -/// Spawns specializations -template -static inline auto extractOriginal(ProcessingContext& pc) +template +bool finalizeOutput(ProcessingContext& context, T& spawns) { - return pc.inputs().get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable(); + context.outputs().adopt(spawns.output(), spawns.asArrowTable()); + return true; } -template -static inline std::vector> extractOriginals(framework::pack, ProcessingContext& pc) +template +bool finalizeOutput(ProcessingContext& context, T& builds) { - return {extractOriginal(pc)...}; + context.outputs().adopt(builds.output(), builds.asArrowTable()); + return true; } -template refs> -static inline auto extractOriginals(ProcessingContext& pc) +/// Service handling +template +bool addService(std::vector&, T&) { - return [&](std::index_sequence) -> std::vector> { - return {pc.inputs().get(o2::aod::label())->asArrowTable()...}; - }(std::make_index_sequence()); + return false; } -template -struct OutputManager> { - static bool appendOutput(std::vector& outputs, Spawns& what, uint32_t) - { - outputs.emplace_back(what.spec()); - return true; +template +bool addService(std::vector& specs, T&) +{ + if constexpr (o2::framework::base_of_template) { + auto p = typename T::service_t{}; + auto loadableServices = PluginManager::parsePluginSpecString(p.loadSpec.c_str()); + PluginManager::loadFromPlugin(loadableServices, specs); } + return true; +} - static bool prepare(ProcessingContext& pc, Spawns& what) - { - using metadata = o2::aod::MetadataTrait>::metadata; - auto originalTable = soa::ArrowHelpers::joinTables(extractOriginals(pc)); - if (originalTable->schema()->fields().empty() == true) { - using base_table_t = typename Spawns::base_table_t::table_t; - originalTable = makeEmptyTable(o2::aod::label()); - } +template +bool prepareService(InitContext&, T&) +{ + return false; +} - what.extension = std::make_shared::extension_t>(o2::framework::spawner>(originalTable, o2::aod::label())); - what.table = std::make_shared(soa::ArrowHelpers::joinTables({what.extension->asArrowTable(), originalTable})); +template +bool prepareService(InitContext& context, T& service) +{ + using S = typename T::service_t; + if constexpr (requires { &S::instance; }) { + service.service = &(S::instance()); // Sigh... return true; - } - - static bool finalize(ProcessingContext& pc, Spawns& what) - { - pc.outputs().adopt(what.output(), what.asArrowTable()); + } else { + service.service = &(context.services().get()); return true; } + return false; +} - static bool postRun(EndOfStreamContext&, Spawns&) - { - return true; - } -}; +template +bool postRunService(EndOfStreamContext&, T&) +{ + return false; +} -/// Builds specialization -template -static inline auto doExtractOriginal(framework::pack, ProcessingContext& pc) +template +bool postRunService(EndOfStreamContext&, T& service) { - if constexpr (sizeof...(Ts) == 1) { - return pc.inputs().get(aod::MetadataTrait>>::metadata::tableLabel())->asArrowTable(); - } else { - return std::vector{pc.inputs().get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable()...}; + // FIXME: for the moment we only need endOfStream to be + // stateless. In the future we might want to pass it EndOfStreamContext + if constexpr (requires { &T::service_t::endOfStream; }) { + service.service->endOfStream(); + return true; } + return false; } -template -static inline auto extractOriginalsVector(framework::pack, ProcessingContext& pc) +/// Filter handling +template +bool updatePlaceholders(InitContext&, T&) { - return std::vector{extractOriginalJoined(pc)...}; + return false; } -template -struct OutputManager> { - static bool appendOutput(std::vector& outputs, Builds& what, uint32_t) - { - outputs.emplace_back(what.spec()); - return true; - } +template +bool updatePlaceholders(InitContext& context, T& filter) +{ + expressions::updatePlaceholders(filter, context); + return true; +} - static bool prepare(ProcessingContext& pc, Builds& what) - { - using metadata = o2::aod::MetadataTrait>::metadata; - return what.template build(what.pack(), extractOriginals(pc)); - } +template +bool updatePlaceholders(InitContext& context, T& partition) +{ + partition.updatePlaceholders(context); + return true; +} - static bool finalize(ProcessingContext& pc, Builds& what) - { - pc.outputs().adopt(what.output(), what.asArrowTable()); - return true; - } +template +bool createExpressionTrees(std::vector&, T&) +{ + return false; +} - static bool postRun(EndOfStreamContext&, Builds&) - { - return true; - } -}; +template +bool createExpressionTrees(std::vector& expressionInfos, T& filter) +{ + expressions::updateExpressionInfos(filter, expressionInfos); + return true; +} template -struct ServiceManager { - template - static bool add(std::vector& /*specs*/, ANY& /*any*/) - { - return false; - } +bool newDataframePartition(T&) +{ + return false; +} - template - static bool prepare(InitContext&, ANY&) - { - return false; - } +template +bool newDataframePartition(T& partition) +{ + partition.dataframeChanged = true; + return true; +} - template - static bool postRun(EndOfStreamContext&, ANY&) - { - return false; - } -}; +template +void setPartition(P&, T&...) +{ +} -template -struct ServiceManager> { - static bool add(std::vector& specs, Service& /*service*/) - { - if constexpr (o2::framework::base_of_template) { - T p = T{}; - auto loadableServices = PluginManager::parsePluginSpecString(p.loadSpec.c_str()); - PluginManager::loadFromPlugin(loadableServices, specs); - } - return true; - } +template +void setPartition(P& partition, T&... tables) +{ + ([&](){ if constexpr (std::same_as) {partition.bindTable(tables);} }(), ...); +} - static bool prepare(InitContext& context, Service& service) - { - if constexpr (requires { &T::instance; }) { - service.service = &(T::instance()); // Sigh... - return true; - } else { - service.service = &(context.services().get()); - return true; - } - return false; - } +template +void bindInternalIndicesPartition(P&, T*) +{ +} - /// If a service has a method endOfStream, it is called at the end of the stream. - static bool postRun(EndOfStreamContext& /*context*/, Service& service) - { - // FIXME: for the moment we only need endOfStream to be - // stateless. In the future we might want to pass it EndOfStreamContext - if constexpr (requires { &T::endOfStream; }) { - service.service->endOfStream(); - return true; - } - return false; +template +void bindInternalIndicesPartition(P& partition, T* table) +{ + if constexpr (o2::soa::is_binding_compatible_v>()) { + partition.bindInternalIndicesTo(table); } -}; +} -template -struct CacheManager { - template - static bool initialize(InitContext&, ANY&) - { - return false; - } - template - static bool initialize(ProcessingContext&, ANY&) - { - return false; - } -}; +template +void bindExternalIndicesPartition(P&, T*...) +{ +} -template <> -struct CacheManager { - static bool initialize(InitContext&, SliceCache&) - { - return false; - } - static bool initialize(ProcessingContext& pc, SliceCache& cache) - { - if (cache.ptr == nullptr) { - cache.ptr = &pc.services().get(); - } - return true; - } -}; +template +void bindExternalIndicesPartition(P& partition, T*... tables) +{ + partition.bindExternalIndices(tables...); +} +/// Cache handling template -struct OptionManager { - template - static bool appendOption(std::vector& options, ANY& x) - { - /// Recurse, in case we are brace constructible - if constexpr (std::derived_from) { - if constexpr (requires { x.prefix; }) { - homogeneous_apply_refs([prefix = x.prefix](C& y) { // apend group prefix if set - if constexpr (requires { y.name; }) { - y.name.insert(0, 1, '.'); - y.name.insert(0, prefix); - } - return true; - }, - x); - } - homogeneous_apply_refs([&options](auto& y) { return OptionManager>::appendOption(options, y); }, x); - return true; - } else { - return false; - } - } +bool preInitializeCache(InitContext&, T&) +{ + return false; +} - template - static bool prepare(InitContext& ic, ANY& x) - { - if constexpr (std::derived_from) { - homogeneous_apply_refs([&ic](auto&& y) { return OptionManager>::prepare(ic, y); }, x); - return true; - } else { - return false; - } - } -}; +template +bool initializeCache(ProcessingContext&, T&) +{ + return false; +} -template -struct OptionManager> { - static bool appendOption(std::vector& options, Configurable& what) - { - return ConfigurableHelpers::appendOption(options, what); +template +bool initializeCache(ProcessingContext& context, T& cache) +{ + if (cache.ptr == nullptr) { + cache.ptr = &context.services().get(); } + return true; +} - static bool prepare(InitContext& context, Configurable& what) - { - if constexpr (variant_trait_v::type> != VariantType::Unknown) { - what.value = context.options().get(what.name.c_str()); - } else { - auto pt = context.options().get(what.name.c_str()); - what.value = RootConfigParamHelpers::as(pt); - } - return true; - } -}; +/// Combinations handling +template + requires(!is_combinations_generator) +void setGroupedCombination(C&, TG&, Ts&...) +{ +} -template -struct OptionManager> { - static bool appendOption(std::vector& options, ProcessConfigurable& what) - { - options.emplace_back(ConfigParamSpec{what.name, variant_trait_v>, what.value, {what.help}, what.kind}); - return true; +template + requires((sizeof...(Ts) > 0) && (C::compatible(framework::pack{}))) +static void setGroupedCombination(C& comb, TG& grouping, std::tuple& associated) +{ + if constexpr (std::same_as) { + comb.setTables(grouping, associated); } +} - static bool prepare(InitContext& context, ProcessConfigurable& what) - { - what.value = context.options().get(what.name.c_str()); - return true; - } -}; +} // analysis_task_parsers template struct UpdateProcessSwitches { @@ -593,44 +529,6 @@ struct UpdateProcessSwitches> { } }; -/// Manager template to facilitate extended tables spawning -template -struct SpawnManager { - static bool requestInputs(std::vector&, T const&) { return false; } -}; - -template -struct SpawnManager> { - static bool requestInputs(std::vector& inputs, Spawns& spawns) - { - auto base_specs = spawns.base_specs(); - for (auto base_spec : base_specs) { - base_spec.metadata.push_back(ConfigParamSpec{std::string{"control:spawn"}, VariantType::Bool, true, {"\"\""}}); - DataSpecUtils::updateInputList(inputs, std::forward(base_spec)); - } - return true; - } -}; - -/// Manager template for building index tables -template -struct IndexManager { - static bool requestInputs(std::vector&, T const&) { return false; }; -}; - -template -struct IndexManager> { - static bool requestInputs(std::vector& inputs, Builds& builds) - { - auto base_specs = builds.base_specs(); - for (auto base_spec : base_specs) { - base_spec.metadata.push_back(ConfigParamSpec{std::string{"control:build"}, VariantType::Bool, true, {"\"\""}}); - DataSpecUtils::updateInputList(inputs, std::forward(base_spec)); - } - return true; - } -}; - /// Manager template to handle slice caching template struct PresliceManager { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 5d18a31dcb955..69d609f279e99 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -319,18 +319,18 @@ struct AnalysisDataProcessorBuilder { auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, processingFunction, infos); // set filtered tables for partitions with grouping - homogeneous_apply_refs([&groupingTable](auto& x) { - PartitionManager>::setPartition(x, groupingTable); - PartitionManager>::bindInternalIndices(x, &groupingTable); + homogeneous_apply_refs([&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([&groupingTable](auto& x) { - PartitionManager>::bindExternalIndices(x, &groupingTable); - GroupedCombinationManager>::setGroupedCombination(x, groupingTable); + homogeneous_apply_refs([&groupingTable](auto& element) { + analysis_task_parsers::bindExternalIndicesPartition(element, &groupingTable); + analysis_task_parsers::setGroupedCombination(element, groupingTable); return true; }, task); @@ -353,7 +353,7 @@ struct AnalysisDataProcessorBuilder { [&task](auto&... t) mutable { (homogeneous_apply_refs( [&t](auto& p) { - PartitionManager>::bindInternalIndices(p, &t); + analysis_task_parsers::bindInternalIndicesPartition(p, &t); return true; }, task), @@ -364,8 +364,8 @@ struct AnalysisDataProcessorBuilder { auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable { x.bindExternalIndices(&groupingTable, &std::get>(associatedTables)...); homogeneous_apply_refs([&x](auto& t) mutable { - PartitionManager>::setPartition(t, x); - PartitionManager>::bindExternalIndices(t, &x); + analysis_task_parsers::setPartition(t, x); + analysis_task_parsers::bindExternalIndicesPartition(t, &x); return true; }, task); @@ -381,7 +381,7 @@ struct AnalysisDataProcessorBuilder { // GroupedCombinations bound separately, as they should be set once for all associated tables homogeneous_apply_refs([&groupingTable, &associatedTables](auto& t) { - GroupedCombinationManager>::setGroupedCombination(t, groupingTable, associatedTables); + analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables); return true; }, task); @@ -399,7 +399,7 @@ struct AnalysisDataProcessorBuilder { // bind partitions and grouping table homogeneous_apply_refs([&groupingTable](auto& x) { - PartitionManager>::bindExternalIndices(x, &groupingTable); + analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, task); @@ -409,7 +409,7 @@ struct AnalysisDataProcessorBuilder { } else { // bind partitions and grouping table homogeneous_apply_refs([&groupingTable](auto& x) { - PartitionManager>::bindExternalIndices(x, &groupingTable); + analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, task); @@ -529,9 +529,9 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector bindingsKeysUnsorted; /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options, &hash](auto& x) { return OptionManager>::appendOption(options, x); }, *task.get()); + homogeneous_apply_refs([&options, &hash](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs - homogeneous_apply_refs([&inputs](auto& x) { return ConditionManager>::appendCondition(inputs, x); }, *task.get()); + homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); /// parse process functions defined by corresponding configurables if constexpr (requires { &T::process; }) { @@ -552,16 +552,10 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) // add preslice declarations to slicing cache definition homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& x) { return PresliceManager>::registerCache(x, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); - // request base tables for spawnable extended tables + // request base tables for spawnable extended tables and indices to be built // this checks for duplications - homogeneous_apply_refs([&inputs](auto& x) { - return SpawnManager>::requestInputs(inputs, x); - }, - *task.get()); - - // request base tables for indices to be built - homogeneous_apply_refs([&inputs](auto& x) { - return IndexManager>::requestInputs(inputs, x); + homogeneous_apply_refs([&inputs](auto& element) { + return analysis_task_parsers::requestInputs(inputs, element); }, *task.get()); @@ -570,40 +564,36 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) LOG(warn) << "Task " << name_str << " has no inputs"; } - homogeneous_apply_refs([&outputs, &hash](auto& x) { return OutputManager>::appendOutput(outputs, x, hash); }, *task.get()); + homogeneous_apply_refs([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); auto requiredServices = CommonServices::defaultServices(); auto arrowServices = CommonServices::arrowServices(); requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end()); - homogeneous_apply_refs([&requiredServices](auto& x) { return ServiceManager>::add(requiredServices, x); }, *task.get()); + homogeneous_apply_refs([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); auto algo = AlgorithmSpec::InitCallback{[task = task, expressionInfos, bindingsKeys, bindingsKeysUnsorted](InitContext& ic) mutable { - homogeneous_apply_refs([&ic](auto&& x) { return OptionManager>::prepare(ic, x); }, *task.get()); - homogeneous_apply_refs([&ic](auto&& x) { return ServiceManager>::prepare(ic, x); }, *task.get()); + homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); + homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); auto& callbacks = ic.services().get(); auto endofdatacb = [task](EndOfStreamContext& eosContext) { - homogeneous_apply_refs([&eosContext](auto&& x) { - using X = std::decay_t; - ServiceManager::postRun(eosContext, x); - return OutputManager::postRun(eosContext, x); }, + homogeneous_apply_refs([&eosContext](auto& element) { + analysis_task_parsers::postRunService(eosContext, element); + analysis_task_parsers::postRunOutput(eosContext, element); + return true;}, *task.get()); eosContext.services().get().readyToQuit(QuitRequest::Me); }; callbacks.set(endofdatacb); - /// update configurables in filters + /// update configurables in filters and partitions homogeneous_apply_refs( - [&ic](auto& x) -> bool { return FilterManager>::updatePlaceholders(x, ic); }, - *task.get()); - /// update configurables in partitions - homogeneous_apply_refs( - [&ic](auto& x) -> bool { PartitionManager>::updatePlaceholders(x, ic); return true; }, + [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); }, *task.get()); /// create for filters gandiva trees matched to schemas and store the pointers into expressionInfos - homogeneous_apply_refs([&expressionInfos](auto& x) { - return FilterManager>::createExpressionTrees(x, expressionInfos); + homogeneous_apply_refs([&expressionInfos](auto& element) { + return analysis_task_parsers::createExpressionTrees(expressionInfos, element); }, *task.get()); @@ -614,16 +604,16 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) ic.services().get().setCaches(std::move(bindingsKeys)); ic.services().get().setCachesUnsorted(std::move(bindingsKeysUnsorted)); // initialize global caches - homogeneous_apply_refs([&ic](auto& x) { - return CacheManager>::initialize(ic, x); + homogeneous_apply_refs([&ic](auto& element) { + return analysis_task_parsers::preInitializeCache(ic, element); }, *(task.get())); return [task, expressionInfos](ProcessingContext& pc) mutable { // load the ccdb object from their cache - homogeneous_apply_refs([&pc](auto&& x) { return ConditionManager>::newDataframe(pc.inputs(), x); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); // reset partitions once per dataframe - homogeneous_apply_refs([](auto&& x) { return PartitionManager>::newDataframe(x); }, *task.get()); + homogeneous_apply_refs([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); // reset selections for the next dataframe for (auto& info : expressionInfos) { info.resetSelection = true; @@ -635,12 +625,9 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) }, *(task.get())); // initialize local caches - homogeneous_apply_refs([&pc](auto& x) { - return CacheManager>::initialize(pc, x); - }, - *(task.get())); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); // prepare outputs - homogeneous_apply_refs([&pc](auto&& x) { return OutputManager>::prepare(pc, x); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); // execute run() if constexpr (requires { task->run(pc); }) { task->run(pc); @@ -662,7 +649,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) }, *task.get()); // finalize outputs - homogeneous_apply_refs([&pc](auto&& x) { return OutputManager>::finalize(pc, x); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); }; }}; diff --git a/Framework/Core/include/Framework/Condition.h b/Framework/Core/include/Framework/Condition.h index 92b2f9e03a23b..69c0ad9442a5d 100644 --- a/Framework/Core/include/Framework/Condition.h +++ b/Framework/Core/include/Framework/Condition.h @@ -42,6 +42,13 @@ struct Condition { } }; +template +concept is_condition = requires (T t) { + typename T::type; + std::same_as; + std::same_as; +}; + /// Can be used to group together a number of Configurables /// to overcome the limit of 100 Configurables per task. /// In order to do so you can do: @@ -58,5 +65,8 @@ struct Condition { struct ConditionGroup { }; +template +concept is_condition_group = std::derived_from; + } // namespace o2::framework #endif // O2_FRAMEWORK_CONDITION_H_ diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index 88e50cf3c7c26..fcae9e3a7aaa9 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -83,8 +83,14 @@ struct Configurable : IP { template using MutableConfigurable = Configurable>; +template +concept is_configurable = requires(T& t) { typename T::type; std::same_as; &T::operator typename T::type; }; + using ConfigurableAxis = Configurable, ConfigParamKind::kAxisSpec, ConfigurablePolicyConst, ConfigParamKind::kAxisSpec>>; +template +concept is_configurable_axis = is_configurable && requires() {T::kind == ConfigParamKind::kAxisSpec;}; + template struct ProcessConfigurable : Configurable { ProcessConfigurable(R (T::*process_)(As...), std::string const& name_, bool&& value_, std::string const& help_) @@ -97,7 +103,7 @@ struct ProcessConfigurable : Configurable { }; template -concept is_process_configurable = base_of_template; +concept is_process_configurable = is_configurable && requires(T& t) { t.process; }; #define PROCESS_SWITCH(_Class_, _Name_, _Help_, _Default_) \ decltype(ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}) do##_Name_ = ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}; @@ -128,5 +134,8 @@ std::ostream& operator<<(std::ostream& os, Configurable const& c) struct ConfigurableGroup { }; +template +concept is_configurable_group = std::derived_from; + } // namespace o2::framework #endif // O2_FRAMEWORK_CONFIGURABLE_H_ diff --git a/Framework/Core/include/Framework/Expressions.h b/Framework/Core/include/Framework/Expressions.h index b9775f031c65c..ff22a35a00a23 100644 --- a/Framework/Core/include/Framework/Expressions.h +++ b/Framework/Core/include/Framework/Expressions.h @@ -418,6 +418,9 @@ struct Filter { size_t designateSubtrees(Node* node, size_t index = 0); }; +template +concept is_filter = std::same_as; + using Projector = Filter; /// Function for creating gandiva selection from our internal filter tree diff --git a/Framework/Core/include/Framework/GroupedCombinations.h b/Framework/Core/include/Framework/GroupedCombinations.h index 21d8384e3aa6e..4628ea25778c2 100644 --- a/Framework/Core/include/Framework/GroupedCombinations.h +++ b/Framework/Core/include/Framework/GroupedCombinations.h @@ -49,6 +49,16 @@ expressions::BindingNode getMatchingIndexNode() template struct GroupedCombinationsGenerator { + using grouping_policy_t = GroupingPolicy; + using g_t = G; + using associated_pack_t = framework::pack; + + template + static consteval bool compatible(framework::pack p) + { + return (framework::has_type(p) && ...); + } + using GroupedIteratorType = pack_to_tuple_t, pack>>; struct GroupedIterator : public GroupingPolicy { @@ -230,6 +240,13 @@ struct GroupedCombinationsGenerator { iterator mEnd; }; +template +concept is_combinations_generator = requires (T t) { + typename T::GroupedIterator; + &T::begin; + &T::end; +}; + // Aliases for 2-particle correlations // 'Pair' and 'Triple' can be used for same kind pair/triple, too, just specify the same type twice template > diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index 9f272be38da0c..6db4bd0a2d0e2 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -252,6 +252,9 @@ class HistogramRegistry std::array mRegistryValue{}; }; +template +concept is_histogram_registry = std::same_as; + //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- // Implementation of HistFiller template functions. diff --git a/Framework/Core/include/Framework/SliceCache.h b/Framework/Core/include/Framework/SliceCache.h index f7312b364b630..db5af94cd5967 100644 --- a/Framework/Core/include/Framework/SliceCache.h +++ b/Framework/Core/include/Framework/SliceCache.h @@ -12,10 +12,8 @@ #ifndef SLICECACHE_H #define SLICECACHE_H -#include "Framework/ServiceHandle.h" #include "Framework/ArrowTableSlicingCache.h" #include -#include #include namespace o2::framework @@ -23,6 +21,9 @@ namespace o2::framework struct SliceCache { ArrowTableSlicingCache* ptr = nullptr; }; + +template +concept is_slice_cache = std::same_as; } // namespace o2::framework #endif // SLICECACHE_H From 844c74ffdc56a6313aa5dc8a5502d83c306216cf Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 7 Feb 2025 10:10:44 +0000 Subject: [PATCH 2/6] Please consider the following formatting changes --- Framework/Core/include/Framework/AnalysisHelpers.h | 8 ++++---- Framework/Core/include/Framework/AnalysisManagers.h | 12 +++++++----- Framework/Core/include/Framework/AnalysisTask.h | 2 +- Framework/Core/include/Framework/Condition.h | 2 +- Framework/Core/include/Framework/Configurable.h | 6 +++++- .../Core/include/Framework/GroupedCombinations.h | 2 +- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index eb091622312c4..8569ac611340f 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -191,7 +191,7 @@ struct Produces : WritingCursor { }; template -concept is_produces = requires (T t) { typename T::cursor_t; typename T::persistent_table_t; &T::cursor; }; +concept is_produces = requires(T t) { typename T::cursor_t; typename T::persistent_table_t; &T::cursor; }; /// Use this to group together produces. Useful to separate them logically /// or simply to stay within the 100 elements per Task limit. @@ -572,7 +572,7 @@ struct OutputObj { }; template -concept is_outputobj = requires (T t) { &T::setObject; std::same_as>; }; +concept is_outputobj = requires(T t) { &T::setObject; std::same_as>; }; /// This helper allows you to fetch a Sevice from the context or /// by using some singleton. This hopefully will hide the Singleton and @@ -593,7 +593,7 @@ struct Service { }; template -concept is_service = requires (T t) { std::same_as; &T::operator->;}; +concept is_service = requires(T t) { std::same_as; &T::operator->; }; auto getTableFromFilter(soa::is_filtered_table auto const& table, soa::SelectionVector&& selection) { @@ -721,7 +721,7 @@ struct Partition { }; template -concept is_partition = requires (T t) {&T::updatePlaceholders; std::same_as; std::same_as>>;}; +concept is_partition = requires(T t) {&T::updatePlaceholders; std::same_as; std::same_as>>; }; } // namespace o2::framework namespace o2::soa diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 24b64734d7a8e..e9352adb5557d 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -31,7 +31,8 @@ namespace o2::framework { -namespace { +namespace +{ template static inline auto extractOriginal(ProcessingContext& pc) { @@ -51,9 +52,10 @@ static inline auto extractOriginals(ProcessingContext& pc) return {pc.inputs().get(o2::aod::label())->asArrowTable()...}; }(std::make_index_sequence()); } -} +} // namespace -namespace analysis_task_parsers { +namespace analysis_task_parsers +{ /// Options handling template @@ -442,7 +444,7 @@ void setPartition(P&, T&...) template void setPartition(P& partition, T&... tables) { - ([&](){ if constexpr (std::same_as) {partition.bindTable(tables);} }(), ...); + ([&]() { if constexpr (std::same_as) {partition.bindTable(tables);} }(), ...); } template @@ -507,7 +509,7 @@ static void setGroupedCombination(C& comb, TG& grouping, std::tuple& asso } } -} // analysis_task_parsers +} // namespace analysis_task_parsers template struct UpdateProcessSwitches { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 69d609f279e99..15e981810b8ca 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -580,7 +580,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) homogeneous_apply_refs([&eosContext](auto& element) { analysis_task_parsers::postRunService(eosContext, element); analysis_task_parsers::postRunOutput(eosContext, element); - return true;}, + return true; }, *task.get()); eosContext.services().get().readyToQuit(QuitRequest::Me); }; diff --git a/Framework/Core/include/Framework/Condition.h b/Framework/Core/include/Framework/Condition.h index 69c0ad9442a5d..3290cee14a123 100644 --- a/Framework/Core/include/Framework/Condition.h +++ b/Framework/Core/include/Framework/Condition.h @@ -43,7 +43,7 @@ struct Condition { }; template -concept is_condition = requires (T t) { +concept is_condition = requires(T t) { typename T::type; std::same_as; std::same_as; diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index fcae9e3a7aaa9..031f1cf1270bf 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -89,7 +89,11 @@ concept is_configurable = requires(T& t) { typename T::type; std::same_as, ConfigParamKind::kAxisSpec, ConfigurablePolicyConst, ConfigParamKind::kAxisSpec>>; template -concept is_configurable_axis = is_configurable && requires() {T::kind == ConfigParamKind::kAxisSpec;}; +concept is_configurable_axis = is_configurable&& + requires() +{ + T::kind == ConfigParamKind::kAxisSpec; +}; template struct ProcessConfigurable : Configurable { diff --git a/Framework/Core/include/Framework/GroupedCombinations.h b/Framework/Core/include/Framework/GroupedCombinations.h index 4628ea25778c2..bdbddee871baa 100644 --- a/Framework/Core/include/Framework/GroupedCombinations.h +++ b/Framework/Core/include/Framework/GroupedCombinations.h @@ -241,7 +241,7 @@ struct GroupedCombinationsGenerator { }; template -concept is_combinations_generator = requires (T t) { +concept is_combinations_generator = requires(T t) { typename T::GroupedIterator; &T::begin; &T::end; From f919b126812d37d1cd88a1d94533f2080c418a09 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 13 Feb 2025 13:04:10 +0100 Subject: [PATCH 3/6] update for preslice --- Framework/Core/include/Framework/ASoA.h | 10 ++ .../Core/include/Framework/AnalysisManagers.h | 147 +++++++++--------- .../Core/include/Framework/AnalysisTask.h | 18 +-- 3 files changed, 91 insertions(+), 84 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index f72d26e84d82f..59116f4e6f945 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1416,6 +1416,7 @@ template struct PresliceBase : public Policy { constexpr static bool optional = OPT; using target_t = T; + using policy_t = Policy; const std::string binding; PresliceBase(expressions::BindingNode index_) @@ -1453,6 +1454,15 @@ using Preslice = PresliceBase; template using PresliceOptional = PresliceBase; +template +concept is_preslice = requires(T t) { + std::same_as; + std::same_as; + &T::isMising; + &T::updateSliceInfo; + &T::getSliceFor; +}; + } // namespace o2::framework namespace o2::soa diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index e9352adb5557d..1d326e338099f 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -509,98 +509,95 @@ static void setGroupedCombination(C& comb, TG& grouping, std::tuple& asso } } -} // namespace analysis_task_parsers +/// Preslice handling +template +bool registerCache(T&, std::vector&, std::vector&) +{ + return false; +} -template -struct UpdateProcessSwitches { - static bool set(std::pair, ANY&) - { - return false; - } -}; - -template -struct UpdateProcessSwitches> { - static bool set(std::pair setting, ProcessConfigurable& what) - { - if (what.name == setting.first) { - what.value = setting.second; +template + requires std::same_as +bool registerCache(T& preslice, std::vector& bsks, std::vector&) +{ + if constexpr (T::optional) { + if (preslice.binding == "[MISSING]") { return true; } - return false; } -}; - -/// Manager template to handle slice caching -template -struct PresliceManager { - static bool registerCache(T&, std::vector&, std::vector&) - { - return false; + auto locate = std::find_if(bsks.begin(), bsks.end(), [&](auto const& entry) { return (entry.first == preslice.bindingKey.first) && (entry.second == preslice.bindingKey.second); }); + if (locate == bsks.end()) { + bsks.emplace_back(preslice.getBindingKey()); } + return true; +} - static bool updateSliceInfo(T&, ArrowTableSlicingCache&) - { - return false; - } -}; - -template -struct PresliceManager> { - static bool registerCache(PresliceBase& container, std::vector& bsks, std::vector&) - requires std::same_as - { - if constexpr (OPT) { - if (container.binding == "[MISSING]") { - return true; - } - } - auto locate = std::find_if(bsks.begin(), bsks.end(), [&](auto const& entry) { return (entry.first == container.bindingKey.first) && (entry.second == container.bindingKey.second); }); - if (locate == bsks.end()) { - bsks.emplace_back(container.getBindingKey()); +template + requires std::same_as +bool registerCache(T& preslice, std::vector&, std::vector& bsksU) +{ + if constexpr (T::optional) { + if (preslice.binding == "[MISSING]") { + return true; } - return true; } + auto locate = std::find_if(bsksU.begin(), bsksU.end(), [&](auto const& entry) { return (entry.first == preslice.bindingKey.first) && (entry.second == preslice.bindingKey.second); }); + if (locate == bsksU.end()) { + bsksU.emplace_back(preslice.getBindingKey()); + } + return true; +} - static bool registerCache(PresliceBase& container, std::vector&, std::vector& bsksU) - requires std::same_as - { - if constexpr (OPT) { - if (container.binding == "[MISSING]") { - return true; - } - } - auto locate = std::find_if(bsksU.begin(), bsksU.end(), [&](auto const& entry) { return (entry.first == container.bindingKey.first) && (entry.second == container.bindingKey.second); }); - if (locate == bsksU.end()) { - bsksU.emplace_back(container.getBindingKey()); +template +bool updateSliceInfo(T&, ArrowTableSlicingCache&) +{ + return false; +} + +template +static bool updateSliceInfo(T& preslice, ArrowTableSlicingCache& cache) + requires std::same_as +{ + if constexpr (T::optional) { + if (preslice.binding == "[MISSING]") { + return true; } - return true; } + preslice.updateSliceInfo(cache.getCacheFor(preslice.getBindingKey())); + return true; +} - static bool updateSliceInfo(PresliceBase& container, ArrowTableSlicingCache& cache) - requires std::same_as - { - if constexpr (OPT) { - if (container.binding == "[MISSING]") { - return true; - } +template +static bool updateSliceInfo(T& preslice, ArrowTableSlicingCache& cache) + requires std::same_as +{ + if constexpr (T::optional) { + if (preslice.binding == "[MISSING]") { + return true; } - container.updateSliceInfo(cache.getCacheFor(container.getBindingKey())); - return true; } + preslice.updateSliceInfo(cache.getCacheUnsortedFor(preslice.getBindingKey())); + return true; +} - static bool updateSliceInfo(PresliceBase& container, ArrowTableSlicingCache& cache) - requires std::same_as - { - if constexpr (OPT) { - if (container.binding == "[MISSING]") { - return true; - } - } - container.updateSliceInfo(cache.getCacheUnsortedFor(container.getBindingKey())); +/// Process switches handling +template +static bool setProcessSwitch(std::pair, T&) +{ + return false; +} + +template +static bool setProcessSwitch(std::pair setting, T& pc) +{ + if (pc.name == setting.first) { + pc.value = setting.second; return true; } -}; + return false; +} + +} // namespace analysis_task_parsers } // namespace o2::framework #endif // ANALYSISMANAGERS_H diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 15e981810b8ca..b78bf61aea558 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -444,8 +444,8 @@ auto getTaskNameSetProcesses(std::string& outputName, TaskName first, SetDefault auto task = std::make_shared(std::forward(args)...); for (auto& setting : second.map) { homogeneous_apply_refs( - [&](auto& x) { - return UpdateProcessSwitches>::set(setting, x); + [&](auto& element) { + return analysis_task_parsers::setProcessSwitch(setting, element); }, *task.get()); } @@ -459,8 +459,8 @@ auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, auto task = std::make_shared(std::forward(args)...); for (auto& setting : first.map) { homogeneous_apply_refs( - [&](auto& x) { - return UpdateProcessSwitches>::set(setting, x); + [&](auto& element) { + return analysis_task_parsers::setProcessSwitch(setting, element); }, *task.get()); } @@ -474,8 +474,8 @@ auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, auto task = std::make_shared(std::forward(args)...); for (auto& setting : first.map) { homogeneous_apply_refs( - [&](auto& x) { - return UpdateProcessSwitches>::set(setting, x); + [&](auto& element) { + return analysis_task_parsers::setProcessSwitch(setting, element); }, *task.get()); } @@ -550,7 +550,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) *task.get()); // add preslice declarations to slicing cache definition - homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& x) { return PresliceManager>::registerCache(x, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); + homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); // request base tables for spawnable extended tables and indices to be built // this checks for duplications @@ -620,8 +620,8 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&pc, &slices](auto& x) { - return PresliceManager>::updateSliceInfo(x, slices); + homogeneous_apply_refs([&pc, &slices](auto& element) { + return analysis_task_parsers::updateSliceInfo(element, slices); }, *(task.get())); // initialize local caches From 5d1d898a684d9e1030c8f4919e95fcb4930f6abf Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 13 Feb 2025 14:57:59 +0100 Subject: [PATCH 4/6] add requires --- Framework/Core/include/Framework/ASoA.h | 4 ++-- .../Core/include/Framework/AnalysisHelpers.h | 20 ++++++++++++++----- Framework/Core/include/Framework/Condition.h | 4 ++-- .../Core/include/Framework/Configurable.h | 6 +++++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 59116f4e6f945..ca9c49e8bc6c8 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1456,8 +1456,8 @@ using PresliceOptional = PresliceBase; template concept is_preslice = requires(T t) { - std::same_as; - std::same_as; + requires std::same_as; + requires std::same_as; &T::isMising; &T::updateSliceInfo; &T::getSliceFor; diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 8569ac611340f..c64712b565f14 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -287,7 +287,7 @@ struct Spawns : decltype(transformBase()) { template concept is_spawns = requires(T t) { typename T::metadata; - std::same_as; + requires std::same_as; }; /// Policy to control index building @@ -473,7 +473,7 @@ template concept is_builds = requires(T t) { typename T::metadata; typename T::Key; - std::same_as; + requires std::same_as; }; /// This helper class allows you to declare things which will be created by a @@ -572,7 +572,10 @@ struct OutputObj { }; template -concept is_outputobj = requires(T t) { &T::setObject; std::same_as>; }; +concept is_outputobj = requires(T t) { + &T::setObject; + requires std::same_as>; +}; /// This helper allows you to fetch a Sevice from the context or /// by using some singleton. This hopefully will hide the Singleton and @@ -593,7 +596,10 @@ struct Service { }; template -concept is_service = requires(T t) { std::same_as; &T::operator->; }; +concept is_service = requires(T t) { + requires std::same_as; + &T::operator->; +}; auto getTableFromFilter(soa::is_filtered_table auto const& table, soa::SelectionVector&& selection) { @@ -721,7 +727,11 @@ struct Partition { }; template -concept is_partition = requires(T t) {&T::updatePlaceholders; std::same_as; std::same_as>>; }; +concept is_partition = requires(T t) { + &T::updatePlaceholders; + requires std::same_as; + requires std::same_as>>; +}; } // namespace o2::framework namespace o2::soa diff --git a/Framework/Core/include/Framework/Condition.h b/Framework/Core/include/Framework/Condition.h index 3290cee14a123..003674a3c0693 100644 --- a/Framework/Core/include/Framework/Condition.h +++ b/Framework/Core/include/Framework/Condition.h @@ -45,8 +45,8 @@ struct Condition { template concept is_condition = requires(T t) { typename T::type; - std::same_as; - std::same_as; + requires std::same_as; + requires std::same_as; }; /// Can be used to group together a number of Configurables diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index 031f1cf1270bf..f72d2f3a2a7d6 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -84,7 +84,11 @@ template using MutableConfigurable = Configurable>; template -concept is_configurable = requires(T& t) { typename T::type; std::same_as; &T::operator typename T::type; }; +concept is_configurable = requires(T& t) { + typename T::type; + requires std::same_as; + &T::operator typename T::type; +}; using ConfigurableAxis = Configurable, ConfigParamKind::kAxisSpec, ConfigurablePolicyConst, ConfigParamKind::kAxisSpec>>; From 5e06f1d441d4ec5f57948812d5d923fa0b16ad4e Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 13 Feb 2025 15:03:09 +0100 Subject: [PATCH 5/6] fixup! add requires --- Framework/Core/include/Framework/Condition.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/Condition.h b/Framework/Core/include/Framework/Condition.h index 003674a3c0693..3f2edaf286626 100644 --- a/Framework/Core/include/Framework/Condition.h +++ b/Framework/Core/include/Framework/Condition.h @@ -45,7 +45,7 @@ struct Condition { template concept is_condition = requires(T t) { typename T::type; - requires std::same_as; + requires std::same_as; requires std::same_as; }; From 2f13d7e5d10f8ba829e59712345ac386b345a918 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 20 Feb 2025 13:37:31 +0100 Subject: [PATCH 6/6] fix OutputObj identification concept --- Framework/Core/include/Framework/AnalysisHelpers.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index c64712b565f14..59bade6d43cd0 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -573,7 +573,10 @@ struct OutputObj { template concept is_outputobj = requires(T t) { - &T::setObject; + &T::setHash; + &T::spec; + &T::ref; + requires std::same_as()), typename T::obj_t*>; requires std::same_as>; };