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