DereferenceIterator.h
Go to the documentation of this file.
1 /**
2  * @file DereferenceIterator.h
3  * @brief Offer iterators automatically dereferencing their values
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date November 18, 2016
6  *
7  * This is a header only template library.
8  *
9  * It offers:
10  *
11  * - iterators (but you probably do not want to instantiate them directly):
12  * DereferenceIterator, DereferenceConstIterator
13  * - iterator wrappers:
14  * makeDereferenceIterator(), makeDereferenceConstIterator()
15  * - begin and end iterator extractors from collections:
16  * beginDereferenceIterator(), endDereferenceIterator(),
17  * rbeginDereferenceIterator(), rendDereferenceIterator(),
18  * cbeginDereferenceIterator(), cendDereferenceIterator(),
19  * crbeginDereferenceIterator(), crendDereferenceIterator()
20  * - functions to enable range-for loops:
21  * dereferenceIteratorLoop(), dereferenceIteratorReverseLoop(),
22  * dereferenceConstIteratorLoop(), dereferenceConstIteratorReverseLoop()
23  *
24  * @deprecated Boost offers `boost::make_indirect_iterator` and similar,
25  * with header `boost/iterator/indirect_iterator.hpp`.
26  *
27  */
28 
29 #ifndef LARCORE_COREUTILS_DEREFERENCEITERATOR_H
30 #define LARCORE_COREUTILS_DEREFERENCEITERATOR_H
31 
32 // C/C++ standard libraries
33 #include <utility> // std::move(), std::declval()
34 #include <type_traits> // std::add_lvalue_reference_t<>, std::add_pointer_t<>
35 
36 
37 namespace lar {
38  namespace util {
39 
40  namespace detail {
41 
42  template <typename BeginIter, typename EndIter>
43  class IteratorBox {
44  BeginIter b;
45  EndIter e;
46 
47  public:
48  IteratorBox(BeginIter b, EndIter e): b(b), e(e) {}
49 
50  BeginIter const& begin() const { return b; }
51  EndIter const& end() const { return e; }
52 
53  }; // IteratorBox<>
54 
55  template <typename BeginIter, typename EndIter>
56  auto makeIteratorBox(BeginIter b, EndIter e)
57  { return IteratorBox<BeginIter, EndIter>(b, e); }
58 
59 
60 
61  /// Base class for dereferencing iterators
62  template <typename Iter, typename Value>
64  using iterator_t = Iter; ///< wrapped iterator type
66 
67  iterator_t iter; ///< wrapper iterator
68 
69  public:
70  /// Tag used for initialization
71  struct initialize_tag {};
72 
73  /// @{
74  /// @name Type definitions for standard iterators
75 
76  using difference_type = typename iterator_t::difference_type;
77  using value_type = Value;
78  using pointer = std::add_pointer_t<value_type>;
79  using reference = std::add_lvalue_reference_t<value_type>;
80  using iterator_category = typename iterator_t::iterator_category;
81 
82  /// @}
83 
84 
85  /// Default constructor
86  DereferenceIteratorBase() = default;
87 
88  /// Constructor: copies the specified iterator in
90  : iter(iter) {}
91 
92  /// Constructor: acquires the specified iterator
94  : iter(std::move(iter)) {}
95 
96  /// @brief Generic copy constructor
97  /// @tparam OtherIter base iterator: must be assignable to iterator_t
98  /// @tparam OtherValue value type: must be convertible into value_type
99  template <typename OtherIter, typename OtherValue>
102  : iter(other.iter)
103  {
105  "Copying from a iterator with incompatible value"
106  );
107  }
108 
109  /// @brief Generic move constructor
110  /// @tparam OtherIter base iterator: must be assignable to iterator_t
111  /// @tparam OtherValue value type: must be convertible into value_type
112  template <typename OtherIter, typename OtherValue>
115  : iter(std::move(other.iter))
116  {
118  "Moving from a iterator with incompatible value"
119  );
120  }
121 
122 
123  /// Returns a reference to the data pointed by the original iterator
124  reference operator* () const { return **iter; }
125 
126  /// Returns a reference to the data pointed by the original iterator
127  pointer operator-> () const { return *iter; }
128 
129  /// Returns a reference to the i-th element after the pointed one
130  reference operator[] (difference_type i) const { return *(iter[i]); }
131 
132  /// Prefix increment operator
133  this_t& operator++() { ++iter; return *this; }
134 
135  /// Prefix decrement operator
136  this_t& operator--() { --iter; return *this; }
137 
138  /// Postfix increment operator
139  this_t operator++(int) { return this_t(iter++, {}); }
140 
141  /// Postfix decrement operator
142  this_t operator--(int) { return this_t(iter--, {}); }
143 
144  /// @{
145  /// Arithmetic operators (symmetric)
147  { return { iter + offset }; }
149  { return { iter - offset }; }
150 
152  { iter += offset; return *this; }
153  this_t& operator-= (difference_type offset)
154  { iter -= offset; return *this; }
155 
156  /// @}
157 
158  /// Returns the difference from another iterator
159  difference_type operator- (this_t const& other) const
160  { return iter - other.iter; }
161 
162  /// Bonus: returns true if the pointer is not dereferentiable
163  bool is_null() const { return iterator_t::operator* () == nullptr; }
164 
165  /// @{
166  /// @name Comparison operators between iterators
167 
168  bool operator== (this_t const& other) const
169  { return other.iter == iter; }
170  bool operator!= (this_t const& other) const
171  { return other.iter != iter; }
172  bool operator<= (this_t const& other) const
173  { return other.iter <= iter; }
174  bool operator>= (this_t const& other) const
175  { return other.iter >= iter; }
176  bool operator< (this_t const& other) const
177  { return other.iter < iter; }
178  bool operator> (this_t const& other) const
179  { return other.iter < iter; }
180 
181  /// @}
182 
183  }; // class DereferenceIteratorBase
184 
185  /// Swapped addition operator
186  template <typename Iter, typename Value>
190  )
191  { return iter + offset; }
192 
193 
194  } // namespace detail
195 
196 
197  /** ************************************************************************
198  * @brief An iterator wrapper to dereference pointed values
199  * @tparam Iter type of iterator being wrapped
200  * @see beginDereferenceIterator(), endDereferenceIterator(),
201  * dereferenceIteratorLoop()
202  *
203  * This iterator is useful to iterate a collection of pointers accessing
204  * directly the pointed values.
205  *
206  * It's probably easier to use cbeginDereferenceIterator(),
207  * cendDereferenceIterator() and dereferenceConstIteratorLoop() rather than
208  * instantiating this class directly.
209  *
210  * @note Note the bizarre construction mechanism, needed to differentiate
211  * from copy constructor. This allows nesting iterators.
212  *
213  * @deprecated Just use `boost::indirect_iterator` instead
214  * (`boost/iterator/indirect_iterator.hpp`).
215  */
216  template <typename Iter>
218  Iter,
219  std::add_const_t<std::decay_t<decltype(**(std::declval<Iter>()))>>
220  >;
221 
222  /**
223  * @brief An iterator wrapper to dereferencing pointed values as constant
224  * @tparam Iter type of iterator being wrapped
225  * @see DereferenceConstIterator
226  *
227  * This class behaves like DereferenceConstIterator, except that it returns
228  * mutable references to values.
229  *
230  * @deprecated Just use `boost::indirect_iterator` instead
231  * (`boost/iterator/indirect_iterator.hpp`).
232  */
233  template <typename Iter>
235  Iter,
236  std::decay_t<decltype(**(std::declval<Iter>()))>
237  >;
238 
239 
240 
241  /**
242  * @brief Returns a dereference iterator to the begin of specified container
243  * @tparam Iter type of the iterator to be wrapped (may be constant)
244  * @param iter the iterator to be wrapped
245  * @return a dereference iterator of iter
246  * @see beginDereferenceIterator(), endDereferenceIterator(),
247  * rbeginDereferenceIterator(), rendDereferenceIterator(),
248  * dereferenceIteratorLoop(), dereferenceIteratorReverseLoop()
249  *
250  * If the type is constant, the iterator will likely be constant too.
251  * This wrapper is quite blind to the meaning of iterators and their
252  * constantness.
253  */
254  template <typename Iter>
255  auto makeDereferenceIterator(Iter&& iter)
256  { return DereferenceIterator<Iter>(std::forward<Iter>(iter), {}); }
257 
258  /**
259  * @brief Returns a dereference iterator to the begin of specified container
260  * @tparam Cont type of the container (may be constant)
261  * @param cont container to extract the iterator from
262  * @return a dereference iterator of cont.begin()
263  *
264  * If the type is constant, the iterator will likely be constant too.
265  * This wrapper is quite blind to the meaning of iterators and their
266  * constantness.
267  */
268  template <typename Cont>
269  auto beginDereferenceIterator(Cont& cont)
270  { return makeDereferenceIterator(cont.begin()); }
271 
272  /**
273  * @brief Returns a dereference iterator to the end of specified container
274  * @tparam Cont type of the container (may be constant)
275  * @param cont container to extract the iterator from
276  * @return a dereference iterator of cont.end()
277  *
278  * If the type is constant, the iterator will likely be constant too.
279  * This wrapper is quite blind to the meaning of iterators and their
280  * constantness.
281  */
282  template <typename Cont>
283  auto endDereferenceIterator(Cont& cont)
284  { return makeDereferenceIterator(cont.end()); }
285 
286  /**
287  * @brief Returns a dereference reverse iterator to the begin of container
288  * @tparam Cont type of the container (may be constant)
289  * @param cont container to extract the iterator from
290  * @return a dereference iterator of cont.rbegin()
291  *
292  * If the type is constant, the iterator will likely be constant too.
293  * This wrapper is quite blind to the meaning of iterators and their
294  * constantness.
295  */
296  template <typename Cont>
297  auto rbeginDereferenceIterator(Cont& cont)
298  { return makeDereferenceIterator(cont.rbegin()); }
299 
300  /**
301  * @brief Returns a dereference reverse iterator to the end of container
302  * @tparam Cont type of the container (may be constant)
303  * @param cont container to extract the iterator from
304  * @return a dereference iterator of cont.rend()
305  *
306  * If the type is constant, the iterator will likely be constant too.
307  * This wrapper is quite blind to the meaning of iterators and their
308  * constantness.
309  */
310  template <typename Cont>
311  auto rendDereferenceIterator(Cont& cont)
312  { return makeDereferenceIterator(cont.rend()); }
313 
314  /**
315  * @brief Returns an object enabling a dereferencing range-for loop
316  * @tparam Cont type of the container (may be constant)
317  * @param cont container to extract the iterator from
318  * @return an object enabling a dereferencing range-for loop
319  * @see dereferenceIteratorReverseLoop()
320  *
321  * Example of usage:
322  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
323  * std::vector<std::unique_ptr<int>> v;
324  *
325  * // fill the vector
326  *
327  * for (int& i: dereferenceIteratorLoop(v)) {
328  *
329  * std::cout << i << std::endl;
330  *
331  * } // for i
332  *
333  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334  * If the type is constant, the loop variable will likely be constant too.
335  * This wrapper is quite blind to the meaning of iterators and their
336  * constantness.
337  *
338  */
339  template <typename Cont>
340  auto dereferenceIteratorLoop(Cont& cont)
341  {
344  } // dereferenceIteratorLoop()
345 
346 
347  /**
348  * @brief Returns an object enabling a dereferencing reverse range-for loop
349  * @tparam Cont type of the container (may be constant)
350  * @param cont container to extract the iterator from
351  * @return an object enabling a dereferencing range-for loop
352  * @see dereferenceIteratorLoop()
353  *
354  * This function is similar to dereferenceIteratorLoop(), but the order of
355  * iteration is reversed.
356  *
357  * Example of usage:
358  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359  * std::vector<std::unique_ptr<int>> v;
360  *
361  * // fill the vector
362  *
363  * for (int& i: dereferenceIteratorReverseLoop(v)) {
364  *
365  * std::cout << i << std::endl;
366  *
367  * } // for i
368  *
369  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370  * If the type is constant, the loop variable will likely be constant too.
371  * This wrapper is quite blind to the meaning of iterators and their
372  * constantness.
373  *
374  */
375  template <typename Cont>
377  {
380  } // dereferenceIteratorReverseLoop()
381 
382 
383  /// @{
384  /// @name Constant iterator functions
385  ///
386  /// See the documentation of the similar non-const ones.
387 
388  /// @see makeDereferenceIterator
389  template <typename Iter>
391  { return DereferenceConstIterator<Iter>(std::forward<Iter>(iter), {}); }
392 
393  /// @see beginDereferenceIterator
394  template <typename Cont>
395  auto cbeginDereferenceIterator(Cont& cont)
396  { return makeDereferenceConstIterator(cont.cbegin()); }
397 
398  /// @see endDereferenceIterator
399  template <typename Cont>
400  auto cendDereferenceIterator(Cont& cont)
401  { return makeDereferenceConstIterator(cont.cend()); }
402 
403  /// @see rbeginDereferenceIterator
404  template <typename Cont>
405  auto crbeginDereferenceIterator(Cont& cont)
406  { return makeDereferenceConstIterator(cont.crbegin()); }
407 
408  /// @see crendDereferenceIterator
409  template <typename Cont>
410  auto crendDereferenceIterator(Cont& cont)
411  { return makeDereferenceConstIterator(cont.crend()); }
412 
413  /**
414  * @brief Returns an object enabling a dereferencing range-for loop
415  * @tparam Cont type of the container (may be constant)
416  * @param cont container to extract the iterator from
417  * @return an object enabling a dereferencing range-for loop
418  * @see dereferenceIteratorReverseLoop()
419  *
420  * Example of usage:
421  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422  * std::vector<std::unique_ptr<int>> v;
423  *
424  * // fill the vector
425  *
426  * for (int const& i: dereferenceConstIteratorLoop(v)) {
427  *
428  * std::cout << i << std::endl;
429  *
430  * } // for i
431  *
432  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433  * This wrapper forces the iteration variable to be constant.
434  */
435  template <typename Cont>
437  {
440  } // dereferenceConstIteratorLoop()
441 
442 
443  /**
444  * @brief Returns an object enabling a dereferencing reverse range-for loop
445  * @tparam Cont type of the container (may be constant)
446  * @param cont container to extract the iterator from
447  * @return an object enabling a dereferencing range-for loop
448  * @see dereferenceConstIteratorLoop()
449  *
450  * This function is similar to dereferenceConstIteratorLoop(), but the order
451  * of iteration is reversed.
452  *
453  * Example of usage:
454  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
455  * std::vector<std::unique_ptr<int>> v;
456  *
457  * // fill the vector
458  *
459  * for (int const& i: dereferenceConstIteratorReverseLoop(v)) {
460  *
461  * std::cout << i << std::endl;
462  *
463  * } // for i
464  *
465  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466  * If the type is constant, the loop variable will likely be constant too.
467  * This wrapper is quite blind to the meaning of iterators and their
468  * constantness.
469  *
470  */
471  template <typename Cont>
473  {
476  } // dereferenceConstIteratorReverseLoop()
477 
478  /// @}
479 
480  } // namespace util
481 } // namespace lar
482 
483 
484 #endif // LARCORE_COREUTILS_DEREFERENCEITERATOR_H
typename iterator_t::difference_type difference_type
auto operator+(typename DereferenceIteratorBase< Iter, Value >::difference_type offset, DereferenceIteratorBase< Iter, Value > const &iter)
Swapped addition operator.
auto crbeginDereferenceIterator(Cont &cont)
Namespace for general, non-LArSoft-specific utilities.
auto crendDereferenceIterator(Cont &cont)
DereferenceIteratorBase(Iter const &iter, initialize_tag)
Constructor: copies the specified iterator in.
bool operator>(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:53
DoubleProduct & operator+=(DoubleProduct &left, DoubleProduct const &right)
Definition: ToyProducts.h:103
BeginIter const & begin() const
auto dereferenceConstIteratorLoop(Cont &cont)
Returns an object enabling a dereferencing range-for loop.
auto dereferenceIteratorLoop(Cont &cont)
Returns an object enabling a dereferencing range-for loop.
EndIter const & end() const
STL namespace.
auto rendDereferenceIterator(Cont &cont)
Returns a dereference reverse iterator to the end of container.
auto dereferenceIteratorReverseLoop(Cont &cont)
Returns an object enabling a dereferencing reverse range-for loop.
auto beginDereferenceIterator(Cont &cont)
Returns a dereference iterator to the begin of specified container.
this_t & operator++()
Prefix increment operator.
Base class for dereferencing iterators.
auto makeIteratorBox(BeginIter b, EndIter e)
bool operator!=(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
QuadExpr operator-(double v, const QuadExpr &e)
Definition: QuadExpr.h:38
bool operator<(ProductInfo const &a, ProductInfo const &b)
Definition: ProductInfo.cc:51
std::add_lvalue_reference_t< value_type > reference
bool operator<=(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:47
std::add_pointer_t< value_type > pointer
auto makeDereferenceConstIterator(Iter &&iter)
this_t & operator--()
Prefix decrement operator.
def move(depos, offset)
Definition: depos.py:107
auto makeDereferenceIterator(Iter &&iter)
Returns a dereference iterator to the begin of specified container.
typename iterator_t::iterator_category iterator_category
bool is_null() const
Bonus: returns true if the pointer is not dereferentiable.
auto dereferenceConstIteratorReverseLoop(Cont &cont)
Returns an object enabling a dereferencing reverse range-for loop.
auto rbeginDereferenceIterator(Cont &cont)
Returns a dereference reverse iterator to the begin of container.
this_t operator--(int)
Postfix decrement operator.
DereferenceIteratorBase(Iter &&iter, initialize_tag)
Constructor: acquires the specified iterator.
LArSoft-specific namespace.
bool operator>=(ScheduleID const left, ScheduleID const right) noexcept
Definition: ScheduleID.cc:59
auto cendDereferenceIterator(Cont &cont)
auto cbeginDereferenceIterator(Cont &cont)
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:39
this_t operator++(int)
Postfix increment operator.
auto endDereferenceIterator(Cont &cont)
Returns a dereference iterator to the end of specified container.
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
IteratorBox(BeginIter b, EndIter e)