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