File indexing completed on 2025-12-16 10:19:17
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #ifndef FWCORE_FUNCTIONALUTILS_H
0020 #define FWCORE_FUNCTIONALUTILS_H
0021
0022 #include "Gaudi/Functional/details.h"
0023 #include "GaudiKernel/AnyDataWrapper.h"
0024 #include "GaudiKernel/DataObjID.h"
0025 #include "GaudiKernel/DataObjectHandle.h"
0026 #include "GaudiKernel/EventContext.h"
0027 #include "GaudiKernel/IDataProviderSvc.h"
0028 #include "GaudiKernel/ThreadLocalContext.h"
0029 #include <GaudiKernel/GaudiException.h>
0030
0031 #include "podio/CollectionBase.h"
0032
0033 #include "k4FWCore/DataWrapper.h"
0034
0035
0036
0037 #include <fmt/format.h>
0038
0039 #include <memory>
0040 #include <tuple>
0041 #include <type_traits>
0042
0043 namespace k4FWCore {
0044
0045 static const std::string frameLocation = "/_Frame";
0046
0047 namespace details {
0048
0049
0050 template <typename T>
0051 struct EventStoreType {
0052 using type = std::unique_ptr<podio::CollectionBase>;
0053 };
0054 using EventStoreType_t = typename EventStoreType<void>::type;
0055
0056
0057 template <typename T, typename P>
0058 requires(!std::is_same_v<P, podio::CollectionBase*>)
0059 const auto& maybeTransformToEDM4hep(const P& arg) {
0060 return arg;
0061 }
0062
0063
0064 template <typename T, typename P>
0065 requires std::same_as<P, podio::CollectionBase*>
0066 const auto& maybeTransformToEDM4hep(P&& arg) {
0067 return static_cast<const T&>(*arg);
0068 }
0069
0070
0071 template <typename T, typename P>
0072 requires(std::is_base_of_v<podio::CollectionBase, P> && !std::same_as<podio::CollectionBase, P>)
0073 const auto& maybeTransformToEDM4hep(P* arg) {
0074 return *arg;
0075 }
0076
0077 template <typename T, bool addPtr = std::is_base_of_v<podio::CollectionBase, T>>
0078 using addPtrIfColl = std::conditional_t<addPtr, std::add_pointer_t<T>, T>;
0079
0080
0081
0082
0083
0084 template <typename T>
0085 struct isVectorLike : std::false_type {};
0086
0087 template <typename Value>
0088 requires std::is_base_of_v<podio::CollectionBase, std::remove_cv_t<Value>> ||
0089 std::is_same_v<podio::CollectionBase*, std::remove_cv_t<Value>>
0090 struct isVectorLike<std::vector<Value*>> : std::true_type {};
0091
0092 template <typename Value>
0093 requires std::is_base_of_v<podio::CollectionBase, std::remove_cv_t<Value>>
0094 struct isVectorLike<std::vector<Value>> : std::true_type {};
0095
0096 template <class T>
0097 inline constexpr bool isVectorLike_v = isVectorLike<T>::value;
0098
0099 template <typename T>
0100 auto convertToUniquePtr(T&& arg) {
0101
0102
0103 if constexpr (std::same_as<T, podio::CollectionBase*>) {
0104 return std::unique_ptr<podio::CollectionBase>(std::forward<T>(arg));
0105 } else {
0106
0107
0108 return std::make_unique<T>(std::forward<T>(arg));
0109 }
0110 }
0111
0112 template <typename... In>
0113 struct filter_evtcontext_tt {
0114 static_assert(!std::disjunction_v<std::is_same<EventContext, In>...>,
0115 "EventContext can only appear as first argument");
0116
0117 template <typename Algorithm, typename Handles>
0118 static auto apply(const Algorithm& algo, Handles& handles) {
0119 return std::apply(
0120 [&](const auto&... handle) { return algo(get(handle, algo, Gaudi::Hive::currentContext())...); }, handles);
0121 }
0122
0123 template <typename Algorithm, typename Handles>
0124 static auto apply(const Algorithm& algo, const EventContext&, Handles& handles) {
0125 auto inputTuple = std::tuple<addPtrIfColl<In>...>();
0126
0127
0128
0129 readVectorInputs<0, In...>(handles, &algo, inputTuple);
0130
0131 return std::apply([&](const auto&... input) { return algo(maybeTransformToEDM4hep<decltype(input)>(input)...); },
0132 inputTuple);
0133 }
0134 };
0135
0136 template <size_t Index, typename... In, typename... Handles, typename InputTuple>
0137 void readVectorInputs(const std::tuple<Handles...>& handles, auto thisClass, InputTuple& inputTuple) {
0138 if constexpr (Index < sizeof...(Handles)) {
0139 using TupleType = std::tuple_element_t<Index, std::tuple<In...>>;
0140 if constexpr (isVectorLike_v<TupleType>) {
0141
0142 using EDM4hepType = std::remove_cv_t<std::remove_pointer_t<typename TupleType::value_type>>;
0143 auto inputMap = std::vector<const EDM4hepType*>();
0144 for (auto& handle : std::get<Index>(handles)) {
0145 podio::CollectionBase* in = handle.get()->get();
0146 auto* typedIn = dynamic_cast<const EDM4hepType*>(in);
0147 if (typedIn) {
0148 inputMap.push_back(typedIn);
0149 } else {
0150 throw GaudiException(
0151 thisClass->name(),
0152 fmt::format("Failed to cast collection {} to the required type {}, the type of the collection is {}",
0153 handle.objKey(), typeid(EDM4hepType).name(), in ? in->getTypeName() : "[undetermined]"),
0154 StatusCode::FAILURE);
0155 }
0156 }
0157 std::get<Index>(inputTuple) = std::move(inputMap);
0158 } else {
0159
0160 using EDM4hepType = std::remove_cv_t<std::remove_pointer_t<TupleType>>;
0161 try {
0162 podio::CollectionBase* in = std::get<Index>(handles)[0].get()->get();
0163 auto* typedIn = dynamic_cast<EDM4hepType*>(in);
0164 if (typedIn) {
0165 std::get<Index>(inputTuple) = typedIn;
0166 } else {
0167 throw GaudiException(
0168 thisClass->name(),
0169 fmt::format("Failed to cast collection {} to the required type {}, the type of the collection is {}",
0170 std::get<Index>(handles)[0].objKey(), typeid(EDM4hepType).name(),
0171 in ? in->getTypeName() : "[undetermined]"),
0172 StatusCode::FAILURE);
0173 }
0174 } catch (GaudiException& e) {
0175
0176
0177
0178 if (e.message().find("different from") != std::string::npos) {
0179 thisClass->debug() << "Trying to cast the collection " << std::get<Index>(handles)[0].objKey()
0180 << " to the requested type didn't work " << endmsg;
0181 DataObject* p;
0182 IDataProviderSvc* svc = thisClass->evtSvc();
0183 svc->retrieveObject("/Event/" + std::get<Index>(handles)[0].objKey(), p).ignore();
0184
0185 const auto* wrp = dynamic_cast<const DataWrapper<EDM4hepType>*>(p);
0186
0187 const auto* marlinWrp = dynamic_cast<const DataWrapper<podio::CollectionBase>*>(p);
0188 if (!wrp && !marlinWrp) {
0189 throw GaudiException(thisClass->name(),
0190 "Failed to cast collection " + std::get<Index>(handles)[0].objKey() +
0191 " to the requested type " + typeid(EDM4hepType).name(),
0192 StatusCode::FAILURE);
0193 }
0194 if (wrp) {
0195 std::get<Index>(inputTuple) = const_cast<EDM4hepType*>(wrp->getData());
0196 } else {
0197 std::get<Index>(inputTuple) =
0198 dynamic_cast<EDM4hepType*>(const_cast<podio::CollectionBase*>(marlinWrp->getData()));
0199 }
0200 } else {
0201 throw e;
0202 }
0203 }
0204 }
0205
0206
0207 readVectorInputs<Index + 1, In...>(handles, thisClass, inputTuple);
0208 }
0209 }
0210
0211 template <size_t Index, typename... Out, typename... Handles>
0212 void putVectorOutputs(std::tuple<Handles...>&& handles, const auto& m_outputs, auto thisClass) {
0213 if constexpr (Index < sizeof...(Handles)) {
0214 if constexpr (isVectorLike_v<std::tuple_element_t<Index, std::tuple<Out...>>>) {
0215 int i = 0;
0216 if (std::get<Index>(handles).size() != std::get<Index>(m_outputs).size()) {
0217 std::string msg = "Size of the output vector " + std::to_string(std::get<Index>(handles).size()) +
0218 " with type " + typeid(std::get<Index>(handles)).name() +
0219 " does not match the expected size from the steering file " +
0220 std::to_string(std::get<Index>(m_outputs).size());
0221 throw GaudiException(thisClass->name(), msg, StatusCode::FAILURE);
0222 }
0223 for (auto& val : std::get<Index>(handles)) {
0224 Gaudi::Functional::details::put(std::get<Index>(m_outputs)[i], convertToUniquePtr(std::move(val)));
0225 i++;
0226 }
0227 } else {
0228 Gaudi::Functional::details::put(std::get<Index>(m_outputs)[0],
0229 convertToUniquePtr(std::move(std::get<Index>(handles))));
0230 }
0231
0232
0233 putVectorOutputs<Index + 1, Out...>(std::move(handles), m_outputs, thisClass);
0234 }
0235 }
0236
0237 inline std::vector<DataObjID> to_DataObjID(const std::vector<std::string>& in) {
0238 std::vector<DataObjID> out;
0239 out.reserve(in.size());
0240 std::transform(in.begin(), in.end(), std::back_inserter(out), [](const std::string& i) { return DataObjID{i}; });
0241 return out;
0242 }
0243
0244
0245
0246
0247 template <typename T>
0248 class FunctionalDataObjectReadHandle : public ::details::ReadHandle<T> {
0249 template <typename... Args, std::size_t... Is>
0250 FunctionalDataObjectReadHandle(std::tuple<Args...>&& args, std::index_sequence<Is...>)
0251 : FunctionalDataObjectReadHandle(std::get<Is>(std::move(args))...) {}
0252
0253 public:
0254
0255
0256 template <typename OWNER, typename K, typename = std::enable_if_t<std::is_base_of_v<IProperty, OWNER>>>
0257 FunctionalDataObjectReadHandle(OWNER* owner, std::string propertyName, K key = {}, std::string doc = "")
0258 : ::details::ReadHandle<T>(owner, Gaudi::DataHandle::Reader, std::move(propertyName), std::move(key),
0259 std::move(doc)) {}
0260
0261 template <typename... Args>
0262 FunctionalDataObjectReadHandle(std::tuple<Args...>&& args)
0263 : FunctionalDataObjectReadHandle(std::move(args), std::index_sequence_for<Args...>{}) {}
0264
0265 const T& get() const;
0266 };
0267
0268 template <typename T>
0269 const T& FunctionalDataObjectReadHandle<T>::get() const {
0270 auto dataObj = this->fetch();
0271 if (!dataObj) {
0272 throw GaudiException("Cannot retrieve \'" + this->objKey() + "\' from transient store.",
0273 this->m_owner ? this->owner()->name() : "no owner", StatusCode::FAILURE);
0274 }
0275 auto ptr = dynamic_cast<AnyDataWrapper<std::unique_ptr<podio::CollectionBase>>*>(dataObj);
0276 return maybeTransformToEDM4hep<T>(ptr->getData().get());
0277 }
0278
0279 struct BaseClass_t {
0280 template <typename T>
0281 using InputHandle = FunctionalDataObjectReadHandle<T>;
0282
0283
0284 using BaseClass = Gaudi::Algorithm;
0285 };
0286
0287 }
0288 }
0289
0290 #endif