CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
MultiAssociation.h
Go to the documentation of this file.
1 #ifndef DataFormats_Common_MultiAssociation_h
2 #define DataFormats_Common_MultiAssociation_h
3 /* \class MultiAssociation
4  *
5  * \author Giovanni Petrucciani, SNS Pisa and CERN PH-CMG
6  *
7  * One-to-Many variant of edm::Association<C> / edm::ValueMap<T>,
8  *
9  * Given a key, it will return a range of iterators within a collection (fast access), or collection by value (slow access mode)
10  *
11  * The range of iterators is handled through boost::sub_range, so it should feel like a collection:
12  * 1) it has a '::const_iterator', a 'begin()' and an 'end()'
13  * 2) it has a 'size()' and an 'empty()'
14  * 3) it has a 'front()', 'back()'
15  * 4) it works as an array (i.e. you can use range[index] to pick an element)
16  * 5) if your MultiAssociation is not const, you can modify the values associated to each key
17  * (but you can't push_back new values for a given key)
18  * ( details at http://www.boost.org/doc/libs/1_37_0/libs/range/doc/utility_class.html#sub_range )
19  *
20  * The collection can be a RefVector<C> (to work a la edm::Association<C>), a std::vector<T> (to work a la ValueMap<T>), a PtrVector<T>...
21  * The collection must be compatible with sub_range and support a few other features. Usually you need:
22  * - that it has a default constructor
23  * - that it has a const_iterator, and "begin() const" returns such const_iterator.
24  * - that it has an iterator, and "begin()" returns such iterator (note: it doesn't have to be writable, it can be const as well)
25  * - that it has a swap method
26  * - that 'begin() + offset' is legal (and fast, otherwise this thing is will be awfully slow)
27  * - that you can push_back on a C the * of a C::const_iterator. Namely this should be legal
28  * <code>
29  * C::const_iterator it = ..something..
30  * C someOtherC = ...
31  * someOtherC.push_back(*it);
32  * </code>
33  *
34  * It can be filled through a FastFiller or a LazyFiller.
35  * FastFiller is probably faster, but has many constraints:
36  * - you must fill only one product id at time
37  * - you must fill items in strict key order
38  * - there is no way to abort a filling operation
39  * Try LazyFiller first, unless you're doing some sort of batch task that satisfies the FastFiller requirements
40  *
41  * It stores:
42  * - for each collection of keys: a product id and an offset
43  * - for each key (even those not mapped to any value): one offset
44  * - for each value: one value
45  * With respect to ValueMap / Association, there is one extra int32 for each key (but we don't store null values)
46  *
47  * Its backbone is given by edm::helper::IndexRangeAssociation, that maps keys to ranges, and is not templated.
48  *
49  */
50 
51 #include <vector>
52 #include <map>
53 #include <memory>
54 #include <boost/utility.hpp>
55 #include <boost/range.hpp>
60 
61 namespace edm {
62  namespace helper {
67 
75  public:
76  typedef std::pair<unsigned int, unsigned int> range;
77 
79 
82  template<typename RefKey>
83  range operator[](const RefKey &r) const {
84  return get(r.id(), r.key());
85  }
86 
89  range get(const edm::ProductID & id, unsigned int t) const ;
90 
92  bool contains(ProductID id) const ;
93 
95  unsigned int size() const { return ref_offsets_.empty() ? 0 : ref_offsets_.size() - 1; }
96 
98  bool empty() const { return ref_offsets_.empty(); }
99 
104  class FastFiller : boost::noncopyable {
105  public:
107  FastFiller(IndexRangeAssociation &assoc, ProductID id, unsigned int size) ;
108 
110  ~FastFiller() ;
111 
113  template<typename RefKey>
114  void insert(const RefKey &r, unsigned int startingOffset, unsigned int size) {
115  insert(r.id(), r.key(), startingOffset, size);
116  }
117 
119  void insert(edm::ProductID id, unsigned int key, unsigned int startingOffset, unsigned int size) ;
120  private:
122  const ProductID id_;
123  unsigned int start_, end_; // indices into assoc_.ref_offsets_ (end_ points to the end marker, so it's valid)
125  int lastKey_;
126  }; // FastFiller
127  friend class FastFiller;
128 
129  void swap(IndexRangeAssociation &other) ;
130 
131  static void throwUnexpectedProductID(ProductID found, ProductID expected, const char *where) ;
132  private:
133  typedef std::pair<edm::ProductID,unsigned int> id_off_pair;
134  typedef std::vector<id_off_pair> id_offset_vector; // sorted by product id
135  typedef std::vector<int> offset_vector;
138 
139  bool isFilling_; // transient, to check no two fillers exist at the same time
140  struct IDComparator {
141  bool operator()(const id_off_pair &p, const edm::ProductID &id) const { return p.first < id; }
142  }; // IDComparator
143 
144 
145  };
146 
147  // Free swap function
148  inline void swap(IndexRangeAssociation& lhs, IndexRangeAssociation& rhs) { lhs.swap(rhs); }
149 
150  } // Helper Namespace
151 
152  template<typename C>
154  public:
155  typedef C Collection;
156  typedef boost::sub_range<const Collection> const_range;
157  typedef boost::sub_range<Collection> range;
158 
160 
162  template<typename RefKey>
163  const_range operator[](const RefKey &r) const {
164  return get(r.id(), r.key());
165  }
166  // ---- and the non-const sister
168  template<typename RefKey>
169  range operator[](const RefKey &r) {
170  return get(r.id(), r.key());
171  }
172 
174  template<typename RefKey>
175  Collection getValues(const RefKey &r) const {
176  return getValues(r.id(), r.key());
177  }
178 
180  bool contains(const edm::ProductID &id) const { return indices_.contains(id); }
181 
183  const_range get(const edm::ProductID &id, unsigned int t) const ;
184  // ---- and the non-const sister
186  range get(const edm::ProductID &id, unsigned int t) ;
187 
189  Collection getValues(const edm::ProductID &id, unsigned int t) const ;
190 
191  void swap(MultiAssociation &other) {
192  indices_.swap(other.indices_);
193  data_.swap(other.data_);
194  }
195 
197  unsigned int dataSize() const { return data_.size(); }
198 
200  unsigned int size() const { return indices_.size(); }
201 
203  bool empty() const { return indices_.empty(); }
204 
209  class FastFiller {
210  public:
211  template<typename HandleType>
212  FastFiller(MultiAssociation &assoc, const HandleType &handle) :
213  assoc_(assoc), indexFiller_(new IndexFiller(assoc_.indices_, handle.id(), handle->size())) {}
214 
215  FastFiller(MultiAssociation &assoc, edm::ProductID id, unsigned int size) :
216  assoc_(assoc), indexFiller_(new IndexFiller(assoc_.indices_, id, size)) {}
217 
219 
221  template<typename KeyRef>
222  void setValues(const KeyRef &k, const Collection &refs) { setValues(k.id(), k.key(), refs); }
223 
225  void setValues(const edm::ProductID &id, unsigned int key, const Collection &refs);
226  private:
229  std::shared_ptr<IndexFiller> indexFiller_;
230 
231  }; // FastFiller
232  friend class FastFiller;
233 
234  template<typename HandleType>
235  FastFiller fastFiller(const HandleType &handle) { return FastFiller(*this, handle); }
236 
242  class LazyFiller {
243  public:
244  template<typename HandleType>
245  LazyFiller(MultiAssociation &assoc, const HandleType &handle, bool fillOnExit=false) :
246  assoc_(assoc),
247  id_(handle.id()), size_(handle->size()),
248  tempValues_(new TempValues()), fillOnExit_(fillOnExit) {}
250 
255  void fill() noexcept(false);
256 
258  void setFillOnExit(bool fillOnExit) { fillOnExit_ = fillOnExit; }
259 
261  template<typename KeyRef>
262  void setValues(const KeyRef &k, const Collection &refs) ;
263 
266  template<typename KeyRef>
267  void swapValues(const KeyRef &k, Collection &refs) ;
268  private:
269  typedef std::map<unsigned int, Collection> TempValues;
272  unsigned int size_;
273  std::shared_ptr<TempValues> tempValues_;
275  }; // LazyFiller
276  friend class LazyFiller;
277 
278  template<typename HandleType>
279  LazyFiller lazyFiller(const HandleType &h, bool fillOnExit=false) { return LazyFiller(*this, h, fillOnExit); }
280 
281  //Used by ROOT storage
283 
284  private:
285  typedef helper::IndexRangeAssociation Indices;
286  Indices indices_;
288 
289 }; // class
290 
291  // Free swap function
292  template <typename C>
293  inline void swap(MultiAssociation<C>& lhs, MultiAssociation<C>& rhs) { lhs.swap(rhs); }
294 
295  //============= IMPLEMENTATION OF THE METHODS =============
296  template<typename C>
297  typename MultiAssociation<C>::const_range
298  MultiAssociation<C>::get(const edm::ProductID & id, unsigned int key) const {
299  Indices::range idxrange = indices_.get(id,key);
300  return const_range(data_.begin()+idxrange.first, data_.begin()+idxrange.second);
301  }
302 
303  template<typename C>
305  MultiAssociation<C>::get(const edm::ProductID & id, unsigned int key) {
306  Indices::range idxrange = indices_.get(id,key);
307  return range(data_.begin()+idxrange.first, data_.begin()+idxrange.second);
308  }
309 
310 
311  template<typename C>
313  MultiAssociation<C>::getValues(const edm::ProductID & id, unsigned int key) const {
314  Collection ret;
315  const_range values = get(id,key);
316  for (typename const_range::const_iterator it = values.begin(), ed = values.end(); it != ed; ++it) {
317  ret.push_back(*it);
318  }
319  return ret;
320  }
321 
322  template<typename C>
324  indexFiller_->insert(id, key, assoc_.data_.size(), vals.size());
325  for (typename Collection::const_iterator it = vals.begin(), ed = vals.end(); it != ed; ++it) {
326  assoc_.data_.push_back(*it);
327  }
328  }
329 
330  template<typename C>
331  template<typename KeyRef>
333  if (k.id() != id_) Indices::throwUnexpectedProductID(k.id(),id_,"LazyFiller::insert");
334  (*tempValues_)[k.key()] = vals;
335  }
336 
337  template<typename C>
338  template<typename KeyRef>
340  if (k.id() != id_) Indices::throwUnexpectedProductID(k.id(),id_,"LazyFiller::insert");
341  vals.swap((*tempValues_)[k.key()]);
342  }
343 
344 
345  template<typename C>
347  if (id_ != ProductID()) { // protection against double filling
348  typename MultiAssociation<C>::FastFiller filler(assoc_, id_, size_);
349  for (typename TempValues::const_iterator it = tempValues_->begin(), ed = tempValues_->end(); it != ed; ++it) {
350  filler.setValues(id_, it->first, it->second);
351  }
352  id_ = ProductID(); // protection against double filling
353  }
354  }
355 
356 
357 } // namespace
358 
359 #endif
unsigned int dataSize() const
Returns the number of values.
static void throwUnexpectedProductID(ProductID found, ProductID expected, const char *where)
boost::sub_range< const Collection > const_range
range operator[](const RefKey &r)
Get a range of values for this key (fast)
FastFiller(MultiAssociation &assoc, edm::ProductID id, unsigned int size)
void swapValues(const KeyRef &k, Collection &refs)
const_range get(const edm::ProductID &id, unsigned int t) const
Get a range of values for this product id and index (fast)
Collection getValues(const RefKey &r) const
Get a copy of the values for this key (slow!)
bool empty() const
True if it&#39;s empty (no keys)
LazyFiller(MultiAssociation &assoc, const HandleType &handle, bool fillOnExit=false)
unsigned int size() const
Returns the number of keys.
FastFiller(IndexRangeAssociation &assoc, ProductID id, unsigned int size)
Make a filler for a collection with a given product id and size.
std::map< unsigned int, Collection > TempValues
LazyFiller lazyFiller(const HandleType &h, bool fillOnExit=false)
#define noexcept
#define CMS_CLASS_VERSION(_version_)
Definition: classes.h:31
boost::sub_range< Collection > range
void swap(IndexRangeAssociation &other)
std::shared_ptr< TempValues > tempValues_
edm::helper::IndexRangeAssociation::FastFiller IndexFiller
unsigned int size() const
Size of this collection (number of keys)
void swap(IndexRangeAssociation &lhs, IndexRangeAssociation &rhs)
int lastKey_
last key used to fill (to check that the new key must be strictly greater than lastKey_) ...
~FastFiller()
When the FastFiller goes out of scope, it unlocks the map so you can make a new one.
range operator[](const RefKey &r) const
tuple handle
Definition: patZpeak.py:22
bool contains(ProductID id) const
True if this IndexRangeAssociation has info for this product id.
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
const_range operator[](const RefKey &r) const
Get a range of values for this key (fast)
std::pair< unsigned int, unsigned int > range
void insert(const RefKey &r, unsigned int startingOffset, unsigned int size)
Sets the starting offset for this key.
std::shared_ptr< IndexFiller > indexFiller_
FastFiller fastFiller(const HandleType &handle)
void setFillOnExit(bool fillOnExit)
If set to true, the LazyFiller wil call &#39;fill()&#39; when it goes out of scope.
bool operator()(const id_off_pair &p, const edm::ProductID &id) const
#define private
Definition: FWFileEntry.h:17
range get(const edm::ProductID &id, unsigned int t) const
list key
Definition: combine.py:13
FastFiller(MultiAssociation &assoc, const HandleType &handle)
void swap(MultiAssociation &other)
bool contains(const edm::ProductID &id) const
True if there are keys from this product id.
size_(0)
Definition: OwnArray.h:181
bool empty() const
Returns true if there are no keys.
volatile std::atomic< bool > shutdown_flag false
std::pair< edm::ProductID, unsigned int > id_off_pair
std::vector< id_off_pair > id_offset_vector
def template
Definition: svgfig.py:520
void setValues(const KeyRef &k, const Collection &refs)
Sets the Collection values associated to this key, making copies of those in refs.
void setValues(const KeyRef &k, const Collection &refs)
Sets the Collection values associated to this key, making copies of those in refs.