xref: /aosp_15_r20/external/abseil-cpp/absl/functional/internal/function_ref.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
16 #define ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
17 
18 #include <cassert>
19 #include <functional>
20 #include <type_traits>
21 
22 #include "absl/base/internal/invoke.h"
23 #include "absl/functional/any_invocable.h"
24 #include "absl/meta/type_traits.h"
25 
26 namespace absl {
27 ABSL_NAMESPACE_BEGIN
28 namespace functional_internal {
29 
30 // Like a void* that can handle function pointers as well. The standard does not
31 // allow function pointers to round-trip through void*, but void(*)() is fine.
32 //
33 // Note: It's important that this class remains trivial and is the same size as
34 // a pointer, since this allows the compiler to perform tail-call optimizations
35 // when the underlying function is a callable object with a matching signature.
36 union VoidPtr {
37   const void* obj;
38   void (*fun)();
39 };
40 
41 // Chooses the best type for passing T as an argument.
42 // Attempt to be close to SystemV AMD64 ABI. Objects with trivial copy ctor are
43 // passed by value.
44 template <typename T,
45           bool IsLValueReference = std::is_lvalue_reference<T>::value>
46 struct PassByValue : std::false_type {};
47 
48 template <typename T>
49 struct PassByValue<T, /*IsLValueReference=*/false>
50     : std::integral_constant<bool,
51                              absl::is_trivially_copy_constructible<T>::value &&
52                                  absl::is_trivially_copy_assignable<
53                                      typename std::remove_cv<T>::type>::value &&
54                                  std::is_trivially_destructible<T>::value &&
55                                  sizeof(T) <= 2 * sizeof(void*)> {};
56 
57 template <typename T>
58 struct ForwardT : std::conditional<PassByValue<T>::value, T, T&&> {};
59 
60 // An Invoker takes a pointer to the type-erased invokable object, followed by
61 // the arguments that the invokable object expects.
62 //
63 // Note: The order of arguments here is an optimization, since member functions
64 // have an implicit "this" pointer as their first argument, putting VoidPtr
65 // first allows the compiler to perform tail-call optimization in many cases.
66 template <typename R, typename... Args>
67 using Invoker = R (*)(VoidPtr, typename ForwardT<Args>::type...);
68 
69 //
70 // InvokeObject and InvokeFunction provide static "Invoke" functions that can be
71 // used as Invokers for objects or functions respectively.
72 //
73 // static_cast<R> handles the case the return type is void.
74 template <typename Obj, typename R, typename... Args>
75 R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
76   auto o = static_cast<const Obj*>(ptr.obj);
77   return static_cast<R>(
78       absl::base_internal::invoke(*o, std::forward<Args>(args)...));
79 }
80 
81 template <typename Fun, typename R, typename... Args>
82 R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
83   auto f = reinterpret_cast<Fun>(ptr.fun);
84   return static_cast<R>(
85       absl::base_internal::invoke(f, std::forward<Args>(args)...));
86 }
87 
88 template <typename Sig>
89 void AssertNonNull(const std::function<Sig>& f) {
90   assert(f != nullptr);
91   (void)f;
92 }
93 
94 template <typename Sig>
95 void AssertNonNull(const AnyInvocable<Sig>& f) {
96   assert(f != nullptr);
97   (void)f;
98 }
99 
100 template <typename F>
101 void AssertNonNull(const F&) {}
102 
103 template <typename F, typename C>
104 void AssertNonNull(F C::*f) {
105   assert(f != nullptr);
106   (void)f;
107 }
108 
109 template <bool C>
110 using EnableIf = typename ::std::enable_if<C, int>::type;
111 
112 }  // namespace functional_internal
113 ABSL_NAMESPACE_END
114 }  // namespace absl
115 
116 #endif  // ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
117