1 // Implementation of std::move_only_function -*- C++ -*-
2 
3 // Copyright The GNU Toolchain Authors.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file include/bits/mofunc_impl.h
26  *  This is an internal header file, included by other library headers.
27  *  Do not attempt to use it directly. @headername{functional}
28  */
29 
30 #ifndef _GLIBCXX_MOF_CV
31 # define _GLIBCXX_MOF_CV
32 #endif
33 
34 #ifdef _GLIBCXX_MOF_REF
35 # define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
36 #else
37 # define _GLIBCXX_MOF_REF
38 # define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV &
39 #endif
40 
41 #define _GLIBCXX_MOF_CV_REF _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
42 
_GLIBCXX_VISIBILITY(default)43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 
47   /**
48    *  @brief Polymorphic function wrapper.
49    *  @ingroup functors
50    *  @since C++23
51    *  @headerfile functional
52    *
53    *  The `std::move_only_function` class template is a call wrapper similar
54    *  to `std::function`, but does not require the stored target function
55    *  to be copyable.
56    *
57    *  It also supports const-qualification, ref-qualification, and
58    *  no-throw guarantees. The qualifications and exception-specification
59    *  of the `move_only_function::operator()` member function are respected
60    *  when invoking the target function.
61    */
62   template<typename _Res, typename... _ArgTypes, bool _Noex>
63     class move_only_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
64                                      _GLIBCXX_MOF_REF noexcept(_Noex)>
65     : _Mofunc_base
66     {
67       template<typename _Tp>
68           using __callable
69             = __conditional_t<_Noex,
70                                   is_nothrow_invocable_r<_Res, _Tp, _ArgTypes...>,
71                                   is_invocable_r<_Res, _Tp, _ArgTypes...>>;
72 
73       // [func.wrap.mov.con]/1 is-callable-from<VT>
74       template<typename _Vt>
75           static constexpr bool __is_callable_from
76             = __and_v<__callable<_Vt _GLIBCXX_MOF_CV_REF>,
77                         __callable<_Vt _GLIBCXX_MOF_INV_QUALS>>;
78 
79     public:
80       using result_type = _Res;
81 
82       /// Creates an empty object.
83       move_only_function() noexcept { }
84 
85       /// Creates an empty object.
86       move_only_function(nullptr_t) noexcept { }
87 
88       /// Moves the target object, leaving the source empty.
89       move_only_function(move_only_function&& __x) noexcept
90       : _Mofunc_base(static_cast<_Mofunc_base&&>(__x)),
91           _M_invoke(std::__exchange(__x._M_invoke, nullptr))
92       { }
93 
94       /// Stores a target object initialized from the argument.
95       template<typename _Fn, typename _Vt = decay_t<_Fn>>
96           requires (!is_same_v<_Vt, move_only_function>)
97             && (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
98           move_only_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
99           {
100             if constexpr (is_function_v<remove_pointer_t<_Vt>>
101                               || is_member_pointer_v<_Vt>
102                               || __is_move_only_function_v<_Vt>)
103               {
104                 if (__f == nullptr)
105                     return;
106               }
107             _M_init<_Vt>(std::forward<_Fn>(__f));
108             _M_invoke = &_S_invoke<_Vt>;
109           }
110 
111       /// Stores a target object initialized from the arguments.
112       template<typename _Tp, typename... _Args>
113           requires is_constructible_v<_Tp, _Args...>
114             && __is_callable_from<_Tp>
115           explicit
116           move_only_function(in_place_type_t<_Tp>, _Args&&... __args)
117           noexcept(_S_nothrow_init<_Tp, _Args...>())
118           : _M_invoke(&_S_invoke<_Tp>)
119           {
120             static_assert(is_same_v<decay_t<_Tp>, _Tp>);
121             _M_init<_Tp>(std::forward<_Args>(__args)...);
122           }
123 
124       /// Stores a target object initialized from the arguments.
125       template<typename _Tp, typename _Up, typename... _Args>
126           requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
127             && __is_callable_from<_Tp>
128           explicit
129           move_only_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
130                                  _Args&&... __args)
131           noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
132           : _M_invoke(&_S_invoke<_Tp>)
133           {
134             static_assert(is_same_v<decay_t<_Tp>, _Tp>);
135             _M_init<_Tp>(__il, std::forward<_Args>(__args)...);
136           }
137 
138       /// Stores a new target object, leaving `x` empty.
139       move_only_function&
140       operator=(move_only_function&& __x) noexcept
141       {
142           _Mofunc_base::operator=(static_cast<_Mofunc_base&&>(__x));
143           _M_invoke = std::__exchange(__x._M_invoke, nullptr);
144           return *this;
145       }
146 
147       /// Destroys the target object (if any).
148       move_only_function&
149       operator=(nullptr_t) noexcept
150       {
151           _Mofunc_base::operator=(nullptr);
152           _M_invoke = nullptr;
153           return *this;
154       }
155 
156       /// Stores a new target object, initialized from the argument.
157       template<typename _Fn>
158           requires is_constructible_v<move_only_function, _Fn>
159           move_only_function&
160           operator=(_Fn&& __f)
161           noexcept(is_nothrow_constructible_v<move_only_function, _Fn>)
162           {
163             move_only_function(std::forward<_Fn>(__f)).swap(*this);
164             return *this;
165           }
166 
167       ~move_only_function() = default;
168 
169       /// True if a target object is present, false otherwise.
170       explicit operator bool() const noexcept { return _M_invoke != nullptr; }
171 
172       /** Invoke the target object.
173        *
174        * The target object will be invoked using the supplied arguments,
175        * and as an lvalue or rvalue, and as const or non-const, as dictated
176        * by the template arguments of the `move_only_function` specialization.
177        *
178        * @pre Must not be empty.
179        */
180       _Res
181       operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
182       {
183           __glibcxx_assert(*this != nullptr);
184           return _M_invoke(this, std::forward<_ArgTypes>(__args)...);
185       }
186 
187       /// Exchange the target objects (if any).
188       void
189       swap(move_only_function& __x) noexcept
190       {
191           _Mofunc_base::swap(__x);
192           std::swap(_M_invoke, __x._M_invoke);
193       }
194 
195       /// Exchange the target objects (if any).
196       friend void
197       swap(move_only_function& __x, move_only_function& __y) noexcept
198       { __x.swap(__y); }
199 
200       /// Check for emptiness by comparing with `nullptr`.
201       friend bool
202       operator==(const move_only_function& __x, nullptr_t) noexcept
203       { return __x._M_invoke == nullptr; }
204 
205     private:
206       template<typename _Tp>
207           using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
208 
209       using _Invoker = _Res (*)(_Mofunc_base _GLIBCXX_MOF_CV*,
210                                         __param_t<_ArgTypes>...) noexcept(_Noex);
211 
212       template<typename _Tp>
213           static _Res
214           _S_invoke(_Mofunc_base _GLIBCXX_MOF_CV* __self,
215                       __param_t<_ArgTypes>... __args) noexcept(_Noex)
216           {
217             using _TpCv = _Tp _GLIBCXX_MOF_CV;
218             using _TpInv = _Tp _GLIBCXX_MOF_INV_QUALS;
219             return std::__invoke_r<_Res>(
220                 std::forward<_TpInv>(*_S_access<_TpCv>(__self)),
221                 std::forward<__param_t<_ArgTypes>>(__args)...);
222           }
223 
224       _Invoker _M_invoke = nullptr;
225     };
226 
227 #undef _GLIBCXX_MOF_CV_REF
228 #undef _GLIBCXX_MOF_CV
229 #undef _GLIBCXX_MOF_REF
230 #undef _GLIBCXX_MOF_INV_QUALS
231 
232 _GLIBCXX_END_NAMESPACE_VERSION
233 } // namespace std
234