// Implementation of std::move_only_function -*- C++ -*- // Copyright The GNU Toolchain Authors. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file include/bits/move_only_function.h * This is an internal header file, included by other library headers. * Do not attempt to use it directly. @headername{functional} */ #ifndef _GLIBCXX_MOVE_ONLY_FUNCTION_H #define _GLIBCXX_MOVE_ONLY_FUNCTION_H 1 #pragma GCC system_header #include #ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED #include #include namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template class move_only_function; // not defined /// @cond undocumented class _Mofunc_base { protected: _Mofunc_base() noexcept : _M_manage(_S_empty) { } _Mofunc_base(_Mofunc_base&& __x) noexcept { _M_manage = std::__exchange(__x._M_manage, _S_empty); _M_manage(_M_storage, &__x._M_storage); } template static constexpr bool _S_nothrow_init() noexcept { if constexpr (__stored_locally<_Tp>) return is_nothrow_constructible_v<_Tp, _Args...>; return false; } template void _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>()) { if constexpr (__stored_locally<_Tp>) ::new (_M_storage._M_addr()) _Tp(std::forward<_Args>(__args)...); else _M_storage._M_p = new _Tp(std::forward<_Args>(__args)...); _M_manage = &_S_manage<_Tp>; } _Mofunc_base& operator=(_Mofunc_base&& __x) noexcept { _M_manage(_M_storage, nullptr); _M_manage = std::__exchange(__x._M_manage, _S_empty); _M_manage(_M_storage, &__x._M_storage); return *this; } _Mofunc_base& operator=(nullptr_t) noexcept { _M_manage(_M_storage, nullptr); _M_manage = _S_empty; return *this; } ~_Mofunc_base() { _M_manage(_M_storage, nullptr); } void swap(_Mofunc_base& __x) noexcept { // Order of operations here is more efficient if __x is empty. _Storage __s; __x._M_manage(__s, &__x._M_storage); _M_manage(__x._M_storage, &_M_storage); __x._M_manage(_M_storage, &__s); std::swap(_M_manage, __x._M_manage); } template static _Tp* _S_access(_Self* __self) noexcept { if constexpr (__stored_locally>) return static_cast<_Tp*>(__self->_M_storage._M_addr()); else return static_cast<_Tp*>(__self->_M_storage._M_p); } private: struct _Storage { void* _M_addr() noexcept { return &_M_bytes[0]; } const void* _M_addr() const noexcept { return &_M_bytes[0]; } // We want to have enough space to store a simple delegate type. struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; }; union { void* _M_p; alignas(_Delegate) alignas(void(*)()) unsigned char _M_bytes[sizeof(_Delegate)]; }; }; template static constexpr bool __stored_locally = sizeof(_Tp) <= sizeof(_Storage) && alignof(_Tp) <= alignof(_Storage) && is_nothrow_move_constructible_v<_Tp>; // A function that either destroys the target object stored in __target, // or moves the target object from *__src to __target. using _Manager = void (*)(_Storage& __target, _Storage* __src) noexcept; // The no-op manager function for objects with no target. static void _S_empty(_Storage&, _Storage*) noexcept { } // The real manager function for a target object of type _Tp. template static void _S_manage(_Storage& __target, _Storage* __src) noexcept { if constexpr (__stored_locally<_Tp>) { if (__src) { _Tp* __rval = static_cast<_Tp*>(__src->_M_addr()); ::new (__target._M_addr()) _Tp(std::move(*__rval)); __rval->~_Tp(); } else static_cast<_Tp*>(__target._M_addr())->~_Tp(); } else { if (__src) __target._M_p = __src->_M_p; else delete static_cast<_Tp*>(__target._M_p); } } _Storage _M_storage; _Manager _M_manage; }; template inline constexpr bool __is_move_only_function_v = false; template constexpr bool __is_move_only_function_v> = true; /// @endcond namespace __detail::__variant { template struct _Never_valueless_alt; // see // Provide the strong exception-safety guarantee when emplacing a // move_only_function into a variant. template struct _Never_valueless_alt> : true_type { }; } // namespace __detail::__variant _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #include "mofunc_impl.h" #define _GLIBCXX_MOF_CV const #include "mofunc_impl.h" #define _GLIBCXX_MOF_REF & #include "mofunc_impl.h" #define _GLIBCXX_MOF_REF && #include "mofunc_impl.h" #define _GLIBCXX_MOF_CV const #define _GLIBCXX_MOF_REF & #include "mofunc_impl.h" #define _GLIBCXX_MOF_CV const #define _GLIBCXX_MOF_REF && #include "mofunc_impl.h" #endif // __glibcxx_move_only_function #endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H