1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
#ifndef DataFormats_Common_AssociativeIterator_h
#define DataFormats_Common_AssociativeIterator_h
/**
* \class AssociativeIterator<KeyRefType, AssociativeCollection>
*
* \author Giovanni Petrucciani, SNS Pisa
*
* Allows iteraton on a "new style" associative container (ValueMap, Association)
* as a collection of std::pair<key, value>.
*
* The key is built on the fly using a helper (ItemGetter) that produces keys given ProductID and index
* At the moment such a helper is available only in full framework (EdmEventItemGetter<RefType>)
*
* KeyRefType can be Ref<C>, RefToBase<T>, Ptr<T>
* AssociativeCollection can be ValueMap<V>, Association<C>
*
* Example usage is as follows:
* Handle<ValueMap<double> > hDiscriminators;
* iEvent.getByLabel(..., hDiscriminators);
* AssociativeIterator<RefToBase<Jet>, ValueMap<double> > itBTags(*hDiscriminators, EdmEventItemGetter(iEvent)), endBTags = itBTags.end();
* for ( ; itBTags != endBTags; ++itBTags ) {
* cout << " Jet PT = " << itBTags->first->pt() << ", disc = " << itBTags->second << endl;
* }
* or, for edm::Association
* Handle<Association<GenParticleCollection> > hMCMatch;
* iEvent.getByLabel(..., hMCMatch);
* AssociativeIterator<RefToBase<Candidate>, Association<GenParticleCollection> > itMC(*hMCMatch, EdmEventItemGetter(iEvent)), endMC = itMC.end();
* for ( ; itMC != endMC; ++itMC ) {
* cout << " Particle with PT = " << itMC->first->pt() ;
* if (itMC->second.isNull()) {
* cout << " UNMATCHED." << endl;
* } else {
* cout << " matched. MC PT = " << itMC->second->pt() << endl;
* }
* }
*
* NOTE: This class is not safe to use the same instance across threads, even if only call const methods.
*
*/
#include "DataFormats/Provenance/interface/ProductID.h"
#include "DataFormats/Common/interface/EDProductGetter.h"
#include "FWCore/Utilities/interface/thread_safety_macros.h"
namespace edm {
class Event;
template <class T>
class View;
template <class T>
class Handle;
template <class T>
class Association;
template <class T>
class RefToBase;
template <class T>
class Ptr;
template <class C, class T, class F>
class Ref;
} // namespace edm
namespace edm {
// Helper classes to convert one ref type to another.
// Now it's able to convert anything to itself, and RefToBase to anything else
// This won't be needed if we used Ptr
namespace helper {
template <typename RefFrom, typename RefTo>
struct RefConverter {
static RefTo convert(const RefFrom &ref) { return RefTo(ref); }
};
template <typename T>
struct RefConverter<RefToBase<T>, Ptr<T> > {
static Ptr<T> convert(const RefToBase<T> &ref) {
return Ptr<T>(ref.id(), ref.isAvailable() ? ref.get() : 0, ref.key());
}
};
template <typename T, typename C, typename V, typename F>
struct RefConverter<RefToBase<T>, Ref<C, V, F> > {
static Ref<C, V, F> convert(const RefToBase<T> &ref) { return ref.template castTo<Ref<C, V, F> >(); }
};
} // namespace helper
/// Helper class that fetches some type of Ref given ProductID and index, using the edm::Event
// the implementation uses View, and works for RefType = Ref, RefToBase and Ptr
template <typename RefType, typename EventType>
class EventItemGetter {
public:
typedef typename RefType::value_type element_type;
EventItemGetter(const EventType &iEvent) : iEvent_(iEvent) {}
~EventItemGetter() {}
RefType get(const ProductID &id, size_t idx) const {
typedef typename edm::RefToBase<element_type>
BaseRefType; // could also use Ptr, but then I can't do Ptr->RefToBase
if (id_ != id) {
id_ = id;
iEvent_.get(id_, view_);
}
BaseRefType ref = view_->refAt(idx);
typedef typename helper::RefConverter<BaseRefType, RefType> conv;
return conv::convert(ref);
}
private:
//This class is not intended to be used across threads
CMS_SA_ALLOW mutable Handle<View<element_type> > view_;
CMS_SA_ALLOW mutable ProductID id_;
const EventType &iEvent_;
};
// unfortunately it's not possible to define value_type of an Association<C> correctly
// so we need yet another template trick
namespace helper {
template <typename AC>
struct AssociativeCollectionValueType {
typedef typename AC::value_type type;
};
template <typename C>
struct AssociativeCollectionValueType<Association<C> > {
typedef typename Association<C>::reference_type type;
};
} // namespace helper
template <typename KeyRefType, typename AssociativeCollection, typename ItemGetter>
class AssociativeIterator {
public:
typedef KeyRefType key_type;
typedef typename KeyRefType::value_type key_val_type;
typedef typename helper::AssociativeCollectionValueType<AssociativeCollection>::type val_type;
typedef typename std::pair<key_type, val_type> value_type;
typedef AssociativeIterator<KeyRefType, AssociativeCollection, ItemGetter> self_type;
/// Create the associative iterator, pointing at the beginning of the collection
AssociativeIterator(const AssociativeCollection &map, const ItemGetter &getter);
self_type &operator++();
self_type &operator--();
self_type &nextProductID();
// self_type & skipTo(const ProductID &id, size_t offs = 0) ; // to be implemented one day
const value_type &operator*() const { return *(this->get()); }
const value_type *operator->() const { return (this->get()); }
const value_type *get() const {
chkPair();
return &pair_;
}
const key_type &key() const {
chkPair();
return pair_.first;
}
const val_type &val() const { return map_.get(idx_); }
const ProductID &id() const { return ioi_->first; }
operator bool() const { return idx_ < map_.size(); }
self_type end() const;
bool operator==(const self_type &other) const { return other.idx_ == idx_; }
bool operator!=(const self_type &other) const { return other.idx_ != idx_; }
bool operator<(const self_type &other) const { return other.idx_ < idx_; }
private:
typedef typename AssociativeCollection::id_offset_vector id_offset_vector;
typedef typename id_offset_vector::const_iterator id_offset_iterator;
const AssociativeCollection &map_;
id_offset_iterator ioi_, ioi2_;
size_t idx_;
ItemGetter getter_;
//This class is not intended to be used across threads
CMS_SA_ALLOW mutable bool pairOk_;
CMS_SA_ALLOW mutable value_type pair_;
void chkPair() const;
};
template <typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType, AC, IG>::AssociativeIterator(const AC &map, const IG &getter)
: map_(map), ioi_(map_.ids().begin()), ioi2_(ioi_ + 1), idx_(0), getter_(getter), pairOk_(false) {}
template <typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::operator++() {
pairOk_ = false;
idx_++;
if (ioi2_ < map_.ids().end()) {
if (ioi2_->second == idx_) {
++ioi_;
++ioi2_;
}
}
return *this;
}
template <typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::operator--() {
pairOk_ = false;
idx_--;
if (ioi_->second < idx_) {
--ioi_;
--ioi2_;
}
return *this;
}
template <typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType, AC, IG> &AssociativeIterator<KeyRefType, AC, IG>::nextProductID() {
pairOk_ = false;
ioi_++;
ioi2_++;
if (ioi_ == map_.ids().end()) {
idx_ = map_.size();
} else {
idx_ = ioi_->second;
}
}
/*
template<typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType,AC,IG> & AssociativeIterator<KeyRefType,AC,IG>::skipTo(const ProductID &id, size_t offs) {
pairOk_ = false;
throw Exception(errors::UnimplementedFeature);
}
*/
template <typename KeyRefType, typename AC, typename IG>
AssociativeIterator<KeyRefType, AC, IG> AssociativeIterator<KeyRefType, AC, IG>::end() const {
self_type ret(map_, getter_);
ret.ioi_ = map_.ids().end();
ret.ioi2_ = ret.ioi_ + 1;
ret.idx_ = map_.size();
return ret;
}
template <typename KeyRefType, typename AC, typename IG>
void AssociativeIterator<KeyRefType, AC, IG>::chkPair() const {
if (pairOk_)
return;
pair_.first = getter_.get(id(), idx_ - ioi_->second);
pair_.second = map_.get(idx_);
pairOk_ = true;
}
template <typename KeyRefType, typename AC, typename EventType>
AssociativeIterator<KeyRefType, AC, edm::EventItemGetter<KeyRefType, EventType> > makeAssociativeIterator(
const AC &map, const EventType &event) {
using Getter = edm::EventItemGetter<KeyRefType, EventType>;
return AssociativeIterator<KeyRefType, AC, Getter>(map, Getter{event});
}
} // namespace edm
#endif
|