1 // Copyright (C) 2019 T. Zachary Laine 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 #ifndef BOOST_STL_INTERFACES_REVERSE_ITERATOR_HPP 7 #define BOOST_STL_INTERFACES_REVERSE_ITERATOR_HPP 8 9 #include <boost/stl_interfaces/iterator_interface.hpp> 10 11 12 namespace boost { namespace stl_interfaces { inline namespace v1 { 13 14 namespace v1_dtl { 15 template<typename Iter> ce_dist(Iter f,Iter l,std::random_access_iterator_tag)16 constexpr auto ce_dist(Iter f, Iter l, std::random_access_iterator_tag) 17 -> decltype(l - f) 18 { 19 return l - f; 20 } 21 template<typename Iter, typename Tag> ce_dist(Iter f,Iter l,Tag)22 constexpr auto ce_dist(Iter f, Iter l, Tag) 23 -> decltype(std::distance(f, l)) 24 { 25 decltype(std::distance(f, l)) retval = 0; 26 for (; f != l; ++f) { 27 ++retval; 28 } 29 return retval; 30 } 31 32 template<typename Iter> ce_prev(Iter it)33 constexpr Iter ce_prev(Iter it) 34 { 35 return --it; 36 } 37 38 template<typename Iter, typename Offset> 39 constexpr void ce_adv(Iter & f,Offset n,std::random_access_iterator_tag)40 ce_adv(Iter & f, Offset n, std::random_access_iterator_tag) 41 { 42 f += n; 43 } 44 template<typename Iter, typename Offset, typename Tag> ce_adv(Iter & f,Offset n,Tag)45 constexpr void ce_adv(Iter & f, Offset n, Tag) 46 { 47 if (0 < n) { 48 for (Offset i = 0; i < n; ++i) { 49 ++f; 50 } 51 } else { 52 for (Offset i = 0; i < -n; ++i) { 53 --f; 54 } 55 } 56 } 57 } 58 59 /** This type is very similar to the C++20 version of 60 `std::reverse_iterator`; it is `constexpr`-, `noexcept`-, and 61 proxy-friendly. */ 62 template<typename BidiIter> 63 struct reverse_iterator 64 : iterator_interface< 65 reverse_iterator<BidiIter>, 66 #if 201703L < __cplusplus && defined(__cpp_lib_ranges) 67 typename v2::detail::iter_concept_t<BidiIter>, 68 #else 69 typename std::iterator_traits<BidiIter>::iterator_category, 70 #endif 71 typename std::iterator_traits<BidiIter>::value_type, 72 typename std::iterator_traits<BidiIter>::reference, 73 typename std::iterator_traits<BidiIter>::pointer, 74 typename std::iterator_traits<BidiIter>::difference_type> 75 { reverse_iteratorboost::stl_interfaces::v1::reverse_iterator76 constexpr reverse_iterator() noexcept(noexcept(BidiIter())) : it_() {} reverse_iteratorboost::stl_interfaces::v1::reverse_iterator77 constexpr reverse_iterator(BidiIter it) noexcept( 78 noexcept(BidiIter(it))) : 79 it_(it) 80 {} 81 template< 82 typename BidiIter2, 83 typename E = std::enable_if_t< 84 std::is_convertible<BidiIter2, BidiIter>::value>> reverse_iteratorboost::stl_interfaces::v1::reverse_iterator85 reverse_iterator(reverse_iterator<BidiIter2> const & it) : it_(it.it_) 86 {} 87 88 friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR auto operator -(reverse_iterator lhs,reverse_iterator rhs)89 operator-(reverse_iterator lhs, reverse_iterator rhs) noexcept( 90 noexcept(v1_dtl::ce_dist( 91 lhs.it_, 92 rhs.it_, 93 typename std::iterator_traits<BidiIter>::iterator_category{}))) 94 { 95 return -v1_dtl::ce_dist( 96 rhs.it_, 97 lhs.it_, 98 typename std::iterator_traits<BidiIter>::iterator_category{}); 99 } 100 101 constexpr typename std::iterator_traits<BidiIter>::reference operator *boost::stl_interfaces::v1::reverse_iterator102 operator*() const noexcept( 103 noexcept(std::prev(v1_dtl::ce_prev(std::declval<BidiIter &>())))) 104 { 105 return *v1_dtl::ce_prev(it_); 106 } 107 operator +=boost::stl_interfaces::v1::reverse_iterator108 constexpr reverse_iterator & operator+=( 109 typename std::iterator_traits<BidiIter>::difference_type 110 n) noexcept(noexcept(v1_dtl:: 111 ce_adv( 112 std::declval<BidiIter &>(), 113 -n, 114 typename std::iterator_traits< 115 BidiIter>:: 116 iterator_category{}))) 117 { 118 v1_dtl::ce_adv( 119 it_, 120 -n, 121 typename std::iterator_traits<BidiIter>::iterator_category{}); 122 return *this; 123 } 124 baseboost::stl_interfaces::v1::reverse_iterator125 constexpr BidiIter base() const noexcept { return it_; } 126 127 private: 128 friend access; base_referenceboost::stl_interfaces::v1::reverse_iterator129 constexpr BidiIter & base_reference() noexcept { return it_; } base_referenceboost::stl_interfaces::v1::reverse_iterator130 constexpr BidiIter const & base_reference() const noexcept 131 { 132 return it_; 133 } 134 135 template<typename BidiIter2> 136 friend struct reverse_iterator; 137 138 BidiIter it_; 139 }; 140 141 template<typename BidiIter> operator ==(reverse_iterator<BidiIter> lhs,reverse_iterator<BidiIter> rhs)142 constexpr auto operator==( 143 reverse_iterator<BidiIter> lhs, 144 reverse_iterator<BidiIter> 145 rhs) noexcept(noexcept(lhs.base() == rhs.base())) 146 -> decltype(rhs.base() == lhs.base()) 147 { 148 return lhs.base() == rhs.base(); 149 } 150 151 template<typename BidiIter1, typename BidiIter2> operator ==(reverse_iterator<BidiIter1> lhs,reverse_iterator<BidiIter2> rhs)152 constexpr auto operator==( 153 reverse_iterator<BidiIter1> lhs, 154 reverse_iterator<BidiIter2> 155 rhs) noexcept(noexcept(lhs.base() == rhs.base())) 156 -> decltype(rhs.base() == lhs.base()) 157 { 158 return lhs.base() == rhs.base(); 159 } 160 161 /** Makes a `reverse_iterator<BidiIter>` from an iterator of type 162 `Bidiiter`. */ 163 template<typename BidiIter> make_reverse_iterator(BidiIter it)164 auto make_reverse_iterator(BidiIter it) 165 { 166 return reverse_iterator<BidiIter>(it); 167 } 168 169 }}} 170 171 172 #if 201703L < __cplusplus && defined(__cpp_lib_concepts) || \ 173 defined(BOOST_STL_INTERFACES_DOXYGEN) 174 175 namespace boost { namespace stl_interfaces { namespace v2 { 176 177 /** A template alias for `std::reverse_iterator`. This only exists to 178 make migration from Boost.STLInterfaces to C++20 easier; switch to the 179 one in `std` as soon as you can. */ 180 template<typename BidiIter> 181 using reverse_iterator = std::reverse_iterator<BidiIter>; 182 183 184 /** Makes a `reverse_iterator<BidiIter>` from an iterator of type 185 `Bidiiter`. This only exists to make migration from 186 Boost.STLInterfaces to C++20 easier; switch to the one in `std` as 187 soon as you can. */ 188 template<typename BidiIter> make_reverse_iterator(BidiIter it)189 auto make_reverse_iterator(BidiIter it) 190 { 191 return reverse_iterator<BidiIter>(it); 192 } 193 194 }}} 195 196 #endif 197 198 #endif 199