File: callback_internal.h

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (219 lines) | stat: -rw-r--r-- 7,978 bytes parent folder | download | duplicates (2)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains utility functions and classes that help the
// implementation, and management of the Callback objects.

#ifndef BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_
#define BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_

#include <utility>

#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"

namespace base {

struct FakeBindState;

namespace internal {

class BindStateBase;

template <typename Functor, typename... BoundArgs>
struct BindState;

struct BASE_EXPORT BindStateBaseRefCountTraits {
  static void Destruct(const BindStateBase*);
};

template <typename T>
using PassingType = std::conditional_t<std::is_scalar_v<T>, T, T&&>;

// BindStateBase is used to provide an opaque handle that the Callback
// class can use to represent a function object with bound arguments.  It
// behaves as an existential type that is used by a corresponding
// DoInvoke function to perform the function execution.  This allows
// us to shield the Callback class from the types of the bound argument via
// "type erasure."
// At the base level, the only task is to add reference counting data. Avoid
// using or inheriting any virtual functions. Creating a vtable for every
// BindState template instantiation results in a lot of bloat. Its only task is
// to call the destructor which can be done with a function pointer.
class BASE_EXPORT BindStateBase
    : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> {
 public:
  REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();

  enum CancellationQueryMode {
    IS_CANCELLED,
    MAYBE_VALID,
  };

  using InvokeFuncStorage = void (*)();

  BindStateBase(const BindStateBase&) = delete;
  BindStateBase& operator=(const BindStateBase&) = delete;

 private:
  BindStateBase(InvokeFuncStorage polymorphic_invoke,
                void (*destructor)(const BindStateBase*));
  BindStateBase(InvokeFuncStorage polymorphic_invoke,
                void (*destructor)(const BindStateBase*),
                bool (*query_cancellation_traits)(const BindStateBase*,
                                                  CancellationQueryMode mode));

  ~BindStateBase() = default;

  friend struct BindStateBaseRefCountTraits;
  friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>;

  friend class BindStateHolder;

  // Allowlist subclasses that access the destructor of BindStateBase.
  template <typename Functor, typename... BoundArgs>
  friend struct BindState;
  friend struct ::base::FakeBindState;

  bool IsCancelled() const {
    return query_cancellation_traits_(this, IS_CANCELLED);
  }

  bool MaybeValid() const {
    return query_cancellation_traits_(this, MAYBE_VALID);
  }

  // In C++, it is safe to cast function pointers to function pointers of
  // another type. It is not okay to use void*. We create a InvokeFuncStorage
  // that that can store our function pointer, and then cast it back to
  // the original type on usage.
  InvokeFuncStorage polymorphic_invoke_;

  // Pointer to a function that will properly destroy |this|.
  void (*destructor_)(const BindStateBase*);
  bool (*query_cancellation_traits_)(const BindStateBase*,
                                     CancellationQueryMode mode);
};

// Minimal wrapper around a `scoped_refptr<BindStateBase>`. It allows more
// expensive operations (such as ones that destroy `BindStateBase` or manipulate
// refcounts) to be defined out-of-line to reduce binary size.
class BASE_EXPORT TRIVIAL_ABI BindStateHolder {
 public:
  using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;

  // Used to construct a null callback.
  inline constexpr BindStateHolder() noexcept;

  // Used to construct a callback by `base::BindOnce()`/`base::BindRepeating().
  inline explicit BindStateHolder(BindStateBase* bind_state);

  // BindStateHolder is always copyable so it can be used by `OnceCallback` and
  // `RepeatingCallback`. `OnceCallback` restricts copies so a `BindStateHolder`
  // used with a `OnceCallback will never be copied.
  BindStateHolder(const BindStateHolder&);
  BindStateHolder& operator=(const BindStateHolder&);

  // Subtle: since `this` is marked as TRIVIAL_ABI, the move operations must
  // leave a moved-from `BindStateHolder` in a trivially destructible state.
  inline BindStateHolder(BindStateHolder&&) noexcept;
  BindStateHolder& operator=(BindStateHolder&&) noexcept;

  ~BindStateHolder();

  bool is_null() const { return !bind_state_; }
  explicit operator bool() const { return !is_null(); }

  bool IsCancelled() const;
  bool MaybeValid() const;

  void Reset();

  bool operator==(const BindStateHolder& other) const {
    return bind_state_ == other.bind_state_;
  }

  const scoped_refptr<BindStateBase>& bind_state() const { return bind_state_; }

  InvokeFuncStorage polymorphic_invoke() const {
    return bind_state_->polymorphic_invoke_;
  }

 private:
  scoped_refptr<BindStateBase> bind_state_;
};

constexpr BindStateHolder::BindStateHolder() noexcept = default;

// TODO(dcheng): Try plumbing a scoped_refptr all the way through, since
// scoped_refptr is marked as TRIVIAL_ABI.
BindStateHolder::BindStateHolder(BindStateBase* bind_state)
    : bind_state_(AdoptRef(bind_state)) {}

// Unlike the copy constructor, copy assignment operator, and move assignment
// operator, the move constructor is defaulted in the header because it
// generates minimal code: move construction does not change any refcounts, nor
// does it potentially destroy `BindStateBase`.
BindStateHolder::BindStateHolder(BindStateHolder&&) noexcept = default;

// Helpers for the `Then()` implementation.
template <typename OriginalCallback, typename ThenCallback>
struct ThenHelper;

// Specialization when original callback returns `void`.
template <template <typename> class OriginalCallback,
          template <typename>
          class ThenCallback,
          typename... OriginalArgs,
          typename ThenR,
          typename... ThenArgs>
struct ThenHelper<OriginalCallback<void(OriginalArgs...)>,
                  ThenCallback<ThenR(ThenArgs...)>> {
  static_assert(sizeof...(ThenArgs) == 0,
                "|then| callback cannot accept parameters if |this| has a "
                "void return type.");

  static auto CreateTrampoline() {
    return [](OriginalCallback<void(OriginalArgs...)> c1,
              ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
      std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...);
      return std::move(c2).Run();
    };
  }
};

// Specialization when original callback returns a non-void type.
template <template <typename> class OriginalCallback,
          template <typename>
          class ThenCallback,
          typename OriginalR,
          typename... OriginalArgs,
          typename ThenR,
          typename... ThenArgs>
struct ThenHelper<OriginalCallback<OriginalR(OriginalArgs...)>,
                  ThenCallback<ThenR(ThenArgs...)>> {
  static_assert(sizeof...(ThenArgs) == 1,
                "|then| callback must accept exactly one parameter if |this| "
                "has a non-void return type.");
  // TODO(dcheng): This should probably check is_convertible as well (same with
  // `AssertBindArgsValidity`).
  static_assert(std::is_constructible_v<ThenArgs..., OriginalR&&>,
                "|then| callback's parameter must be constructible from "
                "return type of |this|.");

  static auto CreateTrampoline() {
    return [](OriginalCallback<OriginalR(OriginalArgs...)> c1,
              ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
      return std::move(c2).Run(
          std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...));
    };
  }
};

}  // namespace internal
}  // namespace base

#endif  // BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_