RangeForWrapper.h
Go to the documentation of this file.
1 /**
2  * @file lardata/Utilities/RangeForWrapper.h
3  * @brief Utility function to enable range-for on different type iterators
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date December 12, 2016
6  *
7  * This header will be needed likely until C++20, since range library is not
8  * providing some definitions that are needed for range for loops.
9  */
10 
11 #ifndef LARDATA_UTILITIES_RANGEFORWRAPPER_H
12 #define LARDATA_UTILITIES_RANGEFORWRAPPER_H
13 
14 // Boost libraries
15 #include "boost/variant.hpp"
16 
17 // C/C++ standard libraries
18 #include <stdexcept> // std::logic_error
19 #include <utility> // std::move(), std::declval(), ...
20 #include <iterator> // std::iterator_traits
21 #include <type_traits> // std::is_same<>, std::enable_if_t<>, ...
22 
23 
24 namespace util {
25 
26  namespace details {
27 
28  /// Iterator wrapping one of two types of iterators.
29  /// @see RangeForWrapperBox
30  template <typename BeginIter, typename EndIter>
32 
33  using traits_t = std::iterator_traits<BeginIter>;
34 
35  public:
36  using begin_t = BeginIter; ///< Type of begin iterator we can store.
37  using end_t = EndIter; ///< Type of end iterator we can store.
39 
40  /// @{
41  /// @brief Iterator traits, imported from the wrapped begin iterator.
42  using difference_type = typename traits_t::difference_type;
43  using value_type = typename traits_t::value_type;
44  using pointer = typename traits_t::pointer;
45  using reference = typename traits_t::reference;
46  //
47  // This wrapper fully supports up to bidirectional iterators;
48  // if the wrapped iterator is a random or contiguous iterator,
49  // the wrapper will still expose only a bidirectional iterator interface.
50  // Supporting random access is possible, but writing a proper unit test
51  // is tedious... open a feature request if needed.
52  //
53  using iterator_category = std::conditional_t<
55  std::bidirectional_iterator_tag,
56  typename traits_t::iterator_category
57  >;
58  /// @}
59 
60  /// Constructor: initializes with a end-type default-constructed iterator.
62  : fIter(end_t{})
63  {}
64 
65  /// Constructor: initializes with a begin-type iterator.
67  : fIter(std::move(begin))
68  {}
69 
70  /// Constructor: initializes with a end-type iterator.
72  : fIter(std::move(end))
73  {}
74 
75  /// Returns the pointed value (just like the original iterator).
77  { return boost::apply_visitor(Dereferencer(), fIter); }
78 
79  /// Returns the pointed value (just like the original iterator).
81  { return boost::apply_visitor(MemberAccessor(), fIter); }
82 
83  /// Increments the iterator (prefix operator).
85  { boost::apply_visitor(Incrementer(), fIter); return *this; }
86 
87  /// Decrements the iterator (prefix operator).
89  { boost::apply_visitor(Decrementer(), fIter); return *this; }
90 
91  /// Increments the iterator (postfix operator).
93  { auto old = *this; this_t::operator++(); return old; }
94 
95  /// Decrements the iterator (postfix operator).
97  { auto old = *this; this_t::operator--(); return old; }
98 
99  /// Returns whether the other iterator is not equal to this one.
100  bool operator!=(this_t const& other) const
101  { return boost::apply_visitor(Comparer(), fIter, other.fIter); }
102 
103  /// Returns whether the other iterator is equal to this one.
104  bool operator==(this_t const& other) const
105  { return !(this->operator!=(other)); }
106 
107 
109  { return boost::apply_visitor(IndexAccessor(offset), fIter); }
110 
112  { return boost::apply_visitor(Difference(), fIter, other.fIter); }
113 
114  private:
116  "RangeForWrapperIterator requires two different iterator types."
117  );
118 
119  boost::variant<begin_t, end_t> fIter; ///< The actual iterator we store.
120 
121  //
122  // We opt for allowing all the operations if the underlying operators do.
123  // While it is true that, for example, an end iterator should not be
124  // dereferenced, if it's bidirectional, its operator--() may make it
125  // useful, but its type will still be the one of the end iterator.
126  // Therefore we don't judge by the type, but by the action.
127  //
128 
129  /// Visitor to dereference an iterator.
130  struct Dereferencer: public boost::static_visitor<reference> {
131 
132  template <typename Iter>
133  auto operator() (Iter& iter) const -> decltype(auto)
135 
136  private:
137  template <typename Result, typename Iter, typename = void>
139 
140  }; // Dereferencer
141 
142  /// Visitor to access a data member of the pointed class.
143  struct MemberAccessor: public boost::static_visitor<pointer> {
144 
145  template <typename Iter>
146  auto operator() (Iter& iter) const -> decltype(auto)
148 
149  private:
150  template <typename Result, typename Iter, typename = void>
152 
153  }; // MemberAccessor
154 
155  /// Visitor to increment an iterator.
156  struct Incrementer: public boost::static_visitor<> {
157 
158  template <typename Iter>
159  void operator() (Iter& iter) const
161 
162  private:
163  template <typename Iter, typename = void>
165 
166  }; // Incrementer
167 
168  /// Visitor to decrement an iterator.
169  struct Decrementer: public boost::static_visitor<> {
170 
171  template <typename Iter>
172  void operator() (Iter& iter) const
174 
175  private:
176  template <typename Iter, typename = void>
178 
179  }; // Decrementer
180 
181 
182  /// Visitor to compare iterators (returns whether they differ).
183  struct Comparer: public boost::static_visitor<bool> {
184 
185  template <typename A, typename B>
186  bool operator() (A const& left, B const& right) const
187  { return ComparerImpl<A, B>::compare(left, right); }
188 
189  private:
190  template <typename A, typename B, typename = void>
191  struct ComparerImpl;
192 
193  }; // Comparer
194 
195  /// Visitor to access element by index.
196  struct IndexAccessor: public boost::static_visitor<reference> {
197 
199 
200  IndexAccessor(difference_type offset): offset(offset) {}
201 
202  template <typename Iter>
203  bool operator() (Iter& iter) const
204  { return IndexAccessorImpl<reference, Iter>(offset).access(iter); }
205 
206  private:
207  template <typename Result, typename Iter, typename = void>
209 
210  }; // IndexAccessor
211 
212  /// Visitor to compare iterators (returns whether they differ).
213  struct Difference: public boost::static_visitor<difference_type > {
214 
215  template <typename A, typename B>
216  difference_type operator() (A const& minuend, B const& subtrahend) const
217  { return DifferenceImpl<A, B>::subtract(minuend, subtrahend); }
218 
219  private:
220  template <typename A, typename B, typename = void>
222 
223  }; // Difference
224 
225  }; // class RangeForWrapperIterator<>
226 
227 
228 
229  /// Class defining types and traits for RangeForWrapperBox
230  template <typename RangeRef>
232 
233  using RangeRef_t = RangeRef; ///< Type of the stored reference.
234 
235  ///< Type of the stored range (constantness is preserved).
236  using Range_t = std::remove_reference_t<RangeRef_t>;
237 
238  /// Extractor of the begin iterator from a range.
239  static auto extractBegin(RangeRef_t range)
240  { using namespace std; return begin(range); }
241 
242  /// Extracts the end iterator from a range object.
243  static auto extractEnd(RangeRef_t range)
244  { using namespace std; return end(range); }
245 
246  /// Type of wrapped begin iterator.
247  using BeginIter_t = decltype(extractBegin(std::declval<RangeRef_t>()));
248 
249  /// Type of wrapped end iterator.
250  using EndIter_t = decltype(extractEnd(std::declval<RangeRef_t>()));
251 
252  /// True if the range has iterators of the same type.
253  static constexpr bool sameIteratorTypes
254  = std::is_same<BeginIter_t, EndIter_t>();
255 
256  /// Type of wrapper iterators (same for begin and end iterators).
258 
259  using value_type = typename BeginIter_t::value_type;
260  using size_type = std::size_t;
261  using difference_type = typename BeginIter_t::difference_type;
262  using reference = typename BeginIter_t::value_type;
263  using pointer = typename BeginIter_t::pointer;
264 
265  }; // class RangeForWrapperTraits<>
266 
267 
268  /**
269  * @brief Class offering begin/end iterators of the same type out of a range
270  * of iterators of different types.
271  * @tparam RangeRef type of reference to be stored (constantness embedded)
272  *
273  * The class steals (moves) the value if `RangeRef` is a rvalue reference
274  * type, while it just references the original one otherwise.
275  */
276  template <typename RangeRef>
278 
280  "RangeForWrapperBox requires a reference type.");
281 
283 
284  public:
285 
286  // Import traits
288  using Range_t = typename Traits_t::Range_t;
289 
290  /// Type of wrapper iterators (same for begin and end iterators).
292 
293  /// Type of number of stored elements.
294  using size_type = typename Traits_t::size_type;
295 
296  /// Type of difference between element positions.
298 
299  /// Type of value contained in the wrapped sequence.
301 
302 
303  /// Constructor: references the specified range (lvalue reference).
305  : fRange(range)
306  {}
307 
308  /// Constructor: references the specified range (rvalue reference).
310  : fRange(std::move(range))
311  {}
312 
313  /// Returns a begin-of-range iterator.
315  { return Iterator_t(wrappedBegin()); }
316 
317  /// Returns a end-of-range iterator.
318  Iterator_t end() const
319  { return Iterator_t(wrappedEnd()); }
320 
321  /// @{
322  /// @name Reduced container interface.
323 
324  auto size() const { return std::distance(begin(), end()); }
325 
326  bool empty() const { return !(wrappedBegin() != wrappedEnd()); }
327 
328  auto operator[] (difference_type index) const -> decltype(auto)
329  { return wrappedBegin()[index]; }
330 
331  /// @}
332 
333 
334  private:
335 
336  struct DataBox {
337 
338  using Stored_t = std::conditional_t<
340  std::remove_reference_t<RangeRef_t>,
341  RangeRef_t
342  >;
343  using Data_t = std::remove_reference_t<Stored_t>;
344 
346 
347  // only one of these is valid...
348  DataBox(Data_t& data): data(data) {}
349  DataBox(Data_t&& data): data(std::move(data)) {}
350 
351  operator RangeRef_t() const { return RangeRef_t(data); }
352  operator RangeRef_t() { return RangeRef_t(data); }
353 
354  }; // DataBox
355 
356  DataBox fRange; ///< A reference to the original range.
357 
358  auto wrappedBegin() const -> decltype(auto)
359  { return Traits_t::extractBegin(static_cast<RangeRef_t>(fRange)); }
360  auto wrappedEnd() const -> decltype(auto)
361  { return Traits_t::extractEnd(static_cast<RangeRef_t>(fRange)); }
362 
363  }; // class RangeForWrapperBox<>
364 
365 
366  /// Tag for internal use.
367  struct SameIterTag {};
368 
369  /// Tag for internal use.
370  struct DiffIterTag {};
371 
372  /// Wraps an object for use in a range-for loop
373  /// (same iterator types: pass through)
374  // the return type decltype(auto) is necessary to preserve the forwarded
375  // referenceness
376  template <
377  typename BaseRange,
378  bool SameIteratorsType
380  >
382 
383  // Template specialization for same iterator types
384  template <typename BaseRange>
385  struct WrapRangeForDispatcher<BaseRange, true> {
386 
387  using BaseRange_t = std::decay_t<BaseRange>;
388 
389  static BaseRange_t wrap(BaseRange_t&& range) { return std::move(range); }
390  static BaseRange_t& wrap(BaseRange_t& range) { return range; }
391  static BaseRange_t const& wrap(BaseRange_t const& range) { return range; }
392  }; // WrapRangeForDispatcher<BaseRange, true>
393 
394 
395  // Template specialization for different-iterator types
396  template <typename BaseRange>
397  struct WrapRangeForDispatcher<BaseRange, false> {
398  template <typename Range>
399  static auto wrap(Range&& range)
400  {
402  (static_cast<decltype(range)>(range));
403  }
404  }; // WrapRangeForDispatcher<BaseRange, false>
405 
406  } // namespace details
407 
408 
409  /**
410  * @brief Wraps an object for use in a range-for loop
411  * @tparam Range type of range object (anything with begin() and end())
412  * @param range instance of the range object to be wrapped
413  *
414  * This is necessary only when the argument provides different types for
415  * the begin-of-range and end-of-range iterators.
416  * This is also superfluous for compilers adhering to C++ 2017 standard,
417  * which accepts iterators of different types by requirement.
418  * Example of usage:
419  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
420  * Range data; // initialization
421  * for (auto&& value: util::wrapRangeFor(data)) // ...
422  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
423  * where data is supposed to gave begin and end iterators of different types.
424  */
425  template <typename Range>
426  auto wrapRangeFor(Range&& range) -> decltype(auto)
427  {
429  (std::forward<Range>(range));
430  }
431 
432 
433  /// Tag marking the use of RangeForWrapperBox
435 
436  /// Constant to be used with
437  /// `operator|(Range&&, details::RangeForWrapperTag)`.
439 
440  /**
441  * @brief Transforms a range so that it can be used in a range-for loop
442  * @tparam Range the type of range to be transformed
443  * @param range the range to be transformed
444  * @return an equivalent range object to be used in a range-for loop
445  *
446  * This is necessary only when the argument provides different types for
447  * the begin-of-range and end-of-range iterators.
448  * This is also superfluous for compilers adhering to C++ 2017 standard,
449  * which accepts iterators of different types by requirement.
450  * Example of usage:
451  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
452  * Range data; // initialization
453  * for (auto&& value: data | util::range_for) // ...
454  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
455  * where data is supposed to gave begin and end iterators of different types.
456  */
457  template <typename Range>
458  auto operator| (Range&& range, RangeForWrapperTag) -> decltype(auto)
459  { return wrapRangeFor(std::forward<Range>(range)); }
460 
461 
462 } // namespace util
463 
464 
465 //------------------------------------------------------------------------------
466 //--- template implementation
467 //------------------------------------------------------------------------------
468 namespace util {
469 
470  namespace details {
471 
472  //--------------------------------------------------------------------------
473  template <typename T>
474  struct is_type: public std::true_type {};
475 
476  template <typename T>
477  constexpr bool is_type_v = is_type<T>();
478 
479 
480  //--------------------------------------------------------------------------
481  template <typename BeginIter, typename EndIter>
482  template <typename A, typename B, typename /* = void */>
483  struct RangeForWrapperIterator<BeginIter, EndIter>::Comparer::ComparerImpl {
484  // this would be worth a static_assert(), but apparently boost::variant
485  // visitor instantiates it even when it's not called
486  static bool compare(A const&, B const&)
487  { throw std::logic_error("These iterators can't be compared!"); }
488  }; //
489 
490  //--------------------------------------------------------------------------
491  template <typename BeginIter, typename EndIter>
492  template <typename A, typename B>
493  struct RangeForWrapperIterator<BeginIter, EndIter>::Comparer::ComparerImpl<
494  A, B, std::enable_if_t<
495  std::is_convertible
496  <decltype(std::declval<A>() != std::declval<B>()), bool>::value
497  >
498  >
499  {
500  static bool compare(A const& left, B const& right)
501  { return left != right; }
502  }; //
503 
504 
505  //--------------------------------------------------------------------------
506  template <typename BeginIter, typename EndIter>
507  template <typename Result, typename Iter, typename /* = void */>
508  struct RangeForWrapperIterator<BeginIter, EndIter>::Dereferencer::DereferencerImpl {
509  // this would be worth a static_assert(), but apparently boost::variant
510  // visitor instantiates it even when it's not called
511  [[noreturn]] static Result dereference(Iter const&)
512  { throw std::logic_error("This iterator can't be dereferenced!"); }
513  }; //
514 
515  //--------------------------------------------------------------------------
516  template <typename BeginIter, typename EndIter>
517  template <typename Result, typename Iter>
519  Result, Iter, std::enable_if_t<is_type_v<decltype(*(std::declval<Iter>()))>>
520  >
521  {
522  static Result dereference(Iter const& iter)
523  { return *iter; }
524  }; //
525 
526 
527  //--------------------------------------------------------------------------
528  template <typename BeginIter, typename EndIter>
529  template <typename Result, typename Iter, typename /* = void */>
530  struct RangeForWrapperIterator<BeginIter, EndIter>::MemberAccessor::MemberAccessorImpl {
531  // this would be worth a static_assert(), but apparently boost::variant
532  // visitor instantiates it even when it's not called
533  [[noreturn]] static Result access(Iter const&)
534  { throw std::logic_error("This iterator can't be dereferenced!"); }
535  }; //
536 
537  //--------------------------------------------------------------------------
538  template <typename BeginIter, typename EndIter>
539  template <typename Result, typename Iter>
541  Result, Iter, std::enable_if_t<is_type_v<decltype(std::declval<Iter>().operator->())>>
542  >
543  {
544  static Result access(Iter const& iter)
545  { return iter.operator->(); }
546  }; //
547 
548 
549  //--------------------------------------------------------------------------
550  template <typename BeginIter, typename EndIter>
551  template <typename Iter, typename /* = void */>
552  struct RangeForWrapperIterator<BeginIter, EndIter>::Incrementer::IncrementerImpl {
553  // this would be worth a static_assert(), but apparently boost::variant
554  // visitor instantiates it even when it's not called
555  [[noreturn]] static void increment(Iter&)
556  { throw std::logic_error("This iterator can't be incremented!"); }
557  }; //
558 
559  //--------------------------------------------------------------------------
560  template <typename BeginIter, typename EndIter>
561  template <typename Iter>
563  Iter, std::enable_if_t<is_type_v<decltype(++(std::declval<Iter>()))>>
564  >
565  {
566  static void increment(Iter& iter)
567  { ++iter; }
568  }; //
569 
570 
571  //--------------------------------------------------------------------------
572  template <typename BeginIter, typename EndIter>
573  template <typename Iter, typename /* = void */>
574  struct RangeForWrapperIterator<BeginIter, EndIter>::Decrementer::DecrementerImpl {
575  // this would be worth a static_assert(), but apparently boost::variant
576  // visitor instantiates it even when it's not called
577  [[noreturn]] static void decrement(Iter&)
578  { throw std::logic_error("This iterator can't be decremented!"); }
579  }; //
580 
581  //--------------------------------------------------------------------------
582  template <typename BeginIter, typename EndIter>
583  template <typename Iter>
585  Iter, std::enable_if_t<is_type_v<decltype(--(std::declval<Iter>()))>>
586  >
587  {
588  static void decrement(Iter& iter)
589  { --iter; }
590  }; //
591 
592 
593  //--------------------------------------------------------------------------
594  template <typename BeginIter, typename EndIter>
595  template <typename Result, typename Iter, typename /* = void */>
596  struct RangeForWrapperIterator<BeginIter, EndIter>::IndexAccessor::IndexAccessorImpl {
597  // this would be worth a static_assert(), but apparently boost::variant
598  // visitor instantiates it even when it's not called
599 
601 
602  [[noreturn]] Result access(Iter const&) const
603  { throw std::logic_error("This iterator can't be indexed!"); }
604  }; //
605 
606  //--------------------------------------------------------------------------
607  template <typename BeginIter, typename EndIter>
608  template <typename Result, typename Iter>
610  Result, Iter, std::enable_if_t<is_type_v<decltype((std::declval<Iter>())[0])>>
611  >
612  {
614 
615  IndexAccessorImpl(difference_type offset): offset(offset) {}
616 
617  Result dereference(Iter const& iter) const
618  { return iter[offset]; }
619  }; //
620 
621 
622  //--------------------------------------------------------------------------
623  template <typename BeginIter, typename EndIter>
624  template <typename A, typename B, typename /* = void */>
625  struct RangeForWrapperIterator<BeginIter, EndIter>::Difference::DifferenceImpl {
626  // this would be worth a static_assert(), but apparently boost::variant
627  // visitor instantiates it even when it's not called
628  static difference_type subtract(A const&, B const&)
629  { throw std::logic_error("These iterators can't be subtracted!"); }
630  }; //
631 
632  //--------------------------------------------------------------------------
633  template <typename BeginIter, typename EndIter>
634  template <typename A, typename B>
636  A, B, std::enable_if_t<
637  std::is_convertible<
638  decltype(std::declval<A>() - std::declval<B>()),
639  typename RangeForWrapperIterator<BeginIter, EndIter>::difference_type>::value
640  >
641  >
642  {
643  static difference_type subtract(A const& minuend, B const& subtrahend)
644  { return minuend - subtrahend; }
645  }; //
646 
647 
648  //--------------------------------------------------------------------------
649 
650 
651  } // namespace details
652 } // namespace util
653 
654 
655 //------------------------------------------------------------------------------
656 
657 
658 #endif // LARDATA_UTILITIES_RANGEFORWRAPPER_H
reference operator*() const
Returns the pointed value (just like the original iterator).
static BaseRange_t wrap(BaseRange_t &&range)
std::remove_reference_t< RangeRef_t > Range_t
DataBox fRange
A reference to the original range.
static BaseRange_t & wrap(BaseRange_t &range)
std::iterator_traits< BeginIter > traits_t
auto operator|(Range &&range, RangeForWrapperTag) -> decltype(auto)
Transforms a range so that it can be used in a range-for loop.
Namespace for general, non-LArSoft-specific utilities.
this_t & operator++()
Increments the iterator (prefix operator).
bool operator==(this_t const &other) const
Returns whether the other iterator is equal to this one.
auto wrappedEnd() const -> decltype(auto)
Tag for internal use.
int compare(unsigned *r, sha1::digest_t const &d)
Definition: sha1_test_2.cc:60
static auto extractEnd(RangeRef_t range)
Extracts the end iterator from a range object.
this_t operator--(int)
Decrements the iterator (postfix operator).
typename Traits_t::difference_type difference_type
Type of difference between element positions.
typename Traits_t::Iterator_t Iterator_t
Type of wrapper iterators (same for begin and end iterators).
difference_type operator-(this_t const &other) const
Visitor to compare iterators (returns whether they differ).
RangeForWrapperIterator(begin_t &&begin)
Constructor: initializes with a begin-type iterator.
bool operator!=(this_t const &other) const
Returns whether the other iterator is not equal to this one.
RangeRef RangeRef_t
Type of the stored range (constantness is preserved).
Class offering begin/end iterators of the same type out of a range of iterators of different types...
typename traits_t::reference reference
STL namespace.
reference operator[](difference_type offset) const
static auto extractBegin(RangeRef_t range)
Extractor of the begin iterator from a range.
Iterator_t begin() const
Returns a begin-of-range iterator.
static difference_type subtract(A const &, B const &)
typename Traits_t::value_type value_type
Type of value contained in the wrapped sequence.
typename BeginIter_t::pointer pointer
typename BeginIter_t::value_type reference
static BaseRange_t const & wrap(BaseRange_t const &range)
EndIter end_t
Type of end iterator we can store.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
boost::variant< begin_t, end_t > fIter
The actual iterator we store.
auto wrapRangeFor(Range &&range) -> decltype(auto)
Wraps an object for use in a range-for loop.
std::remove_reference_t< Stored_t > Data_t
constexpr RangeForWrapperTag range_for
pointer operator->() const
Returns the pointed value (just like the original iterator).
typename Traits_t::Range_t Range_t
typename traits_t::difference_type difference_type
Iterator traits, imported from the wrapped begin iterator.
def move(depos, offset)
Definition: depos.py:107
Tag for internal use.
RangeForWrapperBox(Range_t &range)
Constructor: references the specified range (lvalue reference).
typename BeginIter_t::value_type value_type
Visitor to access a data member of the pointed class.
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
this_t operator++(int)
Increments the iterator (postfix operator).
typename traits_t::pointer pointer
typename Traits_t::RangeRef_t RangeRef_t
auto wrappedBegin() const -> decltype(auto)
decltype(extractBegin(std::declval< RangeRef_t >())) BeginIter_t
Type of wrapped begin iterator.
typename traits_t::value_type value_type
Iterator_t end() const
Returns a end-of-range iterator.
#define A
Definition: memgrp.cpp:38
represents a "Range" w/ notion of ordering. A range is defined by a pair of "start" and "end" values...
Definition: Range.h:34
def access(path, mode)
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
typename Traits_t::size_type size_type
Type of number of stored elements.
std::conditional_t< std::is_base_of< std::bidirectional_iterator_tag, typename traits_t::iterator_category >::value, std::bidirectional_iterator_tag, typename traits_t::iterator_category > iterator_category
RangeForWrapperIterator()
Constructor: initializes with a end-type default-constructed iterator.
BeginIter begin_t
Type of begin iterator we can store.
typename BeginIter_t::difference_type difference_type
this_t & operator--()
Decrements the iterator (prefix operator).
RangeForWrapperBox(Range_t &&range)
Constructor: references the specified range (rvalue reference).
constexpr bool is_type_v
decltype(extractEnd(std::declval< RangeRef_t >())) EndIter_t
Type of wrapped end iterator.
Class defining types and traits for RangeForWrapperBox.
RangeForWrapperIterator(end_t &&end)
Constructor: initializes with a end-type iterator.
Tag marking the use of RangeForWrapperBox.
auto operator()(Iter &iter) const -> decltype(auto)
std::conditional_t< std::is_rvalue_reference< RangeRef_t >::value, std::remove_reference_t< RangeRef_t >, RangeRef_t > Stored_t
Visitor to compare iterators (returns whether they differ).