• 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 <type_traits>
9 #include <utility>
10 
11 #include "base/functional/bind_internal.h"
12 #include "third_party/abseil-cpp/absl/base/attributes.h"
13 #include "third_party/abseil-cpp/absl/functional/function_ref.h"
14 
15 namespace base {
16 
17 template <typename Signature>
18 class FunctionRef;
19 
20 // A non-owning reference to any invocable object (e.g. function pointer, method
21 // pointer, functor, lambda, et cetera) suitable for use as a type-erased
22 // argument to ForEach-style functions or other visitor patterns that:
23 //
24 // - do not need to copy or take ownership of the argument
25 // - synchronously call the invocable that was passed as an argument
26 //
27 // `base::FunctionRef` makes no heap allocations: it is trivially copyable and
28 // should be passed by value.
29 //
30 // `base::FunctionRef` has no null/empty state: a `base::FunctionRef` is always
31 // valid to invoke.
32 //
33 // The usual lifetime precautions for other non-owning references types (e.g.
34 // `base::StringPiece`, `base::span`) also apply to `base::FunctionRef`.
35 // `base::FunctionRef` should typically be used as an argument; returning a
36 // `base::FunctionRef` or storing a `base::FunctionRef` as a field is dangerous
37 // and likely to result in lifetime bugs.
38 //
39 // `base::RepeatingCallback` and `base::BindRepeating()` is another common way
40 // to represent type-erased invocable objects. In contrast, it requires a heap
41 // allocation and is not trivially copyable. It should be used when there are
42 // ownership requirements (e.g. partial application of arguments to a function
43 // stored for asynchronous execution).
44 //
45 // Note: `base::FunctionRef` is similar to `absl::FunctionRef<R(Args...)>`, but
46 // with stricter conversions between function types. Return type conversions are
47 // allowed (e.g. `int` -> `bool`, `Derived*` -> `Base*`); other than that,
48 // function parameter types must match exactly, and return values may not be
49 // silently discarded, e.g. `absl::FunctionRef` allows the following:
50 //
51 //   // Silently discards `42`.
52 //   [] (absl::FunctionRef<void()> r) {
53 //     r();
54 //   }([] { return 42; });
55 //
56 // But with `base::FunctionRef`:
57 //
58 //   // Does not compile!
59 //   [] (base::FunctionRef<void()> r) {
60 //     r();
61 //   }([] { return 42; });
62 template <typename R, typename... Args>
63 class FunctionRef<R(Args...)> {
64  private:
65   template <typename Functor,
66             typename FunctorReturnType =
67                 typename internal::BindTypeHelper<Functor>::ReturnType,
68             typename FunctorArgsAsTypeList =
69                 typename internal::BindTypeHelper<Functor>::RunParamsList>
70   using EnableIfCompatible = std::enable_if_t<
71       std::is_convertible_v<FunctorReturnType, R> &&
72       std::is_same_v<FunctorArgsAsTypeList, internal::TypeList<Args...>>>;
73 
74  public:
75   // `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important since `FunctionRef` retains
76   // only a reference to `functor`, `functor` must outlive `this`.
77   template <typename Functor, typename = EnableIfCompatible<Functor>>
78   // NOLINTNEXTLINE(google-explicit-constructor)
FunctionRef(const Functor & functor ABSL_ATTRIBUTE_LIFETIME_BOUND)79   FunctionRef(const Functor& functor ABSL_ATTRIBUTE_LIFETIME_BOUND)
80       : wrapped_func_ref_(functor) {}
81 
82   // Null FunctionRefs are not allowed.
83   FunctionRef() = delete;
84 
85   FunctionRef(const FunctionRef&) = default;
86   // Reduce the likelihood of lifetime bugs by disallowing assignment.
87   FunctionRef& operator=(const FunctionRef&) = delete;
88 
operator()89   R operator()(Args... args) const {
90     return wrapped_func_ref_(std::forward<Args>(args)...);
91   }
92 
ToAbsl()93   absl::FunctionRef<R(Args...)> ToAbsl() const { return wrapped_func_ref_; }
94 
95   // In Chrome, converting to `absl::FunctionRef` should be explicitly done
96   // through `ToAbsl()`.
97   template <typename Signature>
98   operator absl::FunctionRef<Signature>() = delete;
99 
100  private:
101   absl::FunctionRef<R(Args...)> wrapped_func_ref_;
102 };
103 
104 }  // namespace base
105 
106 #endif  // BASE_FUNCTIONAL_FUNCTION_REF_H_
107