LArSoft  v06_85_00
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 
344  void reserve(size_type n) { storage().reserve(n); }
345 
347  void clear();
348 
350  void shrink_to_fit() { storage().shrink_to_fit(); }
351 
353  // --- END Container operations --------------------------------------------
354 
355  private:
357 
359  size_type fFirstIndex = fData.max_size();
361 
364 
366  Data_t& storage() { return fData; }
368  Data_t const& storage() const { return fData; }
370 
372  size_type index_of(size_type pos) const { return pos - fFirstIndex; }
373 
375  void expand(size_type pos);
376 
378  void init(size_type pos, size_type n = 1U);
379 
381  void expand_front(size_type pos);
382 
384  void expand_back(size_type pos);
385 
387  void fix_size();
388 
390  void data_clear();
391 
393  void check_range(size_type pos) const;
394 
395 
397  static value_type const& defaultValueType() { return fDefaultDefaultValue; }
398 
399 
400  }; // LazyVector<>
401 
402 } // namespace util
403 
404 
405 //------------------------------------------------------------------------------
406 //--- template implementation
407 //------------------------------------------------------------------------------
408 template <typename T, typename A /* = std::vector<T>::allocator_type */>
411 
412 
413 //------------------------------------------------------------------------------
414 template <typename T, typename A /* = std::vector<T>::allocator_type */>
416  : fData(a)
417  {}
418 
419 
420 //------------------------------------------------------------------------------
421 template <typename T, typename A /* = std::vector<T>::allocator_type */>
424  {}
425 
426 
427 //------------------------------------------------------------------------------
428 template <typename T, typename A /* = std::vector<T>::allocator_type */>
430  : fNominalSize(n)
431  , fDefValue(defValue)
432  {}
433 
434 
435 //------------------------------------------------------------------------------
436 template <typename T, typename A /* = std::vector<T>::allocator_type */>
438  (size_type pos)
439 {
440  /*
441  * Behaviour summary:
442  * * if `pos` is out of vector range, throw an exception
443  * * if element at `pos` has no storage, create storage for it
444  * * return a reference to the element at `pos`
445  */
446  check_range(pos); // verify that `pos` is valid, throw otherwise
447  expand(pos);
448  return storage()[index_of(pos)]; // we already know it's valid
449 }
450 
451 
452 //------------------------------------------------------------------------------
453 template <typename T, typename A /* = std::vector<T>::allocator_type */>
455  (size_type pos) const
456 {
457  /*
458  * Behaviour summary:
459  * * if `pos` is out of vector range, throw an exception
460  * * if element at `pos` has no storage, return a copy of the default value
461  * * otherwise, return a copy of the element at `pos`
462  */
463  check_range(pos); // verify that `pos` is valid, throw otherwise
464  return data_has_index(pos)? storage()[index_of(pos)]: data_defvalue();
465 } // util::LazyVector<T,A>::at() const
466 
467 
468 //------------------------------------------------------------------------------
469 template <typename T, typename A /* = std::vector<T>::allocator_type */>
471  (size_type pos)
472 {
473  /*
474  * Behaviour summary:
475  * * if `pos` is out of vector range, behaviour is undefined
476  * * if element at `pos` has no storage, create storage for it
477  * * return a reference to the element at `pos`
478  */
479  // to have the common case where the requested position has storage be handled
480  // the fastest, we "enforce" the order by nesting (optimiser has last word)
481  if (!data_has_index(pos)) {
482  if (has_index(pos)) expand(pos);
483  }
484  return storage()[index_of(pos)];
485 } // util::LazyVector<T,A>::operator[]()
486 
487 
488 //------------------------------------------------------------------------------
489 template <typename T, typename A /* = std::vector<T>::allocator_type */>
491  (size_type pos) const
492 {
493  /*
494  * Behaviour summary:
495  * * if `pos` is out of vector range, behaviour is undefined
496  * * if element at `pos` has no storage, return a copy of the default value
497  * * otherwise, return a copy of the element at `pos`
498  */
499  // this implementation will return a default value if `pos` is out of range;
500  // this is not a requirement, and may change at any time.
501  if (pos < data_begin_index()) return data_defvalue();
502  auto const index = index_of(pos);
503  return (index < data_size())? storage()[index]: data_defvalue();
504 } // util::LazyVector<T,A>::operator[] () const
505 
506 
507 //------------------------------------------------------------------------------
508 template <typename T, typename A /* = std::vector<T>::allocator_type */>
511 {
512  /*
513  * Behaviour summary:
514  * * if `pos` is out of vector range, behaviour is undefined
515  * * if element at `pos` has no storage, return nullptr
516  * * otherwise, return the pointer to the specified element
517  */
518  // this implementation will return nullptr if `pos` is out of range;
519  // this is not a requirement, and may change at any time.
520  if (pos < data_begin_index()) return nullptr;
521  auto const index = index_of(pos);
522  return (index < data_size())? storage().data() + index: nullptr;
523 } // util::LazyVector<T,A>::data_address()
524 
525 
526 //------------------------------------------------------------------------------
527 template <typename T, typename A /* = std::vector<T>::allocator_type */>
529  /*
530  * Behaviour summary:
531  * * when extending, do not change storage
532  * * when shrinking, cut the excess storage
533  */
534  fNominalSize = newSize;
535  // delete any excess data
536  if (data_end_index() > newSize) {
537  if (fNominalSize <= data_begin_index()) data_clear(); // no data is left
538  else {
539  storage().erase
541  }
542  }
543 } // util::LazyVector<T,A>::resize()
544 
545 
546 //------------------------------------------------------------------------------
547 template <typename T, typename A /* = std::vector<T>::allocator_type */>
549  data_clear();
550  fNominalSize = 0U;
551 } // util::LazyVector<T,A>::clear()
552 
553 
554 //------------------------------------------------------------------------------
555 template <typename T, typename A /* = std::vector<T>::allocator_type */>
557  // this is just a dispatcher
558  if (data_empty()) init(pos);
559  else if (pos < data_begin_index()) expand_front(pos);
560  else if (pos >= data_end_index()) expand_back(pos);
561 }
562 
563 
564 //------------------------------------------------------------------------------
565 template <typename T, typename A /* = std::vector<T>::allocator_type */>
567  assert(data_empty());
568  storage().assign(n, data_defvalue());
569  fFirstIndex = pos;
570  fix_size();
571 }
572 
573 
574 //------------------------------------------------------------------------------
575 template <typename T, typename A /* = std::vector<T>::allocator_type */>
577  assert(pos < data_begin_index());
578  storage().insert
579  (storage().begin(), data_begin_index() - pos, data_defvalue());
580  fFirstIndex = pos;
581 }
582 
583 
584 //------------------------------------------------------------------------------
585 template <typename T, typename A /* = std::vector<T>::allocator_type */>
587  assert(pos >= data_end_index());
588  storage().resize(pos + 1U - data_begin_index(), data_defvalue());
589  fix_size();
590 }
591 
592 
593 //------------------------------------------------------------------------------
594 template <typename T, typename A /* = std::vector<T>::allocator_type */>
596  auto const min_size = data_end_index();
597  if (fNominalSize < min_size) fNominalSize = min_size;
598 }
599 
600 
601 //------------------------------------------------------------------------------
602 template <typename T, typename A /* = std::vector<T>::allocator_type */>
604  storage().clear();
605  fFirstIndex = storage().max_size();
606 } // util::LazyVector<T,A>::data_clear()
607 
608 
609 //------------------------------------------------------------------------------
610 template <typename T, typename A /* = std::vector<T>::allocator_type */>
612  if (has_index(pos)) return;
613  throw std::out_of_range(
614  "Index " + std::to_string(pos) + " is out of LazyVector range (size: "
615  + std::to_string(size()) + ")"
616  );
617 } // util::LazyVector<T,A>::check_range()
618 
619 
620 //------------------------------------------------------------------------------
621 
622 #endif // LARDATAOBJ_UTILITIES_LAZYVECTOR_H
const_pointer data_address(size_type pos) const
Returns a constant pointer to the specified element.
Definition: LazyVector.h:510
value_type operator[](size_type pos) const
Returns a copy of the specified element.
Definition: LazyVector.h:491
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:397
std::vector< TF1, typename std::vector< TF1 >::allocator_type > Data_t
Actual data storage type.
Definition: LazyVector.h:80
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:603
typename Data_t::reference reference
Definition: LazyVector.h:92
void clear()
Removes all stored data and sets the nominal size to 0.
Definition: LazyVector.h:548
void check_range(size_type pos) const
Throws std::out_of_range if pos is not contained in the vector.
Definition: LazyVector.h:611
size_type index_of(size_type pos) const
Returns the internal storage index for the specified position.
Definition: LazyVector.h:372
void reserve(size_type n)
Allocates enough memory in storage to store n elements.
Definition: LazyVector.h:344
void expand_front(size_type pos)
Expands the storage to include the specified position behind it.
Definition: LazyVector.h:576
void shrink_to_fit()
Reduces memory usage to the amount needed by the elements with storage.
Definition: LazyVector.h:350
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:595
static value_type const fDefaultDefaultValue
Default-initialised value of type value_type used as default fallback.
Definition: LazyVector.h:363
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:356
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:367
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:586
typename Data_t::const_pointer const_pointer
Definition: LazyVector.h:95
value_type at(size_type pos) const
Returns a reference to the specified element, throws an exception if not present. ...
Definition: LazyVector.h:455
Data_t const & storage() const
Returns the data storage.
Definition: LazyVector.h:368
typename Data_t::difference_type difference_type
Definition: LazyVector.h:91
size_type fNominalSize
Alleged data size.
Definition: LazyVector.h:358
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:566
size_type fFirstIndex
First element currently stored.
Definition: LazyVector.h:359
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
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:556
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:528
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:360