Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #ifndef DataFormats_Common_AssociativeIterator_h
0002 #define DataFormats_Common_AssociativeIterator_h
0003 /**
0004  * \class AssociativeIterator<KeyRefType, AssociativeCollection>
0005  *
0006  * \author Giovanni Petrucciani, SNS Pisa
0007  *
0008  * Allows iteraton on a "new style" associative container (ValueMap, Association)
0009  * as a collection of std::pair<key, value>.
0010  *
0011  * The key is built on the fly using a helper (ItemGetter) that produces keys given ProductID and index
0012  * At the moment such a helper is available only in full framework (EdmEventItemGetter<RefType>)
0013  * 
0014  * KeyRefType can be Ref<C>, RefToBase<T>, Ptr<T>
0015  * AssociativeCollection can be ValueMap<V>, Association<C>
0016  *
0017  * Example usage is as follows:
0018  *   Handle<ValueMap<double> > hDiscriminators;
0019  *   iEvent.getByLabel(..., hDiscriminators);
0020  *   AssociativeIterator<RefToBase<Jet>, ValueMap<double> > itBTags(*hDiscriminators, EdmEventItemGetter(iEvent)), endBTags = itBTags.end();
0021  *   for ( ; itBTags != endBTags; ++itBTags ) {
0022  *      cout << " Jet PT = " << itBTags->first->pt() << ", disc = " << itBTags->second << endl;
0023  *   }
0024  * or, for edm::Association
0025  *   Handle<Association<GenParticleCollection> > hMCMatch;
0026  *   iEvent.getByLabel(..., hMCMatch);
0027  *   AssociativeIterator<RefToBase<Candidate>, Association<GenParticleCollection> > itMC(*hMCMatch, EdmEventItemGetter(iEvent)), endMC = itMC.end();
0028  *   for ( ; itMC != endMC; ++itMC ) {
0029  *      cout << " Particle with PT = " << itMC->first->pt() ;
0030  *      if (itMC->second.isNull()) { 
0031  *          cout << " UNMATCHED." << endl;
0032  *      } else {
0033  *          cout << " matched. MC PT = " << itMC->second->pt() << endl;
0034  *      }
0035  *   }
0036  *
0037  * NOTE: This class is not safe to use the same instance across threads, even if only call const methods.
0038  *
0039  */
0040 
0041 #include "DataFormats/Provenance/interface/ProductID.h"
0042 #include "DataFormats/Common/interface/EDProductGetter.h"
0043 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0044 
0045 namespace edm {
0046   class Event;
0047   template <class T>
0048   class View;
0049   template <class T>
0050   class Handle;
0051   template <class T>
0052   class Association;
0053   template <class T>
0054   class RefToBase;
0055   template <class T>
0056   class Ptr;
0057   template <class C, class T, class F>
0058   class Ref;
0059 }  // namespace edm
0060 
0061 namespace edm {
0062 
0063   // Helper classes to convert one ref type to another.
0064   // Now it's able to convert anything to itself, and RefToBase to anything else
0065   // This won't be needed if we used Ptr
0066   namespace helper {
0067     template <typename RefFrom, typename RefTo>
0068     struct RefConverter {
0069       static RefTo convert(const RefFrom &ref) { return RefTo(ref); }
0070     };
0071     template <typename T>
0072     struct RefConverter<RefToBase<T>, Ptr<T> > {
0073       static Ptr<T> convert(const RefToBase<T> &ref) {
0074         return Ptr<T>(ref.id(), ref.isAvailable() ? ref.get() : 0, ref.key());
0075       }
0076     };
0077     template <typename T, typename C, typename V, typename F>
0078     struct RefConverter<RefToBase<T>, Ref<C, V, F> > {
0079       static Ref<C, V, F> convert(const RefToBase<T> &ref) { return ref.template castTo<Ref<C, V, F> >(); }
0080     };
0081   }  // namespace helper
0082 
0083   /// Helper class that fetches some type of Ref given ProductID and index, using the edm::Event
0084   //  the implementation uses View, and works for RefType = Ref, RefToBase and Ptr
0085   template <typename RefType, typename EventType>
0086   class EventItemGetter {
0087   public:
0088     typedef typename RefType::value_type element_type;
0089     EventItemGetter(const EventType &iEvent) : iEvent_(iEvent) {}
0090     ~EventItemGetter() {}
0091 
0092     RefType get(const ProductID &id, size_t idx) const {
0093       typedef typename edm::RefToBase<element_type>
0094           BaseRefType;  // could also use Ptr, but then I can't do Ptr->RefToBase
0095       if (id_ != id) {
0096         id_ = id;
0097         iEvent_.get(id_, view_);
0098       }
0099       BaseRefType ref = view_->refAt(idx);
0100       typedef typename helper::RefConverter<BaseRefType, RefType> conv;
0101       return conv::convert(ref);
0102     }
0103 
0104   private:
0105     //This class is not intended to be used across threads
0106     CMS_SA_ALLOW mutable Handle<View<element_type> > view_;
0107     CMS_SA_ALLOW mutable ProductID id_;
0108     const EventType &iEvent_;
0109   };
0110 
0111   // unfortunately it's not possible to define value_type of an Association<C> correctly
0112   // so we need yet another template trick
0113   namespace helper {
0114     template <typename AC>
0115     struct AssociativeCollectionValueType {
0116       typedef typename AC::value_type type;
0117     };
0118 
0119     template <typename C>
0120     struct AssociativeCollectionValueType<Association<C> > {
0121       typedef typename Association<C>::reference_type type;
0122     };
0123   }  // namespace helper
0124 
0125   template <typename KeyRefType, typename AssociativeCollection, typename ItemGetter>
0126   class AssociativeIterator {
0127   public:
0128     typedef KeyRefType key_type;
0129     typedef typename KeyRefType::value_type key_val_type;
0130     typedef typename helper::AssociativeCollectionValueType<AssociativeCollection>::type val_type;
0131     typedef typename std::pair<key_type, val_type> value_type;
0132 
0133     typedef AssociativeIterator<KeyRefType, AssociativeCollection, ItemGetter> self_type;
0134 
0135     /// Create the associative iterator, pointing at the beginning of the collection
0136     AssociativeIterator(const AssociativeCollection &map, const ItemGetter &getter);
0137 
0138     self_type &operator++();
0139     self_type &operator--();
0140     self_type &nextProductID();
0141     // self_type & skipTo(const ProductID &id, size_t offs = 0) ; // to be implemented one day
0142 
0143     const value_type &operator*() const { return *(this->get()); }
0144     const value_type *operator->() const { return (this->get()); }
0145     const value_type *get() const {
0146       chkPair();
0147       return &pair_;
0148     }
0149 
0150     const key_type &key() const {
0151       chkPair();
0152       return pair_.first;
0153     }
0154     const val_type &val() const { return map_.get(idx_); }
0155     const ProductID &id() const { return ioi_->first; }
0156 
0157     operator bool() const { return idx_ < map_.size(); }
0158     self_type end() const;
0159 
0160     bool operator==(const self_type &other) const { return other.idx_ == idx_; }
0161     bool operator!=(const self_type &other) const { return other.idx_ != idx_; }
0162     bool operator<(const self_type &other) const { return other.idx_ < idx_; }
0163 
0164   private:
0165     typedef typename AssociativeCollection::id_offset_vector id_offset_vector;
0166     typedef typename id_offset_vector::const_iterator id_offset_iterator;
0167     const AssociativeCollection &map_;
0168     id_offset_iterator ioi_, ioi2_;
0169     size_t idx_;
0170 
0171     ItemGetter getter_;
0172 
0173     //This class is not intended to be used across threads
0174     CMS_SA_ALLOW mutable bool pairOk_;
0175     CMS_SA_ALLOW mutable value_type pair_;
0176 
0177     void chkPair() const;
0178   };
0179 
0180   template <typename KeyRefType, typename AC, typename IG>
0181   AssociativeIterator<KeyRefType, AC, IG>::AssociativeIterator(const AC &map, const IG &getter)
0182       : map_(map), ioi_(map_.ids().begin()), ioi2_(ioi_ + 1), idx_(0), getter_(getter), pairOk_(false) {}
0183 
0184   template <typename KeyRefType, typename AC, typename IG>
0185   AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::operator++() {
0186     pairOk_ = false;
0187     idx_++;
0188     if (ioi2_ < map_.ids().end()) {
0189       if (ioi2_->second == idx_) {
0190         ++ioi_;
0191         ++ioi2_;
0192       }
0193     }
0194     return *this;
0195   }
0196 
0197   template <typename KeyRefType, typename AC, typename IG>
0198   AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::operator--() {
0199     pairOk_ = false;
0200     idx_--;
0201     if (ioi_->second < idx_) {
0202       --ioi_;
0203       --ioi2_;
0204     }
0205     return *this;
0206   }
0207 
0208   template <typename KeyRefType, typename AC, typename IG>
0209   AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::nextProductID() {
0210     pairOk_ = false;
0211     ioi_++;
0212     ioi2_++;
0213     if (ioi_ == map_.ids().end()) {
0214       idx_ = map_.size();
0215     } else {
0216       idx_ = ioi_->second;
0217     }
0218   }
0219 
0220   /*
0221     template<typename KeyRefType, typename AC, typename IG>
0222     AssociativeIterator<KeyRefType,AC,IG> & AssociativeIterator<KeyRefType,AC,IG>::skipTo(const ProductID &id, size_t offs) {
0223         pairOk_ = false;
0224         throw Exception(errors::UnimplementedFeature);
0225     }
0226     */
0227 
0228   template <typename KeyRefType, typename AC, typename IG>
0229   AssociativeIterator<KeyRefType, AC, IG> AssociativeIterator<KeyRefType, AC, IG>::end() const {
0230     self_type ret(map_, getter_);
0231     ret.ioi_ = map_.ids().end();
0232     ret.ioi2_ = ret.ioi_ + 1;
0233     ret.idx_ = map_.size();
0234     return ret;
0235   }
0236 
0237   template <typename KeyRefType, typename AC, typename IG>
0238   void AssociativeIterator<KeyRefType, AC, IG>::chkPair() const {
0239     if (pairOk_)
0240       return;
0241     pair_.first = getter_.get(id(), idx_ - ioi_->second);
0242     pair_.second = map_.get(idx_);
0243     pairOk_ = true;
0244   }
0245 
0246   template <typename KeyRefType, typename AC, typename EventType>
0247   AssociativeIterator<KeyRefType, AC, edm::EventItemGetter<KeyRefType, EventType> > makeAssociativeIterator(
0248       const AC &map, const EventType &event) {
0249     using Getter = edm::EventItemGetter<KeyRefType, EventType>;
0250     return AssociativeIterator<KeyRefType, AC, Getter>(map, Getter{event});
0251   }
0252 }  // namespace edm
0253 
0254 #endif