Update include/base headers for C++11/14 (see issue #3140)

See the issue for update guidelines.
This commit is contained in:
Marshall Greenblatt
2021-06-17 15:40:57 -04:00
parent 6d80ec69d7
commit 43f9baa23a
57 changed files with 5466 additions and 11523 deletions

View File

@ -36,72 +36,156 @@
#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_
#define CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_
#include <stddef.h>
#include "include/base/cef_atomic_ref_count.h"
#include "include/base/cef_macros.h"
#include "include/base/cef_callback_forward.h"
#include "include/base/cef_ref_counted.h"
#include "include/base/cef_scoped_ptr.h"
#include "include/base/cef_template_util.h"
template <typename T>
class ScopedVector;
namespace base {
namespace cef_internal {
class CallbackBase;
// At the base level, the only task is to add reference counting data. Don't use
// RefCountedThreadSafe since it requires the destructor to be a virtual method.
// 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 BindStateBase {
protected:
explicit BindStateBase(void (*destructor)(BindStateBase*))
: ref_count_(0), destructor_(destructor) {}
~BindStateBase() {}
struct FakeBindState;
namespace internal {
class BindStateBase;
class FinallyExecutorCommon;
class ThenAndCatchExecutorCommon;
template <typename ReturnType>
class PostTaskExecutor;
template <typename Functor, typename... BoundArgs>
struct BindState;
class CallbackBase;
class CallbackBaseCopyable;
struct BindStateBaseRefCountTraits {
static void Destruct(const BindStateBase*);
};
template <typename T>
using PassingType = std::conditional_t<std::is_scalar<T>::value, 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 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:
friend class scoped_refptr<BindStateBase>;
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 CallbackBase;
friend class CallbackBaseCopyable;
void AddRef();
void Release();
// Allowlist subclasses that access the destructor of BindStateBase.
template <typename Functor, typename... BoundArgs>
friend struct BindState;
friend struct ::base::FakeBindState;
AtomicRefCount ref_count_;
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_)(BindStateBase*);
DISALLOW_COPY_AND_ASSIGN(BindStateBase);
void (*destructor_)(const BindStateBase*);
bool (*query_cancellation_traits_)(const BindStateBase*,
CancellationQueryMode mode);
};
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
class CallbackBase {
public:
inline CallbackBase(CallbackBase&& c) noexcept;
CallbackBase& operator=(CallbackBase&& c) noexcept;
explicit CallbackBase(const CallbackBaseCopyable& c);
CallbackBase& operator=(const CallbackBaseCopyable& c);
explicit CallbackBase(CallbackBaseCopyable&& c) noexcept;
CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept;
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const { return bind_state_.get() == NULL; }
bool is_null() const { return !bind_state_; }
explicit operator bool() const { return !is_null(); }
// Returns true if the callback invocation will be nop due to an cancellation.
// It's invalid to call this on uninitialized callback.
//
// Must be called on the Callback's destination sequence.
bool IsCancelled() const;
// If this returns false, the callback invocation will be a nop due to a
// cancellation. This may(!) still return true, even on a cancelled callback.
//
// This function is thread-safe.
bool MaybeValid() const;
// Returns the Callback into an uninitialized state.
void Reset();
protected:
// 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.
typedef void (*InvokeFuncStorage)(void);
friend class FinallyExecutorCommon;
friend class ThenAndCatchExecutorCommon;
template <typename ReturnType>
friend class PostTaskExecutor;
using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
bool EqualsInternal(const CallbackBase& other) const;
constexpr inline CallbackBase();
// Allow initializing of |bind_state_| via the constructor to avoid default
// initialization of the scoped_refptr. We do not also initialize
// |polymorphic_invoke_| here because doing a normal assignment in the
// derived Callback templates makes for much nicer compiler errors.
explicit CallbackBase(BindStateBase* bind_state);
// initialization of the scoped_refptr.
explicit inline CallbackBase(BindStateBase* bind_state);
InvokeFuncStorage polymorphic_invoke() const {
return bind_state_->polymorphic_invoke_;
}
// Force the destructor to be instantiated inside this translation unit so
// that our subclasses will not get inlined versions. Avoids more template
@ -109,116 +193,83 @@ class CallbackBase {
~CallbackBase();
scoped_refptr<BindStateBase> bind_state_;
InvokeFuncStorage polymorphic_invoke_;
};
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via .Pass() in a
// destructive way.
template <typename T>
struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
constexpr CallbackBase::CallbackBase() = default;
CallbackBase::CallbackBase(CallbackBase&&) noexcept = default;
CallbackBase::CallbackBase(BindStateBase* bind_state)
: bind_state_(AdoptRef(bind_state)) {}
template <typename U>
static NoType Test(...);
// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
class CallbackBaseCopyable : public CallbackBase {
public:
CallbackBaseCopyable(const CallbackBaseCopyable& c);
CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = default;
CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c);
CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept;
static const bool value =
sizeof(Test<T>(0)) == sizeof(YesType) && !is_const<T>::value;
protected:
constexpr CallbackBaseCopyable() = default;
explicit CallbackBaseCopyable(BindStateBase* bind_state)
: CallbackBase(bind_state) {}
~CallbackBaseCopyable() = default;
};
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
// In particular, it strips off references, and converts arrays to
// pointers for storage; and it avoids accidentally trying to create a
// "reference of a reference" if the argument is a reference type.
//
// This array type becomes an issue for storage because we are passing bound
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
struct CallbackParamTraits {
typedef const T& ForwardType;
typedef T StorageType;
// 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();
};
}
};
// The Storage should almost be impossible to trigger unless someone manually
// specifies type of the bind parameters. However, in case they do,
// this will guard against us accidentally storing a reference parameter.
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraits<T&, false> {
typedef T& ForwardType;
typedef T StorageType;
// 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<ThenArgs..., OriginalR&&>::value,
"|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)...));
};
}
};
// Note that for array types, we implicitly add a const in the conversion. This
// means that it is not possible to bind array arguments to functions that take
// a non-const pointer. Trying to specialize the template based on a "const
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
struct CallbackParamTraits<T[n], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraits<T[], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// Parameter traits for movable-but-not-copyable scopers.
//
// Callback<>/Bind() understands movable-but-not-copyable semantics where
// the type cannot be copied but can still have its state destructively
// transferred (aka. moved) to another instance of the same type by calling a
// helper function. When used with Bind(), this signifies transferal of the
// object's state to the target function.
//
// For these types, the ForwardType must not be a const reference, or a
// reference. A const reference is inappropriate, and would break const
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraits<T, true> {
typedef T ForwardType;
typedef T StorageType;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
// used by the Callback/Bind system for a set of movable-but-not-copyable
// types. It is needed because forwarding a movable-but-not-copyable
// argument to another function requires us to invoke the proper move
// operator to create a rvalue version of the type. The supported types are
// whitelisted below as overloads of the CallbackForward() function. The
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward with C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
// simulate std::forward() and forward the result of one Callback as a
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
return t;
}
template <typename T>
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
return t.Pass();
}
} // namespace cef_internal
} // namespace internal
} // namespace base
#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_