Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-05 10:43:27

0001 #ifndef PODIO_DETAIL_LINK_H
0002 #define PODIO_DETAIL_LINK_H
0003 
0004 #include "podio/detail/LinkFwd.h"
0005 #include "podio/detail/LinkObj.h"
0006 #include "podio/utilities/MaybeSharedPtr.h"
0007 #include "podio/utilities/StaticConcatenate.h"
0008 #include "podio/utilities/TypeHelpers.h"
0009 #include <string_view>
0010 
0011 #ifdef PODIO_JSON_OUTPUT
0012   #include "nlohmann/json.hpp"
0013 #endif
0014 
0015 #include <functional>
0016 #include <ostream>
0017 #include <type_traits>
0018 #include <utility> // std::swap
0019 
0020 namespace podio {
0021 
0022 namespace detail {
0023   /// Check whether a Link<FromT, ToT> can be initialized from values of types
0024   /// FromU and ToU in exactly this order, i.e. whether its From element can be
0025   /// set from a FromU and its To element from a ToU. Passing FromT and ToT in
0026   /// swapped order checks the reversed order.
0027   template <typename FromT, typename ToT, typename FromU, typename ToU>
0028   concept LinkInitializableFrom = requires(podio::MutableLink<FromT, ToT> link, FromU from, ToU to) {
0029     link.setFrom(from);
0030     link.setTo(to);
0031   };
0032 } // namespace detail
0033 
0034 /// Generalized Link type for both Mutable and immutable (default)
0035 /// versions. User facing classes with the expected naming scheme are defined via
0036 /// template aliases in LinkFwd.h
0037 template <typename FromT, typename ToT, bool Mutable>
0038 class LinkT {
0039   // The typedefs in LinkFwd.h should make sure that at this point
0040   // Mutable classes are stripped, i.e. the user should never be able to trigger
0041   // these!
0042   static_assert(std::is_same_v<detail::GetDefaultHandleType<FromT>, FromT>,
0043                 "Links need to be instantiated with the default types!");
0044   static_assert(std::is_same_v<detail::GetDefaultHandleType<ToT>, ToT>,
0045                 "Links need to be instantiated with the default types!");
0046 
0047   using LinkObjT = LinkObj<FromT, ToT>;
0048   friend LinkCollection<FromT, ToT>;
0049   friend LinkCollectionIteratorT<FromT, ToT, Mutable>;
0050   friend LinkT<FromT, ToT, !Mutable>;
0051   friend std::hash<LinkT>;
0052 
0053   /// Helper member variable to check whether FromU and ToU can be used for this
0054   /// Link. We need this to make SFINAE trigger in some cases below
0055   template <typename FromU, typename ToU>
0056   constexpr static bool sameTypes = std::is_same_v<FromU, FromT> && std::is_same_v<ToU, ToT>;
0057 
0058   /// Variable template to for determining whether T is either FromT or ToT.
0059   /// Mainly defined for convenience
0060   template <typename T>
0061   inline constexpr static bool isFromOrToT = detail::isInTuple<T, std::tuple<FromT, ToT>>;
0062 
0063   /// Variable template to for determining whether T is either FromT or ToT or
0064   /// any of their mutable versions.
0065   template <typename T>
0066   inline constexpr static bool isMutableFromOrToT =
0067       detail::isInTuple<T,
0068                         std::tuple<FromT, ToT, detail::GetMutableHandleType<FromT>, detail::GetMutableHandleType<ToT>>>;
0069 
0070 public:
0071   using mutable_type = podio::MutableLink<FromT, ToT>;
0072   using value_type = podio::Link<FromT, ToT>;
0073   using collection_type = podio::LinkCollection<FromT, ToT>;
0074 
0075   static constexpr std::string_view typeName =
0076       utils::static_concatenate_v<detail::link_name_prefix, FromT::typeName, detail::link_name_infix, ToT::typeName,
0077                                   detail::link_name_suffix>;
0078   /// Constructor
0079   LinkT() : m_obj(new LinkObjT{}, podio::utils::MarkOwned) {
0080   }
0081 
0082   /// Constructor with weight
0083   explicit LinkT(float weight) : m_obj(new LinkObjT{}, podio::utils::MarkOwned) {
0084     m_obj->data.weight = weight;
0085   }
0086 
0087   /// Copy constructor
0088   LinkT(const LinkT& other) = default;
0089 
0090   /// Assignment operators
0091   LinkT& operator=(LinkT other) & {
0092     swap(*this, other);
0093     return *this;
0094   }
0095   LinkT& operator=(LinkT other) && = delete; // Prevent rebinding temporary as the changes wouldn't persist
0096 
0097   /// Implicit conversion of mutable to immutable links
0098   template <typename FromU, typename ToU>
0099     requires Mutable && sameTypes<FromU, ToU>
0100   operator LinkT<FromU, ToU, false>() const {
0101     return Link<FromU, ToU>(m_obj);
0102   }
0103 
0104   /// Create a mutable deep-copy
0105   ///
0106   /// @param cloneRelations if set to false only the weight will be cloned but
0107   ///                       not the relations to the objects this link points
0108   ///                       to. Defaults to true
0109   ///
0110   /// @returns A mutable deep-copy of this link which is independent of the
0111   ///          original one
0112   template <typename FromU = FromT, typename ToU = ToT>
0113     requires sameTypes<FromU, ToU>
0114   MutableLink<FromU, ToU> clone(bool cloneRelations = true) const {
0115     auto tmp = new LinkObjT(podio::ObjectID{}, m_obj->data);
0116     if (cloneRelations) {
0117       if (m_obj->m_from) {
0118         tmp->m_from = std::make_unique<FromT>(*m_obj->m_from);
0119       }
0120       if (m_obj->m_to) {
0121         tmp->m_to = std::make_unique<ToT>(*m_obj->m_to);
0122       }
0123     }
0124     return MutableLink<FromU, ToU>(podio::utils::MaybeSharedPtr(tmp, podio::utils::MarkOwned));
0125   }
0126 
0127   /// Create an empty Link handle
0128   template <bool Mut = Mutable>
0129     requires(!Mut && !Mutable)
0130   static Link<FromT, ToT> makeEmpty() {
0131     return {nullptr};
0132   }
0133 
0134   /// Destructor
0135   ~LinkT() = default;
0136 
0137   /// Get the weight of the link
0138   float getWeight() const {
0139     return m_obj->data.weight;
0140   }
0141 
0142   /// Set the weight of the link
0143   template <bool Mut = Mutable>
0144     requires(Mut && Mutable)
0145   void setWeight(float value) {
0146     m_obj->data.weight = value;
0147   }
0148 
0149   /// Access the related-from object
0150   const FromT getFrom() const {
0151     if (!m_obj->m_from) {
0152       return FromT::makeEmpty();
0153     }
0154     return FromT(*(m_obj->m_from));
0155   }
0156 
0157   /// Set the related-from object
0158   ///
0159   /// @note All setFrom overloads are equivalent and the correct one is selected
0160   /// at compile time. We need to differentiate between the handles, only to
0161   /// make the python bindings work
0162   template <typename FromU>
0163     requires(Mutable && std::is_same_v<detail::GetDefaultHandleType<FromU>, FromT> &&
0164              detail::isDefaultHandleType<FromU>)
0165   void setFrom(FromU value) {
0166     m_obj->m_from = std::make_unique<detail::GetDefaultHandleType<FromU>>(value);
0167   }
0168 
0169   /// Set the related-from object
0170   ///
0171   /// @note All setFrom overloads are equivalent and the correct one is selected
0172   /// at compile time. We need to differentiate between the handles, only to
0173   /// make the python bindings work
0174   template <typename FromU>
0175     requires(Mutable && std::is_same_v<detail::GetMutableHandleType<FromT>, FromU> &&
0176              detail::isMutableHandleType<FromU>)
0177   void setFrom(FromU value) {
0178     setFrom(detail::GetDefaultHandleType<FromU>(value));
0179   }
0180 
0181   /// Set the related-from object
0182   ///
0183   /// @note All setFrom overloads are equivalent and the correct one is selected
0184   /// at compile time. We need this overload to allow for an implicit conversion
0185   /// to interface types in case the relation contains an interface type.
0186   template <typename FromU>
0187     requires(Mutable && detail::isInterfaceInitializableFrom<FromT, FromU>)
0188   void setFrom(FromU value) {
0189     setFrom(FromT(value));
0190   }
0191 
0192   /// Access the related-to object
0193   const ToT getTo() const {
0194     if (!m_obj->m_to) {
0195       return ToT::makeEmpty();
0196     }
0197     return ToT(*(m_obj->m_to));
0198   }
0199 
0200   /// Set the related-to object
0201   ///
0202   /// @note All setTo overloads are equivalent and the correct one is selected
0203   /// at compile time. We need to differentiate between the handles, only to
0204   /// make the python bindings work
0205   template <typename ToU>
0206     requires(Mutable && std::is_same_v<detail::GetDefaultHandleType<ToU>, ToT> && detail::isDefaultHandleType<ToU>)
0207   void setTo(ToU value) {
0208     m_obj->m_to = std::make_unique<detail::GetDefaultHandleType<ToU>>(value);
0209   }
0210 
0211   /// Set the related-to object
0212   ///
0213   /// @note All setTo overloads are equivalent and the correct one is selected
0214   /// at compile time. We need to differentiate between the handles, only to
0215   /// make the python bindings work
0216   template <typename ToU>
0217     requires(Mutable && std::is_same_v<detail::GetMutableHandleType<ToT>, ToU> && detail::isMutableHandleType<ToU>)
0218   void setTo(ToU value) {
0219     setTo(detail::GetDefaultHandleType<ToU>(value));
0220   }
0221 
0222   /// Set the related-to object
0223   ///
0224   /// @note All setTo overloads are equivalent and the correct one is selected
0225   /// at compile time. We need this overload to allow for an implicit conversion
0226   /// to interface types in case the relation contains an interface type.
0227   template <typename ToU>
0228     requires(Mutable && detail::isInterfaceInitializableFrom<ToT, ToU>)
0229   void setTo(ToU value) {
0230     setTo(ToT(value));
0231   }
0232 
0233   /// Templated version for getting an element of the link by type. Only
0234   /// available for Links where FromT and ToT are **not the same type**,
0235   /// and if the requested type is actually part of the Link. It is only
0236   /// possible to get the immutable types from this. Will result in a
0237   /// compilation error if any of these conditions is not met.
0238   ///
0239   /// @tparam T the desired type
0240   /// @returns T the element of the Link
0241   template <typename T>
0242     requires(!std::is_same_v<ToT, FromT> && isFromOrToT<T>)
0243   T get() const {
0244     if constexpr (std::is_same_v<T, FromT>) {
0245       return getFrom();
0246     } else {
0247       return getTo();
0248     }
0249   }
0250 
0251   /// Tuple like index based access to the elements of the Link. Returns
0252   /// only immutable types of the links. This method enables structured
0253   /// bindings for Links.
0254   ///
0255   /// @tparam Index an index (smaller than 3) to access an element of the Link
0256   /// @returns Depending on the value of Index:
0257   ///   - 0: The From element of the Link
0258   ///   - 1: The To element of the Link
0259   ///   - 2: The weight of the Link
0260   template <size_t Index>
0261     requires(Index < 3)
0262   auto get() const {
0263     if constexpr (Index == 0) {
0264       return getFrom();
0265     } else if constexpr (Index == 1) {
0266       return getTo();
0267     } else {
0268       return getWeight();
0269     }
0270   }
0271 
0272   /// Templated version for setting an element of the link by type. Only
0273   /// available for Links where FromT and ToT are **not the same type**,
0274   /// and if the requested type is actually part of the Link. Will result
0275   /// in a compilation error if any of these conditions is not met.
0276   ///
0277   /// @tparam T type of value (**inferred!**)
0278   /// @param value the element to set for this link.
0279   template <typename T>
0280     requires(Mutable && !std::is_same_v<ToT, FromT> &&
0281              (isMutableFromOrToT<T> || detail::isInterfaceInitializableFrom<ToT, T> ||
0282               detail::isInterfaceInitializableFrom<FromT, T>))
0283   void set(T value) {
0284     if constexpr (std::is_same_v<T, FromT>) {
0285       setFrom(std::move(value));
0286     } else if constexpr (std::is_same_v<T, ToT>) {
0287       setTo(std::move(value));
0288     } else if constexpr (detail::isInterfaceInitializableFrom<FromT, T> &&
0289                          !detail::isInterfaceInitializableFrom<ToT, T>) {
0290       setFrom(std::move(value));
0291     } else if constexpr (detail::isInterfaceInitializableFrom<ToT, T> &&
0292                          !detail::isInterfaceInitializableFrom<FromT, T>) {
0293       setTo(std::move(value));
0294     } else {
0295       static_assert(detail::always_false<T>, "Argument type is ambiguous, can't determine link direction");
0296     }
0297   }
0298 
0299   /// check whether the object is actually available
0300   bool isAvailable() const {
0301     return m_obj;
0302   }
0303 
0304   /// disconnect from Link instance
0305   void unlink() {
0306     m_obj = podio::utils::MaybeSharedPtr<LinkObjT>(nullptr);
0307   }
0308 
0309   /// Get the ObjectID
0310   podio::ObjectID getObjectID() const {
0311     if (m_obj) {
0312       return m_obj->id;
0313     }
0314     return podio::ObjectID{};
0315   }
0316 
0317   podio::ObjectID id() const {
0318     return getObjectID();
0319   }
0320 
0321   constexpr bool operator==(const LinkT& other) const {
0322     return m_obj == other.m_obj;
0323   }
0324 
0325   constexpr bool operator!=(const LinkT& other) const {
0326     return !(*this == other);
0327   }
0328 
0329   template <typename FromU, typename ToU>
0330     requires sameTypes<FromU, ToU>
0331   constexpr bool operator==(const LinkT<FromU, ToU, !Mutable>& other) const {
0332     return m_obj == other.m_obj;
0333   }
0334 
0335   template <typename FromU, typename ToU>
0336     requires sameTypes<FromU, ToU>
0337   constexpr bool operator!=(const LinkT<FromU, ToU, !Mutable>& other) const {
0338     return !(*this == other);
0339   }
0340 
0341   constexpr bool operator<(const LinkT& other) const {
0342     return m_obj < other.m_obj;
0343   }
0344 
0345   friend void swap(LinkT& a, LinkT& b) {
0346     using std::swap;
0347     swap(a.m_obj, b.m_obj); // swap out the internal pointers
0348   }
0349 
0350 private:
0351   /// Constructor from existing LinkObj
0352   explicit LinkT(podio::utils::MaybeSharedPtr<LinkObjT> obj) : m_obj(std::move(obj)) {
0353   }
0354 
0355   template <bool Mut = Mutable>
0356     requires(!Mut && !Mutable)
0357   LinkT(LinkObjT* obj) : m_obj(podio::utils::MaybeSharedPtr<LinkObjT>(obj)) {
0358   }
0359 
0360   podio::utils::MaybeSharedPtr<LinkObjT> m_obj{nullptr};
0361 };
0362 
0363 template <typename FromT, typename ToT>
0364 std::ostream& operator<<(std::ostream& os, const Link<FromT, ToT>& link) {
0365   if (!link.isAvailable()) {
0366     return os << "[not available]";
0367   }
0368 
0369   return os << " id: " << link.id() << '\n'
0370             << " weight: " << link.getWeight() << '\n'
0371             << " from: " << link.getFrom().id() << '\n'
0372             << " to: " << link.getTo().id() << '\n';
0373 }
0374 
0375 #if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
0376 template <typename FromT, typename ToT>
0377 void to_json(nlohmann::json& j, const podio::LinkT<FromT, ToT, false>& link) {
0378   j = nlohmann::json{{"weight", link.getWeight()}};
0379 
0380   j["from"] = nlohmann::json{{"collectionID", link.getFrom().getObjectID().collectionID},
0381                              {"index", link.getFrom().getObjectID().index}};
0382 
0383   j["to"] = nlohmann::json{{"collectionID", link.getTo().getObjectID().collectionID},
0384                            {"index", link.getTo().getObjectID().index}};
0385 }
0386 #endif
0387 
0388 } // namespace podio
0389 
0390 template <typename FromT, typename ToT, bool Mutable>
0391 struct std::hash<podio::LinkT<FromT, ToT, Mutable>> {
0392   std::size_t operator()(const podio::LinkT<FromT, ToT, Mutable>& obj) const {
0393     return std::hash<typename podio::LinkT<FromT, ToT, Mutable>::LinkObjT*>{}(obj.m_obj.get());
0394   }
0395 };
0396 
0397 #endif // PODIO_DETAIL_LINK_H