Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-08-24 09:50:39

0001 #ifndef DataFormats_Common_RefToBase_h
0002 #define DataFormats_Common_RefToBase_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     Common
0006 // Class  :     RefToBase
0007 //
0008 /**\class RefToBase RefToBase.h DataFormats/Common/interface/RefToBase.h
0009 
0010 Description: Interface to a reference to an item based on the base class of the item
0011 
0012 Usage:
0013 Using an edm:RefToBase<T> allows one to hold references to items in different containers
0014 within the edm::Event where those objects are only related by a base class, T.
0015 
0016 \code
0017 edm::Ref<FooCollection> foo(...);
0018 std::vector<edm::RefToBase<Bar> > bars;
0019 bars.push_back(edm::RefToBase<Bar>(foo));
0020 \endcode
0021 
0022 Cast to concrete type can be done via the castTo<REF>
0023 function template. This function throws an exception
0024 if the type passed as REF does not match the concrete
0025 reference type.
0026 
0027 */
0028 //
0029 // Original Author:  Chris Jones
0030 //         Created:  Mon Apr  3 16:37:59 EDT 2006
0031 //
0032 
0033 // system include files
0034 
0035 // user include files
0036 
0037 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0038 #include "DataFormats/Common/interface/EDProductfwd.h"
0039 #include "FWCore/Utilities/interface/EDMException.h"
0040 #include "DataFormats/Common/interface/BaseHolder.h"
0041 
0042 #include "DataFormats/Common/interface/Holder.h"
0043 #include "DataFormats/Common/interface/IndirectHolder.h"
0044 #include "DataFormats/Common/interface/RefHolder.h"
0045 
0046 #include <memory>
0047 #include <type_traits>
0048 
0049 namespace edm {
0050   //--------------------------------------------------------------------
0051   // Class template RefToBase<T>
0052   //--------------------------------------------------------------------
0053 
0054   /// RefToBase<T> provides a mechanism to refer to an object of type
0055   /// T (or which has T as a public base), held in a collection (of
0056   /// type not known to RefToBase<T>) which itself it in an Event.
0057 
0058   template <typename T>
0059   class RefToBaseVector;
0060   template <typename C, typename T, typename F>
0061   class Ref;
0062   template <typename C>
0063   class RefProd;
0064   template <typename T>
0065   class RefToBaseProd;
0066   template <typename T>
0067   class View;
0068 
0069   template <class T>
0070   class RefToBase {
0071   public:
0072     typedef T value_type;
0073 
0074     RefToBase();
0075     RefToBase(RefToBase const& other);
0076     RefToBase(RefToBase&& other) noexcept;
0077     RefToBase& operator=(RefToBase&& other) noexcept;
0078 
0079     template <typename C1, typename T1, typename F1>
0080     explicit RefToBase(Ref<C1, T1, F1> const& r);
0081     template <typename C>
0082     explicit RefToBase(RefProd<C> const& r);
0083     RefToBase(RefToBaseProd<T> const& r, size_t i);
0084     RefToBase(Handle<View<T>> const& handle, size_t i);
0085     template <typename T1>
0086     explicit RefToBase(RefToBase<T1> const& r);
0087     RefToBase(std::unique_ptr<reftobase::BaseHolder<value_type>>);
0088     RefToBase(std::shared_ptr<reftobase::RefHolderBase> p);
0089 
0090     ~RefToBase() noexcept;
0091 
0092     RefToBase& operator=(RefToBase const& rhs);
0093 
0094     value_type const& operator*() const;
0095     value_type const* operator->() const;
0096     value_type const* get() const;
0097 
0098     ProductID id() const;
0099     size_t key() const;
0100 
0101     template <class REF>
0102       requires requires {
0103         typename REF::value_type;
0104         requires std::is_same_v<T, typename REF::value_type> or std::is_base_of_v<T, typename REF::value_type> or
0105                      std::is_base_of_v<typename REF::value_type, T>;
0106       }
0107     REF castTo() const;
0108 
0109     bool isNull() const;
0110     bool isNonnull() const;
0111     bool operator!() const;
0112 
0113     bool operator==(RefToBase const& rhs) const;
0114     bool operator!=(RefToBase const& rhs) const;
0115 
0116     void swap(RefToBase& other);
0117 
0118     std::unique_ptr<reftobase::RefHolderBase> holder() const;
0119 
0120     EDProductGetter const* productGetter() const;
0121 
0122     /// Checks if collection is in memory or available
0123     /// in the Event. No type checking is done.
0124     /// This function is potentially costly as it might cause a disk
0125     /// read (note that it does not cause the data to be cached locally)
0126     bool isAvailable() const { return holder_ ? holder_->isAvailable() : false; }
0127 
0128     bool isTransient() const { return holder_ ? holder_->isTransient() : false; }
0129 
0130     //Needed for ROOT storage
0131     CMS_CLASS_VERSION(10)
0132   private:
0133     value_type const* getPtrImpl() const;
0134     reftobase::BaseHolder<value_type>* holder_;
0135     friend class RefToBaseVector<T>;
0136     friend class RefToBaseProd<T>;
0137     template <typename B>
0138     friend class RefToBase;
0139   };
0140 
0141   //--------------------------------------------------------------------
0142   // Implementation of RefToBase<T>
0143   //--------------------------------------------------------------------
0144 
0145   template <class T>
0146   inline RefToBase<T>::RefToBase() : holder_(nullptr) {}
0147 
0148   template <class T>
0149   inline RefToBase<T>::RefToBase(RefToBase const& other) : holder_(other.holder_ ? other.holder_->clone() : nullptr) {}
0150 
0151   template <class T>
0152   inline RefToBase<T>::RefToBase(RefToBase&& other) noexcept : holder_(other.holder_) {
0153     other.holder_ = nullptr;
0154   }
0155 
0156   template <class T>
0157   inline RefToBase<T>& RefToBase<T>::operator=(RefToBase&& other) noexcept {
0158     delete holder_;
0159     holder_ = other.holder_;
0160     other.holder_ = nullptr;
0161     return *this;
0162   }
0163 
0164   template <class T>
0165   template <typename C1, typename T1, typename F1>
0166   inline RefToBase<T>::RefToBase(Ref<C1, T1, F1> const& iRef)
0167       : holder_(new reftobase::Holder<T, Ref<C1, T1, F1>>(iRef)) {}
0168 
0169   template <class T>
0170   template <typename C>
0171   inline RefToBase<T>::RefToBase(RefProd<C> const& iRef) : holder_(new reftobase::Holder<T, RefProd<C>>(iRef)) {}
0172 
0173   template <class T>
0174   template <typename T1>
0175   inline RefToBase<T>::RefToBase(RefToBase<T1> const& iRef)
0176       : holder_(
0177             new reftobase::IndirectHolder<T>(std::shared_ptr<edm::reftobase::RefHolderBase>(iRef.holder().release()))) {
0178     // OUT: holder_( new reftobase::Holder<T,RefToBase<T1> >(iRef ) )  {
0179     // Forcing the conversion through IndirectHolder,
0180     //   as Holder<T,RefToBase<T1>> would need dictionaries we will never have.
0181     // In this way we only need the IndirectHolder<T> and the RefHolder of the real type of the item
0182     // This might cause a small performance penalty.
0183     static_assert(std::is_base_of<T, T1>::value, "RefToBase::RefToBase T not base of T1");
0184   }
0185 
0186   template <class T>
0187   inline RefToBase<T>::RefToBase(std::unique_ptr<reftobase::BaseHolder<value_type>> p) : holder_(p.release()) {}
0188 
0189   template <class T>
0190   inline RefToBase<T>::RefToBase(std::shared_ptr<reftobase::RefHolderBase> p)
0191       : holder_(new reftobase::IndirectHolder<T>(p)) {}
0192 
0193   template <class T>
0194   inline RefToBase<T>::~RefToBase() noexcept {
0195     delete holder_;
0196   }
0197 
0198   template <class T>
0199   inline RefToBase<T>& RefToBase<T>::operator=(RefToBase<T> const& iRHS) {
0200     RefToBase<T> temp(iRHS);
0201     temp.swap(*this);
0202     return *this;
0203   }
0204 
0205   template <class T>
0206   inline T const& RefToBase<T>::operator*() const {
0207     return *getPtrImpl();
0208   }
0209 
0210   template <class T>
0211   inline T const* RefToBase<T>::operator->() const {
0212     return getPtrImpl();
0213   }
0214 
0215   template <class T>
0216   inline T const* RefToBase<T>::get() const {
0217     return getPtrImpl();
0218   }
0219 
0220   template <class T>
0221   inline ProductID RefToBase<T>::id() const {
0222     return holder_ ? holder_->id() : ProductID();
0223   }
0224 
0225   template <class T>
0226   inline size_t RefToBase<T>::key() const {
0227     if (holder_ == nullptr) {
0228       Exception::throwThis(errors::InvalidReference,
0229                            "attempting get key from  null RefToBase;\n"
0230                            "You should check for nullity before calling key().");
0231       return 0;
0232     }
0233     return holder_->key();
0234   }
0235 
0236   template <class T>
0237   template <class REF>
0238     requires requires {
0239       typename REF::value_type;
0240       requires std::is_same_v<T, typename REF::value_type> or std::is_base_of_v<T, typename REF::value_type> or
0241                    std::is_base_of_v<typename REF::value_type, T>;
0242     }
0243   REF RefToBase<T>::castTo() const {
0244     if (!holder_) {
0245       Exception::throwThis(errors::InvalidReference,
0246                            "attempting to cast a null RefToBase;\n"
0247                            "You should check for nullity before casting.");
0248     }
0249 
0250     // If REF is type edm::Ref<C,T,F>, then it is impossible to
0251     // check the container type C here. We just have to assume
0252     // that the caller provided the correct type.
0253 
0254     EDProductGetter const* getter = productGetter();
0255     if (getter) {
0256       return REF(id(), key(), getter);
0257     }
0258 
0259     T const* value = get();
0260     if (value == nullptr) {
0261       return REF(id());
0262     }
0263     typename REF::value_type const* newValue;
0264     if constexpr (std::is_same_v<T, typename REF::value_type> or std::is_base_of_v<typename REF::value_type, T>) {
0265       newValue = value;
0266     } else {
0267       newValue = dynamic_cast<typename REF::value_type const*>(value);
0268     }
0269     if (newValue) {
0270       return REF(id(), newValue, key(), isTransient());
0271     }
0272 
0273     Exception::throwThis(errors::InvalidReference,
0274                          "RefToBase<T>::castTo Error attempting to cast mismatched types\n"
0275                          "casting from RefToBase with T: ",
0276                          typeid(T).name(),
0277                          "\ncasting to: ",
0278                          typeid(REF).name());
0279     return REF();
0280   }
0281 
0282   /// Checks for null
0283   template <class T>
0284   inline bool RefToBase<T>::isNull() const {
0285     return !id().isValid();
0286   }
0287 
0288   /// Checks for non-null
0289   template <class T>
0290   inline bool RefToBase<T>::isNonnull() const {
0291     return !isNull();
0292   }
0293 
0294   /// Checks for null
0295   template <class T>
0296   inline bool RefToBase<T>::operator!() const {
0297     return isNull();
0298   }
0299 
0300   template <class T>
0301   inline bool RefToBase<T>::operator==(RefToBase<T> const& rhs) const {
0302     return holder_ ? holder_->isEqualTo(*rhs.holder_) : holder_ == rhs.holder_;
0303   }
0304 
0305   template <class T>
0306   inline bool RefToBase<T>::operator!=(RefToBase<T> const& rhs) const {
0307     return !(*this == rhs);
0308   }
0309 
0310   template <class T>
0311   inline void RefToBase<T>::swap(RefToBase<T>& other) {
0312     std::swap(holder_, other.holder_);
0313   }
0314 
0315   template <class T>
0316   inline EDProductGetter const* RefToBase<T>::productGetter() const {
0317     return holder_ ? holder_->productGetter() : nullptr;
0318   }
0319 
0320   template <class T>
0321   inline T const* RefToBase<T>::getPtrImpl() const {
0322     return holder_ ? holder_->getPtr() : nullptr;
0323   }
0324 
0325   template <class T>
0326   std::unique_ptr<reftobase::RefHolderBase> RefToBase<T>::holder() const {
0327     return holder_ ? holder_->holder() : std::unique_ptr<reftobase::RefHolderBase>();
0328   }
0329 
0330   // Free swap function
0331   template <class T>
0332   inline void swap(RefToBase<T>& a, RefToBase<T>& b) {
0333     a.swap(b);
0334   }
0335 }  // namespace edm
0336 
0337 #include "DataFormats/Common/interface/RefToBaseProd.h"
0338 #include "DataFormats/Common/interface/Handle.h"
0339 #include "DataFormats/Common/interface/View.h"
0340 
0341 namespace edm {
0342   template <class T>
0343   inline RefToBase<T>::RefToBase(RefToBaseProd<T> const& r, size_t i)
0344       : holder_(r.operator->()->refAt(i).holder_->clone()) {}
0345 
0346   template <typename T>
0347   inline RefToBase<T>::RefToBase(Handle<View<T>> const& handle, size_t i)
0348       : holder_(handle.operator->()->refAt(i).holder_->clone()) {}
0349 
0350 }  // namespace edm
0351 
0352 #endif