Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:03:50

0001 #ifndef DataFormats_Common_AssociationVector_h
0002 #define DataFormats_Common_AssociationVector_h
0003 /* class edm::AssociationVector<CKey, CVal>
0004  *
0005  * adds to a std::vector<CVal> a edm::RefProd<CKey>, in such a way
0006  * that, assuming that the CVal and CKey collections have the same
0007  * size and are properly ordered, the two collections can be
0008  * in one-to-one correspondance
0009  *
0010  * \author Luca Lista, INFN
0011  *
0012  */
0013 
0014 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0015 #include "DataFormats/Common/interface/CommonExceptions.h"
0016 #include "DataFormats/Common/interface/FillView.h"
0017 #include "DataFormats/Common/interface/Ref.h"
0018 #include "DataFormats/Common/interface/RefProd.h"
0019 #include "DataFormats/Common/interface/RefToBase.h"
0020 #include "DataFormats/Common/interface/RefToBaseProd.h"
0021 #include "DataFormats/Common/interface/traits.h"
0022 #include "DataFormats/Provenance/interface/ProductID.h"
0023 #include "FWCore/Utilities/interface/EDMException.h"
0024 
0025 #include <atomic>
0026 #include <type_traits>
0027 #include <memory>
0028 
0029 namespace edm {
0030   template <class T>
0031   class Ptr;
0032 
0033   namespace helper {
0034 
0035     struct AssociationIdenticalKeyReference {
0036       template <typename T>
0037       static T const& get(T const& t, ProductID) {
0038         return t;
0039       }
0040     };
0041 
0042     template <typename T>
0043     struct AssociationKeyReferenceTrait {
0044       typedef AssociationIdenticalKeyReference type;
0045     };
0046 
0047     template <typename REFPROD>
0048     struct RefFromRefProdTrait {};
0049 
0050     template <typename C>
0051     struct RefFromRefProdTrait<RefProd<C> > {
0052       typedef Ref<typename RefProd<C>::product_type> ref_type;
0053     };
0054 
0055     template <typename T>
0056     struct RefFromRefProdTrait<RefToBaseProd<T> > {
0057       typedef RefToBase<T> ref_type;
0058     };
0059   }  // namespace helper
0060 
0061   template <typename KeyRefProd,
0062             typename CVal,
0063             typename KeyRef = typename helper::RefFromRefProdTrait<KeyRefProd>::ref_type,
0064             typename SizeType =
0065                 unsigned int,  //the type used here can not change when go from 32bit to 64bit or across platforms
0066             typename KeyReferenceHelper = typename helper::AssociationKeyReferenceTrait<KeyRef>::type>
0067   class AssociationVector {
0068     static_assert(std::is_convertible<SizeType, typename CVal::size_type>::value,
0069                   "Can not convert container size_type to unsigned int.");
0070     typedef AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> self;
0071 
0072   public:
0073     typedef KeyRefProd refprod_type;
0074     typedef typename KeyRefProd::product_type CKey;
0075     typedef SizeType size_type;
0076     typedef typename KeyRef::value_type key_type;
0077     typedef typename std::pair<KeyRef, typename CVal::value_type> value_type;
0078     typedef std::vector<value_type> transient_vector_type;
0079     typedef value_type const& const_reference;
0080     AssociationVector();
0081     AssociationVector(KeyRefProd const& ref, CKey const* = nullptr);
0082     AssociationVector(AssociationVector const&);
0083     ~AssociationVector();
0084 
0085     size_type size() const;
0086     bool empty() const;
0087     const_reference operator[](size_type n) const;
0088     typename CVal::const_reference operator[](KeyRef const& k) const;
0089     typename CVal::reference operator[](KeyRef const& k);
0090 
0091     template <typename K>
0092     typename CVal::const_reference operator[](edm::Ptr<K> const& k) const;
0093     template <typename K>
0094     typename CVal::const_reference operator[](edm::RefToBase<K> const& k) const;
0095 
0096     self& operator=(self const&);
0097 
0098     void clear();
0099     void swap(self& other);
0100     KeyRefProd const& keyProduct() const { return ref_; }
0101     KeyRef key(size_type i) const { return KeyRef(ref_, i); }
0102     typename CVal::value_type const value(size_type i) const { return data_[i]; }
0103     void setValue(size_type i, typename CVal::value_type const& val);
0104     void fillView(ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const;
0105 
0106     typedef typename transient_vector_type::const_iterator const_iterator;
0107 
0108     const_iterator begin() const { return transientVector().begin(); }
0109     const_iterator end() const { return transientVector().end(); }
0110 
0111     //Used by ROOT storage
0112     CMS_CLASS_VERSION(11)
0113 
0114   private:
0115     enum CacheState { kUnset, kFilling, kSet };
0116     CVal data_;
0117     KeyRefProd ref_;
0118     mutable std::atomic<transient_vector_type*> transientVector_;
0119 
0120     transient_vector_type const& transientVector() const;
0121     void fixup() const;
0122   };
0123 
0124   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0125   inline
0126       typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::transient_vector_type const&
0127       AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::transientVector() const {
0128     fixup();
0129     return *(transientVector_.load(std::memory_order_acquire));
0130   }
0131 
0132   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0133   inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector()
0134       : data_(), ref_(), transientVector_(nullptr) {}
0135 
0136   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0137   inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector(
0138       KeyRefProd const& ref, CKey const* coll)
0139       : data_(coll == nullptr ? ref->size() : coll->size()),
0140         ref_(ref),
0141         transientVector_(new transient_vector_type(coll == nullptr ? ref->size() : coll->size())) {}
0142 
0143   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0144   inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector(
0145       AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> const& o)
0146       : data_(o.data_), ref_(o.ref_), transientVector_() {
0147     auto t = o.transientVector_.load(std::memory_order_acquire);
0148     if (t) {
0149       transientVector_.store(new transient_vector_type(*t), std::memory_order_release);
0150     }
0151   }
0152 
0153   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0154   inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::~AssociationVector() {
0155     delete transientVector_.load(std::memory_order_acquire);
0156   }
0157 
0158   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0159   inline typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::const_reference
0160   AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](size_type n) const {
0161     return transientVector()[n];
0162   }
0163 
0164   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0165   inline typename CVal::const_reference
0166   AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](KeyRef const& k) const {
0167     KeyRef keyRef = KeyReferenceHelper::get(k, ref_.id());
0168     checkForWrongProduct(keyRef.id(), ref_.id());
0169     return data_[keyRef.key()];
0170   }
0171 
0172   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0173   template <typename K>
0174   inline typename CVal::const_reference
0175   AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](edm::Ptr<K> const& k) const {
0176     static_assert(std::is_base_of<K, key_type>::value,
0177                   "edm::Ptr's key type is not a base class of AssociationVector's item type");
0178     checkForWrongProduct(k.id(), ref_.id());
0179     return data_[k.key()];
0180   }
0181 
0182   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0183   template <typename K>
0184   typename CVal::const_reference AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](
0185       edm::RefToBase<K> const& k) const {
0186     static_assert(std::is_base_of<K, key_type>::value,
0187                   "edm::RefToBase's key type is not a base class of AssociationVector's item type");
0188     checkForWrongProduct(k.id(), ref_.id());
0189     return data_[k.key()];
0190   }
0191 
0192   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0193   inline typename CVal::reference AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](
0194       KeyRef const& k) {
0195     KeyRef keyRef = KeyReferenceHelper::get(k, ref_.id());
0196     auto t = transientVector_.exchange(nullptr, std::memory_order_acq_rel);
0197     delete t;
0198     checkForWrongProduct(keyRef.id(), ref_.id());
0199     return data_[keyRef.key()];
0200   }
0201 
0202   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0203   inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>&
0204   AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator=(self const& o) {
0205     if (this == &o) {
0206       return *this;
0207     }
0208     data_ = o.data_;
0209     ref_ = o.ref_;
0210     auto t = transientVector_.exchange(nullptr, std::memory_order_acq_rel);
0211     delete t;
0212     return *this;
0213   }
0214 
0215   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0216   inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::setValue(
0217       size_type i, typename CVal::value_type const& val) {
0218     data_[i] = val;
0219     KeyRef ref(ref_, i);
0220     auto t = transientVector_.load(std::memory_order_acquire);
0221     (*t)[i].first = ref;
0222     (*t)[i].second = data_[i];
0223   }
0224 
0225   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0226   inline typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::size_type
0227   AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::size() const {
0228     return data_.size();
0229   }
0230 
0231   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0232   inline bool AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::empty() const {
0233     return data_.empty();
0234   }
0235 
0236   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0237   inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::clear() {
0238     data_.clear();
0239     auto t = transientVector_.load(std::memory_order_acquire);
0240     if (t)
0241       t->clear();
0242     ref_ = KeyRefProd();
0243   }
0244 
0245   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0246   inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::swap(self& other) {
0247     data_.swap(other.data_);
0248     other.transientVector_.store(
0249         transientVector_.exchange(other.transientVector_.load(std::memory_order_acquire), std::memory_order_acq_rel),
0250         std::memory_order_release);
0251     ref_.swap(other.ref_);
0252   }
0253 
0254   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0255   inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::fixup() const {
0256     if (nullptr == transientVector_.load(std::memory_order_acquire)) {
0257       std::unique_ptr<transient_vector_type> newT{new transient_vector_type(size())};
0258       for (size_type i = 0; i != size(); ++i) {
0259         (*newT)[i] = std::make_pair(KeyRef(ref_, i), data_[i]);
0260       }
0261       transient_vector_type* expected = nullptr;
0262       if (transientVector_.compare_exchange_strong(expected, newT.get())) {
0263         newT.release();
0264       }
0265     }
0266   }
0267 
0268   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0269   void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::fillView(
0270       ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const {
0271     detail::reallyFillView(*this, id, pointers, helpers);
0272     //     pointers.reserve(this->size());
0273     //     for(typename CVal::const_iterator i=data_.begin(), e=data_.end(); i!=e; ++i)
0274     //       pointers.push_back(&(*i));
0275     //     // helpers is not yet filled in.
0276     //     //Exception::throwThis(errors::UnimplementedFeature, "AssociationVector<T>::fillView(...)");
0277   }
0278 
0279   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0280   inline void swap(AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>& a,
0281                    AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>& b) {
0282     a.swap(b);
0283   }
0284 
0285   //----------------------------------------------------------------------
0286   //
0287   // Free function template to support creation of Views.
0288 
0289   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0290   inline void fillView(AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> const& obj,
0291                        ProductID const& id,
0292                        std::vector<void const*>& pointers,
0293                        FillViewHelperVector& helpers) {
0294     obj.fillView(id, pointers, helpers);
0295   }
0296 
0297   template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0298   struct has_fillView<AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> > {
0299     static bool const value = true;
0300   };
0301 
0302 }  // namespace edm
0303 
0304 #endif