File indexing completed on 2026-06-04 08:41:09
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
0025 #include "k4FWCore/FunctionalUtils.h"
0026
0027
0028
0029 #include <algorithm>
0030 #include <stdexcept>
0031 #include <type_traits>
0032 #include <utility>
0033 #include <variant>
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 std::is_same_v<In, EventContext>) &&
0049 ...),
0050 "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0051 static_assert((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike_v<Out> ||
0052 std::is_same_v<podio::CollectionBase*, Out>),
0053 "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0054
0055 static constexpr std::size_t N_in = filter_evtcontext<In...>::size;
0056 static constexpr std::size_t N_out = 1;
0057
0058 using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0059
0060 using KeyValue = base_class::KeyValue;
0061 using KeyValues = base_class::KeyValues;
0062
0063 template <typename T>
0064 using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0065 template <typename T>
0066 using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0067
0068 tuple_of_handle_vec_t<InputHandle_t, filter_evtcontext_t<In...>> m_inputs;
0069 std::tuple<std::vector<OutputHandle_t<EventStoreType_t>>> m_outputs;
0070
0071 std::array<Gaudi::Property<DataObjID>, N_in> m_inputLocationsSingle;
0072 std::array<Gaudi::Property<std::vector<DataObjID>>, N_in> m_inputLocationsVector;
0073 Gaudi::Property<DataObjID> m_outputLocationsSingle;
0074 Gaudi::Property<std::vector<DataObjID>> m_outputLocationsVector;
0075
0076 template <typename IArgs, typename OArgs, std::size_t... I>
0077 Transformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0078 const OArgs& outputs)
0079 : base_class(std::move(name), locator),
0080
0081
0082
0083
0084
0085 m_inputLocationsSingle{makeInputPropSingle<InputHandle_t<EventStoreType_t>, KeyValue>(
0086 std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0087 m_inputLocationsVector{makeInputPropVector<InputHandle_t<EventStoreType_t>, KeyValues>(
0088 std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0089 m_outputLocationsSingle{makeOutputPropSingle<OutputHandle_t<EventStoreType_t>, KeyValue>(
0090 std::get<0>(outputs), std::get<0>(m_outputs), this)},
0091 m_outputLocationsVector{makeOutputPropVector<OutputHandle_t<EventStoreType_t>, KeyValues>(
0092 std::get<0>(outputs), std::get<0>(m_outputs), this)} {}
0093
0094 Transformer(std::string name, ISvcLocator* locator,
0095 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_in> const& inputs,
0096 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_out> const& outputs)
0097 : Transformer(std::move(name), locator, inputs, std::make_index_sequence<N_in>{}, outputs) {}
0098
0099 StatusCode execute(const EventContext& ctx) const final {
0100 try {
0101 if constexpr (isVectorLike<Out>::value) {
0102 std::tuple<Out> tmp = filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs);
0103 putVectorOutputs<0, Out>(std::move(tmp), m_outputs, this);
0104 } else {
0105 Gaudi::Functional::details::put(
0106 std::get<0>(this->m_outputs)[0],
0107 convertToUniquePtr(std::move(filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs))));
0108 }
0109 } catch (GaudiException& e) {
0110 (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0111 return e.code();
0112 }
0113 return StatusCode::SUCCESS;
0114 }
0115
0116
0117
0118
0119
0120
0121 auto inputLocations(const size_t i) const {
0122 if (i >= N_in) {
0123 throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0124 ", number of inputs: " + std::to_string(N_in));
0125 }
0126 std::vector<std::string> names;
0127 if (!m_inputLocationsSingle[i].name().empty()) {
0128 names.push_back(m_inputLocationsSingle[i].value().key());
0129 } else {
0130 for (const auto& id : m_inputLocationsVector[i].value()) {
0131 names.push_back(id.key());
0132 }
0133 }
0134 return names;
0135 }
0136
0137
0138
0139
0140
0141 auto inputLocations(std::string_view name) const {
0142 std::vector<std::string> names;
0143 const auto it =
0144 std::ranges::find_if(m_inputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0145 if (it != m_inputLocationsVector.end()) {
0146 for (const auto& id : it->value()) {
0147 names.push_back(id.key());
0148 }
0149 } else {
0150 const auto it2 =
0151 std::ranges::find_if(m_inputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0152 if (it2 == m_inputLocationsSingle.end()) {
0153 throw std::out_of_range("Called inputLocations with a name that does not exist: " + std::string(name));
0154 } else {
0155 names.push_back(it2->value().key());
0156 }
0157 }
0158 return names;
0159 }
0160
0161
0162
0163
0164
0165 auto outputLocations() const {
0166 std::vector<std::string> names;
0167 if (!m_outputLocationsSingle.name().empty()) {
0168 names.push_back(m_outputLocationsSingle.value().key());
0169 } else {
0170 for (const auto& id : m_outputLocationsVector.value()) {
0171 names.push_back(id.key());
0172 }
0173 }
0174 return names;
0175 }
0176
0177
0178
0179
0180
0181 auto outputLocations(std::string_view name) const {
0182 std::vector<std::string> names;
0183 if (m_outputLocationsSingle.name() == name) {
0184 names.push_back(m_outputLocationsSingle.value().key());
0185 } else if (m_outputLocationsVector.name() == name) {
0186 for (const auto& id : m_outputLocationsVector.value()) {
0187 names.push_back(id.key());
0188 }
0189 } else {
0190 throw std::runtime_error("Called outputLocations with an unknown name: " + std::string(name));
0191 }
0192 return names;
0193 }
0194 static constexpr std::size_t inputLocationsSize() { return N_in; }
0195
0196 virtual Out operator()(const In&...) const = 0;
0197 };
0198
0199 template <typename Signature, typename Traits_>
0200 struct MultiTransformer;
0201
0202 template <typename... Out, typename... In, typename Traits_>
0203 struct MultiTransformer<std::tuple<Out...>(const In&...), Traits_>
0204 : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0205 using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0206
0207 static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike<In>::value ||
0208 std::is_same_v<In, EventContext>) &&
0209 ...),
0210 "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0211 static_assert(((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike<Out>::value) && ...),
0212 "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0213
0214 static constexpr std::size_t N_in = filter_evtcontext<In...>::size;
0215 static constexpr std::size_t N_out = sizeof...(Out);
0216
0217 using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0218
0219 using KeyValue = base_class::KeyValue;
0220 using KeyValues = base_class::KeyValues;
0221
0222 template <typename T>
0223 using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0224 template <typename T>
0225 using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0226
0227 tuple_of_handle_vec_t<InputHandle_t, filter_evtcontext_t<In...>> m_inputs;
0228 std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>...> m_outputs;
0229
0230 std::array<Gaudi::Property<DataObjID>, N_in> m_inputLocationsSingle;
0231 std::array<Gaudi::Property<std::vector<DataObjID>>, N_in> m_inputLocationsVector;
0232 std::array<Gaudi::Property<DataObjID>, N_out> m_outputLocationsSingle;
0233 std::array<Gaudi::Property<std::vector<DataObjID>>, N_out> m_outputLocationsVector;
0234
0235 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0236 MultiTransformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0237 const OArgs& outputs, std::index_sequence<J...>)
0238 : base_class(std::move(name), locator),
0239 m_inputLocationsSingle{makeInputPropSingle<InputHandle_t<EventStoreType_t>, KeyValue>(
0240 std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0241 m_inputLocationsVector{makeInputPropVector<InputHandle_t<EventStoreType_t>, KeyValues>(
0242 std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0243 m_outputLocationsSingle{makeOutputPropSingle<OutputHandle_t<EventStoreType_t>, KeyValue>(
0244 std::get<J>(outputs), std::get<J>(m_outputs), this)...},
0245 m_outputLocationsVector{makeOutputPropVector<OutputHandle_t<EventStoreType_t>, KeyValues>(
0246 std::get<J>(outputs), std::get<J>(m_outputs), this)...} {}
0247
0248 MultiTransformer(std::string name, ISvcLocator* locator,
0249 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_in> const& inputs,
0250 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_out> const& outputs)
0251 : MultiTransformer(std::move(name), locator, inputs, std::make_index_sequence<N_in>{}, outputs,
0252 std::make_index_sequence<N_out>{}) {}
0253
0254
0255 StatusCode execute(const EventContext& ctx) const final {
0256 try {
0257 auto tmp = filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs);
0258 putVectorOutputs<0, Out...>(std::move(tmp), m_outputs, this);
0259 return StatusCode::SUCCESS;
0260 } catch (GaudiException& e) {
0261 (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0262 return e.code();
0263 }
0264 }
0265
0266
0267
0268
0269
0270
0271 auto inputLocations(size_t i) const {
0272 if (i >= N_in) {
0273 throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0274 ", number of inputs: " + std::to_string(N_in));
0275 }
0276 std::vector<std::string> names;
0277 if (!m_inputLocationsSingle[i].name().empty()) {
0278 names.push_back(m_inputLocationsSingle[i].value().key());
0279 } else {
0280 for (const auto& id : m_inputLocationsVector[i].value()) {
0281 names.push_back(id.key());
0282 }
0283 }
0284 return names;
0285 }
0286
0287
0288
0289
0290
0291 auto inputLocations(std::string_view name) const {
0292 std::vector<std::string> names;
0293 const auto it =
0294 std::ranges::find_if(m_inputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0295 if (it != m_inputLocationsVector.end()) {
0296 for (const auto& id : it->value()) {
0297 names.push_back(id.key());
0298 }
0299 } else {
0300 const auto it2 =
0301 std::ranges::find_if(m_inputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0302 if (it2 == m_inputLocationsSingle.end()) {
0303 throw std::out_of_range("Called inputLocations with a name that does not exist: " + std::string(name));
0304 } else {
0305 names.push_back(it2->value().key());
0306 }
0307 }
0308 return names;
0309 }
0310
0311
0312
0313
0314
0315
0316 auto outputLocations(size_t i) const {
0317 if (i >= N_out) {
0318 throw std::out_of_range("Called outputLocations with an index out of range");
0319 }
0320 std::vector<std::string> names;
0321 if (!m_outputLocationsSingle[i].name().empty()) {
0322 names.push_back(m_outputLocationsSingle[i].value().key());
0323 } else {
0324 for (const auto& id : m_outputLocationsVector[i].value()) {
0325 names.push_back(id.key());
0326 }
0327 }
0328 return names;
0329 }
0330
0331
0332
0333
0334
0335 auto outputLocations(std::string_view name) const {
0336 std::vector<std::string> names;
0337 const auto it =
0338 std::ranges::find_if(m_outputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0339 if (it != m_outputLocationsVector.end()) {
0340 for (const auto& id : it->value()) {
0341 names.push_back(id.key());
0342 }
0343 } else {
0344 const auto it2 =
0345 std::ranges::find_if(m_outputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0346 if (it2 == m_outputLocationsSingle.end()) {
0347 throw std::out_of_range("Called outputLocations with a name that does not exist: " + std::string(name));
0348 } else {
0349 names.push_back(it2->value().key());
0350 }
0351 }
0352 return names;
0353 }
0354
0355 static constexpr std::size_t inputLocationsSize() { return N_in; }
0356 static constexpr std::size_t outputLocationsSize() { return N_out; }
0357
0358
0359 virtual std::tuple<Out...> operator()(const In&...) const = 0;
0360 };
0361
0362 }
0363
0364 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0365 using MultiTransformer = details::MultiTransformer<Signature, Traits_>;
0366
0367 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0368 using Transformer = details::Transformer<Signature, Traits_>;
0369
0370 }
0371
0372 #endif