sparse_vector.h
Go to the documentation of this file.
1 /**
2  * @file lardataobj/Utilities/sparse_vector.h
3  * @brief Class defining a sparse vector (holes are zeroes)
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date April 22, 2014
6  * @version 1.0
7  *
8  */
9 
10 
11 #ifndef LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
12 #define LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
13 
14 
15 // C/C++ standard library
16 #include <cstddef> // std::ptrdiff_t
17 #include <stdexcept> // std::out_of_range()
18 #include <vector>
19 #include <ostream>
20 #include <iterator> // std::distance()
21 #include <algorithm> // std::upper_bound(), std::max()
22 #include <numeric> // std::accumulate
23 #include <type_traits> // std::is_integral
24 
25 
26 /// Namespace for generic LArSoft-related utilities.
27 namespace lar {
28 
29 // -----------------------------------------------------------------------------
30 // --- utility classes for sparse_vector
31 // ---
32 
33 /**
34  * @brief Little class storing a value.
35  * @tparam T type of the stored value
36  *
37  * This class stores a constant value and returns it as conversion to type T.
38  * It also acts as a left-value of type T, except that the assigned value
39  * is ignored.
40  */
41 template <typename T>
44  public:
45  typedef T value_type; ///< type of the value stored
46 
47  /// Default constructor: stores default value
49 
50  /// Constructor: stores the specified value
51  explicit const_value_box(value_type new_value): value(new_value) {}
52 
53  /// Assignment: the assigned value is ignored
54  this_t& operator= (value_type) { return *this; }
55 
56  //@{
57  /// Conversion to the basic type: always returns the stored value
58  operator value_type() const { return value; }
59  operator const value_type& () const { return value; }
60  //@}
61 
62  protected:
63  value_type value; ///< the value stored for delivery
64 }; // class const_value_box
65 
66 
67 /// @brief A constant iterator returning always the same value
68 /// @tparam T type of the value returned by dereferenciation
69 template <typename T>
71  public std::iterator<std::random_access_iterator_tag, T>
72 {
73  typedef std::iterator<std::random_access_iterator_tag, T> base_t; ///< base type
74  typedef value_const_iterator<T> this_t; ///< alias for this type
75 
76  public:
77 
78  using typename base_t::value_type;
79  using typename base_t::difference_type;
80 
81  /// Default constructor: use the default value
83 
84  /// Constructor: value that will be returned
85  value_const_iterator(value_type new_value): value(new_value) {}
86 
87  /// Constructor: value to be returned and current iterator "position"
88  value_const_iterator(value_type new_value, difference_type offset):
89  index(offset), value(new_value) {}
90 
91  /// Returns a copy of the stored value
92  value_type operator* () const { return value; }
93 
94  /// Returns a copy of the stored value
95  value_type operator[] (difference_type) const { return value; }
96 
97  /// Increments the position of the iterator, returns the new position
98  this_t& operator++() { ++index; return *this; }
99 
100  /// Increments the position of the iterator, returns the old position
101  this_t operator++(int) { this_t copy(*this); ++index; return copy; }
102 
103  /// Decrements the position of the iterator, returns the new position
104  this_t& operator--() { --index; return *this; }
105 
106  /// Decrements the position of the iterator, returns the old position
107  this_t operator--(int) { this_t copy(*this); --index; return copy; }
108 
109  /// Increments the position of the iterator by the specified steps
110  this_t& operator+= (difference_type ofs) { index += ofs; return *this; }
111 
112  /// Decrements the position of the iterator by the specified steps
113  this_t& operator-= (difference_type ofs) { index -= ofs; return *this; }
114 
115  /// Returns an iterator pointing ahead of this one by the specified steps
116  this_t operator+ (difference_type ofs) const
117  { return this_t(value, index + ofs); }
118 
119  /// Returns an iterator pointing behind this one by the specified steps
120  this_t operator- (difference_type ofs) const
121  { return this_t(value, index - ofs); }
122 
123  /// @brief Returns the distance between this iterator and the other
124  /// @return how many steps this iterator is ahead of the other
125  difference_type operator- (const this_t& iter) const
126  { return index - iter.index; }
127 
128  //@{
129  /// Comparison operators: determined by the position pointed by the iterators
130  bool operator== (const this_t& as) const { return index == as.index; }
131  bool operator!= (const this_t& as) const { return index != as.index; }
132 
133  bool operator< (const this_t& as) const { return index < as.index; }
134  bool operator<= (const this_t& as) const { return index <= as.index; }
135  bool operator> (const this_t& as) const { return index > as.index; }
136  bool operator>= (const this_t& as) const { return index >= as.index; }
137  //@}
138 
139  protected:
140  difference_type index{0}; ///< (arbitrary) position pointed by the iterator
141  value_type value; ///< value to be returned when dereferencing
142 }; // class value_const_iterator<>
143 
144 
145 /**
146  * @brief Returns an iterator pointing ahead of this one by the specified steps
147  * @param ofs number of steps ahead
148  * @param iter base iterator
149  */
150 template <typename T>
154 )
155  { return { iter.value, iter.index + ofs }; }
156 
157 /* // not ready yet...
158 template <typename T>
159 class value_iterator: public value_const_iterator<T> {
160  using base_t = value_const_iterator<T>;
161  using this_t = value_iterator<T>;
162  using const_value_box<value_type> = value_box;
163  public:
164 
165  using typename base_t::value_type;
166  using typename base_t::reference;
167 
168  value_box operator* () const { return value_box(value); }
169  value_box operator[] (difference_type) const { return value_box(value); }
170 
171 }; // class value_iterator<>
172 */
173 
174 
175 
176 //------------------------------------------------------------------------------
177 //--- lar::range_t<SIZE>
178 //---
179 /**
180  * @brief A range (interval) of integers
181  * @tparam SIZE type of the indices (expected integral)
182  *
183  * Includes a first and an after-the-last value, and some relation metods.
184  */
185 template <typename SIZE>
186 class range_t {
187  public:
188  typedef SIZE size_type; ///< type for the indices in the range
189  typedef std::ptrdiff_t difference_type; ///< type for index difference
190 
191  static_assert
192  (std::is_integral<size_type>::value, "range_t needs an integral type");
193 
194  size_type offset; ///< offset (absolute index) of the first element
195  size_type last; ///< offset (absolute index) after the last element
196 
197  /// Default constructor: empty range
198  range_t(): offset(0), last(0) {}
199 
200  /// Constructor from first and last index
201  range_t(size_type from, size_type to):
202  offset(from), last(std::max(from, to)) {}
203 
204 
205  /// Sets the borders of the range
206  void set(size_type from, size_type to)
207  { offset = from; last = std::max(from, to); }
208 
209  /// Returns the first absolute index included in the range
210  size_type begin_index() const { return offset; }
211 
212  /// Returns the first absolute index not included in the range
213  size_type end_index() const { return last; }
214 
215  /// Returns the position within the range of the absolute index specified
216  size_type relative_index(size_type index) const { return index - offset; }
217 
218  /// Returns the size of the range
219  size_type size() const { return last - offset; }
220 
221  /// Moves the end of the range to fit the specified size
222  void resize(size_type new_size) { last = offset + new_size; }
223 
224  /// Moves the begin of the range by the specified amount
225  void move_head(difference_type shift) { offset += shift; }
226 
227  /// Moves the end of the range by the specified amount
228  void move_tail(difference_type shift) { last += shift; }
229 
230  /// Returns whether the range is empty
231  bool empty() const { return last <= offset; }
232 
233  /// Returns whether the specified absolute index is included in this range
234  bool includes(size_type index) const
235  { return (index >= offset) && (index < last); }
236 
237  /// Returns whether the specified range is completely included in this one
238  bool includes(const range_t& r) const
239  { return includes(r.begin_index()) && includes(r.end_index()); }
240 
241  /// Returns if this and the specified range overlap
242  bool overlap(const range_t& r) const
243  { return (begin_index() < r.end_index()) && (end_index() > r.begin_index()); }
244 
245  /// Returns if there are elements in between this and the specified range
246  bool separate(const range_t& r) const
247  { return (begin_index() > r.end_index()) || (end_index() < r.begin_index()); }
248 
249  /// @brief Returns whether an index is within or immediately after this range
250  ///
251  /// Returns whether the specified absolute index is included in this range
252  /// or is immediately after it (not before it!)
253  bool borders(size_type index) const
254  { return (index >= offset) && (index <= last); }
255 
256  //@{
257  /// Sort: this range is smaller if its offset is smaller
258  bool operator< (const range_t& than) const { return less(*this, than); }
259  //@}
260 
261  /// Returns whether the specified range has our same offset and size
262  bool operator== (const range_t& as) const
263  { return (offset == as.offset) && (last == as.last); }
264 
265  /// Returns whether the range is valid (that is, non-negative size)
266  bool is_valid() const { return last >= offset; }
267 
268  //@{
269  /// Returns if a is "less" than b
270  static bool less(const range_t& a, const range_t& b)
271  { return a.offset < b.offset; }
272  static bool less(const range_t& a, size_type b)
273  { return a.offset < b; }
274  static bool less(size_type a, const range_t& b)
275  { return a < b.offset; }
276  //@}
277 
278  /// Helper type to be used for binary searches
279  typedef bool (*less_int_range)(size_type, const range_t& b);
280 }; // class range_t
281 
282 
283 
284 // -----------------------------------------------------------------------------
285 // --- lar::sparse_vector<T>
286 // ---
287 
288 // the price of having used subclasses extensively:
289 template <typename T> class sparse_vector;
290 
291 namespace details {
292  template <typename T>
293  decltype(auto) make_const_datarange_t
294  (typename sparse_vector<T>::datarange_t& r);
295 } // namespace details
296 
297 
298 /** ****************************************************************************
299  * @brief A sparse vector
300  * @tparam T type of data stored in the vector
301  * @todo backward iteration; reverse iterators; iterator on non-void elements
302  * only; iterator on non-void elements only, returning a pair (index;value)
303  *
304  * A sparse_vector is a container of items marked by consecutive indices
305  * (that is, a vector like std::vector), where only non-zero elements are
306  * actually stored.
307  * The implementation is a container of ranges of non-zero consecutive values;
308  * the zero elements are effectively not stored in the object, and a zero is
309  * returned whenever they are accessed.
310  * In the following, the regions of zeros between the non-zero ranges are
311  * collectively called "the void".
312  *
313  * See sparse_vector_test.cc for examples of usage.
314  *
315  * Although some level of dynamic assignment is present, the class is not very
316  * flexible and it is best assigned just once, by adding ranges (add_range(); or
317  * by push_back(), which is less efficient).
318  * While this class mimics a good deal of the STL vector interface, it is
319  * *not* a std::vector and it does not support all the tricks of it.
320  *
321  * For the following, let's assume:
322  * ~~~
323  * lar::sparse_vector<double> sv;
324  * std::vector<double> buffer;
325  * ~~~
326  *
327  * Supported usage
328  * ---------------
329  *
330  * ~~~
331  * for (const auto& value: sv) std::cout << " " << value;
332  * ~~~
333  * ~~~
334  * lar::sparse_vector<double>::const_iterator iValue = sv.cbegin(), vend = sv.cend();
335  * while (iSV != sv.end()) std::cout << " " << *(iSV++);
336  * ~~~
337  * ~~~
338  * for (auto value: sv) { ... }
339  * ~~~
340  * Common iteration on all elements. Better to do a constant one.
341  * The first two examples print the full content of the sparse vector, void
342  * included.
343  *
344  * ---
345  *
346  * ~~~
347  * sv[10] = 3.;
348  * ~~~
349  * Assign to an *existing* (not void) element. Assigning to void elements
350  * is not supported, and there is no way to make an existing element to become
351  * void (assigning 0 will yield to an existing element with value 0).
352  *
353  * ---
354  *
355  * ~~~
356  * sv.set_at(10, 3.);
357  * ~~~
358  * Assign a value to an element. The element could be in the void; in any case,
359  * after this call the element will not be in the void anymore (even if the
360  * assigned value is zero; to cast a cell into the void, use unset_at()).
361  *
362  * ---
363  *
364  * ~~~
365  * sv.add_range(20, buffer)
366  * ~~~
367  * ~~~
368  * sv.add_range(20, buffer.begin(), buffer.end())
369  * ~~~
370  * ~~~
371  * sv.add_range(20, std::move(buffer))
372  * ~~~
373  * Add the content of buffer starting at the specified position.
374  * The last line will attempt to use the buffer directly (only happens if the
375  * start of the new range -- 20 in the example -- is in the void and therefore a
376  * new range will be added). The new range is merged with the existing ones when
377  * needed, and it overwrites their content in case of overlap.
378  * If the specified position is beyond the current end of the sparse vector,
379  * the gap will be filled by void.
380  *
381  * ---
382  *
383  * ~~~
384  * sv.append(buffer)
385  * ~~~
386  * ~~~
387  * sv.append(buffer.begin(), buffer.end())
388  * ~~~
389  * ~~~
390  * sv.append(std::move(buffer))
391  * ~~~
392  * Add the content of buffer at the end of the sparse vector.
393  * The last line will attempt to use the buffer directly (only happens if the
394  * end of the sparse vector is in the void and therefore a new range will be
395  * added).
396  *
397  * ---
398  *
399  * ~~~
400  * sv.resize(30)
401  * ~~~
402  * Resizes the sparse vector to the specified size. Truncation may occur, in
403  * which case the data beyond the new size is removed. If an extension occurs
404  * instead, the new area is void.
405  *
406  * ---
407  *
408  * ~~~
409  * for (const lar::sparse_vector<double>::datarange_t& range: sv.get_ranges()) {
410  * size_t first_item = range.begin_index(); // index of the first item
411  * size_t nItems = range.size(); // number of items in this range
412  * for (double value: range) { ... }
413  * }
414  * ~~~
415  * A sparse vector can be parsed range by range, skipping the void. Each range
416  * object itself supports iteration.
417  * Neither the content nor the shape of the ranges can be changed this way.
418  *
419  *
420  * Possible future improvements
421  * ----------------------------
422  *
423  * ~~~
424  * sv[10] = 3.;
425  * ~~~
426  * is not supported if the vector is shorter than 11 (similarly to a
427  * std::vector too), and not even if the item #10 is currently in the void.
428  * This latter could be changed to create a new element/range; this would
429  * require to ship the pointer to the container with the reference (the return
430  * value of "sv[10]"), just in case an assignment will occur, or to create the
431  * element regardless, like for std::map (but this would provoke a disaster
432  * if the caller uses the non-constant operator[] for iteration).
433  * So far, set_at() is the closest thing to it.
434  *
435  *
436  * Non-supported usage
437  * -------------------
438  *
439  * ~~~
440  * sv.reserve(20);
441  * ~~~
442  * This has no clear meaning. A usage analogous to STL would precede a sequence
443  * of push_back's. In that case, we should create a new empty range at the end
444  * of the vector, and reserve that. Empty ranges are currently not allowed.
445  * A replacement of this pattern is to create a new `std::vector`, reserve space
446  * for it and fill it, and finally use `sparse_vector::append()`. If the end
447  * of the vector is void, there will be no performance penalty, otherwise a
448  * reserve + copy will happen.
449  *
450  * ---
451  *
452  * ~~~
453  * for (auto& value: sv) { ... }
454  * ~~~
455  * In order to allow for assignment in an item which is currently not void,
456  * the non-constant iterators do not dereference directly into a reference to
457  * the vector element (which would be non-existent if in the void), but instead
458  * into a lightweight object (still called "reference"). These objects are
459  * semantically working as references, but they are formally rvalues (i.e., just
460  * values, not C++ references), so they can't be assigned to references (like
461  * "auto&"). Nevertheless they work as references and assigning to them does
462  * change the original value. Currently assigning to void cells is not supported
463  * (see above).
464  *
465  */
466 template <typename T>
467 class sparse_vector {
469  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
470  // - - - public interface
471  public:
472  // - - - types
473  typedef T value_type; ///< type of the stored values
474  typedef std::vector<value_type> vector_t;
475  ///< type of STL vector holding this data
476  typedef typename vector_t::size_type size_type; ///< size type
477  typedef typename vector_t::difference_type difference_type;
478  ///< index difference type
479  typedef typename vector_t::pointer pointer;
480  typedef typename vector_t::const_pointer const_pointer;
481 // typedef typename vector_t::reference reference;
482 // typedef typename vector_t::const_reference const_reference;
483 
484  // --- declarations only ---
485  class reference;
486  class const_reference;
487  class iterator;
488  class const_iterator;
489 
490  class datarange_t;
491  class const_datarange_t;
492  // --- ----------------- ---
493 
494  typedef std::vector<datarange_t> range_list_t;
495  ///< type of sparse vector data
497  ///< type of iterator over ranges
499  ///< type of constant iterator over ranges
500 
501 
502  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
503  // - - - public methods
504  /// Default constructor: an empty vector
505  sparse_vector(): nominal_size(0), ranges() {}
506 
507 
508  /// Constructor: a vector with new_size elements in the void
509  sparse_vector(size_type new_size): nominal_size(0), ranges()
510  { resize(new_size); }
511 
512  /**
513  * @brief Constructor: a solid vector from an existing STL vector
514  * @param from vector to copy data from
515  * @param offset (default: 0) index the data starts from (preceeded by void)
516  */
517  sparse_vector(const vector_t& from, size_type offset = 0):
518  nominal_size(0), ranges()
519  { add_range(offset, from.begin(), from.end()); }
520 
521  /// Copy constructor: default
522  sparse_vector(sparse_vector const&) = default;
523 
524  /// Move constructor
525  sparse_vector(sparse_vector&& from)
526  : nominal_size(from.nominal_size)
527  , ranges(std::move(from.ranges))
528  { from.nominal_size = 0; }
529 
530  /// Copy assignment: default
531  sparse_vector& operator=(sparse_vector const&) = default;
532 
533  /// Move assignment
534  sparse_vector& operator=(sparse_vector&& from)
535  {
536  ranges = std::move(from.ranges);
537  nominal_size = from.nominal_size;
538  from.nominal_size = 0;
539  return *this;
540  } // operator= (sparse_vector&&)
541 
542  /**
543  * @brief Constructor: a solid vector from an existing STL vector
544  * @param from vector to move data from
545  * @param offset (default: 0) index the data starts from (preceeded by void)
546  */
547  sparse_vector(vector_t&& from, size_type offset = 0):
548  nominal_size(0), ranges()
549  { add_range(offset, std::move(from)); }
550 
551 
552  /// Destructor: default
553  ~sparse_vector() = default;
554 
555 
556  // - - - STL-like interface
557  /// Removes all the data, making the vector empty
558  void clear() { ranges.clear(); nominal_size = 0; }
559 
560 
561  /// Returns the size of the vector
562  size_type size() const { return nominal_size; }
563 
564  /// Returns whether the vector is empty
565  bool empty() const { return size() == 0; }
566 
567  /// Returns the capacity of the vector (compatibility only)
568  size_type capacity() const { return nominal_size; }
569 
570  //@{
571  /// Resizes the vector to the specified size, adding void
572  void resize(size_type new_size);
573  /// Resizes the vector to the specified size, adding def_value
574  void resize(size_type new_size, value_type def_value);
575  //@}
576 
577  //@{
578  /// Standard iterators interface
579  iterator begin();
580  iterator end();
581  const_iterator begin() const;
582  const_iterator end() const;
583  const_iterator cbegin() const { return begin(); }
584  const_iterator cend() const { return end(); }
585  //@}
586 
587  /// Access to an element (read only)
588  value_type operator[] (size_type index) const;
589 
590  /// Access to an element (read/write for non-void elements only!)
591  reference operator[] (size_type index);
592 
593 
594  // - - - special interface
595 
596  ///@{ @name Cell test
597  ///
598  /// The methods in this group test the single vector cells.
599 
600  // --- element test
601  /**
602  * @brief Returns whether the specified position is void
603  * @param index position of the cell to be tested
604  * @throw out_of_range if index is not in the vector
605  * @see is_back_void()
606  */
607  bool is_void(size_type index) const;
608 
609 
610  /// @brief Returns whether the sparse vector ends with void
611  /// @see is_void()
612  bool back_is_void() const
613  { return ranges.empty() || (ranges.back().end_index() < size()); }
614 
615 
616  /// Returns the number of non-void cells
617  size_type count() const;
618  ///@}
619 
620 
621  ///@{ @name Cell set
622  ///
623  /// The methods in this group access and/or change the cell values.
624  /**
625  * @brief Writes into an element (creating or expanding a range if needed)
626  * @param index the index of the element to set
627  * @param value the value to be set
628  * @return a reference to the changed value
629  * @see unset_at()
630  *
631  * Note that setting the value to zero will not cast the element into void.
632  * Use unset_at for that.
633  */
634  value_type& set_at(size_type index, value_type value);
635 
636  /// Casts the element with the specified index into the void
637  void unset_at(size_type index);
638 
639  //@{
640  /// Adds one element to the end of the vector (zero values too)
641  /// @param value value to be added
642  void push_back(value_type value) { resize(size() + 1, value); }
643 
644  /**
645  * @brief Adds one element to the end of the vector (if zero, just adds void)
646  * @param value value to be added
647  * @param thr threshold below which the value is considered zero
648  *
649  * If the threshold is strictly negative, all values are pushed back
650  */
651  void push_back(value_type value, value_type thr)
652  {
653  if (is_zero(value, thr)) resize(size() + 1);
654  else push_back(value);
655  } // push_back()
656  //@}
657 
658 
659  //@{
660  /**
661  * @brief Copies data from a sequence between two iterators
662  * @tparam ITER type of iterator
663  * @param first iterator pointing to the first element to be copied
664  * @param last iterator pointing after the last element to be copied
665  *
666  * The previous content of the sparse vector is lost.
667  */
668  template <typename ITER>
669  void assign(ITER first, ITER last) { clear(); append(first, last); }
670 
671  /**
672  * @brief Copies data from a container
673  * @tparam CONT type of container supporting the standard begin/end interface
674  * @param new_data container with the data to be copied
675  *
676  * The previous content of the sparse vector is lost.
677  */
678  template <typename CONT>
679  void assign(const CONT& new_data) { clear(); append(new_data); }
680 
681  /**
682  * @brief Moves data from a vector
683  * @param new_data vector with the data to be moved
684  *
685  * The previous content of the sparse vector is lost.
686  */
687  void assign(vector_t&& new_data) { clear(); append(std::move(new_data)); }
688  //@}
689 
690  ///@}
691 
692 
693  // --- BEGIN Ranges ---------------------------------------------------------
694  /**
695  * @name Ranges
696  *
697  * A range is a contiguous region of the sparse vector which contains all
698  * non-void values.
699  *
700  * A sparse vector is effectively a sorted collection of ranges.
701  * This interface allows:
702  * * iteration through all ranges (read only)
703  * * random access to a range by index (read only)
704  * * access to the data of a selected range (read/write)
705  * * look-up of the range containing a specified index
706  * (read/write; use write with care!)
707  * * addition (and more generically, combination with existing data) of a new
708  * range
709  * * extension of the sparse vector by appending a range at the end of it
710  * * remove the data of a range, making it void
711  */
712  /// @{
713 
714  // --- range location
715 
716  /// Returns the internal list of non-void ranges
717  const range_list_t& get_ranges() const { return ranges; }
718  auto iterate_ranges() -> decltype(auto);
719 
720  /// Returns the internal list of non-void ranges
721  size_type n_ranges() const { return ranges.size(); }
722 
723  /// Returns the i-th non-void range (zero-based)
724  const datarange_t& range(size_t i) const { return ranges[i]; }
725 
726  //@{
727  /**
728  * @brief Provides direct access to data of i-th non-void range (zero-based)
729  * @param i index of the range
730  * @return an object suitable for ranged-for iteration
731  *
732  * No information about the positioning of the range itself is provided,
733  * which can be obtained with other means (e.g. `range(i).begin_index()`).
734  * The returned object can be used in a ranged-for loop:
735  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
736  * for (std::size_t iRange = 0; iRange < sv.n_ranges(); ++iRange) {
737  * for (auto& value: sv.range_data(iRange)) {
738  * v *= 2.0;
739  * }
740  * }
741  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
742  * (with `sv` a `lar::sparse_vector` instance).
743  *
744  * While this is a somehow clumsier interface than `get_ranges()`, it allows,
745  * using the non-`const` version, write access to the data elements.
746  * It intentionally provides no write access to the location of each range,
747  * though.
748  */
749  auto range_data(std::size_t i);
750  auto range_data(std::size_t const i) const { return range_const_data(i); }
751  //@}
752 
753  /// Like `range_data()` but with explicitly read-only access to data.
754  auto range_const_data(std::size_t i) const;
755 
756  /// Returns a constant iterator to the first data range
757  range_const_iterator begin_range() const { return ranges.begin(); }
758 
759  /// Returns a constant iterator to after the last data range
760  range_const_iterator end_range() const { return ranges.end(); }
761 
762 
763  //@{
764  /**
765  * @brief Returns an iterator to the range containing the specified index
766  * @param index absolute index of the element to be sought
767  * @return iterator to containing range, or get_ranges().end() if in void
768  * @throw std::out_of_range if index is not in the vector
769  * @see is_void()
770  */
771  range_const_iterator find_range_iterator(size_type index) const;
772  range_iterator find_range_iterator(size_type index)
773  { return ranges.begin() + find_range_number(index); }
774  //@}
775 
776  /**
777  * @brief Returns the number (0-based) of range containing `index`.
778  * @param index absolute index of the element to be sought
779  * @return index of containing range, or `n_ranges()` if in void
780  * @throw std::out_of_range if index is not in the vector
781  * @see is_void()
782  */
783  std::size_t find_range_number(size_type index) const
784  { return find_range_iterator(index) - begin_range(); }
785 
786  //@{
787  /**
788  * @brief Returns the range containing the specified index
789  * @param index absolute index of the element to be sought
790  * @return the containing range
791  * @throw std::out_of_range if index is in no range (how appropriate!)
792  * @see is_void()
793  */
794  const datarange_t& find_range(size_type index) const;
795  datarange_t& find_range(size_type index);
796  //@}
797 
798  /**
799  * @brief Casts the whole range with the specified item into the void
800  * @param index absolute index of the element whose range is cast to void
801  * @return the range just voided
802  * @throw std::out_of_range if index is not in the vector
803  * @see unset(), make_void()
804  */
805  datarange_t make_void_around(size_type index);
806 
807  //@{
808  /**
809  * @brief Adds a sequence of elements as a range with specified offset
810  * @tparam ITER type of iterator
811  * @param offset where to add the elements
812  * @param first iterator to the first element to be added
813  * @param last iterator after the last element to be added
814  * @return the range where the new data was added
815  *
816  * If the offset is beyond the current end of the sparse vector, void is
817  * added before the new range.
818  *
819  * Existing ranges can be merged with the new data if they overlap.
820  */
821  template <typename ITER>
822  const datarange_t& add_range(size_type offset, ITER first, ITER last);
823 
824  /**
825  * @brief Copies the elements in container to a range with specified offset
826  * @tparam CONT type of container supporting the standard begin/end interface
827  * @param offset where to add the elements
828  * @param new_data container holding the data to be copied
829  * @return the range where the new data was added
830  *
831  * If the offset is beyond the current end of the sparse vector, void is
832  * added before the new range.
833  *
834  * Existing ranges can be merged with the new data if they overlap.
835  */
836  template <typename CONT>
837  const datarange_t& add_range(size_type offset, const CONT& new_data)
838  { return add_range(offset, new_data.begin(), new_data.end()); }
839 
840  /**
841  * @brief Adds a sequence of elements as a range with specified offset
842  * @param offset where to add the elements
843  * @param new_data container holding the data to be moved
844  * @return the range where the new data was added
845  *
846  * If the offset is beyond the current end of the sparse vector, void is
847  * added before the new range.
848  *
849  * Existing ranges can be merged with the new data if they overlap.
850  * If no merging happens, new_data vector is directly used as the new range
851  * added; otherwise, it is just copied.
852  */
853  const datarange_t& add_range(size_type offset, vector_t&& new_data);
854  //@}
855 
856  /// @{
857  /**
858  * @brief Combines a sequence of elements as a range with data at `offset`.
859  * @tparam ITER type of iterator
860  * @tparam OP combination operation
861  * @param offset where to add the elements
862  * @param first iterator to the first element to be added
863  * @param last iterator after the last element to be added
864  * @param op operation to be executed element by element
865  * @param void_value (default: `value_zero`) the value to use for void cells
866  * @return the range where the new data landed
867  *
868  * This is a more generic version of `add_range()`, where instead of
869  * replacing the target data with the data in [ `first`, `last` [, the
870  * existing data is combined with the one in that interval.
871  * The operation `op` is a binary operation with signature equivalent to
872  * `Data_t op(Data_t, Data_t)`, and the operation is equivalent to
873  * `v[i + offset] = op(v[i + offset], *(first + offset))`: `op` is a binary
874  * operation whose first operand is the existing value and the second one
875  * is the one being provided.
876  * If the cell `i + offset` is currently void, it will be created and the
877  * value used in the combination will be `void_value`.
878  *
879  * If the offset is beyond the current end of the sparse vector, void is
880  * added before the new range.
881  *
882  * Existing ranges can be merged with the new data if they overlap.
883  */
884  template <typename ITER, typename OP>
885  const datarange_t& combine_range(
886  size_type offset, ITER first, ITER last, OP&& op,
887  value_type void_value = value_zero
888  );
889 
890  /**
891  * @brief Combines the elements in container with the data at `offset`.
892  * @tparam CONT type of container supporting the standard begin/end interface
893  * @tparam OP combination operation
894  * @param offset where to add the elements
895  * @param other container holding the data to be combined
896  * @param op operation to be executed element by element
897  * @param void_value (default: `value_zero`) the value to use for void cells
898  * @return the range where the new data was added
899  * @see `combine_range()`
900  *
901  * This is equivalent to `combine_range(size_type, ITER, ITER, OP, Data_t)`
902  * using as the new data range the full content of `other` container.
903  */
904  template <typename CONT, typename OP>
905  const datarange_t& combine_range(
906  size_type offset, const CONT& other, OP&& op,
907  value_type void_value = value_zero
908  )
909  {
910  return combine_range(offset, other.begin(), other.end(),
911  std::forward<OP>(op), void_value);
912  }
913  /// @}
914 
915  //@{
916  /**
917  * @brief Adds a sequence of elements as a range at the end of the vector.
918  * @param first iterator to the first element to be added
919  * @param last iterator after the last element to be added
920  * @return the range where the new data was added
921  *
922  * The input range is copied at the end of the sparse vector.
923  * If the end of the sparse vector was the end of a range, that range is
924  * expanded, otherwise a new one is created.
925  */
926  template <typename ITER>
927  const datarange_t& append(ITER first, ITER last)
928  { return add_range(size(), first, last); }
929 
930  /**
931  * @brief Adds a sequence of elements as a range at the end of the vector.
932  * @param range_data contained holding the data to be copied or moved
933  * @return the range where the new data was added
934  *
935  * The input data is copied at the end of the sparse vector.
936  * If the end of the sparse vector was the end of a range, that range is
937  * expanded, otherwise a new one is created.
938  */
939  template <typename CONT>
940  const datarange_t& append(const CONT& range_data)
941  { return add_range(size(), range_data); }
942 
943  /**
944  * @brief Adds a sequence of elements as a range at the end of the vector.
945  * @param range_data contained holding the data to be copied or moved
946  * @return the range where the new data was added
947  *
948  * If there is a range at the end of the sparse vector, it will be expanded
949  * with the new data.
950  * Otherwise, this method will use the data vector directly as a new range
951  * added at the end of the sparse vector.
952  */
953  const datarange_t& append(vector_t&& range_data)
954  { return add_range(size(), std::move(range_data)); }
955  //@}
956 
957 
958  //@{
959  /**
960  * @brief Turns the specified range into void
961  * @param iRange iterator or index of range to be deleted
962  * @return the range just voided
963  * @see make_void(), unset_at()
964  *
965  * The range is effectively removed from the sparse vector, rendering void
966  * the interval it previously covered.
967  * The range object itself is returned (no copy is performed).
968  *
969  * The specified range must be valid. Trying to void an invalid range
970  * (including `end_range()`) yields undefined behavior.
971  */
972  datarange_t void_range(range_iterator const iRange);
973  datarange_t void_range(std::size_t const iRange)
974  { return void_range(ranges.begin() + iRange); }
975  //@}
976  ///@}
977 
978 
979  /**
980  * @brief Returns if the vector is in a valid state
981  *
982  * The vector is in a valid state if:
983  * - no ranges overlap or touch each other (a void gap must exist)
984  * - no range is empty
985  * - all ranges are sorted
986  * - the size of the vector is not smaller than the sum of the size of
987  * the ranges plus the internal gaps
988  * An invalid state can be the result of &ldquo;too smart&rdquo; use of this
989  * class, or of a bug, which should be reported to the author.
990  */
991  bool is_valid() const;
992 
993 
994  /// Makes all the elements from first and before last void
995  void make_void(iterator first, iterator last);
996 
997 
998  //@{
999  /// Performs internal optimization, returns whether the object was changed
1000  bool optimize() { return optimize(min_gap()); }
1001  bool optimize(size_t) { return false; /* no optimization implemented yet */ }
1002  //@}
1003 
1004 
1005  ///@{ @name Static members for dealing with this type of value
1006 
1007  static constexpr value_type value_zero{0}; ///< a representation of 0
1008 
1009  /// Returns the module of the specified value
1010  static value_type abs(value_type v) { return (v < value_zero)? -v: v; }
1011 
1012  /// Returns whether the value is exactly zero
1013  static value_type is_zero(value_type v) { return v == value_zero; }
1014 
1015  /// Returns whether the value is zero below a given threshold
1016  static value_type is_zero(value_type v, value_type thr)
1017  { return abs(v - value_zero) <= thr; }
1018 
1019  /// Returns whether two values are the same
1020  static value_type is_equal(value_type a, value_type b)
1021  { return is_zero(abs(a - b)); }
1022 
1023  /// Returns whether two values are the same below a given threshold
1024  static value_type is_equal(value_type a, value_type b, value_type thr)
1025  { return is_zero(abs(a - b), thr); }
1026  ///@}
1027 
1028  ///@{ @name Static members related to data size and optimization
1029 
1030  /// Returns the expected size taken by a vector of specified size
1031  static size_t expected_vector_size(size_t size);
1032 
1033  /// Minimum optimal gap between ranges (a guess)
1034  static size_t min_gap();
1035 
1036  /// Returns if merging the two specified ranges would save memory
1037  static bool should_merge(
1038  const typename datarange_t::base_t& a,
1039  const typename datarange_t::base_t& b
1040  );
1041  ///@}
1042 
1043  // --------------------------------------------------------------------------
1044  protected:
1045 
1046  size_type nominal_size; ///< current size
1047  range_list_t ranges; ///< list of ranges
1048 
1049  //@{
1050  /**
1051  * @brief Returns an iterator to the range after `index`.
1052  * @param index the absolute index
1053  * @return iterator to the next range not including index, or ranges.end()
1054  * if none
1055  */
1056  range_iterator find_next_range_iter(size_type index)
1057  { return find_next_range_iter(index, ranges.begin()); }
1058  range_const_iterator find_next_range_iter(size_type index) const
1059  { return find_next_range_iter(index, ranges.cbegin()); }
1060  //@}
1061  //@{
1062  /**
1063  * @brief Returns an iterator to the range after `index`,
1064  * or `ranges.end()` if none.
1065  * @param index the absolute index
1066  * @param rbegin consider only from this range on
1067  * @return iterator to the next range not including index, or `ranges.end()`
1068  * if none
1069  */
1070  range_iterator find_next_range_iter(size_type index, range_iterator rbegin);
1071  range_const_iterator find_next_range_iter
1072  (size_type index, range_const_iterator rbegin) const;
1073  //@}
1074 
1075  //@{
1076  /**
1077  * @brief Returns an iterator to the range at or after `index`.
1078  * @param index the absolute index
1079  * @return iterator to the next range including index or after it,
1080  * or ranges.end() if none
1081  * @see `find_next_range_iter()`
1082  *
1083  * If `index` is in a range, an iterator to that range is returned.
1084  * If `index` is in the void, an iterator to the next range after `index` is
1085  * returned. If there is no such range after `index`, `ranges.end()` is
1086  * returned.
1087  */
1088  range_iterator find_range_iter_at_or_after(size_type index);
1089  range_const_iterator find_range_iter_at_or_after(size_type index) const;
1090  //@}
1091 
1092  //@{
1093  /**
1094  * @brief Returns an iterator to the range no earlier than `index`,
1095  or `end()` if none.
1096  * @param index the absolute index
1097  * @return iterator to the range including index, or the next range if none
1098  *
1099  * The returned iterator points to a range that "borders" the specified index,
1100  * meaning that the cell at `index` is either within the range, or it is the
1101  * one immediately after that range.
1102  * If `index` is in the middle of the void, though (i.e. if the previous cell
1103  * is void), the next range is returned instead.
1104  * Finally, if there is no next range, `end_range()` is returned.
1105  *
1106  * The result may be also interpreted as follow: if the start of the returned
1107  * range is lower than `index`, then the cell at `index` belongs to that
1108  * range. Otherwise, it initiates its own range (but that range might end up
1109  * being contiguous to the next(.
1110  */
1111  range_iterator find_extending_range_iter(size_type index)
1112  { return find_extending_range_iter(index, ranges.begin()); }
1113  range_const_iterator find_extending_range_iter(size_type index) const
1114  { return find_extending_range_iter(index, ranges.cbegin()); }
1115  //@}
1116 
1117  //@{
1118  /**
1119  * @brief Returns an iterator to the range that contains the first non-void
1120  * element after `index`, or `end()` if none.
1121  * @param index the absolute index
1122  * @param rbegin consider only from this range on
1123  * @return iterator to the next range not including index, or `ranges.end()`
1124  * if none
1125  *
1126  * Note that the returned range can contain `index` as well.
1127  */
1128  range_iterator find_extending_range_iter
1129  (size_type index, range_iterator rbegin);
1130  range_const_iterator find_extending_range_iter
1131  (size_type index, range_const_iterator rbegin) const;
1132  //@}
1133 
1134  /// Returns the size determined by the ranges already present
1135  size_type minimum_size() const
1136  { return ranges.empty()? 0: ranges.back().end_index(); }
1137 
1138  //@{
1139  /// Plug a new data range in the specified position; no check performed
1140  range_iterator insert_range(range_iterator iInsert, const datarange_t& data)
1141  { return data.empty()? iInsert: ranges.insert(iInsert, data); }
1142  range_iterator insert_range(range_iterator iInsert, datarange_t&& data)
1143  { return data.empty()? iInsert: ranges.insert(iInsert, std::move(data)); }
1144  //@}
1145 
1146  /// Implementation detail of `add_range()`, with where to add the range.
1147  const datarange_t& add_range_before
1148  (size_type offset, vector_t&& new_data, range_iterator nextRange);
1149 
1150  /// Voids the starting elements up to index (excluded) of a given range
1151  range_iterator eat_range_head(range_iterator iRange, size_t index);
1152 
1153  /**
1154  * @brief Merges all the following contiguous ranges.
1155  * @param iRange iterator to the range to merge the following ones into
1156  * @return iterator to the merged range
1157  *
1158  * Starting from the range next to `iRange`, if that range is contiguous to
1159  * `iRange` the two are merged. The merging continues while there are
1160  * ranges contiguous to `iRange`. In the end, an iterator is returned pointing
1161  * to a range that has the same starting point that `iRange` had, and that is
1162  * not followed by a contiuguous range, since all contiguous ranges have been
1163  * merged into it.
1164  */
1165  datarange_t& merge_ranges(range_iterator iRange);
1166 
1167  /// Extends the vector size according to the last range
1168  size_type fix_size();
1169 
1170 }; // class sparse_vector<>
1171 
1172 
1173 } // namespace lar
1174 
1175 
1176 /**
1177  * @brief Prints a sparse vector into a stream
1178  * @tparam T template type of the sparse vector
1179  * @param out output stream
1180  * @param v the sparse vector to be written
1181  * @return the output stream (out)
1182  *
1183  * The output is in the form:
1184  * <pre>
1185  * Sparse vector of size ## with ## ranges:
1186  * [min1 - max1] (size1) { elements of the first range }
1187  * [min2 - max2] (size2) { elements of the second range }
1188  * ...
1189  * </pre>
1190  */
1191 template <typename T>
1192 std::ostream& operator<< (std::ostream& out, const lar::sparse_vector<T>& v);
1193 
1194 
1195 
1196 // -----------------------------------------------------------------------------
1197 // --- sparse_vector::datarange_t definition
1198 // ---
1199 
1200 /// Range class, with range and data
1201 template <typename T>
1202 class lar::sparse_vector<T>::datarange_t: public range_t<size_type> {
1203  public:
1204  typedef range_t<size_type> base_t; ///< base class
1205 
1206  typedef typename vector_t::iterator iterator;
1208 
1209  /// Default constructor: an empty range
1210  datarange_t(): base_t(), values() {}
1211 
1212  /// Constructor: range initialized with 0
1213  datarange_t(const base_t& range): base_t(range), values(range.size()) {}
1214 
1215  /// Constructor: offset and data
1216  template <typename ITER>
1217  datarange_t(size_type offset, ITER first, ITER last):
1218  base_t(offset, offset + std::distance(first, last)),
1219  values(first, last)
1220  {}
1221 
1222  /// Constructor: offset and data as a vector (which will be used directly)
1223  datarange_t(size_type offset, vector_t&& data):
1224  base_t(offset, offset + data.size()), values(data)
1225  {}
1226 
1227 
1228  //@{
1229  /// Returns an iterator to the specified absolute value (no check!)
1230  iterator get_iterator(size_type index)
1231  { return values.begin() + index - base_t::begin_index(); }
1232  const_iterator get_iterator(size_type index) const
1233  { return get_const_iterator(index); }
1234  const_iterator get_const_iterator(size_type index) const
1235  { return values.begin() + index - base_t::begin_index(); }
1236  //@}
1237 
1238  //@{
1239  /// begin and end iterators
1240  iterator begin() { return values.begin(); }
1241  iterator end() { return values.end(); }
1242  const_iterator begin() const { return values.begin(); }
1243  const_iterator end() const { return values.end(); }
1244  const_iterator cbegin() const { return values.cbegin(); }
1245  const_iterator cend() const { return values.cend(); }
1246  //@}
1247 
1248  //@{
1249  /// Resizes the range (optionally filling the new elements with def_value)
1250  void resize(size_t new_size)
1251  { values.resize(new_size); fit_size_from_data(); }
1252  void resize(size_t new_size, value_type def_value)
1253  { values.resize(new_size, def_value); fit_size_from_data(); }
1254  //@}
1255 
1256  //@{
1257  /// Returns the value at the specified absolute index
1258  value_type& operator[] (size_type index)
1259  { return values[base_t::relative_index(index)]; }
1260  const value_type& operator[] (size_type index) const
1261  { return values[base_t::relative_index(index)]; }
1262  //@}
1263 
1264  //@{
1265  /// Return the vector of data values
1266  const vector_t& data() const { return values; }
1267 // vector_t& data() { return values; }
1268  //@}
1269 
1270  /**
1271  * @brief Appends the specified elements to this range.
1272  * @tparam ITER type of iterator of the range
1273  * @param index the starting point
1274  * @param first iterator to the first object to copy
1275  * @param last iterator after the last object to copy
1276  * @return the extended range
1277  */
1278  template <typename ITER>
1279  datarange_t& extend(size_type index, ITER first, ITER last);
1280 
1281  /**
1282  * @brief Moves the begin of this range
1283  * @param to_index absolute index to move the head to
1284  * @param def_value value to be inserted in case of expansion of the range
1285  */
1286  void move_head(size_type to_index, value_type def_value = value_zero);
1287 
1288  /**
1289  * @brief Moves the end of this range
1290  * @param to_index absolute index to move the tail to
1291  * @param def_value value to be inserted in case of expansion of the range
1292  */
1293  void move_tail(size_type to_index, value_type def_value = value_zero)
1294  { resize(base_t::relative_index(to_index), def_value); }
1295 
1296  /**
1297  * @brief Dumps the content of this data range into a stream.
1298  * @tparam Stream type of stream to sent the dump to
1299  * @param out stream to sent the dump to
1300  *
1301  * The output format is:
1302  *
1303  * [min - max] (size) { values... }
1304  *
1305  * Output is on a single line, which is not terminated.
1306  */
1307  template <typename Stream>
1308  void dump(Stream&& out) const;
1309 
1310 
1311  protected:
1312  vector_t values; ///< data in the range
1313 
1314  void fit_size_from_data() { base_t::resize(values.size()); }
1315 
1316 }; // class datarange_t
1317 
1318 
1319 /**
1320  * @brief A constant reference to a data range.
1321  *
1322  * Values in the range can be modified, but their position and number can not.
1323  */
1324 template <typename T>
1326  public:
1329 
1330  // `range_t` interface
1331  using datarange_t::offset;
1332  using datarange_t::last;
1333  using datarange_t::begin_index;
1334  using datarange_t::end_index;
1335  using datarange_t::relative_index;
1336  using datarange_t::size;
1337  using datarange_t::empty;
1338  using datarange_t::includes;
1339  using datarange_t::overlap;
1340  using datarange_t::separate;
1341  using datarange_t::borders;
1342  using datarange_t::operator<;
1343  using datarange_t::operator==;
1344  using datarange_t::is_valid;
1345  using datarange_t::less;
1346  using less_int_range = typename datarange_t::less_int_range;
1347 
1348  // `datarange_t` interface
1349  using datarange_t::get_iterator;
1350  decltype(auto) begin() { return datarange_t::begin(); }
1351  decltype(auto) end() { return datarange_t::end(); }
1352 // using datarange_t::begin;
1353 // using datarange_t::end;
1354 // using datarange_t::cbegin;
1355 // using datarange_t::cend;
1356  using datarange_t::operator[];
1357  using datarange_t::dump;
1358 
1359  /// Return the vector of data values (only constant access).
1360  const vector_t& data() const { return base().values; }
1361 
1362  ~const_datarange_t() = delete; // can't destroy; can cast into it though
1363 
1364  protected:
1365  friend decltype(auto) details::make_const_datarange_t<T>(datarange_t&);
1366 
1367  datarange_t const& base() const
1368  { return static_cast<datarange_t const&>(*this); }
1369  datarange_t& base() { return static_cast<datarange_t&>(*this); }
1370 
1371  static void static_check()
1372  { static_assert(sizeof(const_datarange_t) == sizeof(datarange_t)); }
1373 
1374 }; // lar::sparse_vector<T>::const_datarange_t
1375 
1376 
1377 // -----------------------------------------------------------------------------
1378 // --- sparse_vector iterators definition
1379 // ---
1380 
1381 /// Special little box to allow void elements to be treated as references.
1382 template <typename T>
1384  protected:
1385  const value_type* ptr;
1386  public:
1387  const_reference(const value_type* pValue = 0): ptr(pValue) {}
1389 
1390  explicit operator value_type() const { return ptr? *ptr: value_zero; }
1391  operator const value_type&() const
1392  { return ptr? *ptr: value_zero; }
1393 }; // lar::sparse_vector<T>::const_reference
1394 
1395 
1396 /**
1397  * @brief A class representing a cell in a sparse vector.
1398  *
1399  * This class is a little box allowing assignment of values into it;
1400  * if the internal pointer is invalid (as in case of void cell),
1401  * dereferencing or assigning will provoke a segmentation fault.
1402  */
1403 template <typename T>
1405  friend class iterator;
1406 
1407  // This object "disappears" when assigned to: either the assignment is not
1408  // possible, and then a segmentation fault will occur, or the return value
1409  // is an actual C++ reference to the assigned value.
1410  // The same is true when explicitly converting it to a reference.
1411  public:
1412  reference(value_type* pValue = 0): const_reference(pValue) {}
1414 
1415  reference& operator=(const reference&) = default;
1417  { return const_cast<value_type&>(*const_reference::ptr) = v; }
1418 
1419  explicit operator value_type&()
1420  { return const_cast<value_type&>(*const_reference::ptr); }
1421 
1422  protected:
1423  explicit reference(const const_reference& from): const_reference(from) {}
1424 
1425 }; // lar::sparse_vector<T>::reference
1426 
1427 
1428 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1429 /// Iterator to the sparse vector values
1430 template <typename T>
1432  //
1433  // This iterator fulfils the traits of an immutable forward iterator.
1434  //
1435 
1436  protected:
1437  friend class container_t;
1438 
1442 
1443 
1444  public:
1445  // so far, only forward interface is implemented;
1446  // backward is tricky...
1447  typedef std::forward_iterator_tag iterator_category;
1448 
1449  /// Namespace for special initialization
1450  struct special {
1451  class begin {};
1452  class end {};
1453  };
1454 
1455  // types
1458  typedef typename container_t::pointer pointer;
1460  // note that this is not out little box, it's the normal C++ constant
1461  // reference from the underlying vector
1462  typedef typename vector_t::const_reference const_reference;
1463 
1464 
1465  /// Default constructor, does not iterate anywhere
1466  const_iterator(): cont(nullptr), index(0), currentRange() {}
1467 
1468  /// Constructor from a container and a offset
1469  const_iterator(const container_t& c, size_type offset):
1470  cont(&c), index(std::min(offset, c.size())), currentRange()
1471  { refresh_state(); }
1472 
1473  /// Special constructor: initializes at the beginning of the container
1474  const_iterator(const container_t& c, const typename special::begin):
1475  cont(&c), index(0), currentRange(c.get_ranges().begin())
1476  {}
1477 
1478  /// Special constructor: initializes at the end of the container
1479  const_iterator(const container_t& c, const typename special::end):
1480  cont(&c), index(c.size()), currentRange(c.get_ranges().end())
1481  {}
1482 
1483  /// Random access
1484  const_reference operator[] (size_type offset) const
1485  { return (*cont)[index + offset]; }
1486 
1487  /// Constant dereferenciation operator
1488  const_reference operator*() const;
1489 
1490  //@{
1491  /// Increment and decrement operators
1492  const_iterator& operator++();
1494  { const_iterator copy(*this); const_iterator::operator++(); return copy; }
1495  //@}
1496 
1497 
1498  //@{
1499  /// Increment and decrement operators
1500  const_iterator& operator+= (difference_type delta);
1501  const_iterator& operator-= (difference_type delta);
1502  const_iterator operator+ (difference_type delta) const;
1503  const_iterator operator- (difference_type delta) const;
1504  //@}
1505 
1506  /// Distance operator
1507  difference_type operator- (const const_iterator& iter) const;
1508 
1509  //@{
1510  /// Iterator comparisons
1511  bool operator== (const const_iterator& as) const
1512  { return (cont == as.cont) && (index == as.index); }
1513  bool operator!= (const const_iterator& as) const
1514  { return (cont != as.cont) || (index != as.index); }
1515  bool operator< (const const_iterator& than) const
1516  { return (cont == than.cont) && (index < than.index); }
1517  bool operator> (const const_iterator& than) const
1518  { return (cont == than.cont) && (index > than.index); }
1519  bool operator<= (const const_iterator& than) const
1520  { return (cont == than.cont) && (index <= than.index); }
1521  bool operator>= (const const_iterator& than) const
1522  { return (cont == than.cont) && (index >= than.index); }
1523  //@}
1524 
1525  /// Returns the current range internal value; use it at your own risk!!
1526  range_const_iterator get_current_range() const { return currentRange; }
1527 
1528  protected:
1529  //
1530  // Logic of the internals:
1531  // - cont provides the list of ranges
1532  // - index is the absolute index in the container
1533  // - currentRange is a pointer to the "current" range, cached for speed
1534  //
1535  // An iterator past-the-end has the index equal to the size of the
1536  // container it points to. Operations on it are undefined, except that
1537  // going backward by one decrement goes back to the container
1538  // (if not empty) TODO currently backward iteration is not supported
1539  //
1540  // When the iterator is pointing to an element within a range,
1541  // currentRange points to that range.
1542  // When the iterator is pointing into the void of the vector, currentRange
1543  // points to the range next to that void area, or end() if there is none.
1544  // When the iterator is past-the-end, currentRange is not defined.
1545  //
1546  // Conversely, when the index is equal (or greater) to the size of the
1547  // container, the iterator is not dereferenciable, the iterator points
1548  // past-the-end of the container.
1549  // When currentRange points to a valid range and the index
1550  // is before that range, the iterator is pointing to the void.
1551  // When currentRange points to a valid range and the index
1552  // is inside that range, the iterator is pointing to an item in that
1553  // range.
1554  // When currentRange points to a valid range, the index can't point beyond
1555  // that range.
1556  // When currentRange points to the past-to-last range, the iterator is
1557  // pointing to the void (past the last range).
1558  //
1559  const container_t* cont; ///< pointer to the container
1560  size_type index; ///< pointer to the current value, as absolute index
1561  ranges_const_iterator currentRange; ///< pointer to the current (or next) range
1562 
1563  /// Reassigns the internal state according to the index
1564  void refresh_state();
1565 
1566 }; // class lar::sparse_vector<T>::const_iterator
1567 
1568 
1569 /**
1570  * @brief Iterator to the sparse vector values
1571  *
1572  * This iterator respects the traits of an immutable forward iterator,
1573  * EXCEPT that the iterator can be non-dereferenciable even when it's a
1574  * "past the end" iterator.
1575  * That is due to the fact that currently dereferencing (and assigning)
1576  * to a cell which is not in a range already is not supported yet
1577  * (it can be done with some complicate mechanism).
1578  */
1579 template <typename T>
1581  typedef typename const_iterator::container_t container_t;
1582  friend typename const_iterator::container_t;
1583 
1584  public:
1585  typedef typename const_iterator::reference reference;
1586  typedef typename const_iterator::const_reference const_reference;
1587  typedef typename const_iterator::special special;
1588 
1589  /// Default constructor, does not iterate anywhere
1591 
1592  /// Constructor from a container and an offset
1593  iterator(container_t& c, size_type offset = 0):
1594  const_iterator(c, offset) {}
1595 
1596  /// Special constructor: initializes at the beginning of the container
1597  iterator(const container_t& c, const typename special::begin _):
1598  const_iterator(c, _) {}
1599 
1600  /// Special constructor: initializes at the end of the container
1601  iterator(const container_t& c, const typename special::end _):
1602  const_iterator(c, _) {}
1603 
1604  /// Random access
1605  reference operator[] (size_type offset) const
1606  { return (*const_iterator::cont)[const_iterator::index + offset]; }
1607 
1608  //@{
1609  /// Increment and decrement operators
1612  //@}
1613 
1614  //@{
1615  /// Increment and decrement operators
1616  iterator& operator+= (difference_type delta)
1617  { const_iterator::operator+=(delta); return *this; }
1618  iterator& operator-= (difference_type delta)
1619  { const_iterator::operator+=(delta); return *this; }
1620  iterator operator+ (difference_type delta) const
1621  { return const_iterator::operator+(delta); }
1622  iterator operator- (difference_type delta) const
1623  { return const_iterator::operator-(delta); }
1624  //@}
1625 
1626 
1627  /// Dereferenciation operator (can't write non-empty elements!)
1628  reference operator*() const
1629  { return reference(const_iterator::operator*()); }
1630 
1631 // /// Returns the current range internal value; use it at your own risk!!
1632 // range_iterator get_current_range() const
1633 // { return const_iterator::currentRange; }
1634 
1635  protected:
1636 
1637  // also worth conversion
1639 
1640 }; // class lar::sparse_vector<T>::iterator
1641 
1642 
1643 
1644 // -----------------------------------------------------------------------------
1645 // --- implementation --------------------------------------------------------
1646 // -----------------------------------------------------------------------------
1647 namespace lar::details {
1648 
1649  // --------------------------------------------------------------------------
1650  /// Enclosure to use two iterators representing a range in a range-for loop.
1651  template <typename BITER, typename EITER>
1653  BITER b;
1654  EITER e;
1655  public:
1656  iteratorRange(BITER const& b, EITER const& e): b(b), e(e) {}
1657  auto const& begin() const { return b; }
1658  auto const& end() const { return e; }
1659  auto const& size() const { return std::distance(begin(), end()); }
1660  }; // iteratorRange()
1661 
1662 
1663  // --------------------------------------------------------------------------
1664  template <typename T>
1665  decltype(auto) make_const_datarange_t
1667  { return static_cast<typename sparse_vector<T>::const_datarange_t&>(r); }
1668 
1669 
1670  // --------------------------------------------------------------------------
1671  template <typename T>
1676  public:
1677  // minimal set of features for ranged-for loops
1678  const_datarange_iterator() = default;
1680 
1681  const_datarange_iterator& operator++() { ++it; return *this; }
1683  { return make_const_datarange_t<T>(*it); }
1685  { return it != other.it; }
1686 
1687  };
1688 
1689  // --------------------------------------------------------------------------
1690 
1691 } // namespace lar::details
1692 
1693 
1694 //------------------------------------------------------------------------------
1695 //--- sparse_vector implementation
1696 
1697 template <typename T>
1698 constexpr typename lar::sparse_vector<T>::value_type
1700 
1701 template <typename T>
1702 decltype(auto) lar::sparse_vector<T>::iterate_ranges() {
1703  return details::iteratorRange(
1706  );
1707 } // lar::sparse_vector<T>::iterate_ranges()
1708 
1709 template <typename T>
1710 void lar::sparse_vector<T>::resize(size_type new_size) {
1711  if (new_size >= size()) {
1712  nominal_size = new_size;
1713  return;
1714  }
1715 
1716  // truncating...
1717  range_iterator iLastRange = find_next_range_iter(new_size);
1718  ranges.erase(iLastRange, ranges.end());
1719  if (!ranges.empty()) {
1720  range_iterator iLastRange = ranges.end() - 1;
1721  if (new_size == iLastRange->begin_index())
1722  ranges.erase(iLastRange);
1723  else if (new_size < iLastRange->end_index())
1724  iLastRange->resize(new_size - iLastRange->begin_index());
1725  } // if we have ranges
1726 
1727  // formally resize
1728  nominal_size = new_size;
1729 } // lar::sparse_vector<T>::resize()
1730 
1731 
1732 template <typename T>
1733 void lar::sparse_vector<T>::resize(size_type new_size, value_type def_value) {
1734  if (new_size == size()) return;
1735  if (new_size > size()) {
1736 
1737  if (back_is_void()) // add a new range
1738  append(vector_t(new_size - size(), def_value));
1739  else // extend the last range
1740  ranges.back().resize(new_size - ranges.back().begin_index(), def_value);
1741 
1742  nominal_size = new_size;
1743  return;
1744  }
1745  // truncating is the same whether there is a default value or not
1746  resize(new_size);
1747 } // lar::sparse_vector<T>::resize()
1748 
1749 
1750 template <typename T>
1752  { return iterator(*this, typename iterator::special::begin()); }
1753 
1754 template <typename T>
1756  { return iterator(*this, typename iterator::special::end()); }
1757 
1758 template <typename T>
1761  { return const_iterator(*this, typename const_iterator::special::begin()); }
1762 
1763 template <typename T>
1766  { return const_iterator(*this, typename const_iterator::special::end()); }
1767 
1768 template <typename T>
1770  (size_type index) const
1771 {
1772  // first range not including the index
1773  range_const_iterator iNextRange = find_next_range_iter(index);
1774 
1775  // if not even the first range includes the index, we are in the void
1776  // (or in some negative index space, if index signedness allowed);
1777  if (iNextRange == ranges.begin()) return value_zero;
1778 
1779  // otherwise, let's take the previous range;
1780  // if it includes the index, we return its value;
1781  // or it precedes it, and our index is in the void: return zero
1782  const datarange_t& range(*--iNextRange);
1783  return (index < range.end_index())? range[index]: value_zero;
1784 } // lar::sparse_vector<T>::operator[]
1785 
1786 
1787 template <typename T>
1789  (size_type index)
1790 {
1791  // first range not including the index
1792  range_iterator iNextRange = find_next_range_iter(index);
1793 
1794  // if not even the first range includes the index, we are in the void
1795  // (or in some negative index space, if index signedness allowed);
1796  if (iNextRange == ranges.begin()) return reference();
1797 
1798  // otherwise, let's take the previous range;
1799  // if it includes the index, we return its value;
1800  // or it precedes it, and our index is in the void: return zero
1801  datarange_t& range(*--iNextRange);
1802  return (index < range.end_index())? reference(range[index]): reference();
1803 } // lar::sparse_vector<T>::operator[]
1804 
1805 
1806 template <typename T>
1807 bool lar::sparse_vector<T>::is_void(size_type index) const {
1808  if (ranges.empty() || (index >= size()))
1809  throw std::out_of_range("empty sparse vector");
1810  // range after the index:
1811  range_const_iterator iNextRange = find_next_range_iter(index);
1812  return ((iNextRange == ranges.begin())
1813  || ((--iNextRange)->end_index() <= index));
1814 } // lar::sparse_vector<T>::is_void()
1815 
1816 
1817 template <typename T>
1819  const
1820 {
1821  return std::accumulate(begin_range(), end_range(), size_type(0),
1822  [](size_type s, const datarange_t& rng) { return s + rng.size(); }
1823  );
1824 } // count()
1825 
1826 
1827 template <typename T>
1829  (size_type const index, value_type value)
1830 {
1831  // first range not including the index
1832  range_iterator iNextRange = find_next_range_iter(index);
1833 
1834  // if not even the first range includes the index, we are in the void
1835  // (or in some negative index space, if index signedness allowed);
1836  if (iNextRange != ranges.begin()) {
1837  // otherwise, let's take the previous range;
1838  // if it includes the index, we set the existing value;
1839  // or it precedes it, and our index is in the void, add the value as a
1840  // range
1841  datarange_t& range(*std::prev(iNextRange));
1842  if (index < range.end_index()) return range[index] = value;
1843  }
1844  // so we are in the void; add the value as a new range
1845  return const_cast<datarange_t&>(add_range(index, { value }))[index];
1846 } // lar::sparse_vector<T>::set_at()
1847 
1848 
1849 template <typename T>
1850 void lar::sparse_vector<T>::unset_at(size_type index) {
1851  // first range not including the index
1852  range_iterator iNextRange = find_next_range_iter(index);
1853 
1854  // if not even the first range includes the index, we are in the void
1855  // (or in some negative index space, if index signedness allowed);
1856  if (iNextRange == ranges.begin()) return;
1857 
1858  // otherwise, let's take the previous range;
1859  // or it precedes the index, and our index is in the void
1860  datarange_t& range(*--iNextRange);
1861  if (index >= range.end_index()) return; // void already
1862 
1863  // it includes the index:
1864  // - if it's a one-element range, remove the range
1865  if (range.size() == 1) ranges.erase(iNextRange);
1866  // - if it's on a border, resize the range
1867  else if (index == range.begin_index())
1868  range.move_head(index + 1);
1869  else if (index == range.end_index() - 1)
1870  range.move_tail(index);
1871  // - if it's inside, break the range in two
1872  else if (index < range.end_index()) {
1873  // we are going to put a hole in a range;
1874  // this effectively creates two ranges;
1875  // first create the rightmost range, and add it to the list
1876  ranges.emplace(++iNextRange, index + 1,
1877  range.begin() + range.relative_index(index + 1),
1878  range.end()
1879  );
1880  // then cut the existing one
1881  range.move_tail(index);
1882  }
1883 } // lar::sparse_vector<T>::unset_at()
1884 
1885 
1886 template <typename T>
1887 auto lar::sparse_vector<T>::range_data(std::size_t const i)
1888  { auto& r = ranges[i]; return details::iteratorRange(r.begin(), r.end()); }
1889 
1890 template <typename T>
1891 auto lar::sparse_vector<T>::range_const_data(std::size_t const i) const
1892  { auto& r = ranges[i]; return details::iteratorRange(r.cbegin(), r.cend()); }
1893 
1894 
1895 template <typename T>
1898 {
1899  if (ranges.empty()) throw std::out_of_range("empty sparse vector");
1900  // range after the index:
1901  range_const_iterator iNextRange = find_next_range_iter(index);
1902  return ((iNextRange == ranges.begin())
1903  || (index >= (--iNextRange)->end_index()))?
1904  ranges.end(): iNextRange;
1905 } // lar::sparse_vector<T>::find_range_iterator() const
1906 
1907 
1908 template <typename T>
1909 const typename lar::sparse_vector<T>::datarange_t&
1910  lar::sparse_vector<T>::find_range(size_type index) const
1911 {
1912  if (ranges.empty()) throw std::out_of_range("empty sparse vector");
1913  // range on the index:
1914  range_const_iterator iNextRange = find_range_iterator(index);
1915  if (iNextRange == ranges.end())
1916  throw std::out_of_range("index in no range of the sparse vector");
1917  return *iNextRange;
1918 } // lar::sparse_vector<T>::find_range() const
1919 
1920 template <typename T>
1921 inline typename lar::sparse_vector<T>::datarange_t&
1923 {
1924  return const_cast<datarange_t&>
1925  (const_cast<const this_t*>(this)->find_range(index));
1926 } // lar::sparse_vector<T>::find_range()
1927 
1928 
1929 template <typename T>
1931  if (ranges.empty() || (index >= size()))
1932  throw std::out_of_range("empty sparse vector");
1933  // range after the index:
1934  range_iterator iNextRange = find_next_range_iter(index);
1935  if ((iNextRange == ranges.begin())
1936  || ((--iNextRange)->end_index() <= index))
1937  {
1938  return {};
1939  }
1940  return void_range(iNextRange);
1941 } // lar::sparse_vector<T>::make_void_around()
1942 
1943 
1944 template <typename T> template <typename ITER>
1946  (size_type offset, ITER first, ITER last)
1947 {
1948  // insert the new range before the existing range which starts after offset
1949  range_iterator iInsert = find_next_range_iter(offset);
1950 
1951  // is there a range before this, which includes the offset?
1952  if ((iInsert != ranges.begin()) && std::prev(iInsert)->borders(offset)) {
1953  // then we should extend it
1954  (--iInsert)->extend(offset, first, last);
1955  }
1956  else {
1957  // no range before the insertion one includes the offset of the new range;
1958  // ... we need to add it as a new range
1959  iInsert = insert_range(iInsert, { offset, first, last });
1960  }
1961  return merge_ranges(iInsert);
1962 } // lar::sparse_vector<T>::add_range<ITER>()
1963 
1964 
1965 template <typename T>
1967  (size_type offset, vector_t&& new_data)
1968 {
1969  // insert the new range before the existing range which starts after offset
1970  return add_range_before(offset, std::move(new_data),
1971  std::upper_bound(
1972  ranges.begin(), ranges.end(), offset,
1973  typename datarange_t::less_int_range(datarange_t::less)
1974  )
1975  );
1976 
1977 } // lar::sparse_vector<T>::add_range(vector)
1978 
1979 
1980 template <typename T>
1981 template <typename ITER, typename OP>
1983  size_type offset, ITER first, ITER last, OP&& op,
1984  value_type void_value /* = value_zero */
1985  )
1986  -> const datarange_t&
1987 {
1988  /*
1989  * This is a complicate enough task, that we go brute force:
1990  * 1) combine all the input elements within the datarange where offset falls
1991  * in
1992  * 2) create a new datarange combining void with the remaining input elements
1993  * 3) if the void area is over before the input elements are, repeat steps
1994  * (1) and (2) with the updated offset
1995  * 4) at this point we'll have a train of contiguous ranges, result of
1996  * combination of the input elements alternating with existing elements
1997  * and with void cells: apply the regular merge algorithm
1998  *
1999  */
2000 
2001  auto src = first;
2002  auto const insertionPoint = offset; // saved for later
2003  auto destRange = find_range_iter_at_or_after(offset);
2004  while (src != last) {
2005 
2006  //
2007  // (1) combine all the input elements within the datarange including offset
2008  // (NOT extending the range)
2009  //
2010  if ((destRange != end_range()) && destRange->includes(offset)) {
2011  // combine input data until this range is over (or input data is over)
2012  auto dest = destRange->get_iterator(offset);
2013 
2014  auto const end = destRange->end();
2015  while (src != last) {
2016  *dest = op(*dest, *src);
2017  ++src;
2018  ++offset;
2019  if (++dest == end) break;
2020  } // while
2021  if (src == last) break;
2022  offset = destRange->end_index();
2023  ++destRange;
2024  } // if
2025 
2026  //
2027  // (2) create a new datarange combining void with input elements
2028  //
2029  // at this point, offset is in the void, we do have more input data,
2030  // and `destRange` does _not_ contain the current insertion offset;
2031  // we fill as much void as we can with data, creating a new range.
2032  // When to stop? at the beginning of the next range, or when data is over
2033  //
2034  size_type const newRangeSize = (destRange == end_range())
2035  ? std::distance(src, last): (destRange->begin_index() - offset);
2036 
2037  // prepare the data (we'll plug it in directly)
2038  vector_t combinedData;
2039  combinedData.reserve(newRangeSize);
2040  size_type i = 0;
2041  while (i++ < newRangeSize) {
2042  combinedData.push_back(op(void_value, *src));
2043  if (++src == last) break; // no more data
2044  }
2045  // move the data as a new range inserted before the next range we just found
2046  // return value is the iterator to the inserted range
2047  destRange = insert_range(destRange, { offset, std::move(combinedData) });
2048 
2049  //
2050  // (3) if there is more input, repeat steps (1) and (2) with updated offset
2051  //
2052  offset = destRange->end_index();
2053  ++destRange;
2054  } // while
2055 
2056  //
2057  // (4) apply the regular merge algorithm;
2058  // since we did not extend existing ranges, it may happen that we have
2059  // created a new range at `insertionPoint` contiguous to the previous one;
2060  // so we take care of checking that too
2061  //
2062  return merge_ranges
2063  (find_extending_range_iter(insertionPoint == 0? 0: insertionPoint - 1));
2064 
2065 } // lar::sparse_vector<T>::combine_range<ITER>()
2066 
2067 
2068 template <typename T>
2070  // iterators have in "currentRange" either the range they point into,
2071  // or the range next to the void they point to
2072 
2073  if ((first.cont != this) || (last.cont != this)) {
2074  throw std::runtime_error
2075  ("lar::sparse_vector::make_void(): iterators from alien container");
2076  }
2077  // if first is after next, no range is identified
2078  if (first >= last) return;
2079 
2081  first_range
2082  = ranges.begin() + (first.get_current_range() - ranges.begin()),
2083  last_range = ranges.begin() + (last.get_current_range() - ranges.begin());
2084 
2085  //--- "first": void up to this iterator ---
2086  // if first in the last void region, there is nothing to erase
2087  if (first_range == ranges.end()) return;
2088 
2089  // if first is in the middle of a valid range instead, we have to resize it
2090  if (first.index > first_range->begin_index()) {
2091  if (first_range == last_range) {
2092  // we are going to erase a subset of a range;
2093  // this effectively creates two ranges;
2094  // first create the rightmost (last) range, and add it to the list
2095  last_range = ranges.emplace(++last_range, last.index,
2096  first_range->begin() + first_range->relative_index(last.index),
2097  first_range->end()
2098  );
2099  // then cut the existing one
2100  first_range->move_tail(first.index);
2101  return;
2102  }
2103  first_range->move_tail(first.index);
2104  ++first_range; // from next range on, start voiding
2105  }
2106 
2107  //--- "last"
2108  // if the index is inside a range, remove up to it
2109  if ((last_range != ranges.end()) && (last.index > last_range->begin_index()))
2110  eat_range_head(last_range, last.index);
2111 
2112  // finally, remove entirely the ranges in between
2113  ranges.erase(first_range, last_range);
2114 } // lar::sparse_vector<T>::make_void()
2115 
2116 
2117 template <typename T>
2119  auto r { std::move(*iRange) }; // triggering move constructor
2120  ranges.erase(iRange); // the emptied range is removed from vector
2121  return r; // returning it as a temporary avoids copies
2122 } // lar::sparse_vector<T>::void_range()
2123 
2124 
2125 template <typename T>
2127  // a sparse vector with no non-null elements can't be detected invalid
2128  if (ranges.empty()) return true;
2129 
2130  range_const_iterator iNext = ranges.begin(), rend = ranges.end();
2131  while (iNext != rend) {
2132  range_const_iterator iRange = iNext++;
2133  if (iRange->empty()) return false;
2134  if (iNext != rend) {
2135  if (!(*iRange < *iNext)) return false;
2136  if (!iRange->separate(*iNext)) return false;
2137  }
2138  } // while
2139  if (nominal_size < ranges.back().end_index()) return false;
2140  return true;
2141 } // lar::sparse_vector<T>::is_valid()
2142 
2143 
2144 
2145 // --- private methods
2146 
2147 template <typename T>
2150  (size_type index, range_iterator rbegin)
2151 {
2152  // this range has the offset (first index) above the index argument:
2153  return std::upper_bound(
2154  rbegin, ranges.end(), index,
2155  typename datarange_t::less_int_range(datarange_t::less)
2156  );
2157 } // lar::sparse_vector<T>::find_next_range_iter()
2158 
2159 template <typename T>
2162  (size_type index, range_const_iterator rbegin) const
2163 {
2164  // this range has the offset (first index) above the index argument:
2165  return std::upper_bound(
2166  rbegin, ranges.end(), index,
2167  typename datarange_t::less_int_range(datarange_t::less)
2168  );
2169 } // lar::sparse_vector<T>::find_next_range_iter() const
2170 
2171 
2172 template <typename T>
2175 {
2176  // this range has the offset (first index) above the index argument:
2177  auto after = find_next_range_iter(index);
2178  // if the previous range exists and contains index, that's the one we want
2179  return ((after != ranges.begin()) && (index < std::prev(after)->end_index()))
2180  ? std::prev(after): after;
2181 } // lar::sparse_vector<T>::find_range_iter_at_or_after() const
2182 
2183 
2184 template <typename T>
2187 {
2188  // this range has the offset (first index) above the index argument:
2189  auto after = find_next_range_iter(index);
2190  // if the previous range exists and contains index, that's the one we want
2191  return ((after != ranges.begin()) && (index < std::prev(after)->end_index()))
2192  ? std::prev(after): after;
2193 } // lar::sparse_vector<T>::find_range_iter_at_or_after()
2194 
2195 
2196 template <typename T>
2199  (size_type index, range_iterator rbegin)
2200 {
2201  // this range has the offset (first index) above the index argument:
2202  auto it = find_next_range_iter(index, rbegin);
2203  // if index were not void, would it belong to the previous range?
2204  // if so, the previous range is the one we want
2205  return ((it != rbegin) && std::prev(it)->borders(index))? std::prev(it): it;
2206 } // lar::sparse_vector<T>::find_extending_range_iter()
2207 
2208 
2209 template <typename T>
2212  (size_type index, range_const_iterator rbegin) const
2213 {
2214  // this range has the offset (first index) above the index argument:
2215  auto it = find_next_range_iter(index, rbegin);
2216  // if index were not void, would it belong to the previous range?
2217  // if so, the previus range is the one we want
2218  return ((it != rbegin) && std::prev(it)->borders(index))? std::prev(it): it;
2219 } // lar::sparse_vector<T>::find_extending_range_iter() const
2220 
2221 
2222 template <typename T>
2224  (size_type offset, vector_t&& new_data, range_iterator nextRange)
2225 {
2226  // insert the new range before the existing range which starts after offset
2227  range_iterator iInsert = nextRange;
2228 
2229  // is there a range before this, which includes the offset?
2230  if ((iInsert != ranges.begin()) && (iInsert-1)->borders(offset)) {
2231  // then we should extend it
2232  (--iInsert)->extend(offset, new_data.begin(), new_data.end());
2233  }
2234  else {
2235  // no range before the insertion one includes the offset of the new range;
2236  // ... we need to add it as a new range;
2237  // it is not really clear to me [GP] why I need a std::move here, since
2238  // new_data is a rvalue already; in doubt, I have painted all this kind
2239  // of constructs with move()s, just in case
2240  iInsert = insert_range(iInsert, { offset, std::move(new_data) });
2241  }
2242  return merge_ranges(iInsert);
2243 } // lar::sparse_vector<T>::add_range_before(vector, iterator)
2244 
2245 
2246 template <typename T>
2249 {
2250  range_iterator iNext = iRange + 1;
2251  while (iNext != ranges.end()) {
2252  if (!iRange->borders(iNext->begin_index())) break;
2253  // iRange content dominates, but if iNext has data beyond it,
2254  // then we copy it
2255  if (iNext->end_index() > iRange->end_index()) {
2256  iRange->extend
2257  (iRange->end_index(), iNext->get_iterator(iRange->end_index()), iNext->end());
2258  }
2259  iNext = ranges.erase(iNext);
2260  } // while
2261  fix_size();
2262  return *iRange;
2263 } // lar::sparse_vector<T>::merge_ranges()
2264 
2265 
2266 template <typename T>
2268  (range_iterator iRange, size_t index)
2269 {
2270  if (index <= iRange->begin_index()) return iRange;
2271  if (index >= iRange->end_index()) return ranges.erase(iRange);
2272  iRange->move_head(index);
2273  return iRange;
2274 } // lar::sparse_vector<T>::eat_range_head()
2275 
2276 
2277 template <typename T>
2279  if (!ranges.empty())
2280  nominal_size = std::max(nominal_size, ranges.back().end_index());
2281  return nominal_size;
2282 } // lar::sparse_vector<T>::fix_size()
2283 
2284 
2285 // --- static methods
2286 
2287 template <typename T>
2289  // apparently, a chunk of heap memory takes at least 32 bytes;
2290  // that means that a vector of 1 or 5 32-bit integers takes the same
2291  // space; the overhead appears to be 8 bytes, which can be allocated
2292  return sizeof(vector_t)
2293  + std::max(size_t(32), (alignof(datarange_t)*size + 8));
2294 } // lar::sparse_vector<T>::expected_vector_size()
2295 
2296 
2297 template <typename T>
2299  // we assume here that there is no additional overhead by alignment;
2300  // the gap adds the space of another datarange_t, including the vector,
2301  // its data and overhead from heap (apparently, 8 bytes);
2302  //
2303  return (sizeof(datarange_t) + 8) / sizeof(value_type) + 1; // round up
2304 } // lar::sparse_vector<T>::min_gap()
2305 
2306 
2307 template <typename T>
2309  const typename datarange_t::base_t& a,
2310  const typename datarange_t::base_t& b
2311  )
2312 {
2313  size_type gap_size = (a < b)?
2314  b.begin_index() - a.begin_index() - a.size():
2315  a.begin_index() - b.begin_index() - b.size();
2316  return expected_vector_size(a.size() + b.size() + gap_size)
2317  <= expected_vector_size(a.size()) + expected_vector_size(b.size());
2318 } // lar::sparse_vector<T>::should_merge()
2319 
2320 
2321 
2322 // --- non-member functions
2323 template <typename T>
2324 std::ostream& operator<< (std::ostream& out, const lar::sparse_vector<T>& v) {
2325 
2326  out << "Sparse vector of size " << v.size() << " with "
2327  << v.get_ranges().size() << " ranges:";
2329  iRange = v.begin_range(), rend = v.end_range();
2330  while (iRange != rend) {
2331  out << "\n ";
2332  iRange->dump(out);
2333  /*
2334  out << "\n [" << iRange->begin_index() << " - " << iRange->end_index()
2335  << "] (" << iRange->size() << "):";
2336  typename lar::sparse_vector<T>::datarange_t::const_iterator
2337  iValue = iRange->begin(), vend = iRange->end();
2338  while (iValue != vend) out << " " << (*(iValue++));
2339  */
2340  ++iRange;
2341  } // for
2342  return out << std::endl;
2343 } // operator<< (ostream, sparse_vector<T>)
2344 
2345 
2346 
2347 // -----------------------------------------------------------------------------
2348 // --- lar::sparse_vector<T>::datarange_t implementation
2349 // ---
2350 template <typename T> template <typename ITER>
2352  (size_type index, ITER first, ITER last)
2353 {
2354  size_type new_size = std::max(
2355  base_t::relative_index(index) + std::distance(first, last),
2356  base_t::size());
2357  base_t::resize(new_size);
2358  values.resize(new_size);
2359  std::copy(first, last, get_iterator(index));
2360  return *this;
2361 } // lar::sparse_vector<T>::datarange_t::extend()
2362 
2363 
2364 template <typename T>
2366  (size_type to_index, value_type def_value /* = value_zero */)
2367 {
2368  difference_type delta = to_index - base_t::begin_index();
2369  if (delta == 0) return;
2370  base_t::move_head(delta);
2371  if (delta > 0) // shrink
2372  values.erase(values.begin(), values.begin() + delta);
2373  else { // extend
2374  values.insert(values.begin(),
2376  value_const_iterator<value_type>(def_value) - delta
2377  );
2378  }
2379 } // lar::sparse_vector<T>::datarange_t::move_head()
2380 
2381 
2382 template <typename T>
2383 template <typename Stream>
2385  out << "[" << this->begin_index() << " - " << this->end_index() << "] ("
2386  << this->size() << "): {";
2387  for (auto const& v: this->values) out << " " << v;
2388  out << " }";
2389 } // lar::sparse_vector<T>::datarange_t::dump()
2390 
2391 
2392 // -----------------------------------------------------------------------------
2393 // --- lar::sparse_vector<T>::const_iterator implementation
2394 // ---
2395 template <typename T>
2398  // no container, not doing anything;
2399  // index beyond the end: stays there
2400  if (!cont || (index >= cont->size())) return *this;
2401 
2402  // increment the internal index
2403  ++index;
2404 
2405  // were we in a valid range?
2406  if (currentRange != cont->ranges.end()) {
2407  // if the new index is beyond the current range, pick the next
2408  if (currentRange->end_index() <= index) ++currentRange;
2409  }
2410  // if we have no valid range, we are forever in the void
2411  return *this;
2412 } // lar::sparse_vector<T>::iterator::operator++()
2413 
2414 
2415 template <typename T>
2418  // no container, no idea what to do
2419  if (!cont) throw std::out_of_range("iterator to no sparse vector");
2420 
2421  // index beyond the end: can't return any reference
2422  if (index >= cont->size()) return value_zero;
2423 
2424  // are we in a valid range? if not, we are past the last range
2425  if (currentRange == cont->ranges.end()) return value_zero;
2426 
2427  // if the index is beyond the current range, we are in the void
2428  if (index < currentRange->begin_index()) return value_zero;
2429 
2430  return (*currentRange)[index];
2431 } // lar::sparse_vector<T>::const_iterator::operator*()
2432 
2433 
2434 template <typename T>
2437 {
2438  if (delta == 1) return this->operator++();
2439  index += delta;
2440  if ((currentRange == cont->ranges.end())
2441  || !currentRange->includes(index)
2442  )
2443  refresh_state();
2444  return *this;
2445 } // lar::sparse_vector<T>::const_iterator::operator+=()
2446 
2447 template <typename T>
2450  { return this->operator+= (-delta); }
2451 
2452 
2453 template <typename T>
2456 {
2457  if ((currentRange == cont->ranges.end())
2458  || !currentRange->includes(index + delta)
2459  )
2460  return const_iterator(*cont, index + delta);
2461  const_iterator iter(*this);
2462  iter.index += delta;
2463  return iter;
2464 } // lar::sparse_vector<T>::const_iterator::operator+()
2465 
2466 template <typename T>
2469  { return this->operator+ (-delta); }
2470 
2471 
2472 /// distance operator
2473 template <typename T>
2476  (const const_iterator& iter) const
2477 {
2478  if (cont != iter.cont) {
2479  throw std::runtime_error("lar::sparse_vector::const_iterator:"
2480  " difference with alien iterator");
2481  }
2482  return index -iter.index;
2483 } // lar::sparse_vector<T>::const_iterator::operator-(const_iterator)
2484 
2485 
2486 template <typename T>
2488  // update the currentRange
2489  // currentRange is the range including the current item, or next to it
2490  if (cont) {
2491  // the following is actually the range after the index:
2492  currentRange = cont->find_next_range_iter(index);
2493  // if the index is inside the previous index, then we want to move there:
2494  if (currentRange != cont->ranges.begin()) {
2495  if ((currentRange - 1)->end_index() > index) --currentRange;
2496  }
2497  }
2498  else {
2499  currentRange = {};
2500  }
2501 } // lar::sparse_vector<T>::const_iterator::refresh_state()
2502 
2503 
2504 // -----------------------------------------------------------------------------
2505 // --- lar::sparse_vector<T>::iterator implementation
2506 // ---
2507 //
2508 // nothing new so far
2509 //
2510 
2511 
2512 #endif // LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
void clear()
Removes all the data, making the vector empty.
iterator(const container_t &c, const typename special::begin _)
Special constructor: initializes at the beginning of the container.
intermediate_table::iterator iterator
bool includes(const range_t &r) const
Returns whether the specified range is completely included in this one.
std::vector< value_type > vector_t
type of STL vector holding this data
sparse_vector(const vector_t &from, size_type offset=0)
Constructor: a solid vector from an existing STL vector.
sparse_vector()
Default constructor: an empty vector.
void refresh_state()
Reassigns the internal state according to the index.
const datarange_t & range(size_t i) const
Returns the i-th non-void range (zero-based)
const datarange_t & add_range(size_type offset, const CONT &new_data)
Copies the elements in container to a range with specified offset.
Iterator to the sparse vector values.
vector_t::const_pointer const_pointer
size_type n_ranges() const
Returns the internal list of non-void ranges.
reference(value_type &value)
static size_t expected_vector_size(size_t size)
Returns the expected size taken by a vector of specified size.
const_datarange_iterator & operator++()
const_reference(const value_type *pValue=0)
size_type fix_size()
Extends the vector size according to the last range.
void resize(size_type new_size)
Resizes the vector to the specified size, adding void.
void dump(Stream &&out) const
Dumps the content of this data range into a stream.
const datarange_t & append(const CONT &range_data)
Adds a sequence of elements as a range at the end of the vector.
const_reference operator*() const
Constant dereferenciation operator.
bool operator>(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:53
static value_type abs(value_type v)
Returns the module of the specified value.
G4double thr[100]
Definition: G4S2Light.cc:59
vector_t values
data in the range
const_value_box< T > this_t
Definition: sparse_vector.h:43
reference(const const_reference &from)
DoubleProduct & operator+=(DoubleProduct &left, DoubleProduct const &right)
Definition: ToyProducts.h:103
size_type size() const
Returns the size of the vector.
this_t operator++(int)
Increments the position of the iterator, returns the old position.
A class representing a cell in a sparse vector.
vector_t::pointer pointer
iterator(container_t &c, size_type offset=0)
Constructor from a container and an offset.
size_type offset
offset (absolute index) of the first element
range_iterator eat_range_head(range_iterator iRange, size_t index)
Voids the starting elements up to index (excluded) of a given range.
std::iterator< std::random_access_iterator_tag, T > base_t
base type
Definition: sparse_vector.h:73
const_iterator & operator+=(difference_type delta)
Increment and decrement operators.
value_type value
value to be returned when dereferencing
decltype(auto) make_const_datarange_t(typename sparse_vector< T >::datarange_t &r)
size_type minimum_size() const
Returns the size determined by the ranges already present.
auto range_const_data(std::size_t i) const
Like range_data() but with explicitly read-only access to data.
void resize(size_t new_size)
Resizes the range (optionally filling the new elements with def_value)
range_t< size_type > base_t
base class
const_iterator::const_reference const_reference
const container_t * cont
pointer to the container
const datarange_t & add_range(size_type offset, ITER first, ITER last)
Adds a sequence of elements as a range with specified offset.
STL namespace.
const range_list_t & get_ranges() const
Returns the internal list of non-void ranges.
iterator & operator++()
Increment and decrement operators.
reference(value_type *pValue=0)
range_const_iterator find_extending_range_iter(size_type index) const
value_type & operator=(value_type v)
const vector_t & data() const
Return the vector of data values.
const_iterator cend() const
intermediate_table::const_iterator const_iterator
range_const_iterator find_next_range_iter(size_type index) const
const datarange_t & add_range_before(size_type offset, vector_t &&new_data, range_iterator nextRange)
Implementation detail of add_range(), with where to add the range.
auto const & size() const
value_const_iterator< T > operator+(typename value_const_iterator< T >::difference_type ofs, value_const_iterator< T > &iter)
Returns an iterator pointing ahead of this one by the specified steps.
size_type begin_index() const
Returns the first absolute index included in the range.
this_t operator--(int)
Decrements the position of the iterator, returns the old position.
auto range_data(std::size_t i)
Provides direct access to data of i-th non-void range (zero-based)
const_reference(const value_type &value)
container_t::difference_type difference_type
datarange_t void_range(std::size_t const iRange)
const_iterator(const container_t &c, const typename special::end)
Special constructor: initializes at the end of the container.
void resize(Vector< T > &vec1, Index n1, const V &val)
value_type & set_at(size_type index, value_type value)
Writes into an element (creating or expanding a range if needed)
T value_type
type of the stored values
bool is_void(size_type index) const
Returns whether the specified position is void.
bool separate(const range_t &r) const
Returns if there are elements in between this and the specified range.
auto iterate_ranges() -> decltype(auto)
bool operator!=(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
const_iterator get_iterator(size_type index) const
Iterator to the sparse vector values.
bool overlap(const range_t &r) const
Returns if this and the specified range overlap.
datarange_t(size_type offset, ITER first, ITER last)
Constructor: offset and data.
void move_tail(size_type to_index, value_type def_value=value_zero)
Moves the end of this range.
const_datarange_t & operator*() const
const datarange_t & combine_range(size_type offset, const CONT &other, OP &&op, value_type void_value=value_zero)
Combines the elements in container with the data at offset.
ranges_const_iterator currentRange
pointer to the current (or next) range
bool is_valid() const
Returns if the vector is in a valid state.
bool operator!=(const_datarange_iterator const &other) const
size_type end_index() const
Returns the first absolute index not included in the range.
QuadExpr operator-(double v, const QuadExpr &e)
Definition: QuadExpr.h:38
void move_head(difference_type shift)
Moves the begin of the range by the specified amount.
sparse_vector(sparse_vector &&from)
Move constructor.
range_iterator find_extending_range_iter(size_type index)
Returns an iterator to the range no earlier than index, or end() if none.
container_t::size_type size_type
range_t(size_type from, size_type to)
Constructor from first and last index.
static bool should_merge(const typename datarange_t::base_t &a, const typename datarange_t::base_t &b)
Returns if merging the two specified ranges would save memory.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void move_tail(difference_type shift)
Moves the end of the range by the specified amount.
const_iterator cbegin() const
bool empty() const
Returns whether the range is empty.
const_iterator(const container_t &c, const typename special::begin)
Special constructor: initializes at the beginning of the container.
T abs(T value)
datarange_t(const base_t &range)
Constructor: range initialized with 0.
const_value_box(value_type new_value)
Constructor: stores the specified value.
Definition: sparse_vector.h:51
const_iterator cend() const
range_list_t ranges
list of ranges
bool operator<(ProductInfo const &a, ProductInfo const &b)
Definition: ProductInfo.cc:51
static constexpr double as
Definition: Units.h:101
bool operator<=(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:47
bool back_is_void() const
Returns whether the sparse vector ends with void.
fInnerVessel push_back(Point(-578.400000, 0.000000, 0.000000))
vector_t::difference_type difference_type
index difference type
iterator(const_iterator from)
sparse_vector(size_type new_size)
Constructor: a vector with new_size elements in the void.
A range (interval) of integers.
this_t & operator--()
Decrements the position of the iterator, returns the new position.
const double e
static size_t min_gap()
Minimum optimal gap between ranges (a guess)
iterator get_iterator(size_type index)
Returns an iterator to the specified absolute value (no check!)
range_iterator find_next_range_iter(size_type index)
Returns an iterator to the range after index.
constexpr bool is_valid(IDNumber_t< L > const id) noexcept
Definition: IDNumber.h:113
sparse_vector & operator=(sparse_vector &&from)
Move assignment.
Namespace for special initialization.
datarange_t()
Default constructor: an empty range.
static bool less(const range_t &a, const range_t &b)
Returns if a is "less" than b.
const_iterator get_const_iterator(size_type index) const
datarange_t & extend(size_type index, ITER first, ITER last)
Appends the specified elements to this range.
value_const_iterator(value_type new_value, difference_type offset)
Constructor: value to be returned and current iterator "position".
Definition: sparse_vector.h:88
vector_t::size_type size_type
size type
typename sparse_vector< T >::const_datarange_t const_datarange_t
const double a
void assign(const CONT &new_data)
Copies data from a container.
def move(depos, offset)
Definition: depos.py:107
const_iterator operator-(difference_type delta) const
this_t & operator++()
Increments the position of the iterator, returns the new position.
Definition: sparse_vector.h:98
value_const_iterator()
Default constructor: use the default value.
Definition: sparse_vector.h:82
std::vector< datarange_t > range_list_t
type of sparse vector data
range_iterator find_range_iter_at_or_after(size_type index)
Returns an iterator to the range at or after index.
Little class storing a value.
Definition: sparse_vector.h:42
void make_void(iterator first, iterator last)
Makes all the elements from first and before last void.
def dump(input_file, output_file)
Definition: dumpTree.py:102
vector_t::const_reference const_reference
const_iterator & operator++()
Increment and decrement operators.
container_t::range_list_t::const_iterator ranges_const_iterator
datarange_t & merge_ranges(range_iterator iRange)
Merges all the following contiguous ranges.
const vector_t & data() const
Return the vector of data values (only constant access).
range_iterator insert_range(range_iterator iInsert, const datarange_t &data)
Plug a new data range in the specified position; no check performed.
void move_head(size_type to_index, value_type def_value=value_zero)
Moves the begin of this range.
container_t::reference reference
range_const_iterator begin_range() const
Returns a constant iterator to the first data range.
range_t()
Default constructor: empty range.
const datarange_t & append(ITER first, ITER last)
Adds a sequence of elements as a range at the end of the vector.
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
void push_back(value_type value, value_type thr)
Adds one element to the end of the vector (if zero, just adds void)
sparse_vector(vector_t &&from, size_type offset=0)
Constructor: a solid vector from an existing STL vector.
bool is_valid() const
Returns whether the range is valid (that is, non-negative size)
Q_UINT16 values[128]
size_type index
pointer to the current value, as absolute index
sparse_vector< T > this_t
bool optimize(size_t)
static int max(int a, int b)
range_list_t::const_iterator range_const_iterator
type of constant iterator over ranges
const_iterator & operator-=(difference_type delta)
static value_type is_zero(value_type v)
Returns whether the value is exactly zero.
const datarange_t & combine_range(size_type offset, ITER first, ITER last, OP &&op, value_type void_value=value_zero)
Combines a sequence of elements as a range with data at offset.
A constant reference to a data range.
difference_type index
(arbitrary) position pointed by the iterator
const_iterator()
Default constructor, does not iterate anywhere.
void resize(size_t new_size, value_type def_value)
datarange_t make_void_around(size_type index)
Casts the whole range with the specified item into the void.
const datarange_t & append(vector_t &&range_data)
Adds a sequence of elements as a range at the end of the vector.
value_const_iterator< T > this_t
alias for this type
Definition: sparse_vector.h:74
iterator()
Default constructor, does not iterate anywhere.
size_type size() const
Returns the size of the range.
A sparse vector.
static bool less(const range_t &a, size_type b)
static bool less(size_type a, const range_t &b)
typename datarange_t::less_int_range less_int_range
range_const_iterator find_range_iterator(size_type index) const
Returns an iterator to the range containing the specified index.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
SIZE size_type
type for the indices in the range
LArSoft-specific namespace.
size_type nominal_size
current size
const datarange_t & find_range(size_type index) const
Returns the range containing the specified index.
iteratorRange(BITER const &b, EITER const &e)
this_t & operator=(value_type)
Assignment: the assigned value is ignored.
Definition: sparse_vector.h:54
vector_t::const_iterator const_iterator
Namespace hiding implementation details.
Definition: ServiceUtil.h:38
range_iterator find_range_iterator(size_type index)
bool empty() const
Returns whether the vector is empty.
const_iterator(const container_t &c, size_type offset)
Constructor from a container and a offset.
Special little box to allow void elements to be treated as references.
void unset_at(size_type index)
Casts the element with the specified index into the void.
Enclosure to use two iterators representing a range in a range-for loop.
void assign(vector_t &&new_data)
Moves data from a vector.
range_const_iterator get_current_range() const
Returns the current range internal value; use it at your own risk!!
auto range_data(std::size_t const i) const
const_value_box()
Default constructor: stores default value.
Definition: sparse_vector.h:48
auto const & begin() const
std::size_t find_range_number(size_type index) const
Returns the number (0-based) of range containing index.
reference operator*() const
Dereferenciation operator (can&#39;t write non-empty elements!)
const_iterator::special special
iterator begin()
Standard iterators interface.
auto const & end() const
T copy(T const &v)
static bool * b
Definition: config.cpp:1043
Range class, with range and data.
value_type value
the value stored for delivery
Definition: sparse_vector.h:63
void resize(size_type new_size)
Moves the end of the range to fit the specified size.
datarange_t(size_type offset, vector_t &&data)
Constructor: offset and data as a vector (which will be used directly)
const_iterator end() const
static value_type is_zero(value_type v, value_type thr)
Returns whether the value is zero below a given threshold.
range_iterator insert_range(range_iterator iInsert, datarange_t &&data)
datarange_t const & base() const
std::forward_iterator_tag iterator_category
range_const_iterator end_range() const
Returns a constant iterator to after the last data range.
bool includes(size_type index) const
Returns whether the specified absolute index is included in this range.
static value_type is_equal(value_type a, value_type b)
Returns whether two values are the same.
vector< vector< double > > clear
range_list_t::iterator range_iterator
type of iterator over ranges
const_iterator begin() const
value_const_iterator(value_type new_value)
Constructor: value that will be returned.
Definition: sparse_vector.h:85
iterator(const container_t &c, const typename special::end _)
Special constructor: initializes at the end of the container.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
container_t::value_type value_type
void push_back(value_type value)
const_iterator cbegin() const
iterator begin()
begin and end iterators
bool operator>=(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:59
const_iterator::reference reference
size_type last
offset (absolute index) after the last element
const_iterator::container_t container_t
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:39
const_iterator operator+(difference_type delta) const
bool optimize()
Performs internal optimization, returns whether the object was changed.
datarange_t void_range(range_iterator const iRange)
Turns the specified range into void.
void assign(ITER first, ITER last)
Copies data from a sequence between two iterators.
A constant iterator returning always the same value.
Definition: sparse_vector.h:70
int bool
Definition: qglobal.h:345
static QCString * s
Definition: config.cpp:1042
T value_type
type of the value stored
Definition: sparse_vector.h:45
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
std::ptrdiff_t difference_type
type for index difference
QTextStream & endl(QTextStream &s)
size_type capacity() const
Returns the capacity of the vector (compatibility only)
static value_type is_equal(value_type a, value_type b, value_type thr)
Returns whether two values are the same below a given threshold.
size_type relative_index(size_type index) const
Returns the position within the range of the absolute index specified.
bool borders(size_type index) const
Returns whether an index is within or immediately after this range.
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
size_type count() const
Returns the number of non-void cells.