LazyVector.h
Go to the documentation of this file.
1 /**
2  * @file lardataobj/Utilities/LazyVector.h
3  * @brief Contiguous data container with lazy resizing on access.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date July 18, 2018
6  *
7  * This is a header-only library.
8  *
9  */
10 
11 #ifndef LARDATAOBJ_UTILITIES_LAZYVECTOR_H
12 #define LARDATAOBJ_UTILITIES_LAZYVECTOR_H
13 
14 // C/C++ standard libraries
15 #include <algorithm>
16 #include <vector>
17 #include <string> // std::to_string()
18 #include <stdexcept> // std::out_of_range
19 #include <cassert>
20 
21 
22 namespace util {
23 
24  /**
25  * @brief A contiguous data container expanded on write.
26  * @tparam T type of contained data
27  * @tparam A allocator for the data (default: STL vector's default allocator)
28  *
29  * This container class represents a number of data elements contiguously
30  * allocated in memory.
31  * It mimics the behaviour and interface of STL vector, but the actual data
32  * allocation is lazy, that is it happens only when writing to an element is
33  * requested. The internal allocation is always contiguous, including as little
34  * data as it can accommodate elements from the first to the last index written
35  * at any point.
36  *
37  * The interface is also a partial replica of STL vector, with the addition of
38  * members specific to this class, whose names start with `data_`.
39  * Among the relevant features missing from this object there is iterators.
40  *
41  * For some internal resizing operations, a default value is used to construct
42  * the new values. This default value can be specified in some constructors,
43  * Otherwise, a value equivalent to `0` (i.e. `value_type(0)`) is used for
44  * arithmetic value types, and the default-constructed value is used for all
45  * other types.
46  *
47  * Example of usage:
48  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
49  * // start with a lazy vector of nominal size 6 elements and no actual data:
50  * util::LazyVector<double> v(6U);
51  *
52  * // add a value `-4.0` at the previous-to-last element `4`:
53  * // the vector will look like: { ... [4] -4.0 ... }
54  * // (nominal size: 6, 1 stored datum)
55  * v[4] = -4.0;
56  *
57  * // add a value `-2.0` at the third element:
58  * // the vector will look like: { ... [2] -2.0, [3] def, [4] -4.0 ... }
59  * // (nominal size still 6, 3 stored data, the default value "def" is 0.0)
60  * v[2] = -2.0;
61  *
62  * // we want to set element #6 to -6.0: we need to expand the vector first.
63  * v.resize(7U); // barely enough for element #6
64  * // the vector will look like: { ... [2] -2.0, [3] def, [4] -4.0 [5] def [6] -6.0 }
65  * // (nominal size 7, 5 stored data, the default value "def" is 0.0)
66  * v[6] = -6.0;
67  *
68  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
69  *
70  * @note Special care needs to be used when accessing a non-const `LazyVector`,
71  * since every access will create storage for the specified element
72  * (like in STL map `operator[]`).
73  * For this reason, the special methods `const_at(size_type)` and
74  * `const_get(size_type)` are provided, which never create storage.
75  *
76  */
77  template <typename T, typename A = typename std::vector<T>::allocator_type>
78  class LazyVector {
79 
80  using Data_t = std::vector<T, A>; ///< Actual data storage type.
81 
82  public:
83 
84  // --- BEGIN STL vector types ----------------------------------------------
85  /// @name STL vector types
86  /// @{
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 
97  /// @}
98  // --- END STL vector types ------------------------------------------------
99 
100 
101  /// --- BEGIN Constructors -------------------------------------------------
102  /// Default constructor: an empty vector.
103  LazyVector() = default;
104 
105  /// Constructor: like default, but using the specified allocator.
106  LazyVector(allocator_type const& a);
107 
108 
109  /**
110  * @brief Constructor: a lazy vector with a specified maximum size.
111  * @param n the initial maximum size of the vector
112  *
113  * @note This constructor is essentially different from the one of STL
114  * vector with the same signature.
115  *
116  * The vector is set to a nominal size of `n`, with _no stored data_.
117  *
118  * The default value of vector elements is the default-constructed `T`
119  * value, as returned by `defaultValueType()`.
120  */
122 
123  /**
124  * @brief Constructor: a lazy vector with a specified maximum size.
125  * @param n the initial maximum size of the vector
126  * @param defValue value to be used when resizing
127  *
128  * @note This constructor is essentially different from the one of STL
129  * vector with the same signature.
130  *
131  * The vector is set to a nominal size of `n`, with _no stored data_.
132  * A default value `defValue` is registered, so that it can be used when
133  * actual storage is needed for elements whose value is not explicitly
134  * specified by the user:
135  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
136  * util::LazyVector<int> v(3, 5);
137  * v[0] = 0;
138  * v[2] = -2;
139  *
140  * std::cout << "Default element [1]: " << v.at(1) << std::endl;
141  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142  * will print something like: "Default element [1]: 5".
143  */
144  LazyVector(size_type n, value_type const& defValue);
145 
146 
147  /// --- END Constructors -------------------------------------------------
148 
149 
150 
151  // --- BEGIN Container information -----------------------------------------
152  /// @name Container information
153  /// @{
154 
155  /// Returns the size of the vector.
156  size_type size() const noexcept { return fNominalSize; }
157 
158  /// Returns whether the vector is empty.
159  bool empty() const noexcept { return fNominalSize == 0U; }
160 
161  /// Returns the size of data actually stored.
162  size_type data_size() const noexcept { return fData.size(); }
163 
164  /// Returns whether the specified position is within the vector.
165  bool has_index(size_type pos) const noexcept { return pos < size(); }
166 
167  /// Returns whether no data is actually stored.
168  bool data_empty() const noexcept { return fData.empty(); }
169 
170  /// Returns the default value.
171  /// @see `LazyVector(size_type, value_type const&)`
172  value_type const& data_defvalue() const { return fDefValue; }
173 
174  /// Index of the first data element in the storage
175  /// (undefined if `data_empty()`).
177 
178  /// Index after the last data element in the storage
179  /// (undefined if `data_empty()`).
181  { return data_begin_index() + data_size(); }
182 
183  /// Returns the internal storage index for the specified position.
185  { return (pos >= data_begin_index()) && (pos < data_end_index()); }
186 
187  /**
188  * @brief Returns a constant pointer to the specified element.
189  * @param pos position of the element
190  * @return pointer to storage for specified element, `nullptr` if not stored
191  *
192  * If `pos` represents an element that has storage, the pointer to that
193  * element is returned. If instead `pos` represents a valid element with no
194  * storage (default value), `nullptr` is returned.
195  * If `pos` does not represent a valid element, the result is undefined.
196  */
198 
199  /// @}
200  // --- END Container information -------------------------------------------
201 
202 
203 
204  // --- BEGIN Access to data elements ---------------------------------------
205  /**
206  * @name Access to data elements
207  *
208  * There are important differences between the access methods of
209  * `LazyVector` and the ones of STL `vector`.
210  *
211  * The constant versions of the access methods differ from the corresponding
212  * STL `vector` ones in that they return a _copy_ of the element rather than
213  * a reference to it.
214  * This happens because the element could not have current storage, and we
215  * can't create it because the method is constant.
216  *
217  * Also, the non-constant versions of the access methods always ensure
218  * storage for the accessed element. If such behaviour needs to be avoided
219  * (e.g. for performance reasons), use the methods explicitly named
220  * constant: `const_at()` and `const_get()`, explicitly constant versions of
221  * `at()` and `operator[]` respectively. To preserve the naming scheme, a
222  * method `get()` is also provided which is equivalent to the non-constant
223  * version of `operator[]`.
224  */
225  /// @{
226 
227  //@{
228  /**
229  * @brief Returns a reference to the specified element, throws an exception
230  * if not present.
231  * @param pos position to be accessed
232  * @return a copy of the value of requested element
233  * @throw std::out_of_range if the container is too small to contain `pos`
234  *
235  * Returns a copy of the specified element.
236  * If the requested element is beyond the size of the container, an
237  * exception `std::out_of_range` is thrown.
238  *
239  * @note This method differs from the corresponding STL vector in that it
240  * returns a _copy_ of the element rather than a reference to it.
241  * This happens because the element could not have current storage,
242  * and we can't create it because the method is constant.
243  */
244  value_type at(size_type pos) const;
245  value_type const_at(size_type pos) const { return at(pos); }
246  //@}
247 
248  /**
249  * @brief Returns a reference to the specified element, throws an exception
250  * if not present.
251  * @param pos position to be accessed
252  * @return the reference to the requested element
253  * @throw std::out_of_range if the container is too small to contain `pos`
254  * @see `data_defvalue()`
255  *
256  * Returns a reference to the specified element. If the element is not
257  * stored yet, it's created with the default value, and returned.
258  * If the requested element is beyond the size of the container, an
259  * exception `std::out_of_range` is thrown.
260  */
261  reference at(size_type pos);
262 
263  //@{
264  /**
265  * @brief Returns a copy of the specified element.
266  * @param pos position to be accessed
267  * @return a copy of the specified element
268  * @see `at(size_type) const`
269  *
270  * Returns a copy of the specified element.
271  * If the requested element is beyond the size of the container, the result
272  * is undefined.
273  *
274  * @note See `at(value_type) const` for an explanation of why a value is
275  * returned rather than a reference.
276  */
277  value_type operator[](size_type pos) const;
278  value_type const_get(size_type pos) const { return this->operator[](pos); }
279  //@}
280 
281  //@{
282  /**
283  * @brief Returns a reference to the specified element.
284  * @param pos position to be accessed
285  * @return a reference to the specified element
286  * @see `data_defvalue()`
287  *
288  * Returns a reference to the specified element.
289  * If that element is not stored, it is allocated first; all missing
290  * elements, including the required one, are initialised by copying into
291  * them the default value stored at construction.
292  * Like for STL vector, this method does not expand the vector: if `pos` is
293  * beyond the vector size, the result is undefined.
294  */
296  reference get(size_type pos) { return this->operator[](pos); }
297  //@}
298 
299  /// @}
300  // --- END Access to data elements -----------------------------------------
301 
302 
303 
304  // --- BEGIN Setting data elements -----------------------------------------
305  /// @name Setting data elements
306  /// @{
307 
308 
309  /// @}
310  // --- END Setting data elements -------------------------------------------
311 
312 
313 
314  // --- BEGIN Container operations -----------------------------------------
315  /// @name Container operations
316  /// @{
317 
318  /**
319  * @brief Changes the nominal size of the container.
320  * @param newSize new container size
321  *
322  * The nominal size of the vector is set to newSize. Even when `newSize`
323  * is larger than the current nominal size, no additional data is stored.
324  * If the new nominal size is smaller, actual data may be released (i.e.
325  * erased) so that no stored data is beyond the new nominal size.
326  *
327  * @note It is not possible to specify a filling value: the "default" value
328  * specified on construction is always used.
329  */
330  void resize(size_type newSize);
331 
332  /**
333  * @brief Allocates enough memory in storage to store `n` elements.
334  * @param n number of elements to have storage for
335  * @see `data_prepare()`
336  *
337  * Storage allocation is resized to be able to host at least `n` elements
338  * (it is not reduced).
339  * Note that the use of `reserve()` for `LazyVector` is more subtle than for
340  * a STL vector. The common use of `reserve()` is to avoid reallocations
341  * when extending the vector. In this case, after a call to `reserve(n)` the
342  * reallocation is avoided only as long as only the elements from
343  * `data_begin_index()` to `data_begin_index() + n` (excluded) are written.
344  *
345  * Note that `data_prepare()` has a similar purpose and might be more
346  * effective.
347  */
348  void reserve(size_type n) { storage().reserve(n); }
349 
350  /// Removes all stored data and sets the nominal size to 0.
351  void clear();
352 
353  /// Reduces memory usage to the amount needed by the elements with storage.
354  void shrink_to_fit() { storage().shrink_to_fit(); }
355 
356  /**
357  * @brief Prepares the vector to store elements in the specified range.
358  * @param startIndex index of the first element to be stored
359  * @param endIndex index after the last element to be stored
360  * @see `data_prepare(size_type)`
361  *
362  * This method sets the lower index to `startIndex`, and allocates enough
363  * storage to store the whole requested range.
364  * The elements are not initialized or constructed, but
365  * Following access to elements in the specified range will not cause
366  * memory reallocation, and that holds until an access outside that range
367  * happens, after which all bets are off.
368  *
369  * **Old data is lost.**
370  *
371  * @note The nominal size of the vector is not changed, therefore the
372  * specified range might be not honored. If used in combination with
373  * `resize()`, `resize()` should be called first.
374  */
375  void data_prepare(size_type startIndex, size_type endIndex);
376 
377  /**
378  * @brief Prepares the vector to store `n` elements from `0`.
379  * @param n number of elements to prepare storage for
380  * @see `data_prepare(size_type, size_type)`
381  *
382  * This method reserves storage for `n` elements starting with the element
383  * #0.
384  *
385  * **Old data is lost.**
386  *
387  * See `data_prepare(size_type, size_type)` for more information.
388  */
390 
391  /**
392  * @brief Allocates the specified range and stores default values for it.
393  * @param startIndex index of the first element to be initialized
394  * @param endIndex index after the last element to be initialized
395  *
396  * Each element in the range from `startIndex` to `endIndex` is stored and
397  * the default value is assigned to it.
398  *
399  * **Old data is lost.**
400  *
401  * @note The nominal size of the vector is not changed, therefore the
402  * specified range might be not honored. If used in combination with
403  * `resize()`, `resize()` should be called first.
404  */
405  void data_init(size_type startIndex, size_type endIndex);
406 
407  /**
408  * @brief Allocates and initializes `n` elements starting from index 0.
409  * @param n number of elements to be initialized
410  *
411  * Each element in the range from `0` to `n` is stored and
412  * the default value is assigned to it.
413  * This is semantically similar to `std::vector::resize(n, data_defvalue()`,
414  * except that this method does not change the nominal size of the vector.
415  *
416  * **Old data is lost.**
417  *
418  * @note The nominal size of the vector is not changed, therefore the
419  * specified range might be not honored. If used in combination with
420  * `resize()`, `resize()` should be called first.
421  */
422  void data_init(size_type n) { data_init(0U, n); }
423 
424 
425 
426  /// @}
427  // --- END Container operations --------------------------------------------
428 
429  private:
430  Data_t fData; ///< Actual data storage.
431 
432  size_type fNominalSize = 0U; ///< Alleged data size.
433  size_type fFirstIndex = fData.max_size(); ///< First element currently stored.
434  value_type fDefValue = defaultValueType(); ///< Default value.
435 
436  /// Default-initialised value of type `value_type` used as default fallback.
438 
439  //@{
440  /// Returns the data storage.
441  Data_t& storage() { return fData; }
442  Data_t const& storage() const { return fData; }
443  //@}
444 
445  /// Returns the internal storage index for the specified position.
446  size_type index_of(size_type pos) const { return pos - fFirstIndex; }
447 
448  /// Expands the storage to include the specified position.
449  void expand(size_type pos);
450 
451  /// Makes the first data allocation.
452  void init(size_type pos, size_type n = 1U);
453 
454  /// Expands the storage to include the specified position behind it.
455  void expand_front(size_type pos);
456 
457  /// Expands the storage to include the specified position ahead of it.
458  void expand_back(size_type pos);
459 
460  /// Makes sure the nominal size is large enough to include all stored data.
461  void fix_size();
462 
463  /// Erases all stored data from the container; nominal size is not changed.
464  void data_clear();
465 
466  /// Throws `std::out_of_range` if `pos` is not contained in the vector.
467  void check_range(size_type pos) const;
468 
469 
470  /// Returns the class default value (used when user does not specify any).
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 */>
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 */>
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.
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
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
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
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
const double e
typename Data_t::size_type size_type
Definition: LazyVector.h:90
LazyVector()=default
std::void_t< T > n
const double a
Data_t fData
Actual data storage.
Definition: LazyVector.h:430
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
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
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
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
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
void expand(size_type pos)
Expands the storage to include the specified position.
Definition: LazyVector.h:662
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
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
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
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
value_type fDefValue
Default value.
Definition: LazyVector.h:434