LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LazyVector.h
Go to the documentation of this file.
1 
11 #ifndef LARDATAOBJ_UTILITIES_LAZYVECTOR_H
12 #define LARDATAOBJ_UTILITIES_LAZYVECTOR_H
13 
14 // C/C++ standard libraries
15 #include <vector>
16 #include <string> // std::to_string()
17 #include <stdexcept> // std::out_of_range
18 #include <type_traits> // std::enable_if_t, std::is_arithmetic_v
19 #include <cassert>
20 
21 
22 namespace util {
23 
77  template <typename T, typename A = typename std::vector<T>::allocator_type>
78  class LazyVector {
79 
80  using Data_t = std::vector<T, A>;
81 
82  public:
83 
84  // --- BEGIN STL vector types ----------------------------------------------
87 
88  using allocator_type = typename Data_t::allocator_type;
89  using value_type = typename Data_t::value_type;
90  using size_type = typename Data_t::size_type;
91  using difference_type = typename Data_t::difference_type;
92  using reference = typename Data_t::reference;
93  using const_reference = typename Data_t::const_reference;
94  using pointer = typename Data_t::pointer;
95  using const_pointer = typename Data_t::const_pointer;
96 
98  // --- END STL vector types ------------------------------------------------
99 
100 
103  LazyVector() = default;
104 
106  LazyVector(allocator_type const& a);
107 
108 
122 
144  LazyVector(size_type n, value_type const& defValue);
145 
146 
148 
149 
150 
151  // --- BEGIN Container information -----------------------------------------
154 
156  size_type size() const noexcept { return fNominalSize; }
157 
159  bool empty() const noexcept { return fNominalSize == 0U; }
160 
162  size_type data_size() const noexcept { return fData.size(); }
163 
165  bool has_index(size_type pos) const noexcept { return pos < size(); }
166 
168  bool data_empty() const noexcept { return fData.empty(); }
169 
172  value_type const& data_defvalue() const { return fDefValue; }
173 
177 
181  { return data_begin_index() + data_size(); }
182 
184  bool data_has_index(size_type pos) const
185  { return (pos >= data_begin_index()) && (pos < data_end_index()); }
186 
198 
200  // --- END Container information -------------------------------------------
201 
202 
203 
204  // --- BEGIN Access to data elements ---------------------------------------
225 
228 
244  value_type at(size_type pos) const;
245  value_type const_at(size_type pos) const { return at(pos); }
247 
261  reference at(size_type pos);
262 
264 
277  value_type operator[](size_type pos) const;
278  value_type const_get(size_type pos) const { return this->operator[](pos); }
280 
282 
296  reference get(size_type pos) { return this->operator[](pos); }
298 
300  // --- END Access to data elements -----------------------------------------
301 
302 
303 
304  // --- BEGIN Setting data elements -----------------------------------------
307 
308 
310  // --- END Setting data elements -------------------------------------------
311 
312 
313 
314  // --- BEGIN Container operations -----------------------------------------
317 
330  void resize(size_type newSize);
331 
348  void reserve(size_type n) { storage().reserve(n); }
349 
351  void clear();
352 
354  void shrink_to_fit() { storage().shrink_to_fit(); }
355 
375  void data_prepare(size_type startIndex, size_type endIndex);
376 
390 
405  void data_init(size_type startIndex, size_type endIndex);
406 
422  void data_init(size_type n) { data_init(0U, n); }
423 
424 
425 
427  // --- END Container operations --------------------------------------------
428 
429  private:
431 
433  size_type fFirstIndex = fData.max_size();
435 
438 
440  Data_t& storage() { return fData; }
442  Data_t const& storage() const { return fData; }
444 
446  size_type index_of(size_type pos) const { return pos - fFirstIndex; }
447 
449  void expand(size_type pos);
450 
452  void init(size_type pos, size_type n = 1U);
453 
455  void expand_front(size_type pos);
456 
458  void expand_back(size_type pos);
459 
461  void fix_size();
462 
464  void data_clear();
465 
467  void check_range(size_type pos) const;
468 
469 
471  static value_type const& defaultValueType() { return fDefaultDefaultValue; }
472 
473 
474  }; // LazyVector<>
475 
476 } // namespace util
477 
478 
479 //------------------------------------------------------------------------------
480 //--- template implementation
481 //------------------------------------------------------------------------------
482 template <typename T, typename A /* = std::vector<T>::allocator_type */>
485 
486 
487 //------------------------------------------------------------------------------
488 template <typename T, typename A /* = std::vector<T>::allocator_type */>
490  : fData(a)
491  {}
492 
493 
494 //------------------------------------------------------------------------------
495 template <typename T, typename A /* = std::vector<T>::allocator_type */>
498  {}
499 
500 
501 //------------------------------------------------------------------------------
502 template <typename T, typename A /* = std::vector<T>::allocator_type */>
504  : fNominalSize(n)
505  , fDefValue(defValue)
506  {}
507 
508 
509 //------------------------------------------------------------------------------
510 template <typename T, typename A /* = std::vector<T>::allocator_type */>
512  (size_type pos)
513 {
514  /*
515  * Behaviour summary:
516  * * if `pos` is out of vector range, throw an exception
517  * * if element at `pos` has no storage, create storage for it
518  * * return a reference to the element at `pos`
519  */
520  check_range(pos); // verify that `pos` is valid, throw otherwise
521  expand(pos);
522  return storage()[index_of(pos)]; // we already know it's valid
523 }
524 
525 
526 //------------------------------------------------------------------------------
527 template <typename T, typename A /* = std::vector<T>::allocator_type */>
529  (size_type pos) const
530 {
531  /*
532  * Behaviour summary:
533  * * if `pos` is out of vector range, throw an exception
534  * * if element at `pos` has no storage, return a copy of the default value
535  * * otherwise, return a copy of the element at `pos`
536  */
537  check_range(pos); // verify that `pos` is valid, throw otherwise
538  return data_has_index(pos)? storage()[index_of(pos)]: data_defvalue();
539 } // util::LazyVector<T,A>::at() const
540 
541 
542 //------------------------------------------------------------------------------
543 template <typename T, typename A /* = std::vector<T>::allocator_type */>
545  (size_type pos)
546 {
547  /*
548  * Behaviour summary:
549  * * if `pos` is out of vector range, behaviour is undefined
550  * * if element at `pos` has no storage, create storage for it
551  * * return a reference to the element at `pos`
552  */
553  // to have the common case where the requested position has storage be handled
554  // the fastest, we "enforce" the order by nesting (optimiser has last word)
555  if (!data_has_index(pos)) {
556  if (has_index(pos)) expand(pos);
557  }
558  return storage()[index_of(pos)];
559 } // util::LazyVector<T,A>::operator[]()
560 
561 
562 //------------------------------------------------------------------------------
563 template <typename T, typename A /* = std::vector<T>::allocator_type */>
565  (size_type pos) const
566 {
567  /*
568  * Behaviour summary:
569  * * if `pos` is out of vector range, behaviour is undefined
570  * * if element at `pos` has no storage, return a copy of the default value
571  * * otherwise, return a copy of the element at `pos`
572  */
573  // this implementation will return a default value if `pos` is out of range;
574  // this is not a requirement, and may change at any time.
575  if (pos < data_begin_index()) return data_defvalue();
576  auto const index = index_of(pos);
577  return (index < data_size())? storage()[index]: data_defvalue();
578 } // util::LazyVector<T,A>::operator[] () const
579 
580 
581 //------------------------------------------------------------------------------
582 template <typename T, typename A /* = std::vector<T>::allocator_type */>
585 {
586  /*
587  * Behaviour summary:
588  * * if `pos` is out of vector range, behaviour is undefined
589  * * if element at `pos` has no storage, return nullptr
590  * * otherwise, return the pointer to the specified element
591  */
592  // this implementation will return nullptr if `pos` is out of range;
593  // this is not a requirement, and may change at any time.
594  if (pos < data_begin_index()) return nullptr;
595  auto const index = index_of(pos);
596  return (index < data_size())? storage().data() + index: nullptr;
597 } // util::LazyVector<T,A>::data_address()
598 
599 
600 //------------------------------------------------------------------------------
601 template <typename T, typename A /* = std::vector<T>::allocator_type */>
603  /*
604  * Behaviour summary:
605  * * when extending, do not change storage
606  * * when shrinking, cut the excess storage
607  */
608  fNominalSize = newSize;
609  // delete any excess data
610  if (data_end_index() > newSize) {
611  if (fNominalSize <= data_begin_index()) data_clear(); // no data is left
612  else {
613  storage().erase
615  }
616  }
617 } // util::LazyVector<T,A>::resize()
618 
619 
620 //------------------------------------------------------------------------------
621 template <typename T, typename A /* = std::vector<T>::allocator_type */>
623  data_clear();
624  fNominalSize = 0U;
625 } // util::LazyVector<T,A>::clear()
626 
627 
628 //------------------------------------------------------------------------------
629 template <typename T, typename A /* = std::vector<T>::allocator_type */>
631  (size_type startIndex, size_type endIndex)
632 {
633  // we do not go beyond the declared size of the vector:
634  size_type const e = std::min(endIndex, size());
635  if (startIndex >= e) return;
636 
637  data_clear(); // remove the old data
638  storage().reserve(e - startIndex);
639  fFirstIndex = startIndex;
640 
641 } // util::LazyVector<T,A>::data_prepare(size_type, size_type)
642 
643 
644 //------------------------------------------------------------------------------
645 template <typename T, typename A /* = std::vector<T>::allocator_type */>
647  (size_type startIndex, size_type endIndex)
648 {
649  // we do not go beyond the declared size of the vector:
650  size_type const e = std::min(endIndex, size());
651  if (startIndex >= e) return;
652 
653  data_clear(); // remove the old data
654  storage().resize(e - startIndex, data_defvalue());
655  fFirstIndex = startIndex;
656 
657 } // util::LazyVector<T,A>::data_init(size_type, size_type)
658 
659 
660 //------------------------------------------------------------------------------
661 template <typename T, typename A /* = std::vector<T>::allocator_type */>
663  // this is just a dispatcher
664  if (data_empty()) init(pos);
665  else if (pos < data_begin_index()) expand_front(pos);
666  else if (pos >= data_end_index()) expand_back(pos);
667 }
668 
669 
670 //------------------------------------------------------------------------------
671 template <typename T, typename A /* = std::vector<T>::allocator_type */>
673  assert(data_empty());
674  storage().assign(n, data_defvalue());
675  fFirstIndex = pos;
676  fix_size();
677 }
678 
679 
680 //------------------------------------------------------------------------------
681 template <typename T, typename A /* = std::vector<T>::allocator_type */>
683  assert(pos < data_begin_index());
684  storage().insert
685  (storage().begin(), data_begin_index() - pos, data_defvalue());
686  fFirstIndex = pos;
687 }
688 
689 
690 //------------------------------------------------------------------------------
691 template <typename T, typename A /* = std::vector<T>::allocator_type */>
693  assert(pos >= data_end_index());
694  storage().resize(pos + 1U - data_begin_index(), data_defvalue());
695  fix_size();
696 }
697 
698 
699 //------------------------------------------------------------------------------
700 template <typename T, typename A /* = std::vector<T>::allocator_type */>
702  auto const min_size = data_end_index();
703  if (fNominalSize < min_size) fNominalSize = min_size;
704 }
705 
706 
707 //------------------------------------------------------------------------------
708 template <typename T, typename A /* = std::vector<T>::allocator_type */>
710  storage().clear();
711  fFirstIndex = storage().max_size();
712 } // util::LazyVector<T,A>::data_clear()
713 
714 
715 //------------------------------------------------------------------------------
716 template <typename T, typename A /* = std::vector<T>::allocator_type */>
718  if (has_index(pos)) return;
719  throw std::out_of_range(
720  "Index " + std::to_string(pos) + " is out of LazyVector range (size: "
721  + std::to_string(size()) + ")"
722  );
723 } // util::LazyVector<T,A>::check_range()
724 
725 
726 //------------------------------------------------------------------------------
727 
728 #endif // LARDATAOBJ_UTILITIES_LAZYVECTOR_H
const_pointer data_address(size_type pos) const
Returns a constant pointer to the specified element.
Definition: LazyVector.h:584
value_type operator[](size_type pos) const
Returns a copy of the specified element.
Definition: LazyVector.h:565
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
bool has_index(size_type pos) const noexcept
Returns whether the specified position is within the vector.
Definition: LazyVector.h:165
static value_type const & defaultValueType()
Returns the class default value (used when user does not specify any).
Definition: LazyVector.h:471
std::vector< TF1, typename std::vector< TF1 >::allocator_type > Data_t
Actual data storage type.
Definition: LazyVector.h:80
void data_prepare(size_type startIndex, size_type endIndex)
Prepares the vector to store elements in the specified range.
Definition: LazyVector.h:631
value_type const_get(size_type pos) const
Returns a copy of the specified element.
Definition: LazyVector.h:278
void data_clear()
Erases all stored data from the container; nominal size is not changed.
Definition: LazyVector.h:709
typename Data_t::reference reference
Definition: LazyVector.h:92
void data_init(size_type startIndex, size_type endIndex)
Allocates the specified range and stores default values for it.
Definition: LazyVector.h:647
void clear()
Removes all stored data and sets the nominal size to 0.
Definition: LazyVector.h:622
void check_range(size_type pos) const
Throws std::out_of_range if pos is not contained in the vector.
Definition: LazyVector.h:717
size_type index_of(size_type pos) const
Returns the internal storage index for the specified position.
Definition: LazyVector.h:446
void reserve(size_type n)
Allocates enough memory in storage to store n elements.
Definition: LazyVector.h:348
void expand_front(size_type pos)
Expands the storage to include the specified position behind it.
Definition: LazyVector.h:682
void shrink_to_fit()
Reduces memory usage to the amount needed by the elements with storage.
Definition: LazyVector.h:354
value_type const & data_defvalue() const
Definition: LazyVector.h:172
void fix_size()
Makes sure the nominal size is large enough to include all stored data.
Definition: LazyVector.h:701
static value_type const fDefaultDefaultValue
Default-initialised value of type value_type used as default fallback.
Definition: LazyVector.h:437
size_type size() const noexcept
Returns the size of the vector.
Definition: LazyVector.h:156
bool data_empty() const noexcept
Returns whether no data is actually stored.
Definition: LazyVector.h:168
bool empty() const noexcept
Returns whether the vector is empty.
Definition: LazyVector.h:159
typename Data_t::size_type size_type
Definition: LazyVector.h:90
LazyVector()=default
Data_t fData
Actual data storage.
Definition: LazyVector.h:430
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
size_type data_begin_index() const
Definition: LazyVector.h:176
Data_t & storage()
Returns the data storage.
Definition: LazyVector.h:441
typename Data_t::allocator_type allocator_type
Definition: LazyVector.h:88
void expand_back(size_type pos)
Expands the storage to include the specified position ahead of it.
Definition: LazyVector.h:692
typename Data_t::const_pointer const_pointer
Definition: LazyVector.h:95
void data_prepare(size_type n)
Prepares the vector to store n elements from 0.
Definition: LazyVector.h:389
value_type at(size_type pos) const
Returns a reference to the specified element, throws an exception if not present. ...
Definition: LazyVector.h:529
Data_t const & storage() const
Returns the data storage.
Definition: LazyVector.h:442
typename Data_t::difference_type difference_type
Definition: LazyVector.h:91
size_type fNominalSize
Alleged data size.
Definition: LazyVector.h:432
void data_init(size_type n)
Allocates and initializes n elements starting from index 0.
Definition: LazyVector.h:422
value_type const_at(size_type pos) const
Returns a reference to the specified element, throws an exception if not present. ...
Definition: LazyVector.h:245
void init(size_type pos, size_type n=1U)
Makes the first data allocation.
Definition: LazyVector.h:672
size_type fFirstIndex
First element currently stored.
Definition: LazyVector.h:433
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
size_type data_end_index() const
Definition: LazyVector.h:180
Int_t min
Definition: plot.C:26
typename Data_t::value_type value_type
Definition: LazyVector.h:89
typename Data_t::pointer pointer
Definition: LazyVector.h:94
Char_t n[5]
void expand(size_type pos)
Expands the storage to include the specified position.
Definition: LazyVector.h:662
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
A contiguous data container expanded on write.
Definition: LazyVector.h:78
void resize(size_type newSize)
Changes the nominal size of the container.
Definition: LazyVector.h:602
Float_t e
Definition: plot.C:34
bool data_has_index(size_type pos) const
Returns the internal storage index for the specified position.
Definition: LazyVector.h:184
typename Data_t::const_reference const_reference
Definition: LazyVector.h:93
size_type data_size() const noexcept
Returns the size of data actually stored.
Definition: LazyVector.h:162
value_type fDefValue
Default value.
Definition: LazyVector.h:434