// Implementation of std::move_only_function and std::copyable_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/funcwrap.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{functional}
*/
#ifndef _GLIBCXX_FUNCWRAP_H
#define _GLIBCXX_FUNCWRAP_H 1
#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif
#include
#if defined(__glibcxx_move_only_function) || defined(__glibcxx_copyable_function)
#include
#include
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/// @cond undocumented
template
inline constexpr bool __is_polymorphic_function_v = false;
namespace __polyfunc
{
union _Ptrs
{
void* _M_obj;
void (*_M_func)();
};
struct _Storage
{
void* _M_addr() noexcept { return &_M_bytes[0]; }
void const* _M_addr() const noexcept { return &_M_bytes[0]; }
template
static consteval bool
_S_stored_locally() noexcept
{
return sizeof(_Tp) <= sizeof(_Storage)
&& alignof(_Tp) <= alignof(_Storage)
&& is_nothrow_move_constructible_v<_Tp>;
}
template
static consteval bool
_S_nothrow_init() noexcept
{
if constexpr (_S_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 (is_function_v>)
{
static_assert( sizeof...(__args) <= 1 );
// __args can have up to one element, returns nullptr if empty.
_Tp __func = (nullptr, ..., __args);
_M_ptrs._M_func = reinterpret_cast(__func);
}
else if constexpr (!_S_stored_locally<_Tp>())
_M_ptrs._M_obj = new _Tp(std::forward<_Args>(__args)...);
else
::new (_M_addr()) _Tp(std::forward<_Args>(__args)...);
}
template
[[__gnu__::__always_inline__]]
_Tp*
_M_ptr() const noexcept
{
if constexpr (!_S_stored_locally>())
return static_cast<_Tp*>(_M_ptrs._M_obj);
else if constexpr (is_const_v<_Tp>)
return static_cast<_Tp*>(_M_addr());
else
// _Manager and _Invoker pass _Storage by const&, even for mutable sources.
return static_cast<_Tp*>(const_cast(_M_addr()));
}
template
[[__gnu__::__always_inline__]]
_Ref
_M_ref() const noexcept
{
using _Tp = remove_reference_t<_Ref>;
if constexpr (is_function_v>)
return reinterpret_cast<_Tp>(_M_ptrs._M_func);
else
return static_cast<_Ref>(*_M_ptr<_Tp>());
}
// We want to have enough space to store a simple delegate type.
struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
union {
_Ptrs _M_ptrs;
alignas(_Delegate) alignas(void(*)())
unsigned char _M_bytes[sizeof(_Delegate)];
};
};
template
struct _Base_invoker
{
using _Signature = _Ret(*)(_Args...) noexcept(_Noex);
using __storage_func_t = _Ret(*)(const _Storage&, _Args...) noexcept(_Noex);
template
static consteval __storage_func_t
_S_storage()
{ return &_S_call_storage<_Adjust_target<_Tp>>; }
private:
template>
using _Adjust_target =
__conditional_t || is_member_pointer_v<_Td>, _Td, _Tp>;
template
static _Ret
_S_call_storage(const _Storage& __ref, _Args... __args) noexcept(_Noex)
{
return std::__invoke_r<_Ret>(__ref._M_ref<_Tp>(),
std::forward<_Args>(__args)...);
}
};
template
using __param_t = __conditional_t, _Tp, _Tp&&>;
template
using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
template
auto&
__invoker_of(_Func& __f) noexcept
{ return __f._M_invoke; }
template
auto&
__base_of(_Func& __f) noexcept
{ return static_cast<__like_t<_Func&, typename _Func::_Base>>(__f); }
template
consteval bool
__is_invoker_convertible() noexcept
{
if constexpr (requires { typename _Src::_Signature; })
return is_convertible_v;
else
return false;
}
struct _Manager
{
enum class _Op
{
// saves address of entity in *__src to __target._M_ptrs,
_Address,
// moves entity stored in *__src to __target, __src becomes empty
_Move,
// copies entity stored in *__src to __target, supported only if
// _ProvideCopy is specified.
_Copy,
// destroys entity stored in __target, __src is ignoring
_Destroy,
};
// A function that performs operation __op on the __target and possibly __src.
using _Func = void (*)(_Op __op, _Storage& __target, const _Storage* __src);
// The no-op manager function for objects with no target.
static void _S_empty(_Op, _Storage&, const _Storage*) noexcept { }
template
consteval static auto
_S_select()
{
if constexpr (is_function_v>)
return &_S_func;
else if constexpr (!_Storage::_S_stored_locally<_Tp>())
return &_S_ptr<_ProvideCopy, _Tp>;
else if constexpr (is_trivially_copyable_v<_Tp>)
return &_S_trivial;
else
return &_S_local<_ProvideCopy, _Tp>;
}
private:
static void
_S_func(_Op __op, _Storage& __target, const _Storage* __src) noexcept
{
switch (__op)
{
case _Op::_Address:
case _Op::_Move:
case _Op::_Copy:
__target._M_ptrs._M_func = __src->_M_ptrs._M_func;
return;
case _Op::_Destroy:
return;
}
}
static void
_S_trivial(_Op __op, _Storage& __target, const _Storage* __src) noexcept
{
switch (__op)
{
case _Op::_Address:
__target._M_ptrs._M_obj = const_cast(__src->_M_addr());
return;
case _Op::_Move:
case _Op::_Copy:
// N.B. Creating _Storage starts lifetime of _M_bytes char array,
// that implicitly creates, amongst other, all possible trivially
// copyable objects, so we copy any object present in __src._M_bytes.
::new (&__target) _Storage(*__src);
return;
case _Op::_Destroy:
return;
}
}
template
static void
_S_local(_Op __op, _Storage& __target, const _Storage* __src)
noexcept(!_Provide_copy)
{
switch (__op)
{
case _Op::_Address:
__target._M_ptrs._M_obj = __src->_M_ptr<_Tp>();
return;
case _Op::_Move:
{
_Tp* __obj = __src->_M_ptr<_Tp>();
::new(__target._M_addr()) _Tp(std::move(*__obj));
__obj->~_Tp();
}
return;
case _Op::_Destroy:
__target._M_ptr<_Tp>()->~_Tp();
return;
case _Op::_Copy:
if constexpr (_Provide_copy)
::new (__target._M_addr()) _Tp(__src->_M_ref());
else
__builtin_unreachable();
return;
}
}
template
static void
_S_ptr(_Op __op, _Storage& __target, const _Storage* __src)
noexcept(!_Provide_copy)
{
switch (__op)
{
case _Op::_Address:
case _Op::_Move:
__target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
return;
case _Op::_Destroy:
delete __target._M_ptr<_Tp>();
return;
case _Op::_Copy:
if constexpr (_Provide_copy)
__target._M_ptrs._M_obj = new _Tp(__src->_M_ref());
else
__builtin_unreachable();
return;
}
}
};
class _Mo_base
{
protected:
_Mo_base() noexcept
: _M_manage(_Manager::_S_empty)
{ }
_Mo_base(_Mo_base&& __x) noexcept
{ _M_move(__x); }
template
static consteval bool
_S_nothrow_init() noexcept
{ return _Storage::_S_nothrow_init<_Tp, _Args...>(); }
template
void
_M_init(_Args&&... __args)
noexcept(_S_nothrow_init<_Tp, _Args...>())
{
_M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
_M_manage = _Manager::_S_select();
}
void
_M_move(_Mo_base& __x) noexcept
{
using _Op = _Manager::_Op;
_M_manage = std::__exchange(__x._M_manage, _Manager::_S_empty);
_M_manage(_Op::_Move, _M_storage, &__x._M_storage);
}
_Mo_base&
operator=(_Mo_base&& __x) noexcept
{
_M_destroy();
_M_move(__x);
return *this;
}
void
_M_reset() noexcept
{
_M_destroy();
_M_manage = _Manager::_S_empty;
}
~_Mo_base()
{ _M_destroy(); }
void
swap(_Mo_base& __x) noexcept
{
using _Op = _Manager::_Op;
// Order of operations here is more efficient if __x is empty.
_Storage __s;
__x._M_manage(_Op::_Move, __s, &__x._M_storage);
_M_manage(_Op::_Move, __x._M_storage, &_M_storage);
__x._M_manage(_Op::_Move, _M_storage, &__s);
std::swap(_M_manage, __x._M_manage);
}
_Storage _M_storage;
private:
void _M_destroy() noexcept
{ _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); }
_Manager::_Func _M_manage;
#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
friend class _Cpy_base;
#endif // __glibcxx_copyable_function
};
} // namespace __polyfunc
/// @endcond
#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
template
class move_only_function; // not defined
/// @cond undocumented
template
constexpr bool __is_polymorphic_function_v> = true;
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
/// @endcond
#endif // __glibcxx_move_only_function
#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
/// @cond undocumented
namespace __polyfunc
{
class _Cpy_base : public _Mo_base
{
protected:
_Cpy_base() = default;
template
void
_M_init(_Args&&... __args)
noexcept(_S_nothrow_init<_Tp, _Args...>())
{
_M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
_M_manage = _Manager::_S_select();
}
void
_M_copy(_Cpy_base const& __x)
{
using _Op = _Manager::_Op;
__x._M_manage(_Op::_Copy, _M_storage, &__x._M_storage);
_M_manage = __x._M_manage;
}
_Cpy_base(_Cpy_base&&) = default;
_Cpy_base(_Cpy_base const& __x)
{ _M_copy(__x); }
_Cpy_base&
operator=(_Cpy_base&&) = default;
_Cpy_base&
// Needs to use copy and swap for exception guarantees.
operator=(_Cpy_base const&) = delete;
};
} // namespace __polyfunc
/// @endcond
template
class copyable_function; // not defined
template
constexpr bool __is_polymorphic_function_v> = true;
namespace __detail::__variant
{
template struct _Never_valueless_alt; // see
// Provide the strong exception-safety guarantee when emplacing a
// copyable_function into a variant.
template
struct _Never_valueless_alt>
: true_type
{ };
} // namespace __detail::__variant
#endif // __glibcxx_copyable_function
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
#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
#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
#include "cpyfunc_impl.h"
#define _GLIBCXX_MOF_CV const
#include "cpyfunc_impl.h"
#define _GLIBCXX_MOF_REF &
#include "cpyfunc_impl.h"
#define _GLIBCXX_MOF_REF &&
#include "cpyfunc_impl.h"
#define _GLIBCXX_MOF_CV const
#define _GLIBCXX_MOF_REF &
#include "cpyfunc_impl.h"
#define _GLIBCXX_MOF_CV const
#define _GLIBCXX_MOF_REF &&
#include "cpyfunc_impl.h"
#endif // __glibcxx_copyable_function
#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
#endif // _GLIBCXX_FUNCWRAP_H