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_PUSH_MACROS
25 #include <__undef_macros>
26 
27 _LIBCPP_BEGIN_NAMESPACE_STD
28 
29 #if !defined(_LIBCPP_HAS_NO_RANGES)
30 
31 namespace ranges::__iter_move {
32 void iter_move();
33 
34 template<class _Ip>
35 concept __unqualified_iter_move = requires(_Ip&& __i) {
36     iter_move(_VSTD::forward<_Ip>(__i));
37 };
38 
39 // [iterator.cust.move]/1
40 // The name ranges::iter_move denotes a customization point object.
41 // The expression ranges::iter_move(E) for a subexpression E is
42 // expression-equivalent to:
43 struct __fn {
44   // [iterator.cust.move]/1.1
45   // iter_move(E), if E has class or enumeration type and iter_move(E) is a
46   // well-formed expression when treated as an unevaluated operand, [...]
47   template<class _Ip>
48     requires __class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>
49   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Ip&& __i) const
50     noexcept(noexcept(iter_move(_VSTD::forward<_Ip>(__i))))
51   {
52     return iter_move(_VSTD::forward<_Ip>(__i));
53   }
54 
55   // [iterator.cust.move]/1.2
56   // Otherwise, if the expression *E is well-formed:
57   //  1.2.1 if *E is an lvalue, std::move(*E);
58   //  1.2.2 otherwise, *E.
59   template<class _Ip>
60     requires (!(__class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>)) &&
61     requires(_Ip&& __i) { *_VSTD::forward<_Ip>(__i); }
62   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Ip&& __i) const
63     noexcept(noexcept(*_VSTD::forward<_Ip>(__i)))
64   {
65     if constexpr (is_lvalue_reference_v<decltype(*_VSTD::forward<_Ip>(__i))>) {
66       return _VSTD::move(*_VSTD::forward<_Ip>(__i));
67     } else {
68       return *_VSTD::forward<_Ip>(__i);
69     }
70   }
71 
72   // [iterator.cust.move]/1.3
73   // Otherwise, ranges::iter_move(E) is ill-formed.
74 };
75 } // namespace ranges::__iter_move
76 
77 namespace ranges::inline __cpo {
78   inline constexpr auto iter_move = __iter_move::__fn{};
79 }
80 
81 template<__dereferenceable _Tp>
82 requires requires(_Tp& __t) { { ranges::iter_move(__t) } -> __referenceable; }
83 using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<_Tp&>()));
84 
85 #endif // !_LIBCPP_HAS_NO_RANGES
86 
87 _LIBCPP_END_NAMESPACE_STD
88 
89 _LIBCPP_POP_MACROS
90 
91 #endif // _LIBCPP___ITERATOR_ITER_MOVE_H
92