iterator_adaptor.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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 <iterator>
  12. #include <memory>
  13. #include <type_traits>
  14. #include <utility>
  15. namespace boost {
  16. namespace histogram {
  17. namespace detail {
  18. // operator->() needs special support for input iterators to strictly meet the
  19. // standard's requirements. If *i is not a reference type, we must still
  20. // produce an lvalue to which a pointer can be formed. We do that by
  21. // returning a proxy object containing an instance of the reference object.
  22. template <class Reference>
  23. struct operator_arrow_dispatch_t // proxy references
  24. {
  25. struct proxy {
  26. explicit proxy(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 = proxy;
  31. static result_type apply(Reference const& x) noexcept { return proxy(x); }
  32. };
  33. template <class T>
  34. struct operator_arrow_dispatch_t<T&> // "real" references
  35. {
  36. using result_type = T*;
  37. static result_type apply(T& x) noexcept { return std::addressof(x); }
  38. };
  39. // only for random access Base
  40. template <class Derived, class Base, class Reference = std::remove_pointer_t<Base>&,
  41. class Value = std::decay_t<Reference>>
  42. class iterator_adaptor {
  43. using operator_arrow_dispatch = operator_arrow_dispatch_t<Reference>;
  44. public:
  45. using base_type = Base;
  46. using reference = Reference;
  47. using value_type = std::remove_const_t<Value>;
  48. using pointer = typename operator_arrow_dispatch::result_type;
  49. using difference_type = std::ptrdiff_t;
  50. using iterator_category = std::random_access_iterator_tag;
  51. iterator_adaptor() = default;
  52. explicit iterator_adaptor(base_type const& iter) : iter_(iter) {}
  53. pointer operator->() const noexcept {
  54. return operator_arrow_dispatch::apply(this->derived().operator*());
  55. }
  56. reference operator[](difference_type n) const { return *(this->derived() + n); }
  57. Derived& operator++() {
  58. ++iter_;
  59. return this->derived();
  60. }
  61. Derived& operator--() {
  62. --iter_;
  63. return this->derived();
  64. }
  65. Derived operator++(int) {
  66. Derived tmp(this->derived());
  67. ++iter_;
  68. return tmp;
  69. }
  70. Derived operator--(int) {
  71. Derived tmp(this->derived());
  72. --iter_;
  73. return tmp;
  74. }
  75. Derived& operator+=(difference_type n) {
  76. iter_ += n;
  77. return this->derived();
  78. }
  79. Derived& operator-=(difference_type n) {
  80. iter_ -= n;
  81. return this->derived();
  82. }
  83. Derived operator+(difference_type n) const {
  84. Derived tmp(this->derived());
  85. tmp += n;
  86. return tmp;
  87. }
  88. Derived operator-(difference_type n) const { return operator+(-n); }
  89. template <class... Ts>
  90. difference_type operator-(const iterator_adaptor<Ts...>& x) const noexcept {
  91. return iter_ - x.iter_;
  92. }
  93. template <class... Ts>
  94. bool operator==(const iterator_adaptor<Ts...>& x) const noexcept {
  95. return iter_ == x.iter_;
  96. }
  97. template <class... Ts>
  98. bool operator!=(const iterator_adaptor<Ts...>& x) const noexcept {
  99. return !this->derived().operator==(x); // equal operator may be overridden in derived
  100. }
  101. template <class... Ts>
  102. bool operator<(const iterator_adaptor<Ts...>& x) const noexcept {
  103. return iter_ < x.iter_;
  104. }
  105. template <class... Ts>
  106. bool operator>(const iterator_adaptor<Ts...>& x) const noexcept {
  107. return iter_ > x.iter_;
  108. }
  109. template <class... Ts>
  110. bool operator<=(const iterator_adaptor<Ts...>& x) const noexcept {
  111. return iter_ <= x.iter_;
  112. }
  113. template <class... Ts>
  114. bool operator>=(const iterator_adaptor<Ts...>& x) const noexcept {
  115. return iter_ >= x.iter_;
  116. }
  117. friend Derived operator+(difference_type n, const Derived& x) { return x + n; }
  118. Base const& base() const noexcept { return iter_; }
  119. protected:
  120. // for convenience in derived classes
  121. using iterator_adaptor_ = iterator_adaptor;
  122. private:
  123. Derived& derived() noexcept { return *static_cast<Derived*>(this); }
  124. const Derived& derived() const noexcept { return *static_cast<Derived const*>(this); }
  125. Base iter_;
  126. template <class, class, class, class>
  127. friend class iterator_adaptor;
  128. };
  129. } // namespace detail
  130. } // namespace histogram
  131. } // namespace boost
  132. #endif