File indexing completed on 2025-12-15 10:18:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #ifndef FWCORE_TRANSFORMER_H
0020 #define FWCORE_TRANSFORMER_H
0021
0022 #include "Gaudi/Functional/details.h"
0023 #include "Gaudi/Functional/utilities.h"
0024 #include <GaudiKernel/FunctionalFilterDecision.h>
0025
0026 #include "k4FWCore/FunctionalUtils.h"
0027
0028
0029
0030 #include <ranges>
0031 #include <stdexcept>
0032 #include <type_traits>
0033 #include <utility>
0034
0035 namespace k4FWCore {
0036
0037 namespace details {
0038
0039 template <typename Signature, typename Traits_>
0040 struct Transformer;
0041
0042 template <typename Out, typename... In, typename Traits_>
0043 struct Transformer<Out(const In&...), Traits_>
0044 : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0045 using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0046
0047 static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike_v<In>)&&...),
0048 "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0049 static_assert((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike_v<Out> ||
0050 std::is_same_v<podio::CollectionBase*, Out>),
0051 "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0052
0053 template <typename T>
0054 using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0055 template <typename T>
0056 using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0057
0058 std::tuple<std::vector<InputHandle_t<typename EventStoreType<In>::type>>...> m_inputs;
0059 std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>> m_outputs;
0060 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(In)> m_inputLocations{};
0061 Gaudi::Property<std::vector<DataObjID>> m_outputLocations{};
0062
0063 using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0064
0065 using KeyValues = typename base_class::KeyValues;
0066
0067 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0068 Transformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0069 const OArgs& outputs, std::index_sequence<J...>)
0070 : base_class(std::move(name), locator),
0071
0072
0073
0074
0075
0076 m_inputLocations{Gaudi::Property<std::vector<DataObjID>>{
0077 this, std::get<I>(inputs).first, to_DataObjID(std::get<I>(inputs).second),
0078 [this](Gaudi::Details::PropertyBase&) {
0079 std::vector<InputHandle_t<typename EventStoreType<In>::type>> h;
0080 for (auto& value : this->m_inputLocations[I].value()) {
0081 auto handle = InputHandle_t<typename EventStoreType<In>::type>(value, this);
0082 h.push_back(std::move(handle));
0083 }
0084 std::get<I>(m_inputs) = std::move(h);
0085 },
0086 Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...},
0087
0088 m_outputLocations{Gaudi::Property<std::vector<DataObjID>>{
0089 this, std::get<J>(outputs).first, to_DataObjID(std::get<J>(outputs).second),
0090 [this](Gaudi::Details::PropertyBase&) {
0091 std::vector<OutputHandle_t<typename EventStoreType<Out>::type>> h;
0092 for (auto& inpID : this->m_outputLocations.value()) {
0093 if (inpID.key().empty()) {
0094 continue;
0095 }
0096 auto handle = OutputHandle_t<typename EventStoreType<Out>::type>(inpID, this);
0097 h.push_back(std::move(handle));
0098 }
0099 std::get<0>(m_outputs) = std::move(h);
0100 },
0101 Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...} {}
0102
0103 constexpr static std::size_t N_in = sizeof...(In);
0104 constexpr static std::size_t N_out = 1;
0105
0106 Transformer(std::string name, ISvcLocator* locator,
0107 Gaudi::Functional::details::RepeatValues_<KeyValues, N_in> const& inputs,
0108 Gaudi::Functional::details::RepeatValues_<KeyValues, N_out> const& outputs)
0109 : Transformer(std::move(name), locator, inputs, std::index_sequence_for<In...>{}, outputs,
0110 std::index_sequence_for<Out>{}) {}
0111
0112
0113 StatusCode execute(const EventContext& ctx) const final {
0114 try {
0115 if constexpr (isVectorLike<Out>::value) {
0116 std::tuple<Out> tmp = filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs);
0117 putVectorOutputs<0, Out>(std::move(tmp), m_outputs, this);
0118 } else {
0119 Gaudi::Functional::details::put(
0120 std::get<0>(this->m_outputs)[0],
0121 convertToUniquePtr(std::move(filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs))));
0122 }
0123 return Gaudi::Functional::FilterDecision::PASSED;
0124 } catch (GaudiException& e) {
0125 (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0126 return e.code();
0127 }
0128 }
0129
0130
0131
0132
0133
0134
0135 auto inputLocations(size_t i) const {
0136 if (i >= sizeof...(In)) {
0137 throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0138 ", number of inputs: " + std::to_string(sizeof...(In)));
0139 }
0140 return m_inputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0141 }
0142
0143
0144
0145
0146
0147 auto inputLocations(std::string_view name) const {
0148 auto it = std::ranges::find_if(m_inputLocations, [&name](const auto& prop) { return prop.name() == name; });
0149 if (it == m_inputLocations.end()) {
0150 throw std::runtime_error("Called inputLocations with an unknown name");
0151 }
0152 return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0153 }
0154
0155
0156
0157
0158
0159 auto outputLocations() const {
0160 return m_outputLocations | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0161 }
0162
0163
0164
0165
0166
0167 auto outputLocations(std::string_view name) const {
0168 if (name != m_outputLocations.name()) {
0169 throw std::runtime_error("Called outputLocations with an unknown name");
0170 }
0171 return m_outputLocations | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0172 }
0173 static constexpr std::size_t inputLocationsSize() { return sizeof...(In); }
0174
0175
0176 virtual Out operator()(const In&...) const = 0;
0177 };
0178
0179 template <typename Signature, typename Traits_>
0180 struct MultiTransformer;
0181
0182 template <typename... Out, typename... In, typename Traits_>
0183 struct MultiTransformer<std::tuple<Out...>(const In&...), Traits_>
0184 : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0185 using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0186
0187 static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike<In>::value) && ...),
0188 "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0189 static_assert(((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike<Out>::value) && ...),
0190 "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0191
0192 template <typename T>
0193 using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0194 template <typename T>
0195 using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0196
0197 std::tuple<std::vector<InputHandle_t<typename EventStoreType<In>::type>>...> m_inputs;
0198 std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>...> m_outputs;
0199 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(In)> m_inputLocations{};
0200 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(Out)> m_outputLocations{};
0201
0202 using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0203
0204 using KeyValues = typename base_class::KeyValues;
0205
0206 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0207 MultiTransformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0208 const OArgs& outputs, std::index_sequence<J...>)
0209 : base_class(std::move(name), locator),
0210 m_inputLocations{Gaudi::Property<std::vector<DataObjID>>{
0211 this, std::get<I>(inputs).first, to_DataObjID(std::get<I>(inputs).second),
0212 [this](Gaudi::Details::PropertyBase&) {
0213 std::vector<InputHandle_t<typename EventStoreType<In>::type>> h;
0214 for (auto& value : this->m_inputLocations[I].value()) {
0215 auto handle = InputHandle_t<typename EventStoreType<In>::type>(value, this);
0216 h.push_back(std::move(handle));
0217 }
0218 std::get<I>(m_inputs) = std::move(h);
0219 },
0220 Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...},
0221 m_outputLocations{Gaudi::Property<std::vector<DataObjID>>{
0222 this, std::get<J>(outputs).first, to_DataObjID(std::get<J>(outputs).second),
0223 [this](Gaudi::Details::PropertyBase&) {
0224 std::vector<OutputHandle_t<typename EventStoreType<Out>::type>> h;
0225
0226
0227
0228 for (auto& inpID : this->m_outputLocations[J].value()) {
0229 if (inpID.key().empty()) {
0230 continue;
0231 }
0232 auto handle = OutputHandle_t<typename EventStoreType<Out>::type>(inpID, this);
0233 h.push_back(std::move(handle));
0234 }
0235 std::get<J>(m_outputs) = std::move(h);
0236 },
0237 Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...} {}
0238
0239 constexpr static std::size_t N_in = sizeof...(In);
0240 constexpr static std::size_t N_out = sizeof...(Out);
0241
0242 MultiTransformer(std::string name, ISvcLocator* locator,
0243 Gaudi::Functional::details::RepeatValues_<KeyValues, N_in> const& inputs,
0244 Gaudi::Functional::details::RepeatValues_<KeyValues, N_out> const& outputs)
0245 : MultiTransformer(std::move(name), locator, inputs, std::index_sequence_for<In...>{}, outputs,
0246 std::index_sequence_for<Out...>{}) {}
0247
0248
0249 StatusCode execute(const EventContext& ctx) const final {
0250 try {
0251 auto tmp = filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs);
0252 putVectorOutputs<0, Out...>(std::move(tmp), m_outputs, this);
0253 return Gaudi::Functional::FilterDecision::PASSED;
0254 } catch (GaudiException& e) {
0255 (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0256 return e.code();
0257 }
0258 }
0259
0260
0261
0262
0263
0264
0265 auto inputLocations(size_t i) const {
0266 if (i >= sizeof...(In)) {
0267 throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0268 ", number of inputs: " + std::to_string(sizeof...(In)));
0269 }
0270 return m_inputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0271 }
0272
0273
0274
0275
0276
0277 auto inputLocations(std::string_view name) const {
0278 auto it = std::ranges::find_if(m_inputLocations, [&name](const auto& prop) { return prop.name() == name; });
0279 if (it == m_inputLocations.end()) {
0280 throw std::runtime_error("Called inputLocations with an unknown name");
0281 }
0282 return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0283 }
0284
0285
0286
0287
0288
0289
0290 auto outputLocations(size_t i) const {
0291 if (i >= sizeof...(Out)) {
0292 throw std::out_of_range("Called outputLocations with an index out of range");
0293 }
0294 return m_outputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0295 }
0296
0297
0298
0299
0300
0301 auto outputLocations(std::string_view name) const {
0302 auto it = std::ranges::find_if(m_outputLocations.begin(), m_outputLocations.end(),
0303 [&name](const auto& prop) { return prop.name() == name; });
0304 if (it == m_outputLocations.end()) {
0305 throw std::runtime_error("Called outputLocations with an unknown name");
0306 }
0307 return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0308 }
0309 static constexpr std::size_t inputLocationsSize() { return sizeof...(In); }
0310 static constexpr std::size_t outputLocationsSize() { return sizeof...(Out); }
0311
0312
0313 virtual std::tuple<Out...> operator()(const In&...) const = 0;
0314 };
0315
0316 }
0317
0318 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0319 using MultiTransformer = details::MultiTransformer<Signature, Traits_>;
0320
0321 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0322 using Transformer = details::Transformer<Signature, Traits_>;
0323
0324 }
0325
0326 #endif