Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:38:44

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     REF castTo() const;
0103 
0104     bool isNull() const;
0105     bool isNonnull() const;
0106     bool operator!() const;
0107 
0108     bool operator==(RefToBase const& rhs) const;
0109     bool operator!=(RefToBase const& rhs) const;
0110 
0111     void swap(RefToBase& other);
0112 
0113     std::unique_ptr<reftobase::RefHolderBase> holder() const;
0114 
0115     EDProductGetter const* productGetter() const;
0116 
0117     /// Checks if collection is in memory or available
0118     /// in the Event. No type checking is done.
0119     /// This function is potentially costly as it might cause a disk
0120     /// read (note that it does not cause the data to be cached locally)
0121     bool isAvailable() const { return holder_ ? holder_->isAvailable() : false; }
0122 
0123     bool isTransient() const { return holder_ ? holder_->isTransient() : false; }
0124 
0125     //Needed for ROOT storage
0126     CMS_CLASS_VERSION(10)
0127   private:
0128     value_type const* getPtrImpl() const;
0129     reftobase::BaseHolder<value_type>* holder_;
0130     friend class RefToBaseVector<T>;
0131     friend class RefToBaseProd<T>;
0132     template <typename B>
0133     friend class RefToBase;
0134   };
0135 
0136   //--------------------------------------------------------------------
0137   // Implementation of RefToBase<T>
0138   //--------------------------------------------------------------------
0139 
0140   template <class T>
0141   inline RefToBase<T>::RefToBase() : holder_(nullptr) {}
0142 
0143   template <class T>
0144   inline RefToBase<T>::RefToBase(RefToBase const& other) : holder_(other.holder_ ? other.holder_->clone() : nullptr) {}
0145 
0146   template <class T>
0147   inline RefToBase<T>::RefToBase(RefToBase&& other) noexcept : holder_(other.holder_) {
0148     other.holder_ = nullptr;
0149   }
0150 
0151   template <class T>
0152   inline RefToBase<T>& RefToBase<T>::operator=(RefToBase&& other) noexcept {
0153     delete holder_;
0154     holder_ = other.holder_;
0155     other.holder_ = nullptr;
0156     return *this;
0157   }
0158 
0159   template <class T>
0160   template <typename C1, typename T1, typename F1>
0161   inline RefToBase<T>::RefToBase(Ref<C1, T1, F1> const& iRef)
0162       : holder_(new reftobase::Holder<T, Ref<C1, T1, F1>>(iRef)) {}
0163 
0164   template <class T>
0165   template <typename C>
0166   inline RefToBase<T>::RefToBase(RefProd<C> const& iRef) : holder_(new reftobase::Holder<T, RefProd<C>>(iRef)) {}
0167 
0168   template <class T>
0169   template <typename T1>
0170   inline RefToBase<T>::RefToBase(RefToBase<T1> const& iRef)
0171       : holder_(
0172             new reftobase::IndirectHolder<T>(std::shared_ptr<edm::reftobase::RefHolderBase>(iRef.holder().release()))) {
0173     // OUT: holder_( new reftobase::Holder<T,RefToBase<T1> >(iRef ) )  {
0174     // Forcing the conversion through IndirectHolder,
0175     //   as Holder<T,RefToBase<T1>> would need dictionaries we will never have.
0176     // In this way we only need the IndirectHolder<T> and the RefHolder of the real type of the item
0177     // This might cause a small performance penalty.
0178     static_assert(std::is_base_of<T, T1>::value, "RefToBase::RefToBase T not base of T1");
0179   }
0180 
0181   template <class T>
0182   inline RefToBase<T>::RefToBase(std::unique_ptr<reftobase::BaseHolder<value_type>> p) : holder_(p.release()) {}
0183 
0184   template <class T>
0185   inline RefToBase<T>::RefToBase(std::shared_ptr<reftobase::RefHolderBase> p)
0186       : holder_(new reftobase::IndirectHolder<T>(p)) {}
0187 
0188   template <class T>
0189   inline RefToBase<T>::~RefToBase() noexcept {
0190     delete holder_;
0191   }
0192 
0193   template <class T>
0194   inline RefToBase<T>& RefToBase<T>::operator=(RefToBase<T> const& iRHS) {
0195     RefToBase<T> temp(iRHS);
0196     temp.swap(*this);
0197     return *this;
0198   }
0199 
0200   template <class T>
0201   inline T const& RefToBase<T>::operator*() const {
0202     return *getPtrImpl();
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>::get() const {
0212     return getPtrImpl();
0213   }
0214 
0215   template <class T>
0216   inline ProductID RefToBase<T>::id() const {
0217     return holder_ ? holder_->id() : ProductID();
0218   }
0219 
0220   template <class T>
0221   inline size_t RefToBase<T>::key() const {
0222     if (holder_ == nullptr) {
0223       Exception::throwThis(errors::InvalidReference,
0224                            "attempting get key from  null RefToBase;\n"
0225                            "You should check for nullity before calling key().");
0226       return 0;
0227     }
0228     return holder_->key();
0229   }
0230 
0231   namespace {
0232     // If the template parameters are classes or structs they should be
0233     // related by inheritance, otherwise they should be the same type.
0234     template <typename T, typename U>
0235     typename std::enable_if<std::is_class<T>::value>::type checkTypeCompatibility() {
0236       static_assert(std::is_base_of<T, U>::value || std::is_base_of<U, T>::value,
0237                     "RefToBase::castTo error element types are not related by inheritance");
0238     }
0239 
0240     template <typename T, typename U>
0241     typename std::enable_if<!std::is_class<T>::value>::type checkTypeCompatibility() {
0242       static_assert(std::is_same<T, U>::value, "RefToBase::castTo error non-class element types are not the same");
0243     }
0244 
0245     // Convert the pointer types, use dynamic_cast if they are classes
0246     template <typename T, typename OUT>
0247     typename std::enable_if<std::is_class<T>::value, OUT const*>::type convertTo(T const* t) {
0248       return dynamic_cast<OUT const*>(t);
0249     }
0250 
0251     template <typename T, typename OUT>
0252     typename std::enable_if<!std::is_class<T>::value, OUT const*>::type convertTo(T const* t) {
0253       return t;
0254     }
0255   }  // namespace
0256 
0257   template <class T>
0258   template <class REF>
0259   REF RefToBase<T>::castTo() const {
0260     if (!holder_) {
0261       Exception::throwThis(errors::InvalidReference,
0262                            "attempting to cast a null RefToBase;\n"
0263                            "You should check for nullity before casting.");
0264     }
0265 
0266     checkTypeCompatibility<T, typename REF::value_type>();
0267 
0268     // If REF is type edm::Ref<C,T,F>, then it is impossible to
0269     // check the container type C here. We just have to assume
0270     // that the caller provided the correct type.
0271 
0272     EDProductGetter const* getter = productGetter();
0273     if (getter) {
0274       return REF(id(), key(), getter);
0275     }
0276 
0277     T const* value = get();
0278     if (value == nullptr) {
0279       return REF(id());
0280     }
0281     typename REF::value_type const* newValue = convertTo<T, typename REF::value_type>(value);
0282     if (newValue) {
0283       return REF(id(), newValue, key(), isTransient());
0284     }
0285 
0286     Exception::throwThis(errors::InvalidReference,
0287                          "RefToBase<T>::castTo Error attempting to cast mismatched types\n"
0288                          "casting from RefToBase with T: ",
0289                          typeid(T).name(),
0290                          "\ncasting to: ",
0291                          typeid(REF).name());
0292     return REF();
0293   }
0294 
0295   /// Checks for null
0296   template <class T>
0297   inline bool RefToBase<T>::isNull() const {
0298     return !id().isValid();
0299   }
0300 
0301   /// Checks for non-null
0302   template <class T>
0303   inline bool RefToBase<T>::isNonnull() const {
0304     return !isNull();
0305   }
0306 
0307   /// Checks for null
0308   template <class T>
0309   inline bool RefToBase<T>::operator!() const {
0310     return isNull();
0311   }
0312 
0313   template <class T>
0314   inline bool RefToBase<T>::operator==(RefToBase<T> const& rhs) const {
0315     return holder_ ? holder_->isEqualTo(*rhs.holder_) : holder_ == rhs.holder_;
0316   }
0317 
0318   template <class T>
0319   inline bool RefToBase<T>::operator!=(RefToBase<T> const& rhs) const {
0320     return !(*this == rhs);
0321   }
0322 
0323   template <class T>
0324   inline void RefToBase<T>::swap(RefToBase<T>& other) {
0325     std::swap(holder_, other.holder_);
0326   }
0327 
0328   template <class T>
0329   inline EDProductGetter const* RefToBase<T>::productGetter() const {
0330     return holder_ ? holder_->productGetter() : nullptr;
0331   }
0332 
0333   template <class T>
0334   inline T const* RefToBase<T>::getPtrImpl() const {
0335     return holder_ ? holder_->getPtr() : nullptr;
0336   }
0337 
0338   template <class T>
0339   std::unique_ptr<reftobase::RefHolderBase> RefToBase<T>::holder() const {
0340     return holder_ ? holder_->holder() : std::unique_ptr<reftobase::RefHolderBase>();
0341   }
0342 
0343   // Free swap function
0344   template <class T>
0345   inline void swap(RefToBase<T>& a, RefToBase<T>& b) {
0346     a.swap(b);
0347   }
0348 }  // namespace edm
0349 
0350 #include "DataFormats/Common/interface/RefToBaseProd.h"
0351 #include "DataFormats/Common/interface/Handle.h"
0352 #include "DataFormats/Common/interface/View.h"
0353 
0354 namespace edm {
0355   template <class T>
0356   inline RefToBase<T>::RefToBase(RefToBaseProd<T> const& r, size_t i)
0357       : holder_(r.operator->()->refAt(i).holder_->clone()) {}
0358 
0359   template <typename T>
0360   inline RefToBase<T>::RefToBase(Handle<View<T>> const& handle, size_t i)
0361       : holder_(handle.operator->()->refAt(i).holder_->clone()) {}
0362 
0363 }  // namespace edm
0364 
0365 #endif