blob: 520d94db5134fe662a04f4f163f698ffb7a85be0 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2022 The Chromium Authors
Daniel Cheng2248b332022-07-27 06:16:592// 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
Peter Kasting26dc0612023-12-13 19:16:488#include <concepts>
Daniel Cheng2248b332022-07-27 06:16:599#include <type_traits>
10#include <utility>
11
Peter Kasting4b18d0c2024-09-18 00:56:1112#include "base/compiler_specific.h"
Daniel Cheng91f6fbaf2022-09-16 12:07:4813#include "base/functional/bind_internal.h"
Peter Kasting41f335c2024-01-08 21:30:4814#include "base/types/is_instantiation.h"
Daniel Cheng2248b332022-07-27 06:16:5915#include "third_party/abseil-cpp/absl/functional/function_ref.h"
16
17namespace base {
18
19template <typename Signature>
20class 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.
Helmut Januschka1dce9dc2024-06-11 13:05:3536// `std::string_view`, `base::span`) also apply to `base::FunctionRef`.
Daniel Cheng2248b332022-07-27 06:16:5937// `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//
Daniel Chenge66d5de2022-09-16 15:50:1447// 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:
Daniel Cheng2248b332022-07-27 06:16:5952//
Daniel Chenge66d5de2022-09-16 15:50:1453// // Silently discards `42`.
54// [] (absl::FunctionRef<void()> r) {
55// r();
56// }([] { return 42; });
Daniel Cheng2248b332022-07-27 06:16:5957//
Daniel Chenge66d5de2022-09-16 15:50:1458// But with `base::FunctionRef`:
Daniel Cheng2248b332022-07-27 06:16:5959//
Daniel Chenge66d5de2022-09-16 15:50:1460// // Does not compile!
61// [] (base::FunctionRef<void()> r) {
62// r();
63// }([] { return 42; });
Daniel Cheng2248b332022-07-27 06:16:5964template <typename R, typename... Args>
65class FunctionRef<R(Args...)> {
Peter Kasting26dc0612023-12-13 19:16:4866 template <typename Functor,
Peter Kasting8e4901d2024-02-16 16:34:0567 typename RunType = internal::FunctorTraits<Functor>::RunType>
Peter Kasting14f13e42023-12-27 17:29:1168 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:
Peter Kasting4b18d0c2024-09-18 00:56:1173 // `LIFETIME_BOUND` is important; since `FunctionRef` retains
Peter Kasting14f13e42023-12-27 17:29:1174 // only a reference to `functor`, `functor` must outlive `this`.
75 template <typename Functor>
Peter Kasting41f335c2024-01-08 21:30:4876 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.
Daniel Chengfb999fd32025-06-13 02:30:1693 (!is_instantiation<std::decay_t<Functor>, FunctionRef>) &&
Peter Kasting41f335c2024-01-08 21:30:4894 // For the same reason as the second case above, prevent
95 // construction from `absl::FunctionRef`.
Daniel Chengfb999fd32025-06-13 02:30:1696 (!is_instantiation<std::decay_t<Functor>, absl::FunctionRef>)
Daniel Cheng2248b332022-07-27 06:16:5997 // NOLINTNEXTLINE(google-explicit-constructor)
Peter Kasting4b18d0c2024-09-18 00:56:1198 FunctionRef(const Functor& functor LIFETIME_BOUND)
Daniel Cheng2248b332022-07-27 06:16:5999 : wrapped_func_ref_(functor) {}
100
Peter Kastinge3509a12023-12-27 21:57:27101 // Constructs a reference to the given function pointer. This constructor
102 // serves to exclude this case from lifetime analysis, since the underlying
103 // code pointed to by a function pointer is safe to invoke even if the
104 // lifetime of the pointer provided doesn't outlive us, e.g.:
105 // `const FunctionRef<void(int)> ref = +[](int i) { ... };`
106 // Without this constructor, the above code would warn about dangling refs.
107 // TODO(pkasting): Also support ptr-to-member-functions; this requires changes
108 // in `absl::FunctionRef` or else rewriting this class to not use that one.
109 template <typename Func>
110 requires kCompatibleFunctor<Func*>
111 // NOLINTNEXTLINE(google-explicit-constructor)
112 FunctionRef(Func* func) : wrapped_func_ref_(func) {}
113
Daniel Cheng2248b332022-07-27 06:16:59114 // Null FunctionRefs are not allowed.
115 FunctionRef() = delete;
116
117 FunctionRef(const FunctionRef&) = default;
118 // Reduce the likelihood of lifetime bugs by disallowing assignment.
119 FunctionRef& operator=(const FunctionRef&) = delete;
120
121 R operator()(Args... args) const {
122 return wrapped_func_ref_(std::forward<Args>(args)...);
123 }
124
Daniel Cheng2248b332022-07-27 06:16:59125 private:
126 absl::FunctionRef<R(Args...)> wrapped_func_ref_;
127};
128
129} // namespace base
130
131#endif // BASE_FUNCTIONAL_FUNCTION_REF_H_