================ @@ -0,0 +1,233 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This header is unguarded on purpose. This header is an implementation detail of move_only_function.h +// and generates multiple versions of std::move_only_function + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/move_only_function_common.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__utility/exchange.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/pointer_int_pair.h> +#include <__utility/small_buffer.h> +#include <__utility/swap.h> +#include <cstddef> +#include <cstring> +#include <initializer_list> +#include <new> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#ifndef _LIBCPP_IN_MOVE_ONLY_FUNCTION_H +# error This header should only be included from move_only_function.h +#endif + +#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_CV +# define _LIBCPP_MOVE_ONLY_FUNCTION_CV +#endif + +#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_REF ---------------- EricWF wrote:
Here's what I'm imagining... ```c++ #ifndef _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H #define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H #include <__assert> #include <__config> #include <__functional/invoke.h> #include <__type_traits/decay.h> #include <__type_traits/invoke.h> #include <__type_traits/is_function.h> #include <__type_traits/is_member_function_pointer.h> #include <__type_traits/is_pointer.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_constructible.h> #include <__type_traits/is_trivially_destructible.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_pointer.h> #include <__utility/forward.h> #include <__utility/in_place.h> #include <__utility/swap.h> #include <cstddef> #include <initializer_list> #include <new> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif _LIBCPP_BEGIN_NAMESPACE_STD enum class _Quals : unsigned { _None = 0, _Const = 1, _RVRef = 2, _LVRef = 4, _NoExcept = 8, }; constexpr _Quals operator|(_Quals __x, _Quals __y) { return static_cast<_Quals>(static_cast<unsigned>(__x) | static_cast<unsigned>(__y)); } constexpr _Quals operator&(_Quals __x, _Quals __y) { return static_cast<_Quals>(static_cast<unsigned>(__x) & static_cast<unsigned>(__y)); } constexpr _Quals operator^(_Quals __x, _Quals __y) { return static_cast<_Quals>(static_cast<unsigned>(__x) ^ static_cast<unsigned>(__y)); } constexpr _Quals operator~(_Quals __x) { return static_cast<_Quals>(~static_cast<unsigned>(__x)); } constexpr bool operator==(const _Quals __x, const _Quals __y) { return static_cast<unsigned>(__x) == static_cast<unsigned>(__y); } constexpr bool operator!=(const _Quals __x, const _Quals __y) { return static_cast<unsigned>(__x) != static_cast<unsigned>(__y); } constexpr _Quals __cvref_quals(_Quals __q) { return __q & (_Quals::_Const | _Quals::_RVRef | _Quals::_LVRef); } constexpr bool __is_noexcept(_Quals __q) { return (__q & _Quals::_NoExcept) == _Quals::_NoExcept; } constexpr _Quals __ref_quals(_Quals __q) { return __q & (_Quals::_RVRef | _Quals::_LVRef); } template <class _Ptr> struct __unqualify_type; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...)> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...)&> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None | _Quals::_LVRef; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const&> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const | _Quals::_LVRef; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) &&> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None | _Quals::_RVRef; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const&&> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const | _Quals::_RVRef; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None | _Quals::_NoExcept; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const | _Quals::_NoExcept; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) & noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None | _Quals::_LVRef | _Quals::_NoExcept; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const & noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const | _Quals::_LVRef | _Quals::_NoExcept; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) && noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_None | _Quals::_RVRef | _Quals::_NoExcept; }; template <class _Ret, class... _Args> struct __unqualify_type<_Ret(_Args...) const && noexcept> { using type = _Ret(_Args...); static constexpr _Quals __qual = _Quals::_Const | _Quals::_RVRef | _Quals::_NoExcept; }; template <class _Tp> struct __identity { using type = _Tp; }; template <_Quals __qual, class _Ret, class... _Args> constexpr auto __qualify_function_type() { if constexpr (__qual == _Quals::_None) { return __identity<_Ret(_Args...)>{}; } else if constexpr (__qual == _Quals::_Const) { return __identity<_Ret(_Args...) const>{}; } else if constexpr (__qual == _Quals::_LVRef) { return __identity<_Ret(_Args...)&>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_LVRef)) { return __identity<_Ret(_Args...) const&>{}; } else if constexpr (__qual == _Quals::_RVRef) { return __identity<_Ret(_Args...) &&>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_RVRef)) { return __identity<_Ret(_Args...) const&&>{}; } else if constexpr (__qual == _Quals::_NoExcept) { return __identity<_Ret(_Args...) noexcept>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_NoExcept)) { return __identity<_Ret(_Args...) const noexcept>{}; } else if constexpr (__qual == (_Quals::_LVRef | _Quals::_NoExcept)) { return __identity<_Ret(_Args...) & noexcept>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_LVRef | _Quals::_NoExcept)) { return __identity<_Ret(_Args...) const & noexcept>{}; } else if constexpr (__qual == (_Quals::_RVRef | _Quals::_NoExcept)) { return __identity < _Ret(_Args...) && noexcept > {}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_RVRef | _Quals::_NoExcept)) { return __identity < _Ret(_Args...) const && noexcept > {}; } else { static_assert(sizeof(__qual) == 0, "Invalid qualifier"); } } template <_Quals __qual, class _Ret> constexpr auto __qualify_type_impl() { static_assert(!__is_noexcept(__qual), "Noexcept qualifier is not allowed on type"); if constexpr (__qual == _Quals::_None) { return __identity<_Ret>{}; } else if constexpr (__qual == _Quals::_Const) { return __identity<_Ret const>{}; } else if constexpr (__qual == _Quals::_LVRef) { return __identity<_Ret&>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_LVRef)) { return __identity<_Ret const&>{}; } else if constexpr (__qual == _Quals::_RVRef) { return __identity<_Ret&&>{}; } else if constexpr (__qual == (_Quals::_Const | _Quals::_RVRef)) { return __identity<_Ret const&&>{}; } else { static_assert(sizeof(__qual) == 0, "Invalid qualifier"); } } template <_Quals __qual, class _Ret> using __qualify_type_t = typename decltype(__qualify_type_impl<__qual, _Ret>())::type; template <_Quals __quals, class _Tp> __qualify_type_t<__quals, _Tp> __cast_as(void* __ptr) { return std::forward<__qualify_type_t<__quals, _Tp>>(*static_cast<_Tp*>(__ptr)); } template <class _Tp, _Quals __q> struct __move_only_function_base; struct __move_only_function_buffer { union { void* __ptr_; std::byte __buf_[3 * sizeof(void*)]; }; }; struct _AllocGuard { _AllocGuard() = delete; _AllocGuard(_AllocGuard const&) = delete; _AllocGuard(size_t __size, size_t __align) : __ptr_(__libcpp_allocate(__size, __align)), __size_(__size), __align_(__align) {} void* __release() { void* __ret = __ptr_; __ptr_ = nullptr; return __ret; } ~_AllocGuard() { if (__ptr_) { __libcpp_deallocate(__ptr_, __size_, __align_); } } void* __ptr_; size_t __size_; size_t __align_; }; template <class _Functor> constexpr bool __use_inline_storage = sizeof(_Functor) <= sizeof(__move_only_function_buffer) && alignof(_Functor) <= alignof(__move_only_function_buffer) && std::is_trivially_destructible_v<_Functor> && std::is_trivially_move_constructible_v<_Functor>; template <class...> struct move_only_function; template <class _Ret, class... _Args, _Quals __q> struct __move_only_function_base<_Ret(_Args...), __q> { private: using _BufferT = __move_only_function_buffer; static constexpr _Quals __inv_quals = __ref_quals(__q) == _Quals::_None ? __cvref_quals(__q) | _Quals::_LVRef : __cvref_quals(__q); struct _VTable { using __destroy_t = void (*)(_BufferT&); using __call_t = _Ret (*)(_BufferT&, _Args...) noexcept(__is_noexcept(__q)); __call_t __call_ = nullptr; __destroy_t __destroy_ = nullptr; template <class _RawFunctor> static constexpr _VTable __create() { using _Functor = std::decay_t<_RawFunctor>; if constexpr (__use_inline_storage<_Functor>) { return _VTable{.__call_ = [](_BufferT& __buffer, _Args... __args) noexcept(__is_noexcept(__q)) -> _Ret { return std::invoke_r<_Ret>( __cast_as<__inv_quals, _Functor>(__buffer.__buf_), std::forward<_Args>(__args)...); }, .__destroy_ = nullptr}; } else { return _VTable{.__call_ = [](_BufferT& __buffer, _Args... __args) noexcept(__is_noexcept(__q)) -> _Ret { return std::invoke_r<_Ret>( __cast_as<__inv_quals, _Functor>(__buffer.__ptr_), std::forward<_Args>(__args)...); }, .__destroy_ = [](_BufferT& __buffer) noexcept -> void { static_cast<_Functor*>(__buffer.__ptr_)->~_Functor(); __libcpp_deallocate(__buffer.__ptr_, sizeof(_Functor), alignof(_Functor)); }}; }; } }; template <class _Functor> static constexpr _VTable __functor_vtable = _VTable::template __create<_Functor>(); mutable _BufferT __buffer_; const _VTable* __vtable_ = {}; template <class _VT> static constexpr bool __is_callable_from = []() { using _DVT = decay_t<_VT>; if constexpr (__is_noexcept(__q)) { return is_nothrow_invocable_r_v<_Ret, __qualify_type_t<__cvref_quals(__q), _DVT>, _Args...> && is_nothrow_invocable_r_v<_Ret, __qualify_type_t<__inv_quals, _DVT>, _Args...>; } else { return is_invocable_r_v<_Ret, __qualify_type_t<__cvref_quals(__q), _DVT>, _Args...> && is_invocable_r_v<_Ret, __qualify_type_t<__inv_quals, _DVT>, _Args...>; } }(); template <class _Func, class... _FArgs> void __construct(_FArgs&&... __args) { using _DFunc = decay_t<_Func>; if (__use_inline_storage<_DFunc>) { ::new (&__buffer_.__buf_) _DFunc(std::forward<_FArgs>(__args)...); } else { _AllocGuard __alloc(sizeof(_DFunc), alignof(_DFunc)); ::new (__alloc.__ptr_) _DFunc(std::forward<_FArgs>(__args)...); __buffer_.__ptr_ = __alloc.__release(); } __vtable_ = &__functor_vtable<_Func>; } _LIBCPP_HIDE_FROM_ABI void __reset() { if (__vtable_ && __vtable_->__destroy_) __vtable_->__destroy_(__buffer_); __vtable_ = nullptr; } public: using result_type = _Ret; // [func.wrap.move.ctor] __move_only_function_base() noexcept = default; _LIBCPP_HIDE_FROM_ABI __move_only_function_base(__move_only_function_base&& __other) noexcept : __vtable_(__other.__vtable_), __buffer_(__other.__buffer_) { __other.__vtable_ = {}; } template <_Quals __call_qual> static constexpr bool __has_cvref_quals = (__cvref_quals(__q) & __call_qual) == __call_qual; _LIBCPP_HIDE_FROM_ABI ~__move_only_function_base() { __reset(); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) noexcept(__is_noexcept(__q)) requires __has_cvref_quals<_Quals::_None> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) const noexcept(__is_noexcept(__q)) requires __has_cvref_quals<_Quals::_Const> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) & noexcept(__is_noexcept(__q)) requires __has_cvref_quals< _Quals::_LVRef> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) && noexcept(__is_noexcept(__q)) requires __has_cvref_quals<_Quals::_RVRef> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) const& noexcept(__is_noexcept(__q)) requires __has_cvref_quals<_Quals::_Const | _Quals::_LVRef> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI _Ret operator()(_Args... __args) const&& noexcept(__is_noexcept(__q)) requires __has_cvref_quals<_Quals::_Const | _Quals::_RVRef> { _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function"); return __vtable_->__call_(__buffer_, std::forward<_Args>(__args)...); } private: template <class, _Quals> friend struct __move_only_function_base; template <class...> friend struct move_only_function; }; template <class _Ret> struct __is_move_only_function : false_type {}; template <class... _Obj> struct __is_move_only_function<move_only_function<_Obj...>> : true_type{}; template <class _Tp> struct move_only_function<_Tp> : __move_only_function_base<typename __unqualify_type<_Tp>::type, __unqualify_type<_Tp>::__qual> { using __base = __move_only_function_base<typename __unqualify_type<_Tp>::type, __unqualify_type<_Tp>::__qual>; move_only_function() noexcept = default; _LIBCPP_HIDE_FROM_ABI move_only_function(nullptr_t) noexcept {} move_only_function(move_only_function const&) = delete; move_only_function(move_only_function&&) = default; ~move_only_function() = default; template <class _Func> requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value && __base::template __is_callable_from<_Func>) _LIBCPP_HIDE_FROM_ABI move_only_function(_Func&& __func) { using _StoredFunc = decay_t<_Func>; if constexpr ((is_pointer_v<_StoredFunc> && is_function_v<remove_pointer_t<_StoredFunc>>) || is_member_function_pointer_v<_StoredFunc>) { if (__func != nullptr) { this->template __construct<_StoredFunc>(std::forward<_Func>(__func)); } } else if constexpr (__is_move_only_function<_StoredFunc>::value) { if (__func) { std::swap(this->__vtable_, __func.__vtable_); this->__buffer_ = __func.__buffer_; } } else { this->template __construct<_Func>(std::forward<_Func>(__func)); } } template <class _Func, class... _FArgs> requires is_constructible_v<decay_t<_Func>, _FArgs...> && __base::template __is_callable_from<_Func> _LIBCPP_HIDE_FROM_ABI explicit move_only_function( in_place_type_t<_Func>, _FArgs&&... __args) { static_assert(is_same_v<decay_t<_Func>, _Func>); this->template __construct<_Func>(std::forward<_FArgs>(__args)...); } template <class _Func, class _InitListType, class... _Args> requires is_constructible_v<decay_t<_Func>, initializer_list<_InitListType>&, _Args...> && __base::template __is_callable_from<_Func> _LIBCPP_HIDE_FROM_ABI explicit move_only_function( in_place_type_t<_Func>, initializer_list<_InitListType> __il, _Args&&... __args) { static_assert(is_same_v<decay_t<_Func>, _Func>); this->template __construct<_Func>(__il, std::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(move_only_function&& __other) noexcept { move_only_function(std::move(__other)).swap(*this); return *this; } _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(nullptr_t) noexcept { this->__reset(); return *this; } template <class _Func> requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value && __base::template __is_callable_from<_Func>) _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(_Func&& __func) { move_only_function(std::forward<_Func>(__func)).swap(*this); return *this; } explicit operator bool() const noexcept { return this->__vtable_ != nullptr; } using __base::operator(); // [func.wrap.move.util] _LIBCPP_HIDE_FROM_ABI void swap(move_only_function& __other) noexcept { std::swap(this->__vtable_, __other.__vtable_); std::swap(this->__buffer_, __other.__buffer_); } _LIBCPP_HIDE_FROM_ABI friend void swap(move_only_function& __lhs, move_only_function& __rhs) noexcept { __lhs.swap(__rhs); } _LIBCPP_HIDE_FROM_ABI friend bool operator==(const move_only_function& __func, nullptr_t) noexcept { return !__func; } }; _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H ``` https://github.com/llvm/llvm-project/pull/94670 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits