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 43namespace 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