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_
|