Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:25:07

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