| 1 | //===----------------------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H |
| 10 | #define _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H |
| 11 | |
| 12 | #include <__config> |
| 13 | #include <__type_traits/invoke.h> |
| 14 | #include <__type_traits/is_const.h> |
| 15 | #include <__type_traits/is_function.h> |
| 16 | #include <__type_traits/is_object.h> |
| 17 | #include <__type_traits/is_reference.h> |
| 18 | #include <__type_traits/is_trivially_constructible.h> |
| 19 | #include <__type_traits/is_trivially_destructible.h> |
| 20 | #include <__type_traits/remove_cv.h> |
| 21 | #include <__type_traits/remove_pointer.h> |
| 22 | #include <__utility/constant_wrapper.h> |
| 23 | #include <__utility/declval.h> |
| 24 | |
| 25 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 26 | # pragma GCC system_header |
| 27 | #endif |
| 28 | |
| 29 | _LIBCPP_BEGIN_NAMESPACE_STD |
| 30 | |
| 31 | #if _LIBCPP_STD_VER >= 26 |
| 32 | |
| 33 | template <class...> |
| 34 | class function_ref; |
| 35 | |
| 36 | template <class _Fn1, class _Fn2> |
| 37 | struct __is_convertible_from_specialization : false_type {}; |
| 38 | |
| 39 | union __function_ref_storage { |
| 40 | void* __obj_ptr_; |
| 41 | void (*__fn_ptr_)(); |
| 42 | |
| 43 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __function_ref_storage() noexcept : __obj_ptr_(nullptr) {} |
| 44 | |
| 45 | template <class _Tp> |
| 46 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __function_ref_storage(_Tp* __ptr) noexcept { |
| 47 | if constexpr (is_object_v<_Tp>) { |
| 48 | __obj_ptr_ = const_cast<remove_cv_t<_Tp>*>(__ptr); |
| 49 | } else { |
| 50 | static_assert(is_function_v<_Tp>); |
| 51 | __fn_ptr_ = reinterpret_cast<void (*)()>(__ptr); |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | template <class _Tp> |
| 56 | _LIBCPP_HIDE_FROM_ABI static constexpr auto __get(__function_ref_storage __storage) { |
| 57 | if constexpr (is_object_v<_Tp>) { |
| 58 | return static_cast<_Tp*>(__storage.__obj_ptr_); |
| 59 | } else { |
| 60 | static_assert(is_function_v<_Tp>); |
| 61 | return reinterpret_cast<_Tp*>(__storage.__fn_ptr_); |
| 62 | } |
| 63 | } |
| 64 | }; |
| 65 | |
| 66 | template <class _Fp, class _Tp> |
| 67 | struct __function_ref_bind {}; |
| 68 | |
| 69 | // F is of the form R(*)(G, A...) noexcept(E) for a type G. |
| 70 | template <bool _Noexcept, class _Tp, class _Rp, class _Gp, class... _ArgTypes> |
| 71 | struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept(_Noexcept), _Tp> { |
| 72 | using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept(_Noexcept); |
| 73 | }; |
| 74 | |
| 75 | template <class _Tp, class _Mp, class _Gp> |
| 76 | requires is_object_v<_Mp> |
| 77 | struct __function_ref_bind<_Mp _Gp::*, _Tp> { |
| 78 | using type _LIBCPP_NODEBUG = invoke_result_t<_Mp _Gp::*, _Tp&>() noexcept; |
| 79 | }; |
| 80 | |
| 81 | template <class _Fp, class _Tp> |
| 82 | using __function_ref_bind_t _LIBCPP_NODEBUG = __function_ref_bind<_Fp, _Tp>::type; |
| 83 | |
| 84 | template <class _Fp> |
| 85 | requires is_function_v<_Fp> |
| 86 | function_ref(_Fp*) -> function_ref<_Fp>; |
| 87 | |
| 88 | template <auto _Cw, class _Fn> |
| 89 | requires is_function_v<remove_pointer_t<_Fn>> |
| 90 | function_ref(constant_wrapper<_Cw, _Fn>) -> function_ref<remove_pointer_t<_Fn>>; |
| 91 | |
| 92 | template <auto _Cw, class _Fn, class _Tp> |
| 93 | function_ref(constant_wrapper<_Cw, _Fn>, _Tp&&) -> function_ref<__function_ref_bind_t<_Fn, _Tp&>>; |
| 94 | |
| 95 | template <class> |
| 96 | constexpr bool __is_constant_wrapper = false; |
| 97 | |
| 98 | template <auto _Value> |
| 99 | constexpr bool __is_constant_wrapper<constant_wrapper<_Value>> = true; |
| 100 | |
| 101 | template <class _Fn, class... _Args> |
| 102 | concept __statically_callable = requires { _Fn::operator()(std::declval<_Args>()...); }; |
| 103 | |
| 104 | #endif // _LIBCPP_STD_VER >= 26 |
| 105 | |
| 106 | _LIBCPP_END_NAMESPACE_STD |
| 107 | |
| 108 | #endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H |
| 109 | |