Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-04-12 07:44:11

0001 #ifndef DataFormats_Common_AssociationMap_h
0002 #define DataFormats_Common_AssociationMap_h
0003 /** \class edm::AssociationMap
0004  *
0005  * one-to-many or one-to-one associative map using EDM references
0006  *
0007  * \author Luca Lista, INFN
0008  *
0009  * In general, this class is intuitive, but two special cases
0010  * deserves some extra discussion. These are somewhat unusual
0011  * corner cases, but sometimes actually have arisen.
0012  *
0013  * First, one can initialize the AssociationMap by passing in
0014  * a Handle to a collection as an argument to the constructor.
0015  * Usually it is a good way to initialize it. But this will
0016  * fail in the case where a collection template parameter to
0017  * Tag (either CKey or CVal) is a View and the underlying collection
0018  * read into the View is a RefVector, PtrVector, or vector(Ptr).
0019  * AssociationMap will behave improperly if the constructor is passed
0020  * a Handle<View<C> >. In this case, one should initialize with
0021  * a EDProductGetter const* or construct a RefToBaseProd whose
0022  * ProductID is associated with the underlying container, not
0023  * the RefVector, PtrVector, or vector<Ptr>.
0024  *
0025  * AssociationMap is designed to support cases where all the Key
0026  * Ref's point into one container and all the Val Ref's point into
0027  * one other container. For example, if one read a vector<Ptr> into
0028  * a View and the Ptr's pointed into different containers
0029  * and you tried to use these as elements of CVal, then
0030  * AssociationMap will not work.
0031  */
0032 
0033 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0034 #include "DataFormats/Common/interface/RefVector.h"
0035 #include "DataFormats/Common/interface/OneToValue.h"
0036 #include "DataFormats/Common/interface/OneToOne.h"
0037 #include "DataFormats/Common/interface/OneToMany.h"
0038 #include "DataFormats/Common/interface/OneToManyWithQuality.h"
0039 
0040 #include <utility>
0041 #include "oneapi/tbb/concurrent_unordered_map.h"
0042 
0043 namespace edm {
0044 
0045   class EDProductGetter;
0046 
0047   template <typename Tag>
0048   class AssociationMap {
0049     /// This is the second part of the value part of
0050     /// the items stored in the transient map
0051     typedef typename Tag::val_type internal_val_type;
0052 
0053   public:
0054     /// self type
0055     typedef AssociationMap<Tag> self;
0056     /// tag/association type
0057     typedef Tag tag_type;
0058     /// index type
0059     typedef typename Tag::index_type index_type;
0060     /// insert key type
0061     typedef typename Tag::key_type key_type;
0062     /// insert data type
0063     typedef typename Tag::data_type data_type;
0064     /// Holds the RefProd or RefToBaseProd of 1 or 2 collections
0065     typedef typename Tag::ref_type ref_type;
0066     /// map type
0067     typedef typename Tag::map_type map_type;
0068     /// size type
0069     typedef typename map_type::size_type size_type;
0070     /// type returned by dereferenced iterator, also can be inserted
0071     typedef helpers::KeyVal<key_type, internal_val_type> value_type;
0072     /// type return by operator[]
0073     typedef typename value_type::value_type result_type;
0074     /// transient map type
0075     typedef typename oneapi::tbb::concurrent_unordered_map<index_type, value_type> internal_transient_map_type;
0076 
0077     /// const iterator
0078     struct const_iterator {
0079       typedef typename self::value_type value_type;
0080       typedef ptrdiff_t difference_type;
0081       typedef value_type* pointer;
0082       typedef value_type& reference;
0083       typedef typename map_type::const_iterator::iterator_category iterator_category;
0084       const_iterator() : map_(nullptr) {}
0085       const_iterator(const self* map, typename map_type::const_iterator mi) : map_(map), i(mi) {}
0086       const_iterator& operator++() {
0087         ++i;
0088         return *this;
0089       }
0090       const_iterator operator++(int) {
0091         const_iterator ci = *this;
0092         ++i;
0093         return ci;
0094       }
0095       const_iterator& operator--() {
0096         --i;
0097         return *this;
0098       }
0099       const_iterator operator--(int) {
0100         const_iterator ci = *this;
0101         --i;
0102         return ci;
0103       }
0104       bool operator==(const const_iterator& ci) const { return i == ci.i; }
0105       bool operator!=(const const_iterator& ci) const { return i != ci.i; }
0106       const value_type& operator*() const { return map_->get(i->first); }
0107       const value_type* operator->() const { return &operator*(); }
0108 
0109     private:
0110       const self* map_;
0111       typename map_type::const_iterator i;
0112     };
0113 
0114     /// default constructor
0115     AssociationMap() {}
0116 
0117     // You will see better performance if you use other constructors.
0118     // Use this when the arguments the other constructors require are
0119     // not easily available.
0120     explicit AssociationMap(EDProductGetter const* getter) : ref_(getter) {}
0121 
0122     // It is rare for this to be useful
0123     explicit AssociationMap(const ref_type& ref) : ref_(ref) {}
0124 
0125     // In most cases this is the best constructor to use.
0126     // This constructor should be passed 2 arguments, except in the
0127     // case where the template parameter is OneToValue where it should
0128     // be passed 1 argument. In most cases, the arguments will be valid
0129     // Handle's to the containers. Internally, the AssociationMap holds
0130     // a RefProd for each container. An argument passed here is forwarded
0131     // to a RefProd constructor. Alternatively, you can pass in
0132     // a RefProd or anything else a RefProd can be constructed from.
0133     // The exceptional case is when the container template argument
0134     // is a View (For your peace of mind, I suggest you stop reading
0135     // this comment here if you are not dealing with the View case).
0136     // Usually one would not pass a Handle argument in the View
0137     // case. Then internally AssociationMap holds a RefToBaseProd
0138     // for each container instead of a RefProd and one would pass a
0139     // RefToBaseProd as an argument in that case. Also see the comments
0140     // at the top of this file that are relevant to the View case.
0141     // In the View case, the code would sometimes look similar to
0142     // the following:
0143     //
0144     //   typedef edm::AssociationMap<edm::OneToOne<edm::View<X>, edm::View<Y> > > AssocOneToOneView;
0145     //   edm::Handle<edm::View<X> > inputView1;
0146     //   event.getByToken(inputToken1V_, inputView1);
0147     //   edm::Handle<edm::View<Y> > inputView2;
0148     //   event.getByToken(inputToken2V_, inputView2);
0149     //   // If you are certain the Views are not empty!
0150     //   std::unique_ptr<AssocOneToOneView> assoc8(new AssocOneToOneView(
0151     //     edm::makeRefToBaseProdFrom(inputView1->refAt(0), event),
0152     //     edm::makeRefToBaseProdFrom(inputView2->refAt(0), event)
0153     //   ));
0154 
0155     template <typename... Args>
0156     AssociationMap(Args... args) : ref_(std::forward<Args>(args)...) {}
0157 
0158     /// clear map
0159     void clear() {
0160       map_.clear();
0161       transientMap_.clear();
0162     }
0163     /// map size
0164     size_type size() const { return map_.size(); }
0165     /// return true if empty
0166     bool empty() const { return map_.empty(); }
0167     /// insert an association
0168     void insert(const key_type& k, const data_type& v) { Tag::insert(ref_, map_, k, v); }
0169     void insert(const value_type& kv) { Tag::insert(ref_, map_, kv.key, kv.val); }
0170     /// first iterator over the map (read only)
0171     const_iterator begin() const { return const_iterator(this, map_.begin()); }
0172     /// last iterator over the map (read only)
0173     const_iterator end() const { return const_iterator(this, map_.end()); }
0174     /// find element with specified reference key
0175     const_iterator find(const key_type& k) const {
0176       if (ref_.key.id() != k.id())
0177         return end();
0178       return find(k.key());
0179     }
0180     /// erase the element whose key is k
0181     size_type erase(const key_type& k) {
0182       index_type i = k.key();
0183       transientMap_.unsafe_erase(i);
0184       return map_.erase(i);
0185     }
0186     /// find element with specified reference key
0187     const result_type& operator[](const key_type& k) const {
0188       helpers::checkRef(ref_.key, k);
0189       return get(k.key()).val;
0190     }
0191 
0192     template <typename K>
0193     const result_type& operator[](const K& k) const {
0194       helpers::checkRef(ref_.key, k);
0195       return get(k.key()).val;
0196     }
0197 
0198     /// number of associations to a key
0199     size_type numberOfAssociations(const key_type& k) const {
0200       if (ref_.key.id() != k.id())
0201         return 0;
0202       typename map_type::const_iterator f = map_.find(k.key());
0203       if (f == map_.end())
0204         return 0;
0205       return Tag::size(f->second);
0206     }
0207 
0208     template <typename K>
0209     size_type numberOfAssociations(const K& k) const {
0210       if (ref_.key.id() != k.id())
0211         return 0;
0212       typename map_type::const_iterator f = map_.find(k.key());
0213       if (f == map_.end())
0214         return 0;
0215       return Tag::size(f->second);
0216     }
0217 
0218     /// return ref-prod structure
0219     const ref_type& refProd() const { return ref_; }
0220 
0221     /// fill and return a transient map
0222     /// required for ROOT interactive usage
0223     typename Tag::transient_map_type map() { return Tag::transientMap(ref_, map_); }
0224     /// fill and return a transient key vector
0225     /// required for ROOT interactive usage
0226     typename Tag::transient_key_vector keys() { return Tag::transientKeyVector(ref_, map_); }
0227     /// fill and return a transient key vector
0228     /// required for ROOT interactive usage
0229     typename Tag::transient_val_vector values() { return Tag::transientValVector(ref_, map_); }
0230     /// post insert action
0231     void post_insert() { Tag::sort(map_); }
0232 
0233     // Find should be private!  However, generated reflex dictionaries do not compile
0234     // if Find is private.
0235     /// find helper
0236     struct Find {
0237       using first_argument_type = const self&;
0238       using second_argument_type = size_type;
0239       using result_type = const value_type*;
0240 
0241       const result_type operator()(first_argument_type c, second_argument_type i) { return &(*c.find(i)); }
0242     };
0243 
0244     //Used by ROOT storage
0245     CMS_CLASS_VERSION(10)
0246 
0247   private:
0248     /// reference set
0249     ref_type ref_;
0250     /// index map
0251     map_type map_;
0252     /// transient reference map
0253     mutable internal_transient_map_type transientMap_;
0254     /// find element with index i
0255     const_iterator find(size_type i) const {
0256       typename map_type::const_iterator f = map_.find(i);
0257       if (f == map_.end())
0258         return end();
0259       return const_iterator(this, f);
0260     }
0261     /// return value_typeelement with key i
0262     const value_type& get(size_type i) const {
0263       typename internal_transient_map_type::const_iterator tf = transientMap_.find(i);
0264       if (tf == transientMap_.end()) {
0265         typename map_type::const_iterator f = map_.find(i);
0266         if (f == map_.end())
0267           Exception::throwThis(edm::errors::InvalidReference, "can't find reference in AssociationMap at position ", i);
0268         value_type v(key_type(ref_.key, i), Tag::val(ref_, f->second));
0269         std::pair<typename internal_transient_map_type::const_iterator, bool> ins =
0270             transientMap_.insert(std::make_pair(i, v));
0271         return ins.first->second;
0272       } else {
0273         return tf->second;
0274       }
0275     }
0276     friend struct const_iterator;
0277     friend struct Find;
0278     friend struct refhelper::FindTrait<self, value_type>;
0279     template <typename, typename, typename>
0280     friend class OneToValue;
0281     template <typename, typename, typename>
0282     friend class OneToOne;
0283     template <typename, typename, typename>
0284     friend class OneToMany;
0285     template <typename, typename, typename, typename>
0286     friend class OneToManyWithQuality;
0287   };
0288 
0289   namespace refhelper {
0290     template <typename Tag>
0291     struct FindTrait<AssociationMap<Tag>, typename AssociationMap<Tag>::value_type> {
0292       typedef typename AssociationMap<Tag>::Find value;
0293     };
0294   }  // namespace refhelper
0295 
0296 }  // namespace edm
0297 #endif