================ @@ -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 +# define _LIBCPP_MOVE_ONLY_FUNCTION_REF +# define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV& +#else +# define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF +#endif + +#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT false +#endif + +#define _LIBCPP_MOVE_ONLY_FUNCTION_CVREF _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifdef _LIBCPP_ABI_MOVE_ONLY_FUNCTION_TRIVIAL_ABI +# define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI [[_Clang::__trivial_abi__]] +#else +# define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI +#endif + +template <class...> +class move_only_function; + +template <class _ReturnT, class... _ArgTypes> +class _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI move_only_function<_ReturnT( + _ArgTypes...) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT)> { +private: + static constexpr size_t __buffer_size_ = 3 * sizeof(void*); + static constexpr size_t __buffer_alignment_ = alignof(void*); + using _BufferT = __small_buffer<__buffer_size_, __buffer_alignment_>; + + using _TrivialVTable = _MoveOnlyFunctionTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>; + using _NonTrivialVTable = _MoveOnlyFunctionNonTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>; + + template <class _Functor> + static constexpr _TrivialVTable __trivial_vtable_ = { + .__call_ = [](_BufferT& __buffer, _ArgTypes... __args) noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) -> _ReturnT { + return std::invoke_r<_ReturnT>( + static_cast<_Functor _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS>(*__buffer.__get<_Functor>()), + std::forward<_ArgTypes>(__args)...); + }}; + + template <class _Functor> + static constexpr _NonTrivialVTable __non_trivial_vtable_{ + __trivial_vtable_<_Functor>, + [](_BufferT& __buffer) noexcept -> void { + std::destroy_at(__buffer.__get<_Functor>()); + __buffer.__dealloc<_Functor>(); + }, + }; + + template <class _Functor> + _LIBCPP_HIDE_FROM_ABI __pointer_bool_pair<const _TrivialVTable*> __get_vptr() { + if constexpr (_BufferT::__fits_in_buffer<_Functor> && is_trivially_destructible_v<_Functor>) { + return {&__trivial_vtable_<_Functor>, false}; + } else { + return {&__non_trivial_vtable_<_Functor>, true}; + } + } + + template <class _VT> + static constexpr bool __is_callable_from = [] { + using _DVT = decay_t<_VT>; + if (_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + return is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> && + is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>; + } else { + return is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> && + is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>; + } + }(); + + template <class _Func, class... _Args> + _LIBCPP_HIDE_FROM_ABI void __construct(_Args&&... __args) { + static_assert(is_constructible_v<decay_t<_Func>, _Func>); + + using _StoredFunc = decay_t<_Func>; + __vtable_ = __get_vptr<_StoredFunc>(); + __buffer_.__construct<_StoredFunc>(std::forward<_Args>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI void __reset() { + if (__vtable_.__get_value()) ---------------- EricWF wrote:
There's other cost here. There's complexity, there's ABI risk. To speak on the ABI risk.: From my investigations Clang has trouble optimizing around this, where it doesn't have trouble optimizing around what @huixie90 is suggesting, which I've implemented and tested out. And there's two reviewers asking you to remove it. 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