iterator_adaptor.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Uses code segments from boost/iterator/iterator_adaptor.hpp
  8. // and boost/iterator/iterator_fascade.hpp
  9. #ifndef BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP
  10. #define BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP
  11. #include <cstddef>
  12. #include <iterator>
  13. #include <memory>
  14. #include <type_traits>
  15. #include <utility>
  16. namespace boost {
  17. namespace histogram {
  18. namespace detail {
  19. // operator->() needs special support for input iterators to strictly meet the
  20. // standard's requirements. If *i is not a reference type, we must still
  21. // produce an lvalue to which a pointer can be formed. We do that by
  22. // returning a proxy object containing an instance of the reference object.
  23. template <class Reference>
  24. struct operator_arrow_dispatch_t {
  25. struct pointer {
  26. explicit pointer(Reference const& x) noexcept : m_ref(x) {}
  27. Reference* operator->() noexcept { return std::addressof(m_ref); }
  28. Reference m_ref;
  29. };
  30. using result_type = pointer;
  31. static result_type apply(Reference const& x) noexcept { return pointer(x); }
  32. };
  33. // specialization for "real" references
  34. template <class T>
  35. struct operator_arrow_dispatch_t<T&> {
  36. using result_type = T*;
  37. static result_type apply(T& x) noexcept { return std::addressof(x); }
  38. };
  39. // it is ok if void_t is already defined in another header
  40. template <class...>
  41. using void_t = void;
  42. template <class T, class = void>
  43. struct get_difference_type_impl : std::make_signed<T> {};
  44. template <class T>
  45. struct get_difference_type_impl<
  46. T, void_t<typename std::iterator_traits<T>::difference_type>> {
  47. using type = typename std::iterator_traits<T>::difference_type;
  48. };
  49. template <class T>
  50. using get_difference_type = typename get_difference_type_impl<T>::type;
  51. // adaptor supports only random access Base
  52. // Base: underlying base type of the iterator; can be iterator, pointer, integer
  53. // Reference: type returned when pointer is dereferenced
  54. template <class Derived, class Base, class Reference = std::remove_pointer_t<Base>&,
  55. class Value = std::decay_t<Reference>>
  56. class iterator_adaptor {
  57. using operator_arrow_dispatch = operator_arrow_dispatch_t<Reference>;
  58. public:
  59. using base_type = Base;
  60. using reference = Reference;
  61. using value_type = Value;
  62. using pointer = typename operator_arrow_dispatch::result_type;
  63. using difference_type = get_difference_type<base_type>;
  64. using iterator_category = std::random_access_iterator_tag;
  65. iterator_adaptor() = default;
  66. explicit iterator_adaptor(base_type const& iter) : iter_(iter) {}
  67. // you can override this in derived
  68. decltype(auto) operator*() const noexcept { return *iter_; }
  69. // you can override this in derived
  70. Derived& operator+=(difference_type n) {
  71. iter_ += n;
  72. return this->derived();
  73. }
  74. // you should override this in derived if there is an override for operator+=
  75. template <class... Ts>
  76. difference_type operator-(const iterator_adaptor<Ts...>& x) const noexcept {
  77. return iter_ - x.iter_;
  78. }
  79. // you can override this in derived
  80. template <class... Ts>
  81. bool operator==(const iterator_adaptor<Ts...>& x) const noexcept {
  82. return iter_ == x.iter_;
  83. }
  84. reference operator[](difference_type n) const { return *(this->derived() + n); }
  85. pointer operator->() const noexcept {
  86. return operator_arrow_dispatch::apply(this->derived().operator*());
  87. }
  88. Derived& operator-=(difference_type n) { return this->derived().operator+=(-n); }
  89. Derived& operator++() { return this->derived().operator+=(1); }
  90. Derived& operator--() { return this->derived().operator+=(-1); }
  91. Derived operator++(int) {
  92. Derived tmp(this->derived());
  93. operator++();
  94. return tmp;
  95. }
  96. Derived operator--(int) {
  97. Derived tmp(this->derived());
  98. operator--();
  99. return tmp;
  100. }
  101. Derived operator+(difference_type n) const { return Derived(this->derived()) += n; }
  102. Derived operator-(difference_type n) const { return Derived(this->derived()) -= n; }
  103. template <class... Ts>
  104. bool operator!=(const iterator_adaptor<Ts...>& x) const noexcept {
  105. return !this->derived().operator==(x);
  106. }
  107. template <class... Ts>
  108. bool operator<(const iterator_adaptor<Ts...>& x) const noexcept {
  109. return iter_ < x.iter_;
  110. }
  111. template <class... Ts>
  112. bool operator>=(const iterator_adaptor<Ts...>& x) const noexcept {
  113. return iter_ >= x.iter_;
  114. }
  115. template <class... Ts>
  116. bool operator>(const iterator_adaptor<Ts...>& x) const noexcept {
  117. return iter_ > x.iter_;
  118. }
  119. template <class... Ts>
  120. bool operator<=(const iterator_adaptor<Ts...>& x) const noexcept {
  121. return iter_ <= x.iter_;
  122. }
  123. friend Derived operator+(difference_type n, const Derived& x) { return x + n; }
  124. Base const& base() const noexcept { return iter_; }
  125. protected:
  126. // for convenience: refer to base class in derived class
  127. using iterator_adaptor_ = iterator_adaptor;
  128. private:
  129. Derived& derived() noexcept { return *static_cast<Derived*>(this); }
  130. const Derived& derived() const noexcept { return *static_cast<Derived const*>(this); }
  131. base_type iter_;
  132. template <class, class, class, class>
  133. friend class iterator_adaptor;
  134. };
  135. } // namespace detail
  136. } // namespace histogram
  137. } // namespace boost
  138. #endif