LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
CountersMap.h
Go to the documentation of this file.
1 
8 #ifndef COUNTERSMAP_H
9 #define COUNTERSMAP_H
10 
11 // interface include
12 #include <array>
13 #include <cstddef> // std::ptrdiff_t
14 #include <functional> // std::less<>
15 #include <iterator> // std::bidirectional_iterator_tag
16 #include <map>
17 #include <memory> // std::allocator<>
18 #include <type_traits> // std::make_unsigned
19 #include <utility> // std::pair<>
20 
21 namespace lar {
22 
24  constexpr bool IsPowerOf2(unsigned long long int v)
25  {
26  return v & 1 ? v == 1 : IsPowerOf2(v >> 1);
27  }
28 
30  constexpr int LowestSetBit(unsigned long long int v);
31 
32  namespace details {
33 
35  template <typename COUNTER, std::size_t NCounters>
36  class CounterBlock : public std::array<COUNTER, NCounters> {
37  public:
38  using Counter_t = COUNTER;
39 
40  using Array_t = std::array<Counter_t, NCounters>;
41  using value_type = typename Array_t::value_type;
42 
45 
48  {
49  Array_t::operator[](index) = value;
50  }
51 
52  void fill(const value_type& value) { Array_t::fill(value); }
53  void fill(size_t begin, size_t n, const value_type& value)
54  {
55  std::fill(Array_t::data() + begin, Array_t::data() + begin + n, value);
56  }
57 
58  }; // CounterBlock
59 
60  template <typename KEY, typename COUNTER, size_t SIZE>
62 
63  using Key_t = KEY;
64  using Counter_t = COUNTER;
65 
67  static constexpr size_t NCounters = SIZE;
68 
71 
73  using PlainBaseMap_t = std::map<Key_t, CounterBlock_t, std::less<Key_t>>;
74 
76  using DefaultAllocator_t = typename PlainBaseMap_t::allocator_type;
77 
79  template <typename Alloc>
80  using BaseMap_t = std::map<Key_t, CounterBlock_t, std::less<Key_t>, Alloc>;
81 
83  using MapValue_t = typename PlainBaseMap_t::value_type;
84 
85  }; // struct CountersMapTraits
86 
87  } // namespace details
88 
124  template <typename KEY,
125  typename COUNTER,
126  size_t SIZE,
127  typename ALLOC =
129  unsigned int SUBCOUNTERS = 1>
130  class CountersMap {
131  static_assert(SUBCOUNTERS == 1, "subcounters not implemented yet");
132  static_assert(IsPowerOf2(SIZE), "the size of the cluster of counters must be a power of 2");
133 
136 
137  public:
138  using Key_t = KEY;
139  using Counter_t = COUNTER;
140  using Allocator_t = ALLOC;
141 
144 
146  static constexpr size_t NCounters = Traits_t::NCounters;
147 
149  static constexpr size_t NSubcounters = NCounters * SUBCOUNTERS;
150 
153 
155 
157  using BaseMap_t = typename Traits_t::template BaseMap_t<typename std::allocator_traits<
158  Allocator_t>::template rebind_alloc<typename Traits_t::MapValue_t>>;
159 
160  /*
162  using const_iterator = double_fwd_const_iterator<
163  typename BaseMap_t::const_iterator,
164  PairSecond<typename BaseMap_t::value_type>
165  >;
166  */
167 
172  // TODO others are missing
174 
175  using value_type = std::pair<const Key_t, SubCounter_t>;
176 
178  class const_iterator;
179 
182 
184  CountersMap(Allocator_t alloc) : BaseMap_t(alloc) {}
185 
187  SubCounter_t operator[](Key_t key) const { return GetSubCounter(key); }
188 
201 
207  SubCounter_t increment(Key_t key);
208 
214  SubCounter_t decrement(Key_t key);
215 
218  // this stuff needs serious work to be completed
219 
221  const_iterator begin() const;
222 
224  const_iterator end() const;
226 
228  bool empty() const { return counter_map.empty(); }
229 
231  typename std::make_unsigned<Key_t>::type n_counters() const
232  {
233  return counter_map.size() * NSubcounters;
234  }
235 
253  template <typename OALLOC>
254  bool is_equal(const std::map<Key_t, SubCounter_t, std::less<Key_t>, OALLOC>& to,
255  Key_t& first_difference) const;
256 
262  template <typename OALLOC>
263  bool is_equal(const std::map<Key_t, SubCounter_t, std::less<Key_t>, OALLOC>& to) const
264  {
265  Key_t dummy;
266  return is_equal(to, dummy);
267  }
268 
269  protected:
270  using BlockKey_t = Key_t;
271  using CounterIndex_t = typename std::make_unsigned<Key_t>::type;
273 
275  struct CounterKey_t {
278  // there should be a subcluster index here too
279 
280  CounterKey_t() : block(0), counter(0) {}
281 
283  CounterKey_t(BlockKey_t major, CounterIndex_t minor) : block(major), counter(minor) {}
284 
287  : // CounterKey_t(key >> MinorKeyBits, key & MinorKeyMask) {}
288  CounterKey_t(key & ~MinorKeyMask, key & MinorKeyMask)
289  {}
290 
292  // Key_t Key() const { return (block << MinorKeyBits) + counter; }
293  Key_t Key() const { return block + counter; }
294 
296  operator Key_t() const { return Key(); }
297 
299  {
300  if (++counter == MinorKeyRange) next_block();
301  return *this;
302  }
304  {
305  if (counter-- == 0) {
306  prev_block();
307  counter = MinorKeyRange - 1;
308  }
309  return *this;
310  } // operator--()
312  {
313  CounterKey_t old(*this);
314  this->operator++();
315  return old;
316  }
318  {
319  CounterKey_t old(*this);
320  this->operator--();
321  return old;
322  }
323 
326  {
327  counter = 0;
328  return *this;
329  }
330 
333  {
334  block -= MinorKeyRange;
335  return start_block();
336  }
337 
340  {
341  block += MinorKeyRange;
342  return start_block();
343  }
344 
346  static constexpr Key_t MinorKeyRange = NSubcounters;
347 
349  static constexpr Key_t MinorKeyBits = LowestSetBit(MinorKeyRange);
350 
352  static constexpr Key_t MinorKeyMask = MinorKeyRange - 1;
353 
354  static_assert(MinorKeyBits > 0, "Wrong COUNTER value for lar::CountersMap");
355 
356  }; // struct CounterKey_t
357 
359 
361  Counter_t GetCounter(CounterKey_t key) const;
362 
364  // Since subcounters are not implemented yet, this is a no-op
365  SubCounter_t GetSubCounter(CounterKey_t key) const { return GetCounter(key); }
366 
368  Counter_t& GetOrCreateCounter(CounterKey_t key);
369 
371  static CounterKey_t SplitKey(Key_t key) { return key; }
372 
375  {
376  return {it, ix};
377  }
378 
379  private:
381  SubCounter_t unchecked_set(CounterKey_t key, SubCounter_t delta);
382 
384  SubCounter_t unchecked_add(CounterKey_t key, SubCounter_t delta);
385 
386  }; // class CountersMap
387 
388 } // namespace lar
389 
390 //------------------------------------------------------------------------------
391 
392 namespace lar {
393 
394  namespace details {
396  inline constexpr int LowestSetBitScaler(unsigned long long int v, int b)
397  {
398  return (v & 1) ? b : LowestSetBitScaler(v >> 1, b + 1);
399  }
400 
401  namespace counters_map {
402  static constexpr bool bDebug = true;
403 
404  } // namespace counters_map
405  } // namespace details
406 
407  inline constexpr int LowestSetBit(unsigned long long int v)
408  {
409  return (v == 0) ? -1 : details::LowestSetBitScaler(v, 0);
410  }
411 
412  // providing "definitions" of the static constants;
413  // these are required if the code is going to take the address of these
414  // constants, which is most often due to the use of "const size_t&" in some
415  // function, where "size_t" is a template argument type
416  // (or else the reference would not be needed).
417  // I am not providing the same for the protected and private members
418  // (just because of laziness).
419  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
421 
422  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
424 
425  // CountersMap<>::const_iterator does not fully implement the STL iterator
426  // interface, since it does not implement operator-> () (for technical reason:
427  // the value does not actually exist and it does not have an address),
428  // in addition to std::swap().
429  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
430  class CountersMap<K, C, S, A, SUB>::const_iterator : public std::bidirectional_iterator_tag {
432 
433  public:
435  using difference_type = std::ptrdiff_t;
436  using pointer = const value_type*;
437  using reference = const value_type&;
438  using iterator_category = std::bidirectional_iterator_tag;
439 
441 
443  const_iterator() = default;
444 
446  value_type operator*() const { return {key(), iter->second[index]}; }
447 
449  {
450  if (++index >= NSubcounters) {
451  ++iter;
452  index = 0;
453  }
454  return *this;
455  } // operator++
457  {
458  iterator_type old(*this);
459  this->operator++();
460  return old;
461  }
462 
464  {
465  if (index == 0) {
466  --iter;
467  index = NSubcounters - 1;
468  }
469  else
470  --index;
471  return *this;
472  } // operator--()
474  {
475  iterator_type old(*this);
476  this->operator--();
477  return old;
478  }
479 
480  bool operator==(const iterator_type& as) const
481  {
482  return (iter == as.iter) && (index == as.index);
483  }
484  bool operator!=(const iterator_type& as) const
485  {
486  return (iter != as.iter) || (index != as.index);
487  }
488 
490  CounterKey_t key() const { return {iter->first, index}; }
491 
492  protected:
496 
498  const_iterator(typename BaseMap_t::const_iterator it, size_t ix) : iter(it), index(ix) {}
499 
500  }; // CountersMap<>::const_iterator
501 
502  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
504  Key_t key,
506  {
507  return unchecked_set(CounterKey_t(key), value);
508  }
509 
510  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
513  {
514  return unchecked_add(CounterKey_t(key), +1);
515  }
516 
517  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
520  {
521  return unchecked_add(CounterKey_t(key), -1);
522  }
523 
524  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
526  const
527  {
528  return const_iterator{counter_map.begin(), 0};
529  }
530 
531  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
533  const
534  {
535  return const_iterator{counter_map.end(), 0};
536  }
537 
538  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
539  template <typename OALLOC>
541  const std::map<Key_t, SubCounter_t, std::less<Key_t>, OALLOC>& to,
542  Key_t& first_difference) const
543  {
544  // this function is not optimised
545  using CompMap_t = const std::map<Key_t, SubCounter_t, std::less<Key_t>, OALLOC>;
546  typename CompMap_t::const_iterator to_iter = to.begin(), to_end = to.end();
547  for (const typename const_iterator::value_type& p : *this) {
548 
549  if (to_iter != to_end) { // we have still counters to find
550  // if counter is already beyond the next non-empty one froml STL map,
551  // then we are missing some
552  if (p.first > to_iter->first) {
553  first_difference = to_iter->first;
554  return false;
555  }
556  // while (p.first > to_iter->first) {
557  // ++nMissingKeys;
558  // std::cout << "ERROR missing key " << to_iter->first << std::endl;
559  // if (++to_iter == to_end) break;
560  // } // while
561  // } // if
562  //
563  // if (to_iter != to_end) { // we have still counters to find
564  if (p.first == to_iter->first) {
565  // if the counter is in SLT map, the two counts must match
566  // std::cout << " " << p.first << " " << p.second << std::endl;
567  if (to_iter->second != p.second) {
568  // std::cout << "ERROR wrong counter value " << p.second
569  // << ", expected " << to_iter->second << std::endl;
570  // ++nMismatchValue;
571  first_difference = to_iter->first;
572  return false;
573  }
574  ++to_iter; // done with it
575  }
576  else if (p.first < to_iter->first) {
577  // if the counter is not in STL map, then it must be 0
578  if (p.second != 0) {
579  // ++nExtraKeys;
580  // std::cout << "ERROR extra key " << p.first << " (" << p.second << ")"
581  // << std::endl;
582  first_difference = p.first;
583  return false;
584  }
585  // else {
586  // std::cout << " " << p.first << " " << p.second << " (not in STL)"
587  // << std::endl;
588  // }
589  }
590  }
591  else { // if we are at the end of compared map
592  // no more keys in STL map
593  if (p.second != 0) {
594  // ++nExtraKeys;
595  // std::cout << "ERROR extra key " << p.first << " (" << p.second << ")"
596  // << std::endl;
597  first_difference = p.first;
598  return false;
599  }
600  }
601  } // for element in map
602 
603  return true;
604  } // CountersMap<>::is_equal()
605 
606  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
608  CounterKey_t key) const
609  {
610  typename BaseMap_t::const_iterator iBlock = counter_map.find(key.block);
611  return (iBlock == counter_map.end()) ? 0 : iBlock->second[key.counter];
612  } // CountersMap<>::GetCounter() const
613 
614  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
617  {
618  return counter_map[key.block][key.counter];
619  }
620 
621  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
623  CounterKey_t key,
625  {
626  // take it low level here
627  // first get the iterator to the block
628  typename BaseMap_t::iterator iBlock = counter_map.lower_bound(key.block);
629  if (iBlock != counter_map.end()) {
630  if (iBlock->first == key.block) { // sweet, we have that counter already
631  return iBlock->second[key.counter] = value;
632  }
633  }
634  // no counter there yet: create one;
635  // hint to insert before the block in the position we jave already found
636  // (this is optimal in STL map for C++11);
637  // create a block using the special constructor;
638  // the temporary value created here is moved to the map
639  counter_map.insert(iBlock, {key.block, {key.counter, value}});
640  return value;
641  } // CountersMap<>::unchecked_add() const
642 
643  template <typename K, typename C, size_t S, typename A, unsigned int SUB>
645  CounterKey_t key,
646  SubCounter_t delta)
647  {
648  // take it low level here
649  // first get the iterator to the block
650  typename BaseMap_t::iterator iBlock = counter_map.lower_bound(key.block);
651  if (iBlock != counter_map.end()) {
652  if (iBlock->first == key.block) { // sweet, we have that counter already
653  return iBlock->second[key.counter] += delta;
654  }
655  }
656  // no counter there yet: create one;
657  // hint to insert before the block in the position we jave already found
658  // (this is optimal in STL map for C++11);
659  // create a block using the special constructor;
660  // the temporary value created here is moved to the map
661  counter_map.insert(iBlock, {key.block, {key.counter, delta}});
662  return delta;
663  } // CountersMap<>::unchecked_add() const
664 
665 } // namespace lar
666 
667 #endif // BULKALLOCATOR_H
intermediate_table::iterator iterator
SubCounter_t operator[](Key_t key) const
Read-only access to an element; returns 0 if no counter is present.
Definition: CountersMap.h:187
CounterKey_t & operator--(int)
Definition: CountersMap.h:317
Key_t Key() const
Returns the full key.
Definition: CountersMap.h:293
Type of block of counters (just a STL array until SUBCOUNTERS are in)
Definition: CountersMap.h:36
const_iterator end() const
Returns an iterator past-the-end of the counters.
Definition: CountersMap.h:532
CounterKey_t & operator++(int)
Definition: CountersMap.h:311
typename Traits_t::CounterBlock_t CounterBlock_t
Definition: CountersMap.h:154
std::make_unsigned< Key_t >::type n_counters() const
Returns the number of allocated counters.
Definition: CountersMap.h:231
void fill(const value_type &value)
Definition: CountersMap.h:52
CountersMap(Allocator_t alloc)
Constructor, specifies an allocator.
Definition: CountersMap.h:184
static constexpr bool bDebug
Definition: CountersMap.h:402
CounterIndex_t counter
index of the counter in the block
Definition: CountersMap.h:277
KEY Key_t
type of counter key in the map
Definition: CountersMap.h:138
typename std::make_unsigned< Key_t >::type CounterIndex_t
type of index in the block
Definition: CountersMap.h:272
value_type operator*() const
Access to the pointed pair.
Definition: CountersMap.h:446
SubCounter_t increment(Key_t key)
Increments by 1 the specified counter.
Definition: CountersMap.h:512
Allocator_t allocator_type
type of the single counter
Definition: CountersMap.h:171
bool is_equal(const std::map< Key_t, SubCounter_t, std::less< Key_t >, OALLOC > &to, Key_t &first_difference) const
Returns whether the counters in this map are equivalent to another.
Definition: CountersMap.h:540
CounterIndex_t index
index of the counted in the subblock
Definition: CountersMap.h:495
typename CounterMap_t::value_type value_type
value type: pair
Definition: CountersMap.h:434
typename Array_t::value_type value_type
Definition: CountersMap.h:41
typename PlainBaseMap_t::value_type MapValue_t
Type of value in the map.
Definition: CountersMap.h:83
typename Traits_t::template BaseMap_t< typename std::allocator_traits< Allocator_t >::template rebind_alloc< typename Traits_t::MapValue_t >> BaseMap_t
Type of the map used in the implementation.
Definition: CountersMap.h:158
static CounterKey_t SplitKey(Key_t key)
Returns a split key corresponding to the specified key.
Definition: CountersMap.h:371
std::bidirectional_iterator_tag iterator_category
Definition: CountersMap.h:438
intermediate_table::const_iterator const_iterator
BaseMap_t::const_iterator iter
iterator to the block of counters
Definition: CountersMap.h:493
static const_iterator make_const_iterator(typename BaseMap_t::const_iterator it, size_t ix)
Creates a const_iterator (useful in derived classes)
Definition: CountersMap.h:374
void fill(size_t begin, size_t n, const value_type &value)
Definition: CountersMap.h:53
CounterKey_t & next_block()
Skips to the beginning of the next block.
Definition: CountersMap.h:339
COUNTER Counter_t
Type of the single counter.
Definition: CountersMap.h:64
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
BlockKey_t block
key of the counter block
Definition: CountersMap.h:276
bool operator==(const iterator_type &as) const
Definition: CountersMap.h:480
typename PlainBaseMap_t::allocator_type DefaultAllocator_t
Type of allocator for the plain map.
Definition: CountersMap.h:76
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:295
auto array(Array const &a)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:250
Key_t BlockKey_t
type of block key
Definition: CountersMap.h:270
CountersMap()
Default constructor (empty map)
Definition: CountersMap.h:181
iterator_type operator--(int)
Definition: CountersMap.h:473
Counter_t & GetOrCreateCounter(CounterKey_t key)
Returns the counter at the specified split key.
Definition: CountersMap.h:616
constexpr int LowestSetBitScaler(unsigned long long int v, int b)
Internally used by LowestSetBit.
Definition: CountersMap.h:396
SubCounter_t GetSubCounter(CounterKey_t key) const
Returns the value of the subcounter at the specified split key.
Definition: CountersMap.h:365
CounterKey_t(BlockKey_t major, CounterIndex_t minor)
Constructor from a pair.
Definition: CountersMap.h:283
CounterBlock()
Default constructor: initializes the array to 0.
Definition: CountersMap.h:44
CounterKey_t & start_block()
Skips to the beginning of this block.
Definition: CountersMap.h:325
COUNTER Counter_t
type of the single counter
Definition: CountersMap.h:139
CounterKey_t(Key_t key)
Initialize from a mangled key.
Definition: CountersMap.h:286
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
Counter_t GetCounter(CounterKey_t key) const
Returns the value of the counter at the specified split key.
Definition: CountersMap.h:607
const_iterator begin() const
Returns an iterator to the begin of the counters.
Definition: CountersMap.h:525
bool is_equal(const std::map< Key_t, SubCounter_t, std::less< Key_t >, OALLOC > &to) const
Returns whether the counters in this map are equivalent to another.
Definition: CountersMap.h:263
std::map< Key_t, CounterBlock_t, std::less< Key_t >, Alloc > BaseMap_t
Base type of map, allowing a custom allocator.
Definition: CountersMap.h:80
SubCounter_t decrement(Key_t key)
Decrements by 1 the specified counter.
Definition: CountersMap.h:519
const value_type & reference
Definition: CountersMap.h:437
std::array< Counter_t, NCounters > Array_t
type of base class
Definition: CountersMap.h:40
double value
Definition: spectrum.C:18
BaseMap_t counter_map
the actual data structure for counters
Definition: CountersMap.h:358
const_iterator(typename BaseMap_t::const_iterator it, size_t ix)
Private constructor (from a map iterator and a block index)
Definition: CountersMap.h:498
ALLOC Allocator_t
type of the single counter
Definition: CountersMap.h:140
Structure with the index of the counter, split as needed.
Definition: CountersMap.h:275
SubCounter_t unchecked_set(CounterKey_t key, SubCounter_t delta)
Sets the specified counter to a value (no check on value range)
Definition: CountersMap.h:622
SubCounter_t mapped_type
type of the single counter
Definition: CountersMap.h:170
LArSoft-specific namespace.
iterator_type operator++(int)
Definition: CountersMap.h:456
CounterKey_t key() const
Returns the key of the pointed item as a CounterKey_t.
Definition: CountersMap.h:490
std::map< Key_t, CounterBlock_t, std::less< Key_t >> PlainBaseMap_t
General type of map (no special allocator specified).
Definition: CountersMap.h:73
CounterBlock(size_t index, Counter_t value)
Convenience constructor: initializes all counters to 0, except one.
Definition: CountersMap.h:47
KEY Key_t
Type of counter key in the map.
Definition: CountersMap.h:63
Char_t n[5]
Map storing counters in a compact way.
Definition: CountersMap.h:130
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
bool empty() const
Returns whether the map has no counters.
Definition: CountersMap.h:228
SubCounter_t unchecked_add(CounterKey_t key, SubCounter_t delta)
Adds a delta to the specified counter (no check on underflow/overflow)
Definition: CountersMap.h:644
Counter_t SubCounter_t
Type of the subcounter (that is, the actual counter)
Definition: CountersMap.h:152
constexpr int LowestSetBit(unsigned long long int v)
Returns the position of the first set bit (0 for LSB)
Definition: CountersMap.h:407
SubCounter_t set(Key_t key, SubCounter_t value)
Sets the specified counter to a count.
Definition: CountersMap.h:503
CounterKey_t & prev_block()
Skips to the beginning of the previous block.
Definition: CountersMap.h:332
std::pair< const Key_t, SubCounter_t > value_type
Definition: CountersMap.h:175
constexpr bool IsPowerOf2(unsigned long long int v)
Returns true if the argument is a power of 2.
Definition: CountersMap.h:24
bool operator!=(const iterator_type &as) const
Definition: CountersMap.h:484