Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:53:02

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