Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:09:48

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-present
0005 //  Copyright Casey Carter 2016
0006 //
0007 //  Use, modification and distribution is subject to the
0008 //  Boost Software License, Version 1.0. (See accompanying
0009 //  file LICENSE_1_0.txt or copy at
0010 //  http://www.boost.org/LICENSE_1_0.txt)
0011 //
0012 // Project home: https://github.com/ericniebler/range-v3
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     /// \addtogroup group-iterator
0039     /// @{
0040 
0041     /// \cond
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     } // namespace detail
0070     /// \endcond
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     /// \cond
0079     namespace _iter_move_
0080     {
0081 #if RANGES_BROKEN_CPO_LOOKUP
0082         void iter_move(); // unqualified name lookup block
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             // clang-format off
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 // RANGES_WORKAROUND_CLANG_23135
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 // RANGES_WORKAROUND_CLANG_23135
0115             auto CPP_auto_fun(operator())(I &&i)(const)
0116             (
0117                 return static_cast<aux::move_t<R>>(aux::move(*i))
0118             )
0119             // clang-format on
0120         };
0121     } // namespace _iter_move_
0122     /// \endcond
0123 
0124     RANGES_DEFINE_CPO(_iter_move_::fn, iter_move)
0125 
0126     /// \cond
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     } // namespace detail
0148     /// \endcond
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     /// \cond
0168     namespace _iter_swap_
0169     {
0170         struct nope
0171         {};
0172 
0173         // Q: Should std::reference_wrapper be considered a proxy wrt swapping rvalues?
0174         // A: No. Its operator= is currently defined to reseat the references, so
0175         //    std::swap(ra, rb) already means something when ra and rb are (lvalue)
0176         //    reference_wrappers. That reseats the reference wrappers but leaves the
0177         //    referents unmodified. Treating rvalue reference_wrappers differently would
0178         //    be confusing.
0179 
0180         // Q: Then why is it OK to "re"-define swap for pairs and tuples of references?
0181         // A: Because as defined above, swapping an rvalue tuple of references has the
0182         //    same semantics as swapping an lvalue tuple of references. Rather than
0183         //    reseat the references, assignment happens *through* the references.
0184 
0185         // Q: But I have an iterator whose operator* returns an rvalue
0186         //    std::reference_wrapper<T>. How do I make it model indirectly_swappable?
0187         // A: With an overload of iter_swap.
0188 
0189         // Intentionally create an ambiguity with std::iter_swap, which is
0190         // unconstrained.
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         // Test whether an overload of iter_swap for a T and a U can be found
0205         // via ADL with the iter_swap overload above participating in the
0206         // overload set. This depends on user-defined iter_swap overloads
0207         // being a better match than the overload in namespace std.
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             // *If* a user-defined iter_swap is found via ADL, call that:
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             // *Otherwise*, for readable types with swappable reference
0223             // types, call ranges::swap(*a, *b)
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             // *Otherwise*, for readable types that are mutually
0234             // indirectly_movable_storable, implement as:
0235             //      iter_value_t<T0> tmp = iter_move(a);
0236             //      *a = iter_move(b);
0237             //      *b = std::move(tmp);
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     } // namespace _iter_swap_
0253     /// \endcond
0254 
0255     /// \relates _iter_swap_::fn
0256     RANGES_DEFINE_CPO(_iter_swap_::fn, iter_swap)
0257 
0258     /// \cond
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     } // namespace detail
0273     /// \endcond
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     } // namespace cpp20
0299     /// @}
0300 } // namespace ranges
0301 
0302 #include <range/v3/detail/epilogue.hpp>
0303 
0304 #endif // RANGES_V3_ITERATOR_ACCESS_HPP