You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
11KB

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