xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/mofunc_impl.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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