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/move_only_function.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_MOVE_ONLY_FUNCTION_H 31 #define _GLIBCXX_MOVE_ONLY_FUNCTION_H 1 32 33 #pragma GCC system_header 34 35 #if __cplusplus > 202002L 36 37 #include <bits/invoke.h> 38 #include <bits/utility.h> 39 40 namespace std _GLIBCXX_VISIBILITY(default) 41 { 42 _GLIBCXX_BEGIN_NAMESPACE_VERSION 43 44 #define __cpp_lib_move_only_function 202110L 45 46 template<typename... _Signature> 47 class move_only_function; // not defined 48 49 /// @cond undocumented 50 class _Mofunc_base 51 { 52 protected: 53 _Mofunc_base() noexcept 54 : _M_manage(_S_empty) 55 { } 56 57 _Mofunc_base(_Mofunc_base&& __x) noexcept 58 { 59 _M_manage = std::__exchange(__x._M_manage, _S_empty); 60 _M_manage(_M_storage, &__x._M_storage); 61 } 62 63 template<typename _Tp, typename... _Args> 64 static constexpr bool 65 _S_nothrow_init() noexcept 66 { 67 if constexpr (__stored_locally<_Tp>) 68 return is_nothrow_constructible_v<_Tp, _Args...>; 69 return false; 70 } 71 72 template<typename _Tp, typename... _Args> 73 void 74 _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>()) 75 { 76 if constexpr (__stored_locally<_Tp>) 77 ::new (_M_storage._M_addr()) _Tp(std::forward<_Args>(__args)...); 78 else 79 _M_storage._M_p = new _Tp(std::forward<_Args>(__args)...); 80 81 _M_manage = &_S_manage<_Tp>; 82 } 83 84 _Mofunc_base& 85 operator=(_Mofunc_base&& __x) noexcept 86 { 87 _M_manage(_M_storage, nullptr); 88 _M_manage = std::__exchange(__x._M_manage, _S_empty); 89 _M_manage(_M_storage, &__x._M_storage); 90 return *this; 91 } 92 93 _Mofunc_base& 94 operator=(nullptr_t) noexcept 95 { 96 _M_manage(_M_storage, nullptr); 97 _M_manage = _S_empty; 98 return *this; 99 } 100 101 ~_Mofunc_base() { _M_manage(_M_storage, nullptr); } 102 103 void 104 swap(_Mofunc_base& __x) noexcept 105 { 106 // Order of operations here is more efficient if __x is empty. 107 _Storage __s; 108 __x._M_manage(__s, &__x._M_storage); 109 _M_manage(__x._M_storage, &_M_storage); 110 __x._M_manage(_M_storage, &__s); 111 std::swap(_M_manage, __x._M_manage); 112 } 113 114 template<typename _Tp, typename _Self> 115 static _Tp* 116 _S_access(_Self* __self) noexcept 117 { 118 if constexpr (__stored_locally<remove_const_t<_Tp>>) 119 return static_cast<_Tp*>(__self->_M_storage._M_addr()); 120 else 121 return static_cast<_Tp*>(__self->_M_storage._M_p); 122 } 123 124 private: 125 struct _Storage 126 { 127 void* _M_addr() noexcept { return &_M_bytes[0]; } 128 const void* _M_addr() const noexcept { return &_M_bytes[0]; } 129 130 // We want to have enough space to store a simple delegate type. 131 struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; }; 132 union { 133 void* _M_p; 134 alignas(_Delegate) alignas(void(*)()) 135 unsigned char _M_bytes[sizeof(_Delegate)]; 136 }; 137 }; 138 139 template<typename _Tp> 140 static constexpr bool __stored_locally 141 = sizeof(_Tp) <= sizeof(_Storage) && alignof(_Tp) <= alignof(_Storage) 142 && is_nothrow_move_constructible_v<_Tp>; 143 144 // A function that either destroys the target object stored in __target, 145 // or moves the target object from *__src to __target. 146 using _Manager = void (*)(_Storage& __target, _Storage* __src) noexcept; 147 148 // The no-op manager function for objects with no target. 149 static void _S_empty(_Storage&, _Storage*) noexcept { } 150 151 // The real manager function for a target object of type _Tp. 152 template<typename _Tp> 153 static void 154 _S_manage(_Storage& __target, _Storage* __src) noexcept 155 { 156 if constexpr (__stored_locally<_Tp>) 157 { 158 if (__src) 159 { 160 _Tp* __rval = static_cast<_Tp*>(__src->_M_addr()); 161 ::new (__target._M_addr()) _Tp(std::move(*__rval)); 162 __rval->~_Tp(); 163 } 164 else 165 static_cast<_Tp*>(__target._M_addr())->~_Tp(); 166 } 167 else 168 { 169 if (__src) 170 __target._M_p = __src->_M_p; 171 else 172 delete static_cast<_Tp*>(__target._M_p); 173 } 174 } 175 176 _Storage _M_storage; 177 _Manager _M_manage; 178 }; 179 180 template<typename _Tp> 181 inline constexpr bool __is_move_only_function_v = false; 182 template<typename _Tp> 183 constexpr bool __is_move_only_function_v<move_only_function<_Tp>> = true; 184 /// @endcond 185 186 _GLIBCXX_END_NAMESPACE_VERSION 187 } // namespace std 188 189 #include "mofunc_impl.h" 190 #define _GLIBCXX_MOF_CV const 191 #include "mofunc_impl.h" 192 #define _GLIBCXX_MOF_REF & 193 #include "mofunc_impl.h" 194 #define _GLIBCXX_MOF_REF && 195 #include "mofunc_impl.h" 196 #define _GLIBCXX_MOF_CV const 197 #define _GLIBCXX_MOF_REF & 198 #include "mofunc_impl.h" 199 #define _GLIBCXX_MOF_CV const 200 #define _GLIBCXX_MOF_REF && 201 #include "mofunc_impl.h" 202 203 #endif // C++23 204 #endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H 205