CMS 3D CMS Logo

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/range.hpp>
57 
58 namespace edm {
59  namespace helper {
64 
72  public:
73  typedef std::pair<unsigned int, unsigned int> range;
74 
76 
79  template <typename RefKey>
80  range operator[](const RefKey &r) const {
81  return get(r.id(), r.key());
82  }
83 
86  range get(const edm::ProductID &id, unsigned int t) const;
87 
89  bool contains(ProductID id) const;
90 
92  unsigned int size() const { return ref_offsets_.empty() ? 0 : ref_offsets_.size() - 1; }
93 
95  bool empty() const { return ref_offsets_.empty(); }
96 
101  class FastFiller {
102  public:
103  FastFiller(const FastFiller &) = delete;
104  FastFiller &operator=(const FastFiller &) = delete;
105 
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 
121  private:
123  const ProductID id_;
124  unsigned int start_, end_; // indices into assoc_.ref_offsets_ (end_ points to the end marker, so it's valid)
126  int lastKey_;
127  }; // FastFiller
128  friend class FastFiller;
129 
131 
132  static void throwUnexpectedProductID(ProductID found, ProductID expected, const char *where);
133 
134  private:
135  typedef std::pair<edm::ProductID, unsigned int> id_off_pair;
136  typedef std::vector<id_off_pair> id_offset_vector; // sorted by product id
137  typedef std::vector<int> offset_vector;
140 
141  bool isFilling_; // transient, to check no two fillers exist at the same time
142  struct IDComparator {
143  bool operator()(const id_off_pair &p, const edm::ProductID &id) const { return p.first < id; }
144  }; // IDComparator
145  };
146 
147  // Free swap function
148  inline void swap(IndexRangeAssociation &lhs, IndexRangeAssociation &rhs) { lhs.swap(rhs); }
149 
150  } // namespace helper
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 
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>
214 
217 
219 
221  template <typename KeyRef>
222  void setValues(const KeyRef &k, const Collection &refs) {
223  setValues(k.id(), k.key(), refs);
224  }
225 
227  void setValues(const edm::ProductID &id, unsigned int key, const Collection &refs);
228 
229  private:
232  std::shared_ptr<IndexFiller> indexFiller_;
233 
234  }; // FastFiller
235  friend class FastFiller;
236 
237  template <typename HandleType>
238  FastFiller fastFiller(const HandleType &handle) {
239  return FastFiller(*this, handle);
240  }
241 
247  class LazyFiller {
248  public:
249  template <typename HandleType>
250  LazyFiller(MultiAssociation &assoc, const HandleType &handle, bool fillOnExit = false)
251  : assoc_(assoc),
252  id_(handle.id()),
253  size_(handle->size()),
254  tempValues_(new TempValues()),
255  fillOnExit_(fillOnExit) {}
256  ~LazyFiller() noexcept(false) {
257  if (fillOnExit_)
258  fill();
259  }
260 
265  void fill() noexcept(false);
266 
268  void setFillOnExit(bool fillOnExit) { fillOnExit_ = fillOnExit; }
269 
271  template <typename KeyRef>
272  void setValues(const KeyRef &k, const Collection &refs);
273 
276  template <typename KeyRef>
277  void swapValues(const KeyRef &k, Collection &refs);
278 
279  private:
280  typedef std::map<unsigned int, Collection> TempValues;
283  unsigned int size_;
284  std::shared_ptr<TempValues> tempValues_;
286  }; // LazyFiller
287  friend class LazyFiller;
288 
289  template <typename HandleType>
290  LazyFiller lazyFiller(const HandleType &h, bool fillOnExit = false) {
291  return LazyFiller(*this, h, fillOnExit);
292  }
293 
294  //Used by ROOT storage
296 
297  private:
298  typedef helper::IndexRangeAssociation Indices;
301 
302  }; // class
303 
304  // Free swap function
305  template <typename C>
306  inline void swap(MultiAssociation<C> &lhs, MultiAssociation<C> &rhs) {
307  lhs.swap(rhs);
308  }
309 
310  //============= IMPLEMENTATION OF THE METHODS =============
311  template <typename C>
313  Indices::range idxrange = indices_.get(id, key);
314  return const_range(data_.begin() + idxrange.first, data_.begin() + idxrange.second);
315  }
316 
317  template <typename C>
319  Indices::range idxrange = indices_.get(id, key);
320  return range(data_.begin() + idxrange.first, data_.begin() + idxrange.second);
321  }
322 
323  template <typename C>
325  unsigned int key) const {
326  Collection ret;
327  const_range values = get(id, key);
328  for (typename const_range::const_iterator it = values.begin(), ed = values.end(); it != ed; ++it) {
329  ret.push_back(*it);
330  }
331  return ret;
332  }
333 
334  template <typename C>
335  void MultiAssociation<C>::FastFiller::setValues(const edm::ProductID &id, unsigned int key, const Collection &vals) {
336  indexFiller_->insert(id, key, assoc_.data_.size(), vals.size());
337  for (typename Collection::const_iterator it = vals.begin(), ed = vals.end(); it != ed; ++it) {
338  assoc_.data_.push_back(*it);
339  }
340  }
341 
342  template <typename C>
343  template <typename KeyRef>
344  void MultiAssociation<C>::LazyFiller::setValues(const KeyRef &k, const Collection &vals) {
345  if (k.id() != id_)
346  Indices::throwUnexpectedProductID(k.id(), id_, "LazyFiller::insert");
347  (*tempValues_)[k.key()] = vals;
348  }
349 
350  template <typename C>
351  template <typename KeyRef>
353  if (k.id() != id_)
354  Indices::throwUnexpectedProductID(k.id(), id_, "LazyFiller::insert");
355  vals.swap((*tempValues_)[k.key()]);
356  }
357 
358  template <typename C>
360  if (id_ != ProductID()) { // protection against double filling
361  typename MultiAssociation<C>::FastFiller filler(assoc_, id_, size_);
362  for (typename TempValues::const_iterator it = tempValues_->begin(), ed = tempValues_->end(); it != ed; ++it) {
363  filler.setValues(id_, it->first, it->second);
364  }
365  id_ = ProductID(); // protection against double filling
366  }
367  }
368 
369 } // namespace edm
370 
371 #endif
static void throwUnexpectedProductID(ProductID found, ProductID expected, const char *where)
boost::sub_range< const Collection > const_range
const_range get(const edm::ProductID &id, unsigned int t) const
Get a range of values for this product id and index (fast)
bool empty() const
Returns true if there are no keys.
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)
Definition: helper.py:1
unsigned int size() const
Size of this collection (number of keys)
FastFiller & operator=(const FastFiller &)=delete
ret
prodAgent to be discontinued
LazyFiller(MultiAssociation &assoc, const HandleType &handle, bool fillOnExit=false)
std::map< unsigned int, Collection > TempValues
LazyFiller lazyFiller(const HandleType &h, bool fillOnExit=false)
#define CMS_CLASS_VERSION(_version_)
bool contains(ProductID id) const
True if this IndexRangeAssociation has info for this product id.
boost::sub_range< Collection > range
bool operator()(const id_off_pair &p, const edm::ProductID &id) const
void swap(IndexRangeAssociation &other)
unsigned int dataSize() const
Returns the number of values.
std::shared_ptr< TempValues > tempValues_
edm::helper::IndexRangeAssociation::FastFiller IndexFiller
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 get(const edm::ProductID &id, unsigned int t) const
def template(fileName, svg, replaceme="REPLACEME")
Definition: svgfig.py:521
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)
std::pair< edm::ProductID, unsigned int > id_off_pair
void setFillOnExit(bool fillOnExit)
If set to true, the LazyFiller wil call &#39;fill()&#39; when it goes out of scope.
bool empty() const
True if it&#39;s empty (no keys)
unsigned int size() const
Returns the number of keys.
const_range operator[](const RefKey &r) const
Get a range of values for this key (fast)
HLT enums.
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.
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
std::vector< id_off_pair > id_offset_vector
range operator[](const RefKey &r) const
Collection getValues(const RefKey &r) const
Get a copy of the values for this key (slow!)
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.