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/meta/type_traits.h"
24 
25 namespace absl {
26 ABSL_NAMESPACE_BEGIN
27 namespace functional_internal {
28 
29 // Like a void* that can handle function pointers as well. The standard does not
30 // allow function pointers to round-trip through void*, but void(*)() is fine.
31 //
32 // Note: It's important that this class remains trivial and is the same size as
33 // a pointer, since this allows the compiler to perform tail-call optimizations
34 // when the underlying function is a callable object with a matching signature.
35 union VoidPtr {
36   const void* obj;
37   void (*fun)();
38 };
39 
40 // Chooses the best type for passing T as an argument.
41 // Attempt to be close to SystemV AMD64 ABI. Objects with trivial copy ctor are
42 // passed by value.
43 template <typename T>
PassByValue()44 constexpr bool PassByValue() {
45   return !std::is_lvalue_reference<T>::value &&
46          absl::is_trivially_copy_constructible<T>::value &&
47          absl::is_trivially_copy_assignable<
48              typename std::remove_cv<T>::type>::value &&
49          std::is_trivially_destructible<T>::value &&
50          sizeof(T) <= 2 * sizeof(void*);
51 }
52 
53 template <typename T>
54 struct ForwardT : std::conditional<PassByValue<T>(), T, T&&> {};
55 
56 // An Invoker takes a pointer to the type-erased invokable object, followed by
57 // the arguments that the invokable object expects.
58 //
59 // Note: The order of arguments here is an optimization, since member functions
60 // have an implicit "this" pointer as their first argument, putting VoidPtr
61 // first allows the compiler to perform tail-call optimization in many cases.
62 template <typename R, typename... Args>
63 using Invoker = R (*)(VoidPtr, typename ForwardT<Args>::type...);
64 
65 //
66 // InvokeObject and InvokeFunction provide static "Invoke" functions that can be
67 // used as Invokers for objects or functions respectively.
68 //
69 // static_cast<R> handles the case the return type is void.
70 template <typename Obj, typename R, typename... Args>
InvokeObject(VoidPtr ptr,typename ForwardT<Args>::type...args)71 R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
72   auto o = static_cast<const Obj*>(ptr.obj);
73   return static_cast<R>(
74       absl::base_internal::Invoke(*o, std::forward<Args>(args)...));
75 }
76 
77 template <typename Fun, typename R, typename... Args>
InvokeFunction(VoidPtr ptr,typename ForwardT<Args>::type...args)78 R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
79   auto f = reinterpret_cast<Fun>(ptr.fun);
80   return static_cast<R>(
81       absl::base_internal::Invoke(f, std::forward<Args>(args)...));
82 }
83 
84 template <typename Sig>
AssertNonNull(const std::function<Sig> & f)85 void AssertNonNull(const std::function<Sig>& f) {
86   assert(f != nullptr);
87   (void)f;
88 }
89 
90 template <typename F>
AssertNonNull(const F &)91 void AssertNonNull(const F&) {}
92 
93 template <typename F, typename C>
AssertNonNull(F C::* f)94 void AssertNonNull(F C::*f) {
95   assert(f != nullptr);
96   (void)f;
97 }
98 
99 template <bool C>
100 using EnableIf = typename ::std::enable_if<C, int>::type;
101 
102 }  // namespace functional_internal
103 ABSL_NAMESPACE_END
104 }  // namespace absl
105 
106 #endif  // ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
107