Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/podio/detail/Link.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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