1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___ITERATOR_ITER_MOVE_H
11 #define _LIBCPP___ITERATOR_ITER_MOVE_H
12 
13 #include <__config>
14 #include <__iterator/iterator_traits.h>
15 #include <__utility/forward.h>
16 #include <concepts> // __class_or_enum
17 #include <type_traits>
18 #include <utility>
19 
20 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21 #pragma GCC system_header
22 #endif
23 
24 _LIBCPP_BEGIN_NAMESPACE_STD
25 
26 #if !defined(_LIBCPP_HAS_NO_RANGES)
27 
28 namespace ranges::__iter_move {
29 void iter_move();
30 
31 template<class _Ip>
32 concept __unqualified_iter_move = requires(_Ip&& __i) {
33     iter_move(_VSTD::forward<_Ip>(__i));
34 };
35 
36 // [iterator.cust.move]/1
37 // The name ranges::iter_move denotes a customization point object.
38 // The expression ranges::iter_move(E) for a subexpression E is
39 // expression-equivalent to:
40 struct __fn {
41   // [iterator.cust.move]/1.1
42   // iter_move(E), if E has class or enumeration type and iter_move(E) is a
43   // well-formed expression when treated as an unevaluated operand, [...]
44   template<class _Ip>
45     requires __class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>
46   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Ip&& __i) const
47     noexcept(noexcept(iter_move(_VSTD::forward<_Ip>(__i))))
48   {
49     return iter_move(_VSTD::forward<_Ip>(__i));
50   }
51 
52   // [iterator.cust.move]/1.2
53   // Otherwise, if the expression *E is well-formed:
54   //  1.2.1 if *E is an lvalue, std::move(*E);
55   //  1.2.2 otherwise, *E.
56   template<class _Ip>
57     requires (!(__class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>)) &&
58     requires(_Ip&& __i) { *_VSTD::forward<_Ip>(__i); }
59   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Ip&& __i) const
60     noexcept(noexcept(*_VSTD::forward<_Ip>(__i)))
61   {
62     if constexpr (is_lvalue_reference_v<decltype(*_VSTD::forward<_Ip>(__i))>) {
63       return _VSTD::move(*_VSTD::forward<_Ip>(__i));
64     } else {
65       return *_VSTD::forward<_Ip>(__i);
66     }
67   }
68 
69   // [iterator.cust.move]/1.3
70   // Otherwise, ranges::iter_move(E) is ill-formed.
71 };
72 } // namespace ranges::__iter_move
73 
74 namespace ranges::inline __cpo {
75   inline constexpr auto iter_move = __iter_move::__fn{};
76 }
77 
78 template<__dereferenceable _Tp>
79 requires requires(_Tp& __t) { { ranges::iter_move(__t) } -> __referenceable; }
80 using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<_Tp&>()));
81 
82 #endif // !_LIBCPP_HAS_NO_RANGES
83 
84 _LIBCPP_END_NAMESPACE_STD
85 
86 #endif // _LIBCPP___ITERATOR_ITER_MOVE_H
87