access.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-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. #ifndef RANGES_V3_ITERATOR_ACCESS_HPP
  15. #define RANGES_V3_ITERATOR_ACCESS_HPP
  16. #include <iterator>
  17. #include <type_traits>
  18. #include <utility>
  19. #include <std/detail/associated_types.hpp>
  20. #include <meta/meta.hpp>
  21. #include <concepts/concepts.hpp>
  22. #include <range/v3/range_fwd.hpp>
  23. #include <range/v3/utility/move.hpp>
  24. #include <range/v3/utility/static_const.hpp>
  25. #include <range/v3/utility/swap.hpp>
  26. #include <range/v3/detail/prologue.hpp>
  27. namespace ranges
  28. {
  29. /// \addtogroup group-iterator
  30. /// @{
  31. /// \cond
  32. namespace detail
  33. {
  34. template<typename I,
  35. #ifdef RANGES_WORKAROUND_MSVC_683388
  36. typename R = meta::conditional_t<
  37. std::is_pointer<uncvref_t<I>>::value &&
  38. std::is_array<std::remove_pointer_t<uncvref_t<I>>>::value,
  39. std::add_lvalue_reference_t<std::remove_pointer_t<uncvref_t<I>>>,
  40. decltype(*std::declval<I &>())>,
  41. #else
  42. typename R = decltype(*std::declval<I &>()),
  43. #endif
  44. typename = R &>
  45. using iter_reference_t_ = R;
  46. #if defined(RANGES_DEEP_STL_INTEGRATION) && RANGES_DEEP_STL_INTEGRATION && \
  47. !defined(RANGES_DOXYGEN_INVOKED)
  48. template<typename T>
  49. using iter_value_t_ =
  50. typename meta::conditional_t<
  51. is_std_iterator_traits_specialized_v<T>,
  52. std::iterator_traits<T>,
  53. indirectly_readable_traits<T>>::value_type;
  54. #else
  55. template<typename T>
  56. using iter_value_t_ = typename indirectly_readable_traits<T>::value_type;
  57. #endif
  58. } // namespace detail
  59. /// \endcond
  60. template<typename R>
  61. using iter_reference_t = detail::iter_reference_t_<R>;
  62. template<typename R>
  63. using iter_value_t = detail::iter_value_t_<uncvref_t<R>>;
  64. /// \cond
  65. namespace _iter_move_
  66. {
  67. #if RANGES_BROKEN_CPO_LOOKUP
  68. void iter_move(); // unqualified name lookup block
  69. #endif
  70. template<typename T>
  71. decltype(iter_move(std::declval<T>())) try_adl_iter_move_(int);
  72. template<typename T>
  73. void try_adl_iter_move_(long);
  74. template<typename T>
  75. RANGES_INLINE_VAR constexpr bool is_adl_indirectly_movable_v =
  76. !RANGES_IS_SAME(void, decltype(_iter_move_::try_adl_iter_move_<T>(42)));
  77. struct fn
  78. {
  79. // clang-format off
  80. template<typename I,
  81. typename = detail::enable_if_t<is_adl_indirectly_movable_v<I &>>>
  82. #ifndef RANGES_WORKAROUND_CLANG_23135
  83. constexpr
  84. #endif // RANGES_WORKAROUND_CLANG_23135
  85. auto CPP_auto_fun(operator())(I &&i)(const)
  86. (
  87. return iter_move(i)
  88. )
  89. template<
  90. typename I,
  91. typename = detail::enable_if_t<!is_adl_indirectly_movable_v<I &>>,
  92. typename R = iter_reference_t<I>>
  93. #ifndef RANGES_WORKAROUND_CLANG_23135
  94. constexpr
  95. #endif // RANGES_WORKAROUND_CLANG_23135
  96. auto CPP_auto_fun(operator())(I &&i)(const)
  97. (
  98. return static_cast<aux::move_t<R>>(aux::move(*i))
  99. )
  100. // clang-format on
  101. };
  102. } // namespace _iter_move_
  103. /// \endcond
  104. RANGES_DEFINE_CPO(_iter_move_::fn, iter_move)
  105. /// \cond
  106. namespace detail
  107. {
  108. template<typename I, typename O>
  109. auto is_indirectly_movable_(I & (*i)(), O & (*o)(), iter_value_t<I> * v = nullptr)
  110. -> always_<std::true_type,
  111. decltype(iter_value_t<I>(iter_move(i()))),
  112. decltype(*v = iter_move(i())),
  113. decltype(*o() = (iter_value_t<I> &&) * v),
  114. decltype(*o() = iter_move(i()))>;
  115. template<typename I, typename O>
  116. auto is_indirectly_movable_(...) -> std::false_type;
  117. template<typename I, typename O>
  118. auto is_nothrow_indirectly_movable_(iter_value_t<I> * v) -> meta::bool_<
  119. noexcept(iter_value_t<I>(iter_move(std::declval<I &>()))) &&
  120. noexcept(*v = iter_move(std::declval<I &>())) &&
  121. noexcept(*std::declval<O &>() = (iter_value_t<I> &&) * v) &&
  122. noexcept(*std::declval<O &>() = iter_move(std::declval<I &>()))>;
  123. template<typename I, typename O>
  124. auto is_nothrow_indirectly_movable_(...) -> std::false_type;
  125. } // namespace detail
  126. /// \endcond
  127. template<typename I, typename O>
  128. RANGES_INLINE_VAR constexpr bool is_indirectly_movable_v =
  129. decltype(detail::is_indirectly_movable_<I, O>(nullptr, nullptr))::value;
  130. template<typename I, typename O>
  131. RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_movable_v =
  132. decltype(detail::is_nothrow_indirectly_movable_<I, O>(nullptr))::value;
  133. template<typename I, typename O>
  134. struct is_indirectly_movable : meta::bool_<is_indirectly_movable_v<I, O>>
  135. {};
  136. template<typename I, typename O>
  137. struct is_nothrow_indirectly_movable
  138. : meta::bool_<is_nothrow_indirectly_movable_v<I, O>>
  139. {};
  140. /// \cond
  141. namespace _iter_swap_
  142. {
  143. struct nope
  144. {};
  145. // Q: Should std::reference_wrapper be considered a proxy wrt swapping rvalues?
  146. // A: No. Its operator= is currently defined to reseat the references, so
  147. // std::swap(ra, rb) already means something when ra and rb are (lvalue)
  148. // reference_wrappers. That reseats the reference wrappers but leaves the
  149. // referents unmodified. Treating rvalue reference_wrappers differently would
  150. // be confusing.
  151. // Q: Then why is it OK to "re"-define swap for pairs and tuples of references?
  152. // A: Because as defined above, swapping an rvalue tuple of references has the
  153. // same semantics as swapping an lvalue tuple of references. Rather than
  154. // reseat the references, assignment happens *through* the references.
  155. // Q: But I have an iterator whose operator* returns an rvalue
  156. // std::reference_wrapper<T>. How do I make it model indirectly_swappable?
  157. // A: With an overload of iter_swap.
  158. // Intentionally create an ambiguity with std::iter_swap, which is
  159. // unconstrained.
  160. template<typename T, typename U>
  161. nope iter_swap(T, U) = delete;
  162. #ifdef RANGES_WORKAROUND_MSVC_895622
  163. nope iter_swap();
  164. #endif
  165. template<typename T, typename U>
  166. decltype(iter_swap(std::declval<T>(), std::declval<U>())) try_adl_iter_swap_(int);
  167. template<typename T, typename U>
  168. nope try_adl_iter_swap_(long);
  169. // Test whether an overload of iter_swap for a T and a U can be found
  170. // via ADL with the iter_swap overload above participating in the
  171. // overload set. This depends on user-defined iter_swap overloads
  172. // being a better match than the overload in namespace std.
  173. template<typename T, typename U>
  174. RANGES_INLINE_VAR constexpr bool is_adl_indirectly_swappable_v =
  175. !RANGES_IS_SAME(nope, decltype(_iter_swap_::try_adl_iter_swap_<T, U>(42)));
  176. struct fn
  177. {
  178. // *If* a user-defined iter_swap is found via ADL, call that:
  179. template<typename T, typename U>
  180. constexpr detail::enable_if_t<is_adl_indirectly_swappable_v<T, U>> operator()(
  181. T && t, U && u) const noexcept(noexcept(iter_swap((T &&) t, (U &&) u)))
  182. {
  183. (void)iter_swap((T &&) t, (U &&) u);
  184. }
  185. // *Otherwise*, for readable types with swappable reference
  186. // types, call ranges::swap(*a, *b)
  187. template<typename I0, typename I1>
  188. constexpr detail::enable_if_t<
  189. !is_adl_indirectly_swappable_v<I0, I1> &&
  190. is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value>
  191. operator()(I0 && a, I1 && b) const noexcept(noexcept(ranges::swap(*a, *b)))
  192. {
  193. ranges::swap(*a, *b);
  194. }
  195. // *Otherwise*, for readable types that are mutually
  196. // indirectly_movable_storable, implement as:
  197. // iter_value_t<T0> tmp = iter_move(a);
  198. // *a = iter_move(b);
  199. // *b = std::move(tmp);
  200. template<typename I0, typename I1>
  201. constexpr detail::enable_if_t<
  202. !is_adl_indirectly_swappable_v<I0, I1> &&
  203. !is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value &&
  204. is_indirectly_movable_v<I0, I1> && is_indirectly_movable_v<I1, I0>>
  205. operator()(I0 && a, I1 && b) const
  206. noexcept(is_nothrow_indirectly_movable_v<I0, I1> &&
  207. is_nothrow_indirectly_movable_v<I1, I0>)
  208. {
  209. iter_value_t<I0> v0 = iter_move(a);
  210. *a = iter_move(b);
  211. *b = detail::move(v0);
  212. }
  213. };
  214. } // namespace _iter_swap_
  215. /// \endcond
  216. /// \relates _iter_swap_::fn
  217. RANGES_DEFINE_CPO(_iter_swap_::fn, iter_swap)
  218. /// \cond
  219. namespace detail
  220. {
  221. template<typename T, typename U>
  222. auto is_indirectly_swappable_(T & (*t)(), U & (*u)())
  223. -> detail::always_<std::true_type, decltype(iter_swap(t(), u()))>;
  224. template<typename T, typename U>
  225. auto is_indirectly_swappable_(...) -> std::false_type;
  226. template<typename T, typename U>
  227. auto is_nothrow_indirectly_swappable_(int)
  228. -> meta::bool_<noexcept(iter_swap(std::declval<T &>(), std::declval<U &>()))>;
  229. template<typename T, typename U>
  230. auto is_nothrow_indirectly_swappable_(long) -> std::false_type;
  231. } // namespace detail
  232. /// \endcond
  233. template<typename T, typename U>
  234. RANGES_INLINE_VAR constexpr bool is_indirectly_swappable_v =
  235. decltype(detail::is_indirectly_swappable_<T, U>(nullptr, nullptr))::value;
  236. template<typename T, typename U>
  237. RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_swappable_v =
  238. decltype(detail::is_nothrow_indirectly_swappable_<T, U>(0))::value;
  239. template<typename T, typename U>
  240. struct is_indirectly_swappable : meta::bool_<is_indirectly_swappable_v<T, U>>
  241. {};
  242. template<typename T, typename U>
  243. struct is_nothrow_indirectly_swappable
  244. : meta::bool_<is_nothrow_indirectly_swappable_v<T, U>>
  245. {};
  246. namespace cpp20
  247. {
  248. using ranges::iter_move;
  249. using ranges::iter_reference_t;
  250. using ranges::iter_swap;
  251. using ranges::iter_value_t;
  252. } // namespace cpp20
  253. /// @}
  254. } // namespace ranges
  255. #include <range/v3/detail/epilogue.hpp>
  256. #endif // RANGES_V3_ITERATOR_ACCESS_HPP