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