CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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/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 
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 
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 
130  void swap(IndexRangeAssociation &other);
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 
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) {
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;
299  Indices 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
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
tuple ret
prodAgent to be discontinued
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!)
uint16_t *__restrict__ id
bool empty() const
True if it&#39;s empty (no keys)
FastFiller & operator=(const FastFiller &)=delete
LazyFiller(MultiAssociation &assoc, const HandleType &handle, bool fillOnExit=false)
unsigned int size() const
Returns the number of keys.
std::map< unsigned int, Collection > TempValues
LazyFiller lazyFiller(const HandleType &h, bool fillOnExit=false)
#define CMS_CLASS_VERSION(_version_)
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 key
prepare the HTCondor submission files and eventually submit them
tuple handle
Definition: patZpeak.py:25
bool contains(ProductID id) const
True if this IndexRangeAssociation has info for this product id.
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)
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 operator()(const id_off_pair &p, const edm::ProductID &id) const
range get(const edm::ProductID &id, unsigned int t) const
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.
bool empty() const
Returns true if there are no keys.
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
def template
Definition: svgfig.py:521
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.