1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134

base / functional / function_ref.h [blame]

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_FUNCTIONAL_FUNCTION_REF_H_
#define BASE_FUNCTIONAL_FUNCTION_REF_H_

#include <concepts>
#include <string_view>
#include <type_traits>
#include <utility>

#include "base/compiler_specific.h"
#include "base/functional/bind_internal.h"
#include "base/types/is_instantiation.h"
#include "third_party/abseil-cpp/absl/functional/function_ref.h"

namespace base {

template <typename Signature>
class FunctionRef;

// A non-owning reference to any invocable object (e.g. function pointer, method
// pointer, functor, lambda, et cetera) suitable for use as a type-erased
// argument to ForEach-style functions or other visitor patterns that:
//
// - do not need to copy or take ownership of the argument
// - synchronously call the invocable that was passed as an argument
//
// `base::FunctionRef` makes no heap allocations: it is trivially copyable and
// should be passed by value.
//
// `base::FunctionRef` has no null/empty state: a `base::FunctionRef` is always
// valid to invoke.
//
// The usual lifetime precautions for other non-owning references types (e.g.
// `std::string_view`, `base::span`) also apply to `base::FunctionRef`.
// `base::FunctionRef` should typically be used as an argument; returning a
// `base::FunctionRef` or storing a `base::FunctionRef` as a field is dangerous
// and likely to result in lifetime bugs.
//
// `base::RepeatingCallback` and `base::BindRepeating()` is another common way
// to represent type-erased invocable objects. In contrast, it requires a heap
// allocation and is not trivially copyable. It should be used when there are
// ownership requirements (e.g. partial application of arguments to a function
// stored for asynchronous execution).
//
// Note: `base::FunctionRef` is similar to `absl::FunctionRef<R(Args...)>`, but
// with stricter conversions between function types. Return type conversions are
// allowed (e.g. `int` -> `bool`, `Derived*` -> `Base*`); other than that,
// function parameter types must match exactly, and return values may not be
// silently discarded, e.g. `absl::FunctionRef` allows the following:
//
//   // Silently discards `42`.
//   [] (absl::FunctionRef<void()> r) {
//     r();
//   }([] { return 42; });
//
// But with `base::FunctionRef`:
//
//   // Does not compile!
//   [] (base::FunctionRef<void()> r) {
//     r();
//   }([] { return 42; });
template <typename R, typename... Args>
class FunctionRef<R(Args...)> {
  template <typename Functor,
            typename RunType = internal::FunctorTraits<Functor>::RunType>
  static constexpr bool kCompatibleFunctor =
      std::convertible_to<internal::ExtractReturnType<RunType>, R> &&
      std::same_as<internal::ExtractArgs<RunType>, internal::TypeList<Args...>>;

 public:
  // `LIFETIME_BOUND` is important; since `FunctionRef` retains
  // only a reference to `functor`, `functor` must outlive `this`.
  template <typename Functor>
    requires kCompatibleFunctor<Functor> &&
             // Prevent this constructor from participating in overload
             // resolution if the callable is itself an instantiation of the
             // `FunctionRef` template.
             //
             // If the callable is a `FunctionRef` with exactly the same
             // signature as us, then the copy constructor will be used instead,
             // so this has no effect. (Note that if the constructor argument
             // were `Functor&&`, this exclusion would be necessary to force the
             // choice of the copy constructor over this one for non-const ref
             // args; see https://stackoverflow.com/q/57909923.)
             //
             // If the callable is a `FunctionRef` with some other signature
             // then we choose not to support binding to it at all. Conceivably
             // we could teach our trampoline to deal with this, but this may be
             // the sign of an object lifetime bug, and again it's not clear
             // that this isn't just a mistake on the part of the user.
             (!internal::is_instantiation_v<FunctionRef,
                                            std::decay_t<Functor>>) &&
             // For the same reason as the second case above, prevent
             // construction from `absl::FunctionRef`.
             (!internal::is_instantiation_v<absl::FunctionRef,
                                            std::decay_t<Functor>>)
  // NOLINTNEXTLINE(google-explicit-constructor)
  FunctionRef(const Functor& functor LIFETIME_BOUND)
      : wrapped_func_ref_(functor) {}

  // Constructs a reference to the given function pointer. This constructor
  // serves to exclude this case from lifetime analysis, since the underlying
  // code pointed to by a function pointer is safe to invoke even if the
  // lifetime of the pointer provided doesn't outlive us, e.g.:
  //   `const FunctionRef<void(int)> ref = +[](int i) { ... };`
  // Without this constructor, the above code would warn about dangling refs.
  // TODO(pkasting): Also support ptr-to-member-functions; this requires changes
  // in `absl::FunctionRef` or else rewriting this class to not use that one.
  template <typename Func>
    requires kCompatibleFunctor<Func*>
  // NOLINTNEXTLINE(google-explicit-constructor)
  FunctionRef(Func* func) : wrapped_func_ref_(func) {}

  // Null FunctionRefs are not allowed.
  FunctionRef() = delete;

  FunctionRef(const FunctionRef&) = default;
  // Reduce the likelihood of lifetime bugs by disallowing assignment.
  FunctionRef& operator=(const FunctionRef&) = delete;

  R operator()(Args... args) const {
    return wrapped_func_ref_(std::forward<Args>(args)...);
  }

 private:
  absl::FunctionRef<R(Args...)> wrapped_func_ref_;
};

}  // namespace base

#endif  // BASE_FUNCTIONAL_FUNCTION_REF_H_