| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 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 | |
| Peter Kasting | 26dc061 | 2023-12-13 19:16:48 | [diff] [blame] | 8 | #include <concepts> |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 9 | #include <type_traits> |
| 10 | #include <utility> |
| 11 | |
| Peter Kasting | 4b18d0c | 2024-09-18 00:56:11 | [diff] [blame] | 12 | #include "base/compiler_specific.h" |
| Daniel Cheng | 91f6fbaf | 2022-09-16 12:07:48 | [diff] [blame] | 13 | #include "base/functional/bind_internal.h" |
| Peter Kasting | 41f335c | 2024-01-08 21:30:48 | [diff] [blame] | 14 | #include "base/types/is_instantiation.h" |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 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. |
| Helmut Januschka | 1dce9dc | 2024-06-11 13:05:35 | [diff] [blame] | 36 | // `std::string_view`, `base::span`) also apply to `base::FunctionRef`. |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 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 | // |
| Daniel Cheng | e66d5de | 2022-09-16 15:50:14 | [diff] [blame] | 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: |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 52 | // |
| Daniel Cheng | e66d5de | 2022-09-16 15:50:14 | [diff] [blame] | 53 | // // Silently discards `42`. |
| 54 | // [] (absl::FunctionRef<void()> r) { |
| 55 | // r(); |
| 56 | // }([] { return 42; }); |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 57 | // |
| Daniel Cheng | e66d5de | 2022-09-16 15:50:14 | [diff] [blame] | 58 | // But with `base::FunctionRef`: |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 59 | // |
| Daniel Cheng | e66d5de | 2022-09-16 15:50:14 | [diff] [blame] | 60 | // // Does not compile! |
| 61 | // [] (base::FunctionRef<void()> r) { |
| 62 | // r(); |
| 63 | // }([] { return 42; }); |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 64 | template <typename R, typename... Args> |
| 65 | class FunctionRef<R(Args...)> { |
| Peter Kasting | 26dc061 | 2023-12-13 19:16:48 | [diff] [blame] | 66 | template <typename Functor, |
| Peter Kasting | 8e4901d | 2024-02-16 16:34:05 | [diff] [blame] | 67 | typename RunType = internal::FunctorTraits<Functor>::RunType> |
| Peter Kasting | 14f13e4 | 2023-12-27 17:29:11 | [diff] [blame] | 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: |
| Peter Kasting | 4b18d0c | 2024-09-18 00:56:11 | [diff] [blame] | 73 | // `LIFETIME_BOUND` is important; since `FunctionRef` retains |
| Peter Kasting | 14f13e4 | 2023-12-27 17:29:11 | [diff] [blame] | 74 | // only a reference to `functor`, `functor` must outlive `this`. |
| 75 | template <typename Functor> |
| Peter Kasting | 41f335c | 2024-01-08 21:30:48 | [diff] [blame] | 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. |
| Daniel Cheng | fb999fd3 | 2025-06-13 02:30:16 | [diff] [blame] | 93 | (!is_instantiation<std::decay_t<Functor>, FunctionRef>) && |
| Peter Kasting | 41f335c | 2024-01-08 21:30:48 | [diff] [blame] | 94 | // For the same reason as the second case above, prevent |
| 95 | // construction from `absl::FunctionRef`. |
| Daniel Cheng | fb999fd3 | 2025-06-13 02:30:16 | [diff] [blame] | 96 | (!is_instantiation<std::decay_t<Functor>, absl::FunctionRef>) |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 97 | // NOLINTNEXTLINE(google-explicit-constructor) |
| Peter Kasting | 4b18d0c | 2024-09-18 00:56:11 | [diff] [blame] | 98 | FunctionRef(const Functor& functor LIFETIME_BOUND) |
| Daniel Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 99 | : wrapped_func_ref_(functor) {} |
| 100 | |
| Peter Kasting | e3509a1 | 2023-12-27 21:57:27 | [diff] [blame] | 101 | // 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 Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 114 | // 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 Cheng | 2248b33 | 2022-07-27 06:16:59 | [diff] [blame] | 125 | private: |
| 126 | absl::FunctionRef<R(Args...)> wrapped_func_ref_; |
| 127 | }; |
| 128 | |
| 129 | } // namespace base |
| 130 | |
| 131 | #endif // BASE_FUNCTIONAL_FUNCTION_REF_H_ |