| 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 | // This header is unguarded on purpose. This header is an implementation detail of function_ref.h |
| 10 | // and generates multiple versions of std::function_ref |
| 11 | |
| 12 | #include <__assert> |
| 13 | #include <__config> |
| 14 | #include <__functional/function_ref_common.h> |
| 15 | #include <__functional/invoke.h> |
| 16 | #include <__memory/addressof.h> |
| 17 | #include <__type_traits/conditional.h> |
| 18 | #include <__type_traits/conjunction.h> |
| 19 | #include <__type_traits/invoke.h> |
| 20 | #include <__type_traits/is_const.h> |
| 21 | #include <__type_traits/is_convertible.h> |
| 22 | #include <__type_traits/is_function.h> |
| 23 | #include <__type_traits/is_member_pointer.h> |
| 24 | #include <__type_traits/is_object.h> |
| 25 | #include <__type_traits/is_pointer.h> |
| 26 | #include <__type_traits/is_reference.h> |
| 27 | #include <__type_traits/is_same.h> |
| 28 | #include <__type_traits/is_void.h> |
| 29 | #include <__type_traits/register_passable.h> |
| 30 | #include <__type_traits/remove_cv.h> |
| 31 | #include <__type_traits/remove_cvref.h> |
| 32 | #include <__type_traits/remove_pointer.h> |
| 33 | #include <__type_traits/remove_reference.h> |
| 34 | #include <__utility/constant_wrapper.h> |
| 35 | #include <__utility/forward.h> |
| 36 | |
| 37 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 38 | # pragma GCC system_header |
| 39 | #endif |
| 40 | |
| 41 | #ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_H |
| 42 | # error This header should only be included from function_ref.h |
| 43 | #endif |
| 44 | |
| 45 | _LIBCPP_BEGIN_NAMESPACE_STD |
| 46 | |
| 47 | #if _LIBCPP_STD_VER >= 26 |
| 48 | |
| 49 | template <class...> |
| 50 | class function_ref; |
| 51 | |
| 52 | template <bool _NoExcept1, bool _NoExcept2, class _Rp, class... _ArgTypes> |
| 53 | struct __is_convertible_from_specialization< |
| 54 | function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_NoExcept1)>, |
| 55 | function_ref<_Rp(_ArgTypes...) const noexcept(_NoExcept2)> > |
| 56 | : is_convertible<_Rp (&)(_ArgTypes...) noexcept(_NoExcept2), _Rp (&)(_ArgTypes...) noexcept(_NoExcept1)> {}; |
| 57 | |
| 58 | template <bool _NoExcept1, bool _NoExcept2, class _Rp, class... _ArgTypes> |
| 59 | struct __is_convertible_from_specialization< |
| 60 | function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_NoExcept1)>, |
| 61 | function_ref<_Rp(_ArgTypes...) noexcept(_NoExcept2)> > |
| 62 | : _And<is_convertible<_Rp (&)(_ArgTypes...) noexcept(_NoExcept2), _Rp (&)(_ArgTypes...) noexcept(_NoExcept1)>, |
| 63 | is_convertible<_LIBCPP_FUNCTION_REF_CV int&, int&>> {}; |
| 64 | |
| 65 | template <class _Rp, class... _ArgTypes, bool __is_noexcept> |
| 66 | class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(__is_noexcept)> { |
| 67 | private: |
| 68 | template <class... _Tp> |
| 69 | static constexpr bool __is_invocable_using = |
| 70 | _If<__is_noexcept, is_nothrow_invocable_r<_Rp, _Tp..., _ArgTypes...>, is_invocable_r<_Rp, _Tp..., _ArgTypes...>>:: |
| 71 | value; |
| 72 | |
| 73 | template <class _Fn2> |
| 74 | static constexpr bool __is_convertible_from_specialization_v = |
| 75 | __is_convertible_from_specialization<function_ref, _Fn2>::value; |
| 76 | |
| 77 | template <class... _Tp> |
| 78 | friend class function_ref; |
| 79 | |
| 80 | template <class _Arg> |
| 81 | using __arg_t _LIBCPP_NODEBUG = _If<__register_passable<_Arg>, _Arg, _Arg&&>; |
| 82 | |
| 83 | using __storage_t _LIBCPP_NODEBUG = __function_ref_storage; |
| 84 | |
| 85 | using __call_t _LIBCPP_NODEBUG = _Rp (*)(__storage_t, __arg_t<_ArgTypes>...) noexcept(__is_noexcept); |
| 86 | |
| 87 | __storage_t __storage_; |
| 88 | __call_t __call_; |
| 89 | |
| 90 | public: |
| 91 | template <class _Fp> |
| 92 | requires is_function_v<_Fp> && __is_invocable_using<_Fp> |
| 93 | _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept |
| 94 | : __storage_(__fn_ptr), |
| 95 | __call_([](__storage_t __storage, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 96 | _Fp* __fn_ptr1 = __storage_t::template __get<_Fp>(__storage); |
| 97 | return std::invoke_r<_Rp>(__fn_ptr1, std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 98 | }) { |
| 99 | _LIBCPP_ASSERT_NON_NULL(__fn_ptr != nullptr, "the function pointer should not be a nullptr" ); |
| 100 | } |
| 101 | |
| 102 | template <class _Fn, class _Tp = remove_reference_t<_Fn>> |
| 103 | requires(!is_same_v<remove_cvref_t<_Fn>, function_ref> && !is_member_pointer_v<_Tp> && |
| 104 | __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&> && !__is_convertible_from_specialization_v<_Tp>) |
| 105 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(_Fn&& __obj) noexcept { |
| 106 | using _Dn = remove_cv_t<_Tp>; |
| 107 | if constexpr (__statically_callable<_Dn, __arg_t<_ArgTypes>...>) { |
| 108 | __call_ = [](__storage_t, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 109 | return _Dn::operator()(std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 110 | }; |
| 111 | } else { |
| 112 | __storage_ = __storage_t(std::addressof(__obj)), |
| 113 | __call_ = [](__storage_t __storage, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 114 | _LIBCPP_FUNCTION_REF_CV _Tp& __obj1 = *__storage_t::template __get<_Tp>(__storage); |
| 115 | return std::invoke_r<_Rp>(__obj1, std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 116 | }; |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | template <class _Fn, class _Tp = remove_reference_t<_Fn>> |
| 121 | requires(!is_same_v<remove_cvref_t<_Fn>, function_ref> && !is_member_pointer_v<_Tp> && |
| 122 | __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&> && __is_convertible_from_specialization_v<_Tp>) |
| 123 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(_Fn&& __obj) noexcept |
| 124 | : __storage_(__obj.__storage_), __call_(__obj.__call_) {} |
| 125 | |
| 126 | template <auto _Cw, class _Fn> |
| 127 | requires __is_invocable_using<const _Fn&> |
| 128 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_wrapper<_Cw, _Fn> __f) noexcept |
| 129 | : __call_([](__storage_t, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 130 | return std::invoke_r<_Rp>(decltype(__f)::value, std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 131 | }) { |
| 132 | if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) { |
| 133 | static_assert(__f.value != nullptr, "the function pointer should not be a nullptr" ); |
| 134 | } |
| 135 | if constexpr (sizeof...(_ArgTypes) > 0 && (__constexpr_param<remove_cvref_t<_ArgTypes>> && ...)) { |
| 136 | static_assert( |
| 137 | !requires { |
| 138 | typename constant_wrapper<std::invoke(decltype(__f)::value, remove_cvref_t<_ArgTypes>::value...)>; |
| 139 | }, |
| 140 | "cw(args...) should be equivalent to fn(args...), otherwise the intended behavior for a function_ref " |
| 141 | "constructed from cw would be ambiguous" ); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | template <auto _Cw, class _Fn, class _Up, class _Tp = remove_reference_t<_Up>> |
| 146 | requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using<const _Fn&, _LIBCPP_FUNCTION_REF_CV _Tp&> |
| 147 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_wrapper<_Cw, _Fn> __f, _Up&& __obj) noexcept |
| 148 | : __storage_(std::addressof(__obj)), |
| 149 | __call_([](__storage_t __storage, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 150 | auto& __obj1 = static_cast<_LIBCPP_FUNCTION_REF_CV _Tp&>(*__storage_t::template __get<_Tp>(__storage)); |
| 151 | return std::invoke_r<_Rp>(decltype(__f)::value, __obj1, std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 152 | }) { |
| 153 | if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) { |
| 154 | static_assert(__f.value != nullptr, "the function pointer should not be a nullptr" ); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | template <auto _Cw, class _Fn, class _Tp> |
| 159 | requires __is_invocable_using<const _Fn&, _LIBCPP_FUNCTION_REF_CV _Tp*> |
| 160 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_wrapper<_Cw, _Fn> __f, |
| 161 | _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept |
| 162 | : __storage_(__obj_ptr), |
| 163 | __call_([](__storage_t __storage, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp { |
| 164 | auto* __obj = __storage_t::template __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); |
| 165 | return std::invoke_r<_Rp>(decltype(__f)::value, __obj, std::forward<__arg_t<_ArgTypes>>(__args)...); |
| 166 | }) { |
| 167 | if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) { |
| 168 | static_assert(__f.value != nullptr, "the function pointer should not be a nullptr" ); |
| 169 | } |
| 170 | |
| 171 | if constexpr (is_member_pointer_v<_Fn>) { |
| 172 | _LIBCPP_ASSERT_NON_NULL(__obj_ptr != nullptr, "the object pointer should not be a nullptr" ); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref(const function_ref&) noexcept = default; |
| 177 | |
| 178 | _LIBCPP_HIDE_FROM_ABI constexpr function_ref& operator=(const function_ref&) noexcept = default; |
| 179 | |
| 180 | template <class _Tp> |
| 181 | requires(!__is_convertible_from_specialization_v<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_constant_wrapper<_Tp>) |
| 182 | _LIBCPP_HIDE_FROM_ABI function_ref& operator=(_Tp) = delete; |
| 183 | |
| 184 | _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes... __args) const noexcept(__is_noexcept) { |
| 185 | return __call_(__storage_, std::forward<_ArgTypes>(__args)...); |
| 186 | } |
| 187 | }; |
| 188 | |
| 189 | template <class _Tp, class _Rp, class _Gp, class... _ArgTypes, bool __is_noexcept> |
| 190 | struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(__is_noexcept), _Tp> { |
| 191 | using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept(__is_noexcept); |
| 192 | }; |
| 193 | |
| 194 | template <class _Tp, class _Rp, class _Gp, class... _ArgTypes, bool __is_noexcept> |
| 195 | struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(__is_noexcept), _Tp> { |
| 196 | using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept(__is_noexcept); |
| 197 | }; |
| 198 | |
| 199 | #endif // _LIBCPP_STD_VER >= 26 |
| 200 | |
| 201 | _LIBCPP_END_NAMESPACE_STD |
| 202 | |