1 /// \file 2 // Range v3 library 3 // 4 // Copyright Eric Niebler 2014-present 5 // Copyright Casey Carter 2016 6 // 7 // Use, modification and distribution is subject to the 8 // Boost Software License, Version 1.0. (See accompanying 9 // file LICENSE_1_0.txt or copy at 10 // http://www.boost.org/LICENSE_1_0.txt) 11 // 12 // Project home: https://github.com/ericniebler/range-v3 13 // 14 15 #ifndef RANGES_V3_DETAIL_RANGE_ACCESS_HPP 16 #define RANGES_V3_DETAIL_RANGE_ACCESS_HPP 17 18 #include <cstddef> 19 #include <utility> 20 21 #include <meta/meta.hpp> 22 23 #include <concepts/concepts.hpp> 24 25 #include <range/v3/range_fwd.hpp> 26 27 #include <range/v3/iterator/concepts.hpp> 28 29 #include <range/v3/detail/prologue.hpp> 30 31 namespace ranges 32 { 33 /// \addtogroup group-views 34 /// @{ 35 struct range_access 36 { 37 /// \cond 38 private: 39 template<typename T> 40 static std::false_type single_pass_2_(long); 41 template<typename T> 42 static typename T::single_pass single_pass_2_(int); 43 44 template<typename T> 45 struct single_pass_ 46 { 47 using type = decltype(range_access::single_pass_2_<T>(42)); 48 }; 49 50 template<typename T> 51 static std::false_type contiguous_2_(long); 52 template<typename T> 53 static typename T::contiguous contiguous_2_(int); 54 55 template<typename T> 56 struct contiguous_ 57 { 58 using type = decltype(range_access::contiguous_2_<T>(42)); 59 }; 60 61 template<typename T> 62 static basic_mixin<T> mixin_base_2_(long); 63 template<typename T> 64 static typename T::mixin mixin_base_2_(int); 65 66 template<typename Cur> 67 struct mixin_base_ 68 { 69 using type = decltype(range_access::mixin_base_2_<Cur>(42)); 70 }; 71 72 73 public: 74 template<typename Cur> 75 using single_pass_t = meta::_t<single_pass_<Cur>>; 76 77 template<typename Cur> 78 using contiguous_t = meta::_t<contiguous_<Cur>>; 79 80 template<typename Cur> 81 using mixin_base_t = meta::_t<mixin_base_<Cur>>; 82 83 // clang-format off 84 template<typename Rng> 85 static constexpr auto CPP_auto_fun(begin_cursor)(Rng &rng) 86 ( 87 return rng.begin_cursor() 88 ) 89 template<typename Rng> 90 static constexpr auto CPP_auto_fun(end_cursor)(Rng &rng) 91 ( 92 return rng.end_cursor() 93 ) 94 95 template<typename Rng> 96 static constexpr auto CPP_auto_fun(begin_adaptor)(Rng &rng) 97 ( 98 return rng.begin_adaptor() 99 ) 100 template<typename Rng> 101 static constexpr auto CPP_auto_fun(end_adaptor)(Rng &rng) 102 ( 103 return rng.end_adaptor() 104 ) 105 106 template<typename Cur> 107 static constexpr auto CPP_auto_fun(read)(Cur const &pos) 108 ( 109 return pos.read() 110 ) 111 template<typename Cur> 112 static constexpr auto CPP_auto_fun(arrow)(Cur const &pos) 113 ( 114 return pos.arrow() 115 ) 116 template<typename Cur> 117 static constexpr auto CPP_auto_fun(move)(Cur const &pos) 118 ( 119 return pos.move() 120 ) 121 template<typename Cur, typename T> 122 static constexpr auto CPP_auto_fun(write)(Cur &pos, T &&t) 123 ( 124 return pos.write((T &&) t) 125 ) 126 template<typename Cur> 127 static constexpr auto CPP_auto_fun(next)(Cur & pos) 128 ( 129 return pos.next() 130 ) 131 template<typename Cur, typename O> 132 static constexpr auto CPP_auto_fun(equal)(Cur const &pos, O const &other) 133 ( 134 return pos.equal(other) 135 ) 136 template<typename Cur> 137 static constexpr auto CPP_auto_fun(prev)(Cur & pos) 138 ( 139 return pos.prev() 140 ) 141 template<typename Cur, typename D> 142 static constexpr auto CPP_auto_fun(advance)(Cur & pos, D n) 143 ( 144 return pos.advance(n) 145 ) 146 template<typename Cur, typename O> 147 static constexpr auto CPP_auto_fun(distance_to)(Cur const &pos, O const &other) 148 ( 149 return pos.distance_to(other) 150 ) 151 152 private: 153 template<typename Cur> 154 using sized_cursor_difference_t = decltype( 155 range_access::distance_to(std::declval<Cur>(), std::declval<Cur>())); 156 // clang-format on 157 158 template<typename T> 159 static std::ptrdiff_t cursor_difference_2_(detail::ignore_t); 160 template<typename T> 161 static sized_cursor_difference_t<T> cursor_difference_2_(long); 162 template<typename T> 163 static typename T::difference_type cursor_difference_2_(int); 164 165 template<typename T> 166 using cursor_reference_t = decltype(std::declval<T const &>().read()); 167 168 template<typename T> 169 static meta::id<uncvref_t<cursor_reference_t<T>>> cursor_value_2_(long); 170 template<typename T> 171 static meta::id<typename T::value_type> cursor_value_2_(int); 172 173 #ifdef RANGES_WORKAROUND_CWG_1554 174 template<typename Cur> 175 struct cursor_difference 176 { 177 using type = decltype(range_access::cursor_difference_2_<Cur>(42)); 178 }; 179 180 template<typename Cur> 181 struct cursor_value : decltype(range_access::cursor_value_2_<Cur>(42)) 182 {}; 183 #endif // RANGES_WORKAROUND_CWG_1554 184 public: 185 #ifdef RANGES_WORKAROUND_CWG_1554 186 template<typename Cur> 187 using cursor_difference_t = meta::_t<cursor_difference<Cur>>; 188 189 template<typename Cur> 190 using cursor_value_t = meta::_t<cursor_value<Cur>>; 191 #else // ^^^ workaround ^^^ / vvv no workaround vvv 192 template<typename Cur> 193 using cursor_difference_t = decltype(range_access::cursor_difference_2_<Cur>(42)); 194 195 template<typename Cur> 196 using cursor_value_t = meta::_t<decltype(range_access::cursor_value_2_<Cur>(42))>; 197 #endif // RANGES_WORKAROUND_CWG_1554 198 199 template<typename Cur> posranges::range_access200 static constexpr Cur & pos(basic_iterator<Cur> & it) noexcept 201 { 202 return it.pos(); 203 } 204 template<typename Cur> posranges::range_access205 static constexpr Cur const & pos(basic_iterator<Cur> const & it) noexcept 206 { 207 return it.pos(); 208 } 209 template<typename Cur> posranges::range_access210 static constexpr Cur && pos(basic_iterator<Cur> && it) noexcept 211 { 212 return detail::move(it.pos()); 213 } 214 215 template<typename Cur> cursorranges::range_access216 static constexpr Cur cursor(basic_iterator<Cur> it) 217 { 218 return std::move(it.pos()); 219 } 220 /// endcond 221 }; 222 /// @} 223 224 /// \cond 225 namespace detail 226 { 227 // 228 // Concepts that the range cursor must model 229 // clang-format off 230 // 231 template<typename T> 232 CPP_concept cursor = 233 semiregular<T> && semiregular<range_access::mixin_base_t<T>> && 234 constructible_from<range_access::mixin_base_t<T>, T> && 235 constructible_from<range_access::mixin_base_t<T>, T const &>; 236 // Axiom: mixin_base_t<T> has a member get(), accessible to derived classes, 237 // which perfectly-returns the contained cursor object and does not throw 238 // exceptions. 239 240 template<typename T> 241 CPP_requires(has_cursor_next_, 242 requires(T & t) 243 ( 244 range_access::next(t) 245 )); 246 template<typename T> 247 CPP_concept has_cursor_next = CPP_requires_ref(detail::has_cursor_next_, T); 248 249 template<typename S, typename C> 250 CPP_requires(sentinel_for_cursor_, 251 requires(S & s, C & c) // 252 ( 253 range_access::equal(c, s), 254 concepts::requires_<convertible_to<decltype( 255 range_access::equal(c, s)), bool>> 256 )); 257 template<typename S, typename C> 258 CPP_concept sentinel_for_cursor = 259 semiregular<S> && 260 cursor<C> && 261 CPP_requires_ref(detail::sentinel_for_cursor_, S, C); 262 263 template<typename T> 264 CPP_requires(readable_cursor_, 265 requires(T & t) // 266 ( 267 range_access::read(t) 268 )); 269 template<typename T> 270 CPP_concept readable_cursor = CPP_requires_ref(detail::readable_cursor_, T); 271 272 template<typename T> 273 CPP_requires(has_cursor_arrow_, 274 requires(T const & t) // 275 ( 276 range_access::arrow(t) 277 )); 278 template<typename T> 279 CPP_concept has_cursor_arrow = CPP_requires_ref(detail::has_cursor_arrow_, T); 280 281 template<typename T, typename U> 282 CPP_requires(writable_cursor_, 283 requires(T & t, U && u) // 284 ( 285 range_access::write(t, (U &&) u) 286 )); 287 template<typename T, typename U> 288 CPP_concept writable_cursor = 289 CPP_requires_ref(detail::writable_cursor_, T, U); 290 291 template<typename S, typename C> 292 CPP_requires(sized_sentinel_for_cursor_, 293 requires(S & s, C & c) // 294 ( 295 range_access::distance_to(c, s), 296 concepts::requires_<signed_integer_like_<decltype( 297 range_access::distance_to(c, s))>> 298 ) 299 ); 300 template<typename S, typename C> 301 CPP_concept sized_sentinel_for_cursor = 302 sentinel_for_cursor<S, C> && 303 CPP_requires_ref(detail::sized_sentinel_for_cursor_, S, C); 304 305 template<typename T, typename U> 306 CPP_concept output_cursor = 307 writable_cursor<T, U> && cursor<T>; 308 309 template<typename T> 310 CPP_concept input_cursor = 311 readable_cursor<T> && cursor<T> && has_cursor_next<T>; 312 313 template<typename T> 314 CPP_concept forward_cursor = 315 input_cursor<T> && sentinel_for_cursor<T, T> && 316 !range_access::single_pass_t<uncvref_t<T>>::value; 317 318 template<typename T> 319 CPP_requires(bidirectional_cursor_, 320 requires(T & t) // 321 ( 322 range_access::prev(t) 323 )); 324 template<typename T> 325 CPP_concept bidirectional_cursor = 326 forward_cursor<T> && 327 CPP_requires_ref(detail::bidirectional_cursor_, T); 328 329 template<typename T> 330 CPP_requires(random_access_cursor_, 331 requires(T & t) // 332 ( 333 range_access::advance(t, range_access::distance_to(t, t)) 334 )); 335 template<typename T> 336 CPP_concept random_access_cursor = 337 bidirectional_cursor<T> && // 338 sized_sentinel_for_cursor<T, T> && // 339 CPP_requires_ref(detail::random_access_cursor_, T); 340 341 template(class T)( 342 /// \pre 343 requires std::is_lvalue_reference<T>::value) 344 void is_lvalue_reference(T&&); 345 346 template<typename T> 347 CPP_requires(contiguous_cursor_, 348 requires(T & t) // 349 ( 350 detail::is_lvalue_reference(range_access::read(t)) 351 )); 352 template<typename T> 353 CPP_concept contiguous_cursor = 354 random_access_cursor<T> && // 355 range_access::contiguous_t<uncvref_t<T>>::value && // 356 CPP_requires_ref(detail::contiguous_cursor_, T); 357 // clang-format on 358 359 template<typename Cur, bool IsReadable> 360 RANGES_INLINE_VAR constexpr bool is_writable_cursor_ = true; 361 362 template<typename Cur> 363 RANGES_INLINE_VAR constexpr bool is_writable_cursor_<Cur, true> = 364 (bool) writable_cursor<Cur, range_access::cursor_value_t<Cur>>; 365 366 template<typename Cur> 367 RANGES_INLINE_VAR constexpr bool is_writable_cursor_v = 368 is_writable_cursor_<Cur, (bool)readable_cursor<Cur>>; 369 } // namespace detail 370 /// \endcond 371 } // namespace ranges 372 373 #include <range/v3/detail/epilogue.hpp> 374 375 #endif 376