LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
sparse_vector.h
Go to the documentation of this file.
1 
10 #ifndef LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
11 #define LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
12 
13 // C/C++ standard library
14 #include <algorithm> // std::upper_bound(), std::max()
15 #include <cstddef> // std::ptrdiff_t
16 #include <iterator> // std::distance()
17 #include <numeric> // std::accumulate
18 #include <ostream>
19 #include <stdexcept> // std::out_of_range()
20 #include <type_traits> // std::is_integral
21 #include <vector>
22 
24 namespace lar {
25 
26  // -----------------------------------------------------------------------------
27  // --- utility classes for sparse_vector
28  // ---
29 
38  template <typename T>
41 
42  public:
43  typedef T value_type;
44 
47 
49  explicit const_value_box(value_type new_value) : value(new_value) {}
50 
52  this_t& operator=(value_type) { return *this; }
53 
55  operator value_type() const { return value; }
57  operator const value_type&() const { return value; }
59 
60  protected:
61  value_type value;
62  }; // class const_value_box
63 
66  template <typename T>
69 
70  public:
71  using iterator_category = std::random_access_iterator_tag;
72  using value_type = T;
73  using difference_type = std::ptrdiff_t;
74  using pointer = T*;
75  using reference = T&;
76 
79 
81  value_const_iterator(value_type new_value) : value(new_value) {}
82 
85  : index(offset), value(new_value)
86  {}
87 
89  value_type operator*() const { return value; }
90 
93 
95  this_t& operator++()
96  {
97  ++index;
98  return *this;
99  }
100 
102  this_t operator++(int)
103  {
104  this_t copy(*this);
105  ++index;
106  return copy;
107  }
108 
110  this_t& operator--()
111  {
112  --index;
113  return *this;
114  }
115 
117  this_t operator--(int)
118  {
119  this_t copy(*this);
120  --index;
121  return copy;
122  }
123 
126  {
127  index += ofs;
128  return *this;
129  }
130 
133  {
134  index -= ofs;
135  return *this;
136  }
137 
139  this_t operator+(difference_type ofs) const { return this_t(value, index + ofs); }
140 
142  this_t operator-(difference_type ofs) const { return this_t(value, index - ofs); }
143 
146  difference_type operator-(const this_t& iter) const { return index - iter.index; }
147 
149  bool operator==(const this_t& as) const { return index == as.index; }
151  bool operator!=(const this_t& as) const { return index != as.index; }
152 
153  bool operator<(const this_t& as) const { return index < as.index; }
154  bool operator<=(const this_t& as) const { return index <= as.index; }
155  bool operator>(const this_t& as) const { return index > as.index; }
156  bool operator>=(const this_t& as) const { return index >= as.index; }
158 
159  protected:
160  difference_type index{0};
162  }; // class value_const_iterator<>
163 
169  template <typename T>
172  {
173  return {iter.value, iter.index + ofs};
174  }
175 
176  /* // not ready yet...
177 template <typename T>
178 class value_iterator: public value_const_iterator<T> {
179  using base_t = value_const_iterator<T>;
180  using this_t = value_iterator<T>;
181  using const_value_box<value_type> = value_box;
182  public:
183 
184  using typename base_t::value_type;
185  using typename base_t::reference;
186 
187  value_box operator* () const { return value_box(value); }
188  value_box operator[] (difference_type) const { return value_box(value); }
189 
190 }; // class value_iterator<>
191 */
192 
193  //------------------------------------------------------------------------------
194  //--- lar::range_t<SIZE>
195  //---
202  template <typename SIZE>
203  class range_t {
204  public:
205  typedef SIZE size_type;
206  typedef std::ptrdiff_t difference_type;
207 
208  static_assert(std::is_integral<size_type>::value, "range_t needs an integral type");
209 
210  size_type offset;
211  size_type last;
212 
214  range_t() : offset(0), last(0) {}
215 
217  range_t(size_type from, size_type to) : offset(from), last(std::max(from, to)) {}
218 
220  void set(size_type from, size_type to)
221  {
222  offset = from;
223  last = std::max(from, to);
224  }
225 
227  size_type begin_index() const { return offset; }
228 
230  size_type end_index() const { return last; }
231 
233  size_type relative_index(size_type index) const { return index - offset; }
234 
236  size_type size() const { return last - offset; }
237 
239  void resize(size_type new_size) { last = offset + new_size; }
240 
242  void move_head(difference_type shift) { offset += shift; }
243 
245  void move_tail(difference_type shift) { last += shift; }
246 
248  bool empty() const { return last <= offset; }
249 
251  bool includes(size_type index) const { return (index >= offset) && (index < last); }
252 
254  bool includes(const range_t& r) const
255  {
256  return includes(r.begin_index()) && includes(r.end_index());
257  }
258 
260  bool overlap(const range_t& r) const
261  {
262  return (begin_index() < r.end_index()) && (end_index() > r.begin_index());
263  }
264 
266  bool separate(const range_t& r) const
267  {
268  return (begin_index() > r.end_index()) || (end_index() < r.begin_index());
269  }
270 
275  bool borders(size_type index) const { return (index >= offset) && (index <= last); }
276 
278  bool operator<(const range_t& than) const { return less(*this, than); }
281 
283  bool operator==(const range_t& as) const { return (offset == as.offset) && (last == as.last); }
284 
286  bool is_valid() const { return last >= offset; }
287 
289  static bool less(const range_t& a, const range_t& b) { return a.offset < b.offset; }
291  static bool less(const range_t& a, size_type b) { return a.offset < b; }
292  static bool less(size_type a, const range_t& b) { return a < b.offset; }
294 
296  typedef bool (*less_int_range)(size_type, const range_t& b);
297  }; // class range_t
298 
299  // -----------------------------------------------------------------------------
300  // --- lar::sparse_vector<T>
301  // ---
302 
303  // the price of having used subclasses extensively:
304  template <typename T>
306 
307  namespace details {
308  template <typename T>
309  decltype(auto) make_const_datarange_t(typename sparse_vector<T>::datarange_t& r);
310  } // namespace details
311 
480  template <typename T>
481  class sparse_vector {
483  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
484  // - - - public interface
485  public:
486  // - - - types
487  typedef T value_type;
488  typedef std::vector<value_type> vector_t;
490  typedef typename vector_t::size_type size_type;
491  typedef typename vector_t::difference_type difference_type;
493  typedef typename vector_t::pointer pointer;
494  typedef typename vector_t::const_pointer const_pointer;
495  // typedef typename vector_t::reference reference;
496  // typedef typename vector_t::const_reference const_reference;
497 
498  // --- declarations only ---
499  class reference;
500  class const_reference;
501  class iterator;
502  class const_iterator;
503 
504  class datarange_t;
505  class const_datarange_t;
506  // --- ----------------- ---
507 
508  typedef std::vector<datarange_t> range_list_t;
514 
515  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
516  // - - - public methods
518  sparse_vector() : nominal_size(0), ranges() {}
519 
521  sparse_vector(size_type new_size) : nominal_size(0), ranges() { resize(new_size); }
522 
528  sparse_vector(const vector_t& from, size_type offset = 0) : nominal_size(0), ranges()
529  {
530  add_range(offset, from.begin(), from.end());
531  }
532 
534  sparse_vector(sparse_vector const&) = default;
535 
537  sparse_vector(sparse_vector&& from)
538  : nominal_size(from.nominal_size), ranges(std::move(from.ranges))
539  {
540  from.nominal_size = 0;
541  }
542 
544  sparse_vector& operator=(sparse_vector const&) = default;
545 
547  sparse_vector& operator=(sparse_vector&& from)
548  {
549  ranges = std::move(from.ranges);
550  nominal_size = from.nominal_size;
551  from.nominal_size = 0;
552  return *this;
553  } // operator= (sparse_vector&&)
554 
560  sparse_vector(vector_t&& from, size_type offset = 0) : nominal_size(0), ranges()
561  {
562  add_range(offset, std::move(from));
563  }
564 
566  ~sparse_vector() = default;
567 
568  // - - - STL-like interface
570  void clear()
571  {
572  ranges.clear();
573  nominal_size = 0;
574  }
575 
577  size_type size() const { return nominal_size; }
578 
580  bool empty() const { return size() == 0; }
581 
583  size_type capacity() const { return nominal_size; }
584 
586  void resize(size_type new_size);
589  void resize(size_type new_size, value_type def_value);
591 
593  iterator begin();
595  iterator end();
596  const_iterator begin() const;
597  const_iterator end() const;
598  const_iterator cbegin() const { return begin(); }
599  const_iterator cend() const { return end(); }
601 
603  value_type operator[](size_type index) const;
604 
606  reference operator[](size_type index);
607 
608  // - - - special interface
609 
613 
614  // --- element test
621  bool is_void(size_type index) const;
622 
625  bool back_is_void() const { return ranges.empty() || (ranges.back().end_index() < size()); }
626 
628  size_type count() const;
630 
634 
644  value_type& set_at(size_type index, value_type value);
645 
647  void unset_at(size_type index);
648 
650  void push_back(value_type value) { resize(size() + 1, value); }
653 
661  void push_back(value_type value, value_type thr)
662  {
663  if (is_zero(value, thr))
664  resize(size() + 1);
665  else
666  push_back(value);
667  } // push_back()
669 
671 
679  template <typename ITER>
680  void assign(ITER first, ITER last)
681  {
682  clear();
683  append(first, last);
684  }
685 
693  template <typename CONT>
694  void assign(const CONT& new_data)
695  {
696  clear();
697  append(new_data);
698  }
699 
706  void assign(vector_t&& new_data)
707  {
708  clear();
709  append(std::move(new_data));
710  }
712 
714 
715  // --- BEGIN Ranges ---------------------------------------------------------
734 
736  // --- range location
737 
739  const range_list_t& get_ranges() const { return ranges; }
740  auto iterate_ranges() -> decltype(auto);
741 
743  size_type n_ranges() const { return ranges.size(); }
744 
746  const datarange_t& range(size_t i) const { return ranges[i]; }
747 
749 
771  auto range_data(std::size_t i);
772  auto range_data(std::size_t const i) const { return range_const_data(i); }
774 
776  auto range_const_data(std::size_t i) const;
777 
779  range_const_iterator begin_range() const { return ranges.begin(); }
780 
782  range_const_iterator end_range() const { return ranges.end(); }
783 
785 
792  range_const_iterator find_range_iterator(size_type index) const;
793  range_iterator find_range_iterator(size_type index)
794  {
795  return ranges.begin() + find_range_number(index);
796  }
798 
806  std::size_t find_range_number(size_type index) const
807  {
808  return find_range_iterator(index) - begin_range();
809  }
810 
812 
819  const datarange_t& find_range(size_type index) const;
820  datarange_t& find_range(size_type index);
822 
830  datarange_t make_void_around(size_type index);
831 
833 
846  template <typename ITER>
847  const datarange_t& add_range(size_type offset, ITER first, ITER last);
848 
861  template <typename CONT>
862  const datarange_t& add_range(size_type offset, const CONT& new_data)
863  {
864  return add_range(offset, new_data.begin(), new_data.end());
865  }
866 
880  const datarange_t& add_range(size_type offset, vector_t&& new_data);
882 
884 
911  template <typename ITER, typename OP>
912  const datarange_t& combine_range(size_type offset,
913  ITER first,
914  ITER last,
915  OP&& op,
916  value_type void_value = value_zero);
917 
932  template <typename CONT, typename OP>
933  const datarange_t& combine_range(size_type offset,
934  const CONT& other,
935  OP&& op,
936  value_type void_value = value_zero)
937  {
938  return combine_range(offset, other.begin(), other.end(), std::forward<OP>(op), void_value);
939  }
941 
943 
953  template <typename ITER>
954  const datarange_t& append(ITER first, ITER last)
955  {
956  return add_range(size(), first, last);
957  }
958 
968  template <typename CONT>
969  const datarange_t& append(const CONT& range_data)
970  {
971  return add_range(size(), range_data);
972  }
973 
984  const datarange_t& append(vector_t&& range_data)
985  {
986  return add_range(size(), std::move(range_data));
987  }
989 
991 
1004  datarange_t void_range(range_iterator const iRange);
1005  datarange_t void_range(std::size_t const iRange) { return void_range(ranges.begin() + iRange); }
1007 
1021  bool is_valid() const;
1022 
1024  void make_void(iterator first, iterator last);
1025 
1027  bool optimize() { return optimize(min_gap()); }
1029  bool optimize(size_t) { return false; /* no optimization implemented yet */ }
1031 
1033 
1034  static constexpr value_type value_zero{0};
1035 
1037  static value_type abs(value_type v) { return (v < value_zero) ? -v : v; }
1038 
1040  static value_type is_zero(value_type v) { return v == value_zero; }
1041 
1043  static value_type is_zero(value_type v, value_type thr) { return abs(v - value_zero) <= thr; }
1044 
1046  static value_type is_equal(value_type a, value_type b) { return is_zero(abs(a - b)); }
1047 
1049  static value_type is_equal(value_type a, value_type b, value_type thr)
1050  {
1051  return is_zero(abs(a - b), thr);
1052  }
1054 
1056 
1058  static size_t expected_vector_size(size_t size);
1059 
1061  static size_t min_gap();
1062 
1064  static bool should_merge(const typename datarange_t::base_t& a,
1065  const typename datarange_t::base_t& b);
1067 
1068  // --------------------------------------------------------------------------
1069  protected:
1070  size_type nominal_size;
1071  range_list_t ranges;
1072 
1074 
1080  range_iterator find_next_range_iter(size_type index)
1081  {
1082  return find_next_range_iter(index, ranges.begin());
1083  }
1084  range_const_iterator find_next_range_iter(size_type index) const
1085  {
1086  return find_next_range_iter(index, ranges.cbegin());
1087  }
1089 
1090 
1098  range_iterator find_next_range_iter(size_type index, range_iterator rbegin);
1099  range_const_iterator find_next_range_iter(size_type index, range_const_iterator rbegin) const;
1101 
1103 
1115  range_iterator find_range_iter_at_or_after(size_type index);
1116  range_const_iterator find_range_iter_at_or_after(size_type index) const;
1118 
1120 
1138  range_iterator find_extending_range_iter(size_type index)
1139  {
1140  return find_extending_range_iter(index, ranges.begin());
1141  }
1142  range_const_iterator find_extending_range_iter(size_type index) const
1143  {
1144  return find_extending_range_iter(index, ranges.cbegin());
1145  }
1147 
1149 
1159  range_iterator find_extending_range_iter(size_type index, range_iterator rbegin);
1160  range_const_iterator find_extending_range_iter(size_type index,
1161  range_const_iterator rbegin) const;
1163 
1165  size_type minimum_size() const { return ranges.empty() ? 0 : ranges.back().end_index(); }
1166 
1168  range_iterator insert_range(range_iterator iInsert, const datarange_t& data)
1170  {
1171  return data.empty() ? iInsert : ranges.insert(iInsert, data);
1172  }
1173  range_iterator insert_range(range_iterator iInsert, datarange_t&& data)
1174  {
1175  return data.empty() ? iInsert : ranges.insert(iInsert, std::move(data));
1176  }
1178 
1180  const datarange_t& add_range_before(size_type offset,
1181  vector_t&& new_data,
1182  range_iterator nextRange);
1183 
1185  range_iterator eat_range_head(range_iterator iRange, size_t index);
1186 
1199  datarange_t& merge_ranges(range_iterator iRange);
1200 
1202  size_type fix_size();
1203 
1204  }; // class sparse_vector<>
1205 
1206 } // namespace lar
1207 
1223 template <typename T>
1224 std::ostream& operator<<(std::ostream& out, const lar::sparse_vector<T>& v);
1225 
1226 // -----------------------------------------------------------------------------
1227 // --- sparse_vector::datarange_t definition
1228 // ---
1229 
1231 template <typename T>
1232 class lar::sparse_vector<T>::datarange_t : public range_t<size_type> {
1233 public:
1235 
1236  typedef typename vector_t::iterator iterator;
1238 
1240  datarange_t() : base_t(), values() {}
1241 
1243  datarange_t(const base_t& range) : base_t(range), values(range.size()) {}
1244 
1246  template <typename ITER>
1247  datarange_t(size_type offset, ITER first, ITER last)
1248  : base_t(offset, offset + std::distance(first, last)), values(first, last)
1249  {}
1250 
1253  : base_t(offset, offset + data.size()), values(data)
1254  {}
1255 
1257  iterator get_iterator(size_type index) { return values.begin() + index - base_t::begin_index(); }
1259  const_iterator get_iterator(size_type index) const { return get_const_iterator(index); }
1260  const_iterator get_const_iterator(size_type index) const
1261  {
1262  return values.begin() + index - base_t::begin_index();
1263  }
1265 
1267  iterator begin() { return values.begin(); }
1269  iterator end() { return values.end(); }
1270  const_iterator begin() const { return values.begin(); }
1271  const_iterator end() const { return values.end(); }
1272  const_iterator cbegin() const { return values.cbegin(); }
1273  const_iterator cend() const { return values.cend(); }
1275 
1277  void resize(size_t new_size)
1279  {
1280  values.resize(new_size);
1281  fit_size_from_data();
1282  }
1283  void resize(size_t new_size, value_type def_value)
1284  {
1285  values.resize(new_size, def_value);
1286  fit_size_from_data();
1287  }
1289 
1291  value_type& operator[](size_type index) { return values[base_t::relative_index(index)]; }
1293  const value_type& operator[](size_type index) const
1294  {
1295  return values[base_t::relative_index(index)];
1296  }
1298 
1300  const vector_t& data() const { return values; }
1302  // vector_t& data() { return values; }
1304 
1313  template <typename ITER>
1314  datarange_t& extend(size_type index, ITER first, ITER last);
1315 
1321  void move_head(size_type to_index, value_type def_value = value_zero);
1322 
1328  void move_tail(size_type to_index, value_type def_value = value_zero)
1329  {
1330  resize(base_t::relative_index(to_index), def_value);
1331  }
1332 
1344  template <typename Stream>
1345  void dump(Stream&& out) const;
1346 
1347 protected:
1349 
1350  void fit_size_from_data() { base_t::resize(values.size()); }
1351 
1352 }; // class datarange_t
1353 
1359 template <typename T>
1361 public:
1364 
1365  // `range_t` interface
1366  using datarange_t::begin_index;
1367  using datarange_t::borders;
1368  using datarange_t::empty;
1369  using datarange_t::end_index;
1370  using datarange_t::includes;
1371  using datarange_t::last;
1372  using datarange_t::offset;
1373  using datarange_t::overlap;
1374  using datarange_t::relative_index;
1375  using datarange_t::separate;
1376  using datarange_t::size;
1377  using datarange_t::operator<;
1378  using datarange_t::operator==;
1379  using datarange_t::is_valid;
1380  using datarange_t::less;
1381  using less_int_range = typename datarange_t::less_int_range;
1382 
1383  // `datarange_t` interface
1384  using datarange_t::get_iterator;
1385  decltype(auto) begin() { return datarange_t::begin(); }
1386  decltype(auto) end() { return datarange_t::end(); }
1387  // using datarange_t::begin;
1388  // using datarange_t::end;
1389  // using datarange_t::cbegin;
1390  // using datarange_t::cend;
1391  using datarange_t::operator[];
1392  using datarange_t::dump;
1393 
1395  const vector_t& data() const { return base().values; }
1396 
1397  ~const_datarange_t() = delete; // can't destroy; can cast into it though
1398 
1399 protected:
1400  friend decltype(auto) details::make_const_datarange_t<T>(datarange_t&);
1401 
1402  datarange_t const& base() const { return static_cast<datarange_t const&>(*this); }
1403  datarange_t& base() { return static_cast<datarange_t&>(*this); }
1404 
1405  static void static_check() { static_assert(sizeof(const_datarange_t) == sizeof(datarange_t)); }
1406 
1407 }; // lar::sparse_vector<T>::const_datarange_t
1408 
1409 // -----------------------------------------------------------------------------
1410 // --- sparse_vector iterators definition
1411 // ---
1412 
1414 template <typename T>
1416 protected:
1417  const value_type* ptr;
1418 
1419 public:
1420  const_reference(const value_type* pValue = 0) : ptr(pValue) {}
1422 
1423  explicit operator value_type() const { return ptr ? *ptr : value_zero; }
1424  operator const value_type&() const { return ptr ? *ptr : value_zero; }
1425 }; // lar::sparse_vector<T>::const_reference
1426 
1434 template <typename T>
1436  friend class iterator;
1437 
1438  // This object "disappears" when assigned to: either the assignment is not
1439  // possible, and then a segmentation fault will occur, or the return value
1440  // is an actual C++ reference to the assigned value.
1441  // The same is true when explicitly converting it to a reference.
1442 public:
1443  reference(value_type* pValue = 0) : const_reference(pValue) {}
1445 
1446  reference& operator=(const reference&) = default;
1447  value_type& operator=(value_type v) { return const_cast<value_type&>(*const_reference::ptr) = v; }
1448 
1449  explicit operator value_type&() { return const_cast<value_type&>(*const_reference::ptr); }
1450 
1451 protected:
1452  explicit reference(const const_reference& from) : const_reference(from) {}
1453 
1454 }; // lar::sparse_vector<T>::reference
1455 
1456 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1458 template <typename T>
1460  //
1461  // This iterator fulfils the traits of an immutable forward iterator.
1462  //
1463 
1464 protected:
1465  friend class container_t;
1466 
1470 
1471 public:
1472  // so far, only forward interface is implemented;
1473  // backward is tricky...
1474  typedef std::forward_iterator_tag iterator_category;
1475 
1477  struct special {
1478  class begin {};
1479  class end {};
1480  };
1481 
1482  // types
1485  typedef typename container_t::pointer pointer;
1487  // note that this is not out little box, it's the normal C++ constant
1488  // reference from the underlying vector
1489  typedef typename vector_t::const_reference const_reference;
1490 
1492  const_iterator() : cont(nullptr), index(0), currentRange() {}
1493 
1495  const_iterator(const container_t& c, size_type offset)
1496  : cont(&c), index(std::min(offset, c.size())), currentRange()
1497  {
1498  refresh_state();
1499  }
1500 
1502  const_iterator(const container_t& c, const typename special::begin)
1503  : cont(&c), index(0), currentRange(c.get_ranges().begin())
1504  {}
1505 
1507  const_iterator(const container_t& c, const typename special::end)
1508  : cont(&c), index(c.size()), currentRange(c.get_ranges().end())
1509  {}
1510 
1512  const_reference operator[](size_type offset) const { return (*cont)[index + offset]; }
1513 
1515  const_reference operator*() const;
1516 
1518  const_iterator& operator++();
1521  {
1522  const_iterator copy(*this);
1524  return copy;
1525  }
1527 
1529  const_iterator& operator+=(difference_type delta);
1531  const_iterator& operator-=(difference_type delta);
1532  const_iterator operator+(difference_type delta) const;
1533  const_iterator operator-(difference_type delta) const;
1535 
1537  difference_type operator-(const const_iterator& iter) const;
1538 
1540  bool operator==(const const_iterator& as) const
1542  {
1543  return (cont == as.cont) && (index == as.index);
1544  }
1545  bool operator!=(const const_iterator& as) const
1546  {
1547  return (cont != as.cont) || (index != as.index);
1548  }
1549  bool operator<(const const_iterator& than) const
1550  {
1551  return (cont == than.cont) && (index < than.index);
1552  }
1553  bool operator>(const const_iterator& than) const
1554  {
1555  return (cont == than.cont) && (index > than.index);
1556  }
1557  bool operator<=(const const_iterator& than) const
1558  {
1559  return (cont == than.cont) && (index <= than.index);
1560  }
1561  bool operator>=(const const_iterator& than) const
1562  {
1563  return (cont == than.cont) && (index >= than.index);
1564  }
1566 
1568  range_const_iterator get_current_range() const { return currentRange; }
1569 
1570 protected:
1571  //
1572  // Logic of the internals:
1573  // - cont provides the list of ranges
1574  // - index is the absolute index in the container
1575  // - currentRange is a pointer to the "current" range, cached for speed
1576  //
1577  // An iterator past-the-end has the index equal to the size of the
1578  // container it points to. Operations on it are undefined, except that
1579  // going backward by one decrement goes back to the container
1580  // (if not empty) TODO currently backward iteration is not supported
1581  //
1582  // When the iterator is pointing to an element within a range,
1583  // currentRange points to that range.
1584  // When the iterator is pointing into the void of the vector, currentRange
1585  // points to the range next to that void area, or end() if there is none.
1586  // When the iterator is past-the-end, currentRange is not defined.
1587  //
1588  // Conversely, when the index is equal (or greater) to the size of the
1589  // container, the iterator is not dereferenciable, the iterator points
1590  // past-the-end of the container.
1591  // When currentRange points to a valid range and the index
1592  // is before that range, the iterator is pointing to the void.
1593  // When currentRange points to a valid range and the index
1594  // is inside that range, the iterator is pointing to an item in that
1595  // range.
1596  // When currentRange points to a valid range, the index can't point beyond
1597  // that range.
1598  // When currentRange points to the past-to-last range, the iterator is
1599  // pointing to the void (past the last range).
1600  //
1601  const container_t* cont;
1602  size_type index;
1603  ranges_const_iterator currentRange;
1604 
1606  void refresh_state();
1607 
1608 }; // class lar::sparse_vector<T>::const_iterator
1609 
1620 template <typename T>
1622  typedef typename const_iterator::container_t container_t;
1623  friend typename const_iterator::container_t;
1624 
1625 public:
1627  typedef typename const_iterator::const_reference const_reference;
1628  typedef typename const_iterator::special special;
1629 
1632 
1634  iterator(container_t& c, size_type offset = 0) : const_iterator(c, offset) {}
1635 
1637  iterator(const container_t& c, const typename special::begin _) : const_iterator(c, _) {}
1638 
1640  iterator(const container_t& c, const typename special::end _) : const_iterator(c, _) {}
1641 
1643  reference operator[](size_type offset) const
1644  {
1645  return (*const_iterator::cont)[const_iterator::index + offset];
1646  }
1647 
1649  iterator& operator++()
1651  {
1653  return *this;
1654  }
1657 
1661  {
1663  return *this;
1664  }
1666  {
1668  return *this;
1669  }
1673 
1675  reference operator*() const { return reference(const_iterator::operator*()); }
1676 
1677  // /// Returns the current range internal value; use it at your own risk!!
1678  // range_iterator get_current_range() const
1679  // { return const_iterator::currentRange; }
1680 
1681 protected:
1682  // also worth conversion
1684 
1685 }; // class lar::sparse_vector<T>::iterator
1686 
1687 // -----------------------------------------------------------------------------
1688 // --- implementation --------------------------------------------------------
1689 // -----------------------------------------------------------------------------
1690 namespace lar::details {
1691 
1692  // --------------------------------------------------------------------------
1694  template <typename BITER, typename EITER>
1696  BITER b;
1697  EITER e;
1698 
1699  public:
1700  iteratorRange(BITER const& b, EITER const& e) : b(b), e(e) {}
1701  auto const& begin() const { return b; }
1702  auto const& end() const { return e; }
1703  auto const& size() const { return std::distance(begin(), end()); }
1704  }; // iteratorRange()
1705 
1706  // --------------------------------------------------------------------------
1707  template <typename T>
1708  decltype(auto) make_const_datarange_t(typename sparse_vector<T>::datarange_t& r)
1709  {
1710  return static_cast<typename sparse_vector<T>::const_datarange_t&>(r);
1711  }
1712 
1713  // --------------------------------------------------------------------------
1714  template <typename T>
1719 
1720  public:
1721  // minimal set of features for ranged-for loops
1722  const_datarange_iterator() = default;
1724 
1726  {
1727  ++it;
1728  return *this;
1729  }
1730  const_datarange_t& operator*() const { return make_const_datarange_t<T>(*it); }
1731  bool operator!=(const_datarange_iterator const& other) const { return it != other.it; }
1732  };
1733 
1734  // --------------------------------------------------------------------------
1735 
1736 } // namespace lar::details
1737 
1738 //------------------------------------------------------------------------------
1739 //--- sparse_vector implementation
1740 
1741 template <typename T>
1743 
1744 template <typename T>
1746 {
1749 } // lar::sparse_vector<T>::iterate_ranges()
1750 
1751 template <typename T>
1753 {
1754  if (new_size >= size()) {
1755  nominal_size = new_size;
1756  return;
1757  }
1758 
1759  // truncating...
1760  range_iterator iLastRange = find_next_range_iter(new_size);
1761  ranges.erase(iLastRange, ranges.end());
1762  if (!ranges.empty()) {
1763  range_iterator iLastRange = ranges.end() - 1;
1764  if (new_size == iLastRange->begin_index())
1765  ranges.erase(iLastRange);
1766  else if (new_size < iLastRange->end_index())
1767  iLastRange->resize(new_size - iLastRange->begin_index());
1768  } // if we have ranges
1769 
1770  // formally resize
1771  nominal_size = new_size;
1772 } // lar::sparse_vector<T>::resize()
1773 
1774 template <typename T>
1776 {
1777  if (new_size == size()) return;
1778  if (new_size > size()) {
1779 
1780  if (back_is_void()) // add a new range
1781  append(vector_t(new_size - size(), def_value));
1782  else // extend the last range
1783  ranges.back().resize(new_size - ranges.back().begin_index(), def_value);
1784 
1785  nominal_size = new_size;
1786  return;
1787  }
1788  // truncating is the same whether there is a default value or not
1789  resize(new_size);
1790 } // lar::sparse_vector<T>::resize()
1791 
1792 template <typename T>
1794 {
1795  return iterator(*this, typename iterator::special::begin());
1796 }
1797 
1798 template <typename T>
1800 {
1801  return iterator(*this, typename iterator::special::end());
1802 }
1803 
1804 template <typename T>
1806 {
1807  return const_iterator(*this, typename const_iterator::special::begin());
1808 }
1809 
1810 template <typename T>
1812 {
1813  return const_iterator(*this, typename const_iterator::special::end());
1814 }
1815 
1816 template <typename T>
1818 {
1819  // first range not including the index
1820  range_const_iterator iNextRange = find_next_range_iter(index);
1821 
1822  // if not even the first range includes the index, we are in the void
1823  // (or in some negative index space, if index signedness allowed);
1824  if (iNextRange == ranges.begin()) return value_zero;
1825 
1826  // otherwise, let's take the previous range;
1827  // if it includes the index, we return its value;
1828  // or it precedes it, and our index is in the void: return zero
1829  const datarange_t& range(*--iNextRange);
1830  return (index < range.end_index()) ? range[index] : value_zero;
1831 } // lar::sparse_vector<T>::operator[]
1832 
1833 template <typename T>
1835 {
1836  // first range not including the index
1837  range_iterator iNextRange = find_next_range_iter(index);
1838 
1839  // if not even the first range includes the index, we are in the void
1840  // (or in some negative index space, if index signedness allowed);
1841  if (iNextRange == ranges.begin()) return reference();
1842 
1843  // otherwise, let's take the previous range;
1844  // if it includes the index, we return its value;
1845  // or it precedes it, and our index is in the void: return zero
1846  datarange_t& range(*--iNextRange);
1847  return (index < range.end_index()) ? reference(range[index]) : reference();
1848 } // lar::sparse_vector<T>::operator[]
1849 
1850 template <typename T>
1852 {
1853  if (ranges.empty() || (index >= size())) throw std::out_of_range("empty sparse vector");
1854  // range after the index:
1855  range_const_iterator iNextRange = find_next_range_iter(index);
1856  return ((iNextRange == ranges.begin()) || ((--iNextRange)->end_index() <= index));
1857 } // lar::sparse_vector<T>::is_void()
1858 
1859 template <typename T>
1861 {
1862  return std::accumulate(begin_range(),
1863  end_range(),
1864  size_type(0),
1865  [](size_type s, const datarange_t& rng) { return s + rng.size(); });
1866 } // count()
1867 
1868 template <typename T>
1870  value_type value)
1871 {
1872  // first range not including the index
1873  range_iterator iNextRange = find_next_range_iter(index);
1874 
1875  // if not even the first range includes the index, we are in the void
1876  // (or in some negative index space, if index signedness allowed);
1877  if (iNextRange != ranges.begin()) {
1878  // otherwise, let's take the previous range;
1879  // if it includes the index, we set the existing value;
1880  // or it precedes it, and our index is in the void, add the value as a
1881  // range
1882  datarange_t& range(*std::prev(iNextRange));
1883  if (index < range.end_index()) return range[index] = value;
1884  }
1885  // so we are in the void; add the value as a new range
1886  return const_cast<datarange_t&>(add_range(index, {value}))[index];
1887 } // lar::sparse_vector<T>::set_at()
1888 
1889 template <typename T>
1891 {
1892  // first range not including the index
1893  range_iterator iNextRange = find_next_range_iter(index);
1894 
1895  // if not even the first range includes the index, we are in the void
1896  // (or in some negative index space, if index signedness allowed);
1897  if (iNextRange == ranges.begin()) return;
1898 
1899  // otherwise, let's take the previous range;
1900  // or it precedes the index, and our index is in the void
1901  datarange_t& range(*--iNextRange);
1902  if (index >= range.end_index()) return; // void already
1903 
1904  // it includes the index:
1905  // - if it's a one-element range, remove the range
1906  if (range.size() == 1) ranges.erase(iNextRange);
1907  // - if it's on a border, resize the range
1908  else if (index == range.begin_index())
1909  range.move_head(index + 1);
1910  else if (index == range.end_index() - 1)
1911  range.move_tail(index);
1912  // - if it's inside, break the range in two
1913  else if (index < range.end_index()) {
1914  // we are going to put a hole in a range;
1915  // this effectively creates two ranges;
1916  // first create the rightmost range, and add it to the list
1917  ranges.emplace(
1918  ++iNextRange, index + 1, range.begin() + range.relative_index(index + 1), range.end());
1919  // then cut the existing one
1920  range.move_tail(index);
1921  }
1922 } // lar::sparse_vector<T>::unset_at()
1923 
1924 template <typename T>
1925 auto lar::sparse_vector<T>::range_data(std::size_t const i)
1926 {
1927  auto& r = ranges[i];
1928  return details::iteratorRange(r.begin(), r.end());
1929 }
1930 
1931 template <typename T>
1932 auto lar::sparse_vector<T>::range_const_data(std::size_t const i) const
1933 {
1934  auto& r = ranges[i];
1935  return details::iteratorRange(r.cbegin(), r.cend());
1936 }
1937 
1938 template <typename T>
1940  size_type index) const
1941 {
1942  if (ranges.empty()) throw std::out_of_range("empty sparse vector");
1943  // range after the index:
1944  range_const_iterator iNextRange = find_next_range_iter(index);
1945  return ((iNextRange == ranges.begin()) || (index >= (--iNextRange)->end_index())) ? ranges.end() :
1946  iNextRange;
1947 } // lar::sparse_vector<T>::find_range_iterator() const
1948 
1949 template <typename T>
1951  size_type index) const
1952 {
1953  if (ranges.empty()) throw std::out_of_range("empty sparse vector");
1954  // range on the index:
1955  range_const_iterator iNextRange = find_range_iterator(index);
1956  if (iNextRange == ranges.end()) throw std::out_of_range("index in no range of the sparse vector");
1957  return *iNextRange;
1958 } // lar::sparse_vector<T>::find_range() const
1959 
1960 template <typename T>
1962  size_type index)
1963 {
1964  return const_cast<datarange_t&>(const_cast<const this_t*>(this)->find_range(index));
1965 } // lar::sparse_vector<T>::find_range()
1966 
1967 template <typename T>
1969 {
1970  if (ranges.empty() || (index >= size())) throw std::out_of_range("empty sparse vector");
1971  // range after the index:
1972  range_iterator iNextRange = find_next_range_iter(index);
1973  if ((iNextRange == ranges.begin()) || ((--iNextRange)->end_index() <= index)) { return {}; }
1974  return void_range(iNextRange);
1975 } // lar::sparse_vector<T>::make_void_around()
1976 
1977 template <typename T>
1978 template <typename ITER>
1979 const typename lar::sparse_vector<T>::datarange_t&
1980 lar::sparse_vector<T>::add_range(size_type offset, ITER first, ITER last)
1981 {
1982  // insert the new range before the existing range which starts after offset
1983  range_iterator iInsert = find_next_range_iter(offset);
1984 
1985  // is there a range before this, which includes the offset?
1986  if ((iInsert != ranges.begin()) && std::prev(iInsert)->borders(offset)) {
1987  // then we should extend it
1988  (--iInsert)->extend(offset, first, last);
1989  }
1990  else {
1991  // no range before the insertion one includes the offset of the new range;
1992  // ... we need to add it as a new range
1993  iInsert = insert_range(iInsert, {offset, first, last});
1994  }
1995  return merge_ranges(iInsert);
1996 } // lar::sparse_vector<T>::add_range<ITER>()
1997 
1998 template <typename T>
2000  size_type offset,
2001  vector_t&& new_data)
2002 {
2003  // insert the new range before the existing range which starts after offset
2004  return add_range_before(
2005  offset,
2006  std::move(new_data),
2007  std::upper_bound(ranges.begin(),
2008  ranges.end(),
2009  offset,
2010  typename datarange_t::less_int_range(datarange_t::less)));
2011 
2012 } // lar::sparse_vector<T>::add_range(vector)
2013 
2014 template <typename T>
2015 template <typename ITER, typename OP>
2017  ITER first,
2018  ITER last,
2019  OP&& op,
2020  value_type void_value /* = value_zero */
2021  ) -> const datarange_t&
2022 {
2023  /*
2024  * This is a complicate enough task, that we go brute force:
2025  * 1) combine all the input elements within the datarange where offset falls
2026  * in
2027  * 2) create a new datarange combining void with the remaining input elements
2028  * 3) if the void area is over before the input elements are, repeat steps
2029  * (1) and (2) with the updated offset
2030  * 4) at this point we'll have a train of contiguous ranges, result of
2031  * combination of the input elements alternating with existing elements
2032  * and with void cells: apply the regular merge algorithm
2033  *
2034  */
2035 
2036  auto src = first;
2037  auto const insertionPoint = offset; // saved for later
2038  auto destRange = find_range_iter_at_or_after(offset);
2039  while (src != last) {
2040 
2041  //
2042  // (1) combine all the input elements within the datarange including offset
2043  // (NOT extending the range)
2044  //
2045  if ((destRange != end_range()) && destRange->includes(offset)) {
2046  // combine input data until this range is over (or input data is over)
2047  auto dest = destRange->get_iterator(offset);
2048 
2049  auto const end = destRange->end();
2050  while (src != last) {
2051  *dest = op(*dest, *src);
2052  ++src;
2053  ++offset;
2054  if (++dest == end) break;
2055  } // while
2056  if (src == last) break;
2057  offset = destRange->end_index();
2058  ++destRange;
2059  } // if
2060 
2061  //
2062  // (2) create a new datarange combining void with input elements
2063  //
2064  // at this point, offset is in the void, we do have more input data,
2065  // and `destRange` does _not_ contain the current insertion offset;
2066  // we fill as much void as we can with data, creating a new range.
2067  // When to stop? at the beginning of the next range, or when data is over
2068  //
2069  size_type const newRangeSize =
2070  (destRange == end_range()) ? std::distance(src, last) : (destRange->begin_index() - offset);
2071 
2072  // prepare the data (we'll plug it in directly)
2073  vector_t combinedData;
2074  combinedData.reserve(newRangeSize);
2075  size_type i = 0;
2076  while (i++ < newRangeSize) {
2077  combinedData.push_back(op(void_value, *src));
2078  if (++src == last) break; // no more data
2079  }
2080  // move the data as a new range inserted before the next range we just found
2081  // return value is the iterator to the inserted range
2082  destRange = insert_range(destRange, {offset, std::move(combinedData)});
2083 
2084  //
2085  // (3) if there is more input, repeat steps (1) and (2) with updated offset
2086  //
2087  offset = destRange->end_index();
2088  ++destRange;
2089  } // while
2090 
2091  //
2092  // (4) apply the regular merge algorithm;
2093  // since we did not extend existing ranges, it may happen that we have
2094  // created a new range at `insertionPoint` contiguous to the previous one;
2095  // so we take care of checking that too
2096  //
2097  return merge_ranges(find_extending_range_iter(insertionPoint == 0 ? 0 : insertionPoint - 1));
2098 
2099 } // lar::sparse_vector<T>::combine_range<ITER>()
2100 
2101 template <typename T>
2103 {
2104  // iterators have in "currentRange" either the range they point into,
2105  // or the range next to the void they point to
2106 
2107  if ((first.cont != this) || (last.cont != this)) {
2108  throw std::runtime_error("lar::sparse_vector::make_void(): iterators from alien container");
2109  }
2110  // if first is after next, no range is identified
2111  if (first >= last) return;
2112 
2113  range_iterator first_range = ranges.begin() + (first.get_current_range() - ranges.begin()),
2114  last_range = ranges.begin() + (last.get_current_range() - ranges.begin());
2115 
2116  //--- "first": void up to this iterator ---
2117  // if first in the last void region, there is nothing to erase
2118  if (first_range == ranges.end()) return;
2119 
2120  // if first is in the middle of a valid range instead, we have to resize it
2121  if (first.index > first_range->begin_index()) {
2122  if (first_range == last_range) {
2123  // we are going to erase a subset of a range;
2124  // this effectively creates two ranges;
2125  // first create the rightmost (last) range, and add it to the list
2126  last_range = ranges.emplace(++last_range,
2127  last.index,
2128  first_range->begin() + first_range->relative_index(last.index),
2129  first_range->end());
2130  // then cut the existing one
2131  first_range->move_tail(first.index);
2132  return;
2133  }
2134  first_range->move_tail(first.index);
2135  ++first_range; // from next range on, start voiding
2136  }
2137 
2138  //--- "last"
2139  // if the index is inside a range, remove up to it
2140  if ((last_range != ranges.end()) && (last.index > last_range->begin_index()))
2141  eat_range_head(last_range, last.index);
2142 
2143  // finally, remove entirely the ranges in between
2144  ranges.erase(first_range, last_range);
2145 } // lar::sparse_vector<T>::make_void()
2146 
2147 template <typename T>
2149 {
2150  auto r{std::move(*iRange)}; // triggering move constructor
2151  ranges.erase(iRange); // the emptied range is removed from vector
2152  return r; // returning it as a temporary avoids copies
2153 } // lar::sparse_vector<T>::void_range()
2154 
2155 template <typename T>
2157 {
2158  // a sparse vector with no non-null elements can't be detected invalid
2159  if (ranges.empty()) return true;
2160 
2161  range_const_iterator iNext = ranges.begin(), rend = ranges.end();
2162  while (iNext != rend) {
2163  range_const_iterator iRange = iNext++;
2164  if (iRange->empty()) return false;
2165  if (iNext != rend) {
2166  if (!(*iRange < *iNext)) return false;
2167  if (!iRange->separate(*iNext)) return false;
2168  }
2169  } // while
2170  if (nominal_size < ranges.back().end_index()) return false;
2171  return true;
2172 } // lar::sparse_vector<T>::is_valid()
2173 
2174 // --- private methods
2175 
2176 template <typename T>
2178  size_type index,
2179  range_iterator rbegin)
2180 {
2181  // this range has the offset (first index) above the index argument:
2182  return std::upper_bound(
2183  rbegin, ranges.end(), index, typename datarange_t::less_int_range(datarange_t::less));
2184 } // lar::sparse_vector<T>::find_next_range_iter()
2185 
2186 template <typename T>
2188  size_type index,
2189  range_const_iterator rbegin) const
2190 {
2191  // this range has the offset (first index) above the index argument:
2192  return std::upper_bound(
2193  rbegin, ranges.end(), index, typename datarange_t::less_int_range(datarange_t::less));
2194 } // lar::sparse_vector<T>::find_next_range_iter() const
2195 
2196 template <typename T>
2199 {
2200  // this range has the offset (first index) above the index argument:
2201  auto after = find_next_range_iter(index);
2202  // if the previous range exists and contains index, that's the one we want
2203  return ((after != ranges.begin()) && (index < std::prev(after)->end_index())) ? std::prev(after) :
2204  after;
2205 } // lar::sparse_vector<T>::find_range_iter_at_or_after() const
2206 
2207 template <typename T>
2209  size_type index)
2210 {
2211  // this range has the offset (first index) above the index argument:
2212  auto after = find_next_range_iter(index);
2213  // if the previous range exists and contains index, that's the one we want
2214  return ((after != ranges.begin()) && (index < std::prev(after)->end_index())) ? std::prev(after) :
2215  after;
2216 } // lar::sparse_vector<T>::find_range_iter_at_or_after()
2217 
2218 template <typename T>
2220  size_type index,
2221  range_iterator rbegin)
2222 {
2223  // this range has the offset (first index) above the index argument:
2224  auto it = find_next_range_iter(index, rbegin);
2225  // if index were not void, would it belong to the previous range?
2226  // if so, the previous range is the one we want
2227  return ((it != rbegin) && std::prev(it)->borders(index)) ? std::prev(it) : it;
2228 } // lar::sparse_vector<T>::find_extending_range_iter()
2229 
2230 template <typename T>
2233 {
2234  // this range has the offset (first index) above the index argument:
2235  auto it = find_next_range_iter(index, rbegin);
2236  // if index were not void, would it belong to the previous range?
2237  // if so, the previus range is the one we want
2238  return ((it != rbegin) && std::prev(it)->borders(index)) ? std::prev(it) : it;
2239 } // lar::sparse_vector<T>::find_extending_range_iter() const
2240 
2241 template <typename T>
2243  size_type offset,
2244  vector_t&& new_data,
2245  range_iterator nextRange)
2246 {
2247  // insert the new range before the existing range which starts after offset
2248  range_iterator iInsert = nextRange;
2249 
2250  // is there a range before this, which includes the offset?
2251  if ((iInsert != ranges.begin()) && (iInsert - 1)->borders(offset)) {
2252  // then we should extend it
2253  (--iInsert)->extend(offset, new_data.begin(), new_data.end());
2254  }
2255  else {
2256  // no range before the insertion one includes the offset of the new range;
2257  // ... we need to add it as a new range;
2258  // it is not really clear to me [GP] why I need a std::move here, since
2259  // new_data is a rvalue already; in doubt, I have painted all this kind
2260  // of constructs with move()s, just in case
2261  iInsert = insert_range(iInsert, {offset, std::move(new_data)});
2262  }
2263  return merge_ranges(iInsert);
2264 } // lar::sparse_vector<T>::add_range_before(vector, iterator)
2265 
2266 template <typename T>
2268  range_iterator iRange)
2269 {
2270  range_iterator iNext = iRange + 1;
2271  while (iNext != ranges.end()) {
2272  if (!iRange->borders(iNext->begin_index())) break;
2273  // iRange content dominates, but if iNext has data beyond it,
2274  // then we copy it
2275  if (iNext->end_index() > iRange->end_index()) {
2276  iRange->extend(iRange->end_index(), iNext->get_iterator(iRange->end_index()), iNext->end());
2277  }
2278  iNext = ranges.erase(iNext);
2279  } // while
2280  fix_size();
2281  return *iRange;
2282 } // lar::sparse_vector<T>::merge_ranges()
2283 
2284 template <typename T>
2286  range_iterator iRange,
2287  size_t index)
2288 {
2289  if (index <= iRange->begin_index()) return iRange;
2290  if (index >= iRange->end_index()) return ranges.erase(iRange);
2291  iRange->move_head(index);
2292  return iRange;
2293 } // lar::sparse_vector<T>::eat_range_head()
2294 
2295 template <typename T>
2297 {
2298  if (!ranges.empty()) nominal_size = std::max(nominal_size, ranges.back().end_index());
2299  return nominal_size;
2300 } // lar::sparse_vector<T>::fix_size()
2301 
2302 // --- static methods
2303 
2304 template <typename T>
2306 {
2307  // apparently, a chunk of heap memory takes at least 32 bytes;
2308  // that means that a vector of 1 or 5 32-bit integers takes the same
2309  // space; the overhead appears to be 8 bytes, which can be allocated
2310  return sizeof(vector_t) + std::max(size_t(32), (alignof(datarange_t) * size + 8));
2311 } // lar::sparse_vector<T>::expected_vector_size()
2312 
2313 template <typename T>
2315 {
2316  // we assume here that there is no additional overhead by alignment;
2317  // the gap adds the space of another datarange_t, including the vector,
2318  // its data and overhead from heap (apparently, 8 bytes);
2319  //
2320  return (sizeof(datarange_t) + 8) / sizeof(value_type) + 1; // round up
2321 } // lar::sparse_vector<T>::min_gap()
2322 
2323 template <typename T>
2325  const typename datarange_t::base_t& b)
2326 {
2327  size_type gap_size = (a < b) ? b.begin_index() - a.begin_index() - a.size() :
2328  a.begin_index() - b.begin_index() - b.size();
2329  return expected_vector_size(a.size() + b.size() + gap_size) <=
2330  expected_vector_size(a.size()) + expected_vector_size(b.size());
2331 } // lar::sparse_vector<T>::should_merge()
2332 
2333 // --- non-member functions
2334 template <typename T>
2335 std::ostream& operator<<(std::ostream& out, const lar::sparse_vector<T>& v)
2336 {
2337 
2338  out << "Sparse vector of size " << v.size() << " with " << v.get_ranges().size() << " ranges:";
2339  typename lar::sparse_vector<T>::range_const_iterator iRange = v.begin_range(),
2340  rend = v.end_range();
2341  while (iRange != rend) {
2342  out << "\n ";
2343  iRange->dump(out);
2344  /*
2345  out << "\n [" << iRange->begin_index() << " - " << iRange->end_index()
2346  << "] (" << iRange->size() << "):";
2347  typename lar::sparse_vector<T>::datarange_t::const_iterator
2348  iValue = iRange->begin(), vend = iRange->end();
2349  while (iValue != vend) out << " " << (*(iValue++));
2350  */
2351  ++iRange;
2352  } // for
2353  return out << std::endl;
2354 } // operator<< (ostream, sparse_vector<T>)
2355 
2356 // -----------------------------------------------------------------------------
2357 // --- lar::sparse_vector<T>::datarange_t implementation
2358 // ---
2359 template <typename T>
2360 template <typename ITER>
2363 {
2364  size_type new_size =
2365  std::max(base_t::relative_index(index) + std::distance(first, last), base_t::size());
2366  base_t::resize(new_size);
2367  values.resize(new_size);
2368  std::copy(first, last, get_iterator(index));
2369  return *this;
2370 } // lar::sparse_vector<T>::datarange_t::extend()
2371 
2372 template <typename T>
2374  value_type def_value /* = value_zero */)
2375 {
2376  difference_type delta = to_index - base_t::begin_index();
2377  if (delta == 0) return;
2378  base_t::move_head(delta);
2379  if (delta > 0) // shrink
2380  values.erase(values.begin(), values.begin() + delta);
2381  else { // extend
2382  values.insert(values.begin(),
2384  value_const_iterator<value_type>(def_value) - delta);
2385  }
2386 } // lar::sparse_vector<T>::datarange_t::move_head()
2387 
2388 template <typename T>
2389 template <typename Stream>
2391 {
2392  out << "[" << this->begin_index() << " - " << this->end_index() << "] (" << this->size()
2393  << "): {";
2394  for (auto const& v : this->values)
2395  out << " " << v;
2396  out << " }";
2397 } // lar::sparse_vector<T>::datarange_t::dump()
2398 
2399 // -----------------------------------------------------------------------------
2400 // --- lar::sparse_vector<T>::const_iterator implementation
2401 // ---
2402 template <typename T>
2404 {
2405  // no container, not doing anything;
2406  // index beyond the end: stays there
2407  if (!cont || (index >= cont->size())) return *this;
2408 
2409  // increment the internal index
2410  ++index;
2411 
2412  // were we in a valid range?
2413  if (currentRange != cont->ranges.end()) {
2414  // if the new index is beyond the current range, pick the next
2415  if (currentRange->end_index() <= index) ++currentRange;
2416  }
2417  // if we have no valid range, we are forever in the void
2418  return *this;
2419 } // lar::sparse_vector<T>::iterator::operator++()
2420 
2421 template <typename T>
2424 {
2425  // no container, no idea what to do
2426  if (!cont) throw std::out_of_range("iterator to no sparse vector");
2427 
2428  // index beyond the end: can't return any reference
2429  if (index >= cont->size()) return value_zero;
2430 
2431  // are we in a valid range? if not, we are past the last range
2432  if (currentRange == cont->ranges.end()) return value_zero;
2433 
2434  // if the index is beyond the current range, we are in the void
2435  if (index < currentRange->begin_index()) return value_zero;
2436 
2437  return (*currentRange)[index];
2438 } // lar::sparse_vector<T>::const_iterator::operator*()
2439 
2440 template <typename T>
2442  difference_type delta)
2443 {
2444  if (delta == 1) return this->operator++();
2445  index += delta;
2446  if ((currentRange == cont->ranges.end()) || !currentRange->includes(index)) refresh_state();
2447  return *this;
2448 } // lar::sparse_vector<T>::const_iterator::operator+=()
2449 
2450 template <typename T>
2453 {
2454  return this->operator+=(-delta);
2455 }
2456 
2457 template <typename T>
2459  difference_type delta) const
2460 {
2461  if ((currentRange == cont->ranges.end()) || !currentRange->includes(index + delta))
2462  return const_iterator(*cont, index + delta);
2463  const_iterator iter(*this);
2464  iter.index += delta;
2465  return iter;
2466 } // lar::sparse_vector<T>::const_iterator::operator+()
2467 
2468 template <typename T>
2471 {
2472  return this->operator+(-delta);
2473 }
2474 
2476 template <typename T>
2479 {
2480  if (cont != iter.cont) {
2481  throw std::runtime_error("lar::sparse_vector::const_iterator:"
2482  " difference with alien iterator");
2483  }
2484  return index - iter.index;
2485 } // lar::sparse_vector<T>::const_iterator::operator-(const_iterator)
2486 
2487 template <typename T>
2489 {
2490  // update the currentRange
2491  // currentRange is the range including the current item, or next to it
2492  if (cont) {
2493  // the following is actually the range after the index:
2494  currentRange = cont->find_next_range_iter(index);
2495  // if the index is inside the previous index, then we want to move there:
2496  if (currentRange != cont->ranges.begin()) {
2497  if ((currentRange - 1)->end_index() > index) --currentRange;
2498  }
2499  }
2500  else {
2501  currentRange = {};
2502  }
2503 } // lar::sparse_vector<T>::const_iterator::refresh_state()
2504 
2505 // -----------------------------------------------------------------------------
2506 // --- lar::sparse_vector<T>::iterator implementation
2507 // ---
2508 //
2509 // nothing new so far
2510 //
2511 
2512 #endif // LARDATAOBJ_UTILITIES_SPARSE_VECTOR_H
bool operator>(const const_iterator &than) const
Iterator comparisons.
TRandom r
Definition: spectrum.C:23
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.
bool operator!=(const this_t &as) const
Comparison operators: determined by the position pointed by the iterators.
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.
bool operator>=(const const_iterator &than) const
Iterator comparisons.
iterator operator-(difference_type delta) const
Increment and decrement operators.
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)
bool operator>=(const this_t &as) const
Comparison operators: determined by the position pointed by the iterators.
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.
reference operator[](size_type offset) const
Random access.
void dump(Stream &&out) const
Dumps the content of this data range into a stream.
bool operator<=(const const_iterator &than) const
Iterator comparisons.
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.
static value_type abs(value_type v)
Returns the module of the specified value.
vector_t values
data in the range
const_value_box< T > this_t
Definition: sparse_vector.h:40
this_t operator-(difference_type ofs) const
Returns an iterator pointing behind this one by the specified steps.
reference(const const_reference &from)
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::ptrdiff_t difference_type
Definition: sparse_vector.h:73
constexpr bool operator<(CryostatID const &a, CryostatID const &b)
Order cryostats with increasing ID.
Definition: geo_types.h:692
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.
bool operator<(const const_iterator &than) const
Iterator comparisons.
Reference reference
Definition: stdmap_shims.h:58
constexpr auto abs(T v)
Returns the absolute value of the argument.
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.
value_type operator[](difference_type) const
Returns a copy of the stored value.
Definition: sparse_vector.h:92
reference(value_type *pValue=0)
range_const_iterator find_extending_range_iter(size_type index) const
Returns an iterator to the range no earlier than index, or end() if none.
value_type & operator=(value_type v)
const_iterator cend() const
Standard iterators interface.
intermediate_table::const_iterator const_iterator
range_const_iterator find_next_range_iter(size_type index) const
Returns an iterator to the range after index.
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)
Turns the specified range into void.
const_iterator(const container_t &c, const typename special::end)
Special constructor: initializes at the end of the container.
Distance difference_type
Definition: stdmap_shims.h:56
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)
Returns the internal list of non-void ranges.
const_iterator get_iterator(size_type index) const
Returns an iterator to the specified absolute value (no check!)
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
std::random_access_iterator_tag iterator_category
Definition: sparse_vector.h:71
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:40
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.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
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:101
void move_tail(difference_type shift)
Moves the end of the range by the specified amount.
const_iterator cbegin() const
begin and end iterators
bool operator<(const this_t &as) const
Comparison operators: determined by the position pointed by the iterators.
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.
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:49
bool operator<=(const this_t &as) const
Comparison operators: determined by the position pointed by the iterators.
const_iterator cend() const
begin and end iterators
range_list_t ranges
list of ranges
bool back_is_void() const
Returns whether the sparse vector ends with void.
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.
static size_t min_gap()
Minimum optimal gap between ranges (a guess)
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.
const_iterator get_const_iterator(size_type index) const
Returns an iterator to the specified absolute value (no check!)
iterator end()
Standard iterators interface.
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:84
vector_t::size_type size_type
size type
typename sparse_vector< T >::const_datarange_t const_datarange_t
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
void assign(const CONT &new_data)
Copies data from a container.
const_iterator operator-(difference_type delta) const
Increment and decrement operators.
this_t & operator++()
Increments the position of the iterator, returns the new position.
Definition: sparse_vector.h:95
value_const_iterator()
Default constructor: use the default value.
Definition: sparse_vector.h:78
typename sparse_vector< T >::range_iterator base_iterator
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:39
void make_void(iterator first, iterator last)
Makes all the elements from first and before last void.
vector_t::const_reference const_reference
const_iterator & operator++()
Increment and decrement operators.
container_t::range_list_t::const_iterator ranges_const_iterator
this_t & operator-=(difference_type ofs)
Decrements the position of the iterator by the specified steps.
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).
void move_head(size_type to_index, value_type def_value=value_zero)
Moves the begin of this range.
String & operator+=(String &s, VectorDumper< Vector > const &manip)
Appends a string rendering of a vector to the specified string.
Definition: DumpUtils.h:463
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.
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)
value_type operator*() const
Returns a copy of the stored value.
Definition: sparse_vector.h:89
size_type index
pointer to the current value, as absolute index
sparse_vector< T > this_t
bool optimize(size_t)
Performs internal optimization, returns whether the object was changed.
range_list_t::const_iterator range_const_iterator
type of constant iterator over ranges
const_iterator operator++(int)
Increment and decrement operators.
const_iterator & operator-=(difference_type delta)
Increment and decrement operators.
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.
double value
Definition: spectrum.C:18
iterator operator++(int _)
Increment and decrement operators.
difference_type index
(arbitrary) position pointed by the iterator
const_iterator()
Default constructor, does not iterate anywhere.
Collection of utilities for dumping data on screen.
Definition: DumperBase.h:28
void resize(size_t new_size, value_type def_value)
Resizes the range (optionally filling the new elements with def_value)
this_t operator+(difference_type ofs) const
Returns an iterator pointing ahead of this one by the specified steps.
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_type operator[](size_type index) const
Access to an element (read only)
value_const_iterator< T > this_t
alias for this type
Definition: sparse_vector.h:68
iterator()
Default constructor, does not iterate anywhere.
size_type size() const
Returns the size of the range.
const value_type & operator[](size_type index) const
Returns the value at the specified absolute index.
A sparse vector.
static bool less(const range_t &a, size_type b)
Returns if a is "less" than b.
static bool less(size_type a, const range_t &b)
Returns if a is "less" than 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.
SIZE size_type
type for the indices in the range
LArSoft-specific namespace.
size_type nominal_size
current size
iterator operator+(difference_type delta) const
Increment and decrement operators.
const datarange_t & find_range(size_type index) const
Returns the range containing the specified index.
QuadExpr operator+(double v, const QuadExpr &e)
Definition: QuadExpr.h:36
iteratorRange(BITER const &b, EITER const &e)
this_t & operator=(value_type)
Assignment: the assigned value is ignored.
Definition: sparse_vector.h:52
vector_t::const_iterator const_iterator
Namespace hiding implementation details.
Definition: ServiceUtil.h:37
range_iterator find_range_iterator(size_type index)
Returns an iterator to the range containing the specified 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
Returns the internal list of non-void ranges.
const_value_box()
Default constructor: stores default value.
Definition: sparse_vector.h:46
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
Range class, with range and data.
value_type value
the value stored for delivery
Definition: sparse_vector.h:61
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
begin and end iterators
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)
Plug a new data range in the specified position; no check performed.
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.
iterator & operator-=(difference_type delta)
Increment and decrement operators.
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.
const_reference operator[](size_type offset) const
Random access.
range_list_t::iterator range_iterator
type of iterator over ranges
const_iterator begin() const
begin and end iterators
value_const_iterator(value_type new_value)
Constructor: value that will be returned.
Definition: sparse_vector.h:81
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:69
container_t::value_type value_type
const_iterator cbegin() const
Standard iterators interface.
iterator begin()
begin and end iterators
iterator end()
begin and end iterators
const_iterator::reference reference
bool operator!=(const const_iterator &as) const
Iterator comparisons.
Float_t e
Definition: plot.C:35
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:44
bool operator>(const this_t &as) const
Comparison operators: determined by the position pointed by the iterators.
const_iterator operator+(difference_type delta) const
Increment and decrement operators.
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:67
bool operator==(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
Definition: counter.h:278
T value_type
type of the value stored
Definition: sparse_vector.h:43
difference_type operator-(const this_t &iter) const
Returns the distance between this iterator and the other.
bool operator==(const range_t &as) const
Returns whether the specified range has our same offset and size.
vec_iX clear()
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
std::ptrdiff_t difference_type
type for index difference
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.
this_t & operator+=(difference_type ofs)
Increments the position of the iterator by the specified steps.
size_type count() const
Returns the number of non-void cells.