File indexing completed on 2025-01-18 10:09:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef RANGES_V3_ITERATOR_ACCESS_HPP
0016 #define RANGES_V3_ITERATOR_ACCESS_HPP
0017
0018 #include <iterator>
0019 #include <type_traits>
0020 #include <utility>
0021
0022 #include <std/detail/associated_types.hpp>
0023
0024 #include <meta/meta.hpp>
0025
0026 #include <concepts/concepts.hpp>
0027
0028 #include <range/v3/range_fwd.hpp>
0029
0030 #include <range/v3/utility/move.hpp>
0031 #include <range/v3/utility/static_const.hpp>
0032 #include <range/v3/utility/swap.hpp>
0033
0034 #include <range/v3/detail/prologue.hpp>
0035
0036 namespace ranges
0037 {
0038
0039
0040
0041
0042 namespace detail
0043 {
0044 template<typename I,
0045 #ifdef RANGES_WORKAROUND_MSVC_683388
0046 typename R = meta::conditional_t<
0047 std::is_pointer<uncvref_t<I>>::value &&
0048 std::is_array<std::remove_pointer_t<uncvref_t<I>>>::value,
0049 std::add_lvalue_reference_t<std::remove_pointer_t<uncvref_t<I>>>,
0050 decltype(*std::declval<I &>())>,
0051 #else
0052 typename R = decltype(*std::declval<I &>()),
0053 #endif
0054 typename = R &>
0055 using iter_reference_t_ = R;
0056
0057 #if defined(RANGES_DEEP_STL_INTEGRATION) && RANGES_DEEP_STL_INTEGRATION && \
0058 !defined(RANGES_DOXYGEN_INVOKED)
0059 template<typename T>
0060 using iter_value_t_ =
0061 typename meta::conditional_t<
0062 is_std_iterator_traits_specialized_v<T>,
0063 std::iterator_traits<T>,
0064 indirectly_readable_traits<T>>::value_type;
0065 #else
0066 template<typename T>
0067 using iter_value_t_ = typename indirectly_readable_traits<T>::value_type;
0068 #endif
0069 }
0070
0071
0072 template<typename R>
0073 using iter_reference_t = detail::iter_reference_t_<R>;
0074
0075 template<typename R>
0076 using iter_value_t = detail::iter_value_t_<uncvref_t<R>>;
0077
0078
0079 namespace _iter_move_
0080 {
0081 #if RANGES_BROKEN_CPO_LOOKUP
0082 void iter_move();
0083 #endif
0084
0085 template<typename T>
0086 decltype(iter_move(std::declval<T>())) try_adl_iter_move_(int);
0087
0088 template<typename T>
0089 void try_adl_iter_move_(long);
0090
0091 template<typename T>
0092 RANGES_INLINE_VAR constexpr bool is_adl_indirectly_movable_v =
0093 !RANGES_IS_SAME(void, decltype(_iter_move_::try_adl_iter_move_<T>(42)));
0094
0095 struct fn
0096 {
0097
0098 template<typename I,
0099 typename = detail::enable_if_t<is_adl_indirectly_movable_v<I &>>>
0100 #ifndef RANGES_WORKAROUND_CLANG_23135
0101 constexpr
0102 #endif
0103 auto CPP_auto_fun(operator())(I &&i)(const)
0104 (
0105 return iter_move(i)
0106 )
0107
0108 template<
0109 typename I,
0110 typename = detail::enable_if_t<!is_adl_indirectly_movable_v<I &>>,
0111 typename R = iter_reference_t<I>>
0112 #ifndef RANGES_WORKAROUND_CLANG_23135
0113 constexpr
0114 #endif
0115 auto CPP_auto_fun(operator())(I &&i)(const)
0116 (
0117 return static_cast<aux::move_t<R>>(aux::move(*i))
0118 )
0119
0120 };
0121 }
0122
0123
0124 RANGES_DEFINE_CPO(_iter_move_::fn, iter_move)
0125
0126
0127 namespace detail
0128 {
0129 template<typename I, typename O>
0130 auto is_indirectly_movable_(I & (*i)(), O & (*o)(), iter_value_t<I> * v = nullptr)
0131 -> always_<std::true_type,
0132 decltype(iter_value_t<I>(iter_move(i()))),
0133 decltype(*v = iter_move(i())),
0134 decltype(*o() = (iter_value_t<I> &&) * v),
0135 decltype(*o() = iter_move(i()))>;
0136 template<typename I, typename O>
0137 auto is_indirectly_movable_(...) -> std::false_type;
0138
0139 template<typename I, typename O>
0140 auto is_nothrow_indirectly_movable_(iter_value_t<I> * v) -> meta::bool_<
0141 noexcept(iter_value_t<I>(iter_move(std::declval<I &>()))) &&
0142 noexcept(*v = iter_move(std::declval<I &>())) &&
0143 noexcept(*std::declval<O &>() = (iter_value_t<I> &&) * v) &&
0144 noexcept(*std::declval<O &>() = iter_move(std::declval<I &>()))>;
0145 template<typename I, typename O>
0146 auto is_nothrow_indirectly_movable_(...) -> std::false_type;
0147 }
0148
0149
0150 template<typename I, typename O>
0151 RANGES_INLINE_VAR constexpr bool is_indirectly_movable_v =
0152 decltype(detail::is_indirectly_movable_<I, O>(nullptr, nullptr))::value;
0153
0154 template<typename I, typename O>
0155 RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_movable_v =
0156 decltype(detail::is_nothrow_indirectly_movable_<I, O>(nullptr))::value;
0157
0158 template<typename I, typename O>
0159 struct is_indirectly_movable : meta::bool_<is_indirectly_movable_v<I, O>>
0160 {};
0161
0162 template<typename I, typename O>
0163 struct is_nothrow_indirectly_movable
0164 : meta::bool_<is_nothrow_indirectly_movable_v<I, O>>
0165 {};
0166
0167
0168 namespace _iter_swap_
0169 {
0170 struct nope
0171 {};
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 template<typename T, typename U>
0192 nope iter_swap(T, U) = delete;
0193
0194 #ifdef RANGES_WORKAROUND_MSVC_895622
0195 nope iter_swap();
0196 #endif
0197
0198 template<typename T, typename U>
0199 decltype(iter_swap(std::declval<T>(), std::declval<U>())) try_adl_iter_swap_(int);
0200
0201 template<typename T, typename U>
0202 nope try_adl_iter_swap_(long);
0203
0204
0205
0206
0207
0208 template<typename T, typename U>
0209 RANGES_INLINE_VAR constexpr bool is_adl_indirectly_swappable_v =
0210 !RANGES_IS_SAME(nope, decltype(_iter_swap_::try_adl_iter_swap_<T, U>(42)));
0211
0212 struct fn
0213 {
0214
0215 template<typename T, typename U>
0216 constexpr detail::enable_if_t<is_adl_indirectly_swappable_v<T, U>> operator()(
0217 T && t, U && u) const noexcept(noexcept(iter_swap((T &&) t, (U &&) u)))
0218 {
0219 (void)iter_swap((T &&) t, (U &&) u);
0220 }
0221
0222
0223
0224 template<typename I0, typename I1>
0225 constexpr detail::enable_if_t<
0226 !is_adl_indirectly_swappable_v<I0, I1> &&
0227 is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value>
0228 operator()(I0 && a, I1 && b) const noexcept(noexcept(ranges::swap(*a, *b)))
0229 {
0230 ranges::swap(*a, *b);
0231 }
0232
0233
0234
0235
0236
0237
0238 template<typename I0, typename I1>
0239 constexpr detail::enable_if_t<
0240 !is_adl_indirectly_swappable_v<I0, I1> &&
0241 !is_swappable_with<iter_reference_t<I0>, iter_reference_t<I1>>::value &&
0242 is_indirectly_movable_v<I0, I1> && is_indirectly_movable_v<I1, I0>>
0243 operator()(I0 && a, I1 && b) const
0244 noexcept(is_nothrow_indirectly_movable_v<I0, I1> &&
0245 is_nothrow_indirectly_movable_v<I1, I0>)
0246 {
0247 iter_value_t<I0> v0 = iter_move(a);
0248 *a = iter_move(b);
0249 *b = detail::move(v0);
0250 }
0251 };
0252 }
0253
0254
0255
0256 RANGES_DEFINE_CPO(_iter_swap_::fn, iter_swap)
0257
0258
0259 namespace detail
0260 {
0261 template<typename T, typename U>
0262 auto is_indirectly_swappable_(T & (*t)(), U & (*u)())
0263 -> detail::always_<std::true_type, decltype(iter_swap(t(), u()))>;
0264 template<typename T, typename U>
0265 auto is_indirectly_swappable_(...) -> std::false_type;
0266
0267 template<typename T, typename U>
0268 auto is_nothrow_indirectly_swappable_(int)
0269 -> meta::bool_<noexcept(iter_swap(std::declval<T &>(), std::declval<U &>()))>;
0270 template<typename T, typename U>
0271 auto is_nothrow_indirectly_swappable_(long) -> std::false_type;
0272 }
0273
0274
0275 template<typename T, typename U>
0276 RANGES_INLINE_VAR constexpr bool is_indirectly_swappable_v =
0277 decltype(detail::is_indirectly_swappable_<T, U>(nullptr, nullptr))::value;
0278
0279 template<typename T, typename U>
0280 RANGES_INLINE_VAR constexpr bool is_nothrow_indirectly_swappable_v =
0281 decltype(detail::is_nothrow_indirectly_swappable_<T, U>(0))::value;
0282
0283 template<typename T, typename U>
0284 struct is_indirectly_swappable : meta::bool_<is_indirectly_swappable_v<T, U>>
0285 {};
0286
0287 template<typename T, typename U>
0288 struct is_nothrow_indirectly_swappable
0289 : meta::bool_<is_nothrow_indirectly_swappable_v<T, U>>
0290 {};
0291
0292 namespace cpp20
0293 {
0294 using ranges::iter_move;
0295 using ranges::iter_reference_t;
0296 using ranges::iter_swap;
0297 using ranges::iter_value_t;
0298 }
0299
0300 }
0301
0302 #include <range/v3/detail/epilogue.hpp>
0303
0304 #endif