xref: /aosp_15_r20/external/cronet/base/functional/function_ref.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_FUNCTIONAL_FUNCTION_REF_H_
6 #define BASE_FUNCTIONAL_FUNCTION_REF_H_
7 
8 #include <concepts>
9 #include <type_traits>
10 #include <utility>
11 
12 #include "base/functional/bind_internal.h"
13 #include "base/types/is_instantiation.h"
14 #include "third_party/abseil-cpp/absl/base/attributes.h"
15 #include "third_party/abseil-cpp/absl/functional/function_ref.h"
16 
17 namespace base {
18 
19 template <typename Signature>
20 class FunctionRef;
21 
22 // A non-owning reference to any invocable object (e.g. function pointer, method
23 // pointer, functor, lambda, et cetera) suitable for use as a type-erased
24 // argument to ForEach-style functions or other visitor patterns that:
25 //
26 // - do not need to copy or take ownership of the argument
27 // - synchronously call the invocable that was passed as an argument
28 //
29 // `base::FunctionRef` makes no heap allocations: it is trivially copyable and
30 // should be passed by value.
31 //
32 // `base::FunctionRef` has no null/empty state: a `base::FunctionRef` is always
33 // valid to invoke.
34 //
35 // The usual lifetime precautions for other non-owning references types (e.g.
36 // `base::StringPiece`, `base::span`) also apply to `base::FunctionRef`.
37 // `base::FunctionRef` should typically be used as an argument; returning a
38 // `base::FunctionRef` or storing a `base::FunctionRef` as a field is dangerous
39 // and likely to result in lifetime bugs.
40 //
41 // `base::RepeatingCallback` and `base::BindRepeating()` is another common way
42 // to represent type-erased invocable objects. In contrast, it requires a heap
43 // allocation and is not trivially copyable. It should be used when there are
44 // ownership requirements (e.g. partial application of arguments to a function
45 // stored for asynchronous execution).
46 //
47 // Note: `base::FunctionRef` is similar to `absl::FunctionRef<R(Args...)>`, but
48 // with stricter conversions between function types. Return type conversions are
49 // allowed (e.g. `int` -> `bool`, `Derived*` -> `Base*`); other than that,
50 // function parameter types must match exactly, and return values may not be
51 // silently discarded, e.g. `absl::FunctionRef` allows the following:
52 //
53 //   // Silently discards `42`.
54 //   [] (absl::FunctionRef<void()> r) {
55 //     r();
56 //   }([] { return 42; });
57 //
58 // But with `base::FunctionRef`:
59 //
60 //   // Does not compile!
61 //   [] (base::FunctionRef<void()> r) {
62 //     r();
63 //   }([] { return 42; });
64 template <typename R, typename... Args>
65 class FunctionRef<R(Args...)> {
66   template <typename Functor,
67             typename RunType = internal::FunctorTraits<Functor>::RunType>
68   static constexpr bool kCompatibleFunctor =
69       std::convertible_to<internal::ExtractReturnType<RunType>, R> &&
70       std::same_as<internal::ExtractArgs<RunType>, internal::TypeList<Args...>>;
71 
72  public:
73   // `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important; since `FunctionRef` retains
74   // only a reference to `functor`, `functor` must outlive `this`.
75   template <typename Functor>
76     requires kCompatibleFunctor<Functor> &&
77              // Prevent this constructor from participating in overload
78              // resolution if the callable is itself an instantiation of the
79              // `FunctionRef` template.
80              //
81              // If the callable is a `FunctionRef` with exactly the same
82              // signature as us, then the copy constructor will be used instead,
83              // so this has no effect. (Note that if the constructor argument
84              // were `Functor&&`, this exclusion would be necessary to force the
85              // choice of the copy constructor over this one for non-const ref
86              // args; see https://stackoverflow.com/q/57909923.)
87              //
88              // If the callable is a `FunctionRef` with some other signature
89              // then we choose not to support binding to it at all. Conceivably
90              // we could teach our trampoline to deal with this, but this may be
91              // the sign of an object lifetime bug, and again it's not clear
92              // that this isn't just a mistake on the part of the user.
93              (!internal::is_instantiation_v<FunctionRef,
94                                             std::decay_t<Functor>>) &&
95              // For the same reason as the second case above, prevent
96              // construction from `absl::FunctionRef`.
97              (!internal::is_instantiation_v<absl::FunctionRef,
98                                             std::decay_t<Functor>>)
99   // NOLINTNEXTLINE(google-explicit-constructor)
FunctionRef(const Functor & functor ABSL_ATTRIBUTE_LIFETIME_BOUND)100   FunctionRef(const Functor& functor ABSL_ATTRIBUTE_LIFETIME_BOUND)
101       : wrapped_func_ref_(functor) {}
102 
103   // Constructs a reference to the given function pointer. This constructor
104   // serves to exclude this case from lifetime analysis, since the underlying
105   // code pointed to by a function pointer is safe to invoke even if the
106   // lifetime of the pointer provided doesn't outlive us, e.g.:
107   //   `const FunctionRef<void(int)> ref = +[](int i) { ... };`
108   // Without this constructor, the above code would warn about dangling refs.
109   // TODO(pkasting): Also support ptr-to-member-functions; this requires changes
110   // in `absl::FunctionRef` or else rewriting this class to not use that one.
111   template <typename Func>
112     requires kCompatibleFunctor<Func*>
113   // NOLINTNEXTLINE(google-explicit-constructor)
FunctionRef(Func * func)114   FunctionRef(Func* func) : wrapped_func_ref_(func) {}
115 
116   // Null FunctionRefs are not allowed.
117   FunctionRef() = delete;
118 
119   FunctionRef(const FunctionRef&) = default;
120   // Reduce the likelihood of lifetime bugs by disallowing assignment.
121   FunctionRef& operator=(const FunctionRef&) = delete;
122 
operator()123   R operator()(Args... args) const {
124     return wrapped_func_ref_(std::forward<Args>(args)...);
125   }
126 
127  private:
128   absl::FunctionRef<R(Args...)> wrapped_func_ref_;
129 };
130 
131 }  // namespace base
132 
133 #endif  // BASE_FUNCTIONAL_FUNCTION_REF_H_
134