Format include/base comments for Doxygen (see issue #3384)

This commit is contained in:
Marshall Greenblatt
2022-09-05 16:17:57 -04:00
parent cf7e10aacc
commit 12fc72147c
22 changed files with 1316 additions and 1061 deletions

View File

@ -1038,8 +1038,7 @@ EXCLUDE_PATTERNS = *_internal.h
# Note that the wildcards are matched against the file with absolute path, so to # Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/* # exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS = base::cef_internal \ EXCLUDE_SYMBOLS = base::cef_subtle \
base::cef_subtle \
base::internal \ base::internal \
cef_trace_event \ cef_trace_event \
cef::logging cef::logging

View File

@ -49,9 +49,11 @@
namespace base { namespace base {
// A flag that can safely be set from one thread and read from other threads. ///
// /// A flag that can safely be set from one thread and read from other threads.
// This class IS NOT intended for synchronization between threads. ///
/// This class IS NOT intended for synchronization between threads.
///
class AtomicFlag { class AtomicFlag {
public: public:
AtomicFlag(); AtomicFlag();
@ -61,19 +63,26 @@ class AtomicFlag {
~AtomicFlag(); ~AtomicFlag();
// Set the flag. Must always be called from the same thread. ///
/// Set the flag. Must always be called from the same thread.
///
void Set(); void Set();
// Returns true iff the flag was set. If this returns true, the current thread ///
// is guaranteed to be synchronized with all memory operations on the thread /// Returns true iff the flag was set. If this returns true, the current
// which invoked Set() up until at least the first call to Set() on it. /// thread is guaranteed to be synchronized with all memory operations on the
/// thread which invoked Set() up until at least the first call to Set() on
/// it.
///
bool IsSet() const { bool IsSet() const {
// Inline here: this has a measurable performance impact on base::WeakPtr. // Inline here: this has a measurable performance impact on base::WeakPtr.
return flag_.load(std::memory_order_acquire) != 0; return flag_.load(std::memory_order_acquire) != 0;
} }
// Resets the flag. Be careful when using this: callers might not expect ///
// IsSet() to return false after returning true once. /// Resets the flag. Be careful when using this: callers might not expect
/// IsSet() to return false after returning true once.
///
void UnsafeResetForTesting(); void UnsafeResetForTesting();
private: private:

View File

@ -58,19 +58,25 @@ class AtomicRefCount {
explicit constexpr AtomicRefCount(int initial_value) explicit constexpr AtomicRefCount(int initial_value)
: ref_count_(initial_value) {} : ref_count_(initial_value) {}
// Increment a reference count. ///
// Returns the previous value of the count. /// Increment a reference count.
/// Returns the previous value of the count.
///
int Increment() { return Increment(1); } int Increment() { return Increment(1); }
// Increment a reference count by "increment", which must exceed 0. ///
// Returns the previous value of the count. /// Increment a reference count by "increment", which must exceed 0.
/// Returns the previous value of the count.
///
int Increment(int increment) { int Increment(int increment) {
return ref_count_.fetch_add(increment, std::memory_order_relaxed); return ref_count_.fetch_add(increment, std::memory_order_relaxed);
} }
// Decrement a reference count, and return whether the result is non-zero. ///
// Insert barriers to ensure that state written before the reference count /// Decrement a reference count, and return whether the result is non-zero.
// became zero will be visible to a thread that has just made the count zero. /// Insert barriers to ensure that state written before the reference count
/// became zero will be visible to a thread that has just made the count zero.
///
bool Decrement() { bool Decrement() {
// TODO(jbroman): Technically this doesn't need to be an acquire operation // TODO(jbroman): Technically this doesn't need to be an acquire operation
// unless the result is 1 (i.e., the ref count did indeed reach zero). // unless the result is 1 (i.e., the ref count did indeed reach zero).
@ -79,23 +85,29 @@ class AtomicRefCount {
return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1; return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
} }
// Return whether the reference count is one. If the reference count is used ///
// in the conventional way, a refrerence count of 1 implies that the current /// Return whether the reference count is one. If the reference count is used
// thread owns the reference and no other thread shares it. This call /// in the conventional way, a refrerence count of 1 implies that the current
// performs the test for a reference count of one, and performs the memory /// thread owns the reference and no other thread shares it. This call
// barrier needed for the owning thread to act on the object, knowing that it /// performs the test for a reference count of one, and performs the memory
// has exclusive access to the object. /// barrier needed for the owning thread to act on the object, knowing that it
/// has exclusive access to the object.
///
bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; } bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; }
// Return whether the reference count is zero. With conventional object ///
// referencing counting, the object will be destroyed, so the reference count /// Return whether the reference count is zero. With conventional object
// should never be zero. Hence this is generally used for a debug check. /// referencing counting, the object will be destroyed, so the reference count
/// should never be zero. Hence this is generally used for a debug check.
///
bool IsZero() const { bool IsZero() const {
return ref_count_.load(std::memory_order_acquire) == 0; return ref_count_.load(std::memory_order_acquire) == 0;
} }
// Returns the current reference count (with no barriers). This is subtle, and ///
// should be used only for debugging. /// Returns the current reference count (with no barriers). This is subtle,
/// and should be used only for debugging.
///
int SubtleRefCountForDebug() const { int SubtleRefCountForDebug() const {
return ref_count_.load(std::memory_order_relaxed); return ref_count_.load(std::memory_order_relaxed);
} }

View File

@ -28,41 +28,42 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------- ///
// Usage documentation /// \file
// ----------------------------------------------------------------------------- /// base::BindOnce() and base::BindRepeating() are helpers for creating
// /// base::OnceCallback and base::RepeatingCallback objects respectively.
// Overview: ///
// base::BindOnce() and base::BindRepeating() are helpers for creating /// For a runnable object of n-arity, the base::Bind*() family allows partial
// base::OnceCallback and base::RepeatingCallback objects respectively. /// application of the first m arguments. The remaining n - m arguments must be
// /// passed when invoking the callback with Run().
// For a runnable object of n-arity, the base::Bind*() family allows partial ///
// application of the first m arguments. The remaining n - m arguments must be /// <pre>
// passed when invoking the callback with Run(). /// // The first argument is bound at callback creation; the remaining
// /// // two must be passed when calling Run() on the callback object.
// // The first argument is bound at callback creation; the remaining /// base::OnceCallback<long(int, long)> cb = base::BindOnce(
// // two must be passed when calling Run() on the callback object. /// [](short x, int y, long z) { return x * y * z; }, 42);
// base::OnceCallback<long(int, long)> cb = base::BindOnce( /// </pre>
// [](short x, int y, long z) { return x * y * z; }, 42); ///
// /// When binding to a method, the receiver object must also be specified at
// When binding to a method, the receiver object must also be specified at /// callback creation time. When Run() is invoked, the method will be invoked on
// callback creation time. When Run() is invoked, the method will be invoked on /// the specified receiver object.
// the specified receiver object. ///
// /// <pre>
// class C : public base::RefCounted<C> { void F(); }; /// class C : public base::RefCounted<C> { void F(); };
// auto instance = base::MakeRefCounted<C>(); /// auto instance = base::MakeRefCounted<C>();
// auto cb = base::BindOnce(&C::F, instance); /// auto cb = base::BindOnce(&C::F, instance);
// std::move(cb).Run(); // Identical to instance->F() /// std::move(cb).Run(); // Identical to instance->F()
// /// </pre>
// See //docs/callback.md for the full documentation. ///
// /// See https://chromium.googlesource.com/chromium/src/+/lkgr/docs/callback.md
// ----------------------------------------------------------------------------- /// for the full documentation.
///
// Implementation notes // Implementation notes
// -----------------------------------------------------------------------------
// //
// If you're reading the implementation, before proceeding further, you should // If you're reading the implementation, before proceeding further, you should
// read the top comment of base/internal/cef_bind_internal.h for a definition of // read the top comment of base/internal/cef_bind_internal.h for a definition
// common terms and concepts. // of common terms and concepts.
#ifndef CEF_INCLUDE_BASE_CEF_BIND_H_ #ifndef CEF_INCLUDE_BASE_CEF_BIND_H_
#define CEF_INCLUDE_BASE_CEF_BIND_H_ #define CEF_INCLUDE_BASE_CEF_BIND_H_
@ -92,7 +93,9 @@
namespace base { namespace base {
// Bind as OnceCallback. ///
/// Bind as OnceCallback.
///
template <typename Functor, typename... Args> template <typename Functor, typename... Args>
inline OnceCallback<internal::MakeUnboundRunType<Functor, Args...>> BindOnce( inline OnceCallback<internal::MakeUnboundRunType<Functor, Args...>> BindOnce(
Functor&& functor, Functor&& functor,
@ -111,7 +114,9 @@ inline OnceCallback<internal::MakeUnboundRunType<Functor, Args...>> BindOnce(
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
// Bind as RepeatingCallback. ///
/// Bind as RepeatingCallback.
///
template <typename Functor, typename... Args> template <typename Functor, typename... Args>
inline RepeatingCallback<internal::MakeUnboundRunType<Functor, Args...>> inline RepeatingCallback<internal::MakeUnboundRunType<Functor, Args...>>
BindRepeating(Functor&& functor, Args&&... args) { BindRepeating(Functor&& functor, Args&&... args) {
@ -123,9 +128,11 @@ BindRepeating(Functor&& functor, Args&&... args) {
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
// Special cases for binding to a base::Callback without extra bound arguments. ///
// We CHECK() the validity of callback to guard against null pointers /// Special cases for binding to a base::Callback without extra bound arguments.
// accidentally ending up in posted tasks, causing hard-to-debug crashes. /// We CHECK() the validity of callback to guard against null pointers
/// accidentally ending up in posted tasks, causing hard-to-debug crashes.
///
template <typename Signature> template <typename Signature>
OnceCallback<Signature> BindOnce(OnceCallback<Signature> callback) { OnceCallback<Signature> BindOnce(OnceCallback<Signature> callback) {
CHECK(callback); CHECK(callback);
@ -145,44 +152,54 @@ RepeatingCallback<Signature> BindRepeating(
return callback; return callback;
} }
// Unretained() allows binding a non-refcounted class, and to disable ///
// refcounting on arguments that are refcounted objects. /// Unretained() allows binding a non-refcounted class, and to disable
// /// refcounting on arguments that are refcounted objects.
// EXAMPLE OF Unretained(): ///
// /// EXAMPLE OF Unretained():
// class Foo { ///
// public: /// <pre>
// void func() { cout << "Foo:f" << endl; } /// class Foo {
// }; /// public:
// /// void func() { cout << "Foo:f" << endl; }
// // In some function somewhere. /// };
// Foo foo; ///
// OnceClosure foo_callback = /// // In some function somewhere.
// BindOnce(&Foo::func, Unretained(&foo)); /// Foo foo;
// std::move(foo_callback).Run(); // Prints "Foo:f". /// OnceClosure foo_callback =
// /// BindOnce(&Foo::func, Unretained(&foo));
// Without the Unretained() wrapper on |&foo|, the above call would fail /// std::move(foo_callback).Run(); // Prints "Foo:f".
// to compile because Foo does not support the AddRef() and Release() methods. /// </pre>
///
/// Without the Unretained() wrapper on |&foo|, the above call would fail
/// to compile because Foo does not support the AddRef() and Release() methods.
///
template <typename T> template <typename T>
inline internal::UnretainedWrapper<T> Unretained(T* o) { inline internal::UnretainedWrapper<T> Unretained(T* o) {
return internal::UnretainedWrapper<T>(o); return internal::UnretainedWrapper<T>(o);
} }
// RetainedRef() accepts a ref counted object and retains a reference to it. ///
// When the callback is called, the object is passed as a raw pointer. /// RetainedRef() accepts a ref counted object and retains a reference to it.
// /// When the callback is called, the object is passed as a raw pointer.
// EXAMPLE OF RetainedRef(): ///
// /// EXAMPLE OF RetainedRef():
// void foo(RefCountedBytes* bytes) {} ///
// /// <pre>
// scoped_refptr<RefCountedBytes> bytes = ...; /// void foo(RefCountedBytes* bytes) {}
// OnceClosure callback = BindOnce(&foo, base::RetainedRef(bytes)); ///
// std::move(callback).Run(); /// scoped_refptr<RefCountedBytes> bytes = ...;
// /// OnceClosure callback = BindOnce(&foo, base::RetainedRef(bytes));
// Without RetainedRef, the scoped_refptr would try to implicitly convert to /// std::move(callback).Run();
// a raw pointer and fail compilation: /// </pre>
// ///
// OnceClosure callback = BindOnce(&foo, bytes); // ERROR! /// Without RetainedRef, the scoped_refptr would try to implicitly convert to
/// a raw pointer and fail compilation:
///
/// <pre>
/// OnceClosure callback = BindOnce(&foo, bytes); // ERROR!
/// </pre>
///
template <typename T> template <typename T>
inline internal::RetainedRefWrapper<T> RetainedRef(T* o) { inline internal::RetainedRefWrapper<T> RetainedRef(T* o) {
return internal::RetainedRefWrapper<T>(o); return internal::RetainedRefWrapper<T>(o);
@ -192,26 +209,30 @@ inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
return internal::RetainedRefWrapper<T>(std::move(o)); return internal::RetainedRefWrapper<T>(std::move(o));
} }
// Owned() transfers ownership of an object to the callback resulting from ///
// bind; the object will be deleted when the callback is deleted. /// Owned() transfers ownership of an object to the callback resulting from
// /// bind; the object will be deleted when the callback is deleted.
// EXAMPLE OF Owned(): ///
// /// EXAMPLE OF Owned():
// void foo(int* arg) { cout << *arg << endl } ///
// /// <pre>
// int* pn = new int(1); /// void foo(int* arg) { cout << *arg << endl }
// RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn)); ///
// /// int* pn = new int(1);
// foo_callback.Run(); // Prints "1" /// RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn));
// foo_callback.Run(); // Prints "1" ///
// *pn = 2; /// foo_callback.Run(); // Prints "1"
// foo_callback.Run(); // Prints "2" /// foo_callback.Run(); // Prints "1"
// /// *pn = 2;
// foo_callback.Reset(); // |pn| is deleted. Also will happen when /// foo_callback.Run(); // Prints "2"
// // |foo_callback| goes out of scope. ///
// /// foo_callback.Reset(); // |pn| is deleted. Also will happen when
// Without Owned(), someone would have to know to delete |pn| when the last /// // |foo_callback| goes out of scope.
// reference to the callback is deleted. /// </pre>
///
/// Without Owned(), someone would have to know to delete |pn| when the last
/// reference to the callback is deleted.
///
template <typename T> template <typename T>
inline internal::OwnedWrapper<T> Owned(T* o) { inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(o); return internal::OwnedWrapper<T>(o);
@ -223,78 +244,89 @@ inline internal::OwnedWrapper<T, Deleter> Owned(
return internal::OwnedWrapper<T, Deleter>(std::move(ptr)); return internal::OwnedWrapper<T, Deleter>(std::move(ptr));
} }
// OwnedRef() stores an object in the callback resulting from ///
// bind and passes a reference to the object to the bound function. /// OwnedRef() stores an object in the callback resulting from
// /// bind and passes a reference to the object to the bound function.
// EXAMPLE OF OwnedRef(): ///
// /// EXAMPLE OF OwnedRef():
// void foo(int& arg) { cout << ++arg << endl } ///
// /// <pre>
// int counter = 0; /// void foo(int& arg) { cout << ++arg << endl }
// RepeatingClosure foo_callback = BindRepeating(&foo, OwnedRef(counter)); ///
// /// int counter = 0;
// foo_callback.Run(); // Prints "1" /// RepeatingClosure foo_callback = BindRepeating(&foo, OwnedRef(counter));
// foo_callback.Run(); // Prints "2" ///
// foo_callback.Run(); // Prints "3" /// foo_callback.Run(); // Prints "1"
// /// foo_callback.Run(); // Prints "2"
// cout << counter; // Prints "0", OwnedRef creates a copy of counter. /// foo_callback.Run(); // Prints "3"
// ///
// Supports OnceCallbacks as well, useful to pass placeholder arguments: /// cout << counter; // Prints "0", OwnedRef creates a copy of counter.
// /// </pre>
// void bar(int& ignore, const std::string& s) { cout << s << endl } ///
// /// Supports OnceCallbacks as well, useful to pass placeholder arguments:
// OnceClosure bar_callback = BindOnce(&bar, OwnedRef(0), "Hello"); ///
// /// <pre>
// std::move(bar_callback).Run(); // Prints "Hello" /// void bar(int& ignore, const std::string& s) { cout << s << endl }
// ///
// Without OwnedRef() it would not be possible to pass a mutable reference to an /// OnceClosure bar_callback = BindOnce(&bar, OwnedRef(0), "Hello");
// object owned by the callback. ///
/// std::move(bar_callback).Run(); // Prints "Hello"
/// </pre>
///
/// Without OwnedRef() it would not be possible to pass a mutable reference to
/// an object owned by the callback.
///
template <typename T> template <typename T>
internal::OwnedRefWrapper<std::decay_t<T>> OwnedRef(T&& t) { internal::OwnedRefWrapper<std::decay_t<T>> OwnedRef(T&& t) {
return internal::OwnedRefWrapper<std::decay_t<T>>(std::forward<T>(t)); return internal::OwnedRefWrapper<std::decay_t<T>>(std::forward<T>(t));
} }
// Passed() is for transferring movable-but-not-copyable types (eg. unique_ptr) ///
// through a RepeatingCallback. Logically, this signifies a destructive transfer /// Passed() is for transferring movable-but-not-copyable types (eg. unique_ptr)
// of the state of the argument into the target function. Invoking /// through a RepeatingCallback. Logically, this signifies a destructive
// RepeatingCallback::Run() twice on a callback that was created with a Passed() /// transfer of the state of the argument into the target function. Invoking
// argument will CHECK() because the first invocation would have already /// RepeatingCallback::Run() twice on a callback that was created with a
// transferred ownership to the target function. /// Passed() argument will CHECK() because the first invocation would have
// /// already transferred ownership to the target function.
// Note that Passed() is not necessary with BindOnce(), as std::move() does the ///
// same thing. Avoid Passed() in favor of std::move() with BindOnce(). /// Note that Passed() is not necessary with BindOnce(), as std::move() does the
// /// same thing. Avoid Passed() in favor of std::move() with BindOnce().
// EXAMPLE OF Passed(): ///
// /// EXAMPLE OF Passed():
// void TakesOwnership(std::unique_ptr<Foo> arg) { } ///
// std::unique_ptr<Foo> CreateFoo() { return std::make_unique<Foo>(); /// <pre>
// } /// void TakesOwnership(std::unique_ptr<Foo> arg) { }
// /// std::unique_ptr<Foo> CreateFoo() { return std::make_unique<Foo>();
// auto f = std::make_unique<Foo>(); /// }
// ///
// // |cb| is given ownership of Foo(). |f| is now NULL. /// auto f = std::make_unique<Foo>();
// // You can use std::move(f) in place of &f, but it's more verbose. ///
// RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f)); /// // |cb| is given ownership of Foo(). |f| is now NULL.
// /// // You can use std::move(f) in place of &f, but it's more verbose.
// // Run was never called so |cb| still owns Foo() and deletes /// RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f));
// // it on Reset(). ///
// cb.Reset(); /// // Run was never called so |cb| still owns Foo() and deletes
// /// // it on Reset().
// // |cb| is given a new Foo created by CreateFoo(). /// cb.Reset();
// cb = BindRepeating(&TakesOwnership, Passed(CreateFoo())); ///
// /// // |cb| is given a new Foo created by CreateFoo().
// // |arg| in TakesOwnership() is given ownership of Foo(). |cb| /// cb = BindRepeating(&TakesOwnership, Passed(CreateFoo()));
// // no longer owns Foo() and, if reset, would not delete Foo(). ///
// cb.Run(); // Foo() is now transferred to |arg| and deleted. /// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
// cb.Run(); // This CHECK()s since Foo() already been used once. /// // no longer owns Foo() and, if reset, would not delete Foo().
// /// cb.Run(); // Foo() is now transferred to |arg| and deleted.
// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and is /// cb.Run(); // This CHECK()s since Foo() already been used once.
// best suited for use with the return value of a function or other temporary /// </pre>
// rvalues. The second takes a pointer to the scoper and is just syntactic sugar ///
// to avoid having to write Passed(std::move(scoper)). /// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and is
// /// best suited for use with the return value of a function or other temporary
// Both versions of Passed() prevent T from being an lvalue reference. The first /// rvalues. The second takes a pointer to the scoper and is just syntactic
// via use of enable_if, and the second takes a T* which will not bind to T&. /// sugar to avoid having to write Passed(std::move(scoper)).
///
/// Both versions of Passed() prevent T from being an lvalue reference. The
/// first via use of enable_if, and the second takes a T* which will not bind to
/// T&.
///
template <typename T, template <typename T,
std::enable_if_t<!std::is_lvalue_reference<T>::value>* = nullptr> std::enable_if_t<!std::is_lvalue_reference<T>::value>* = nullptr>
inline internal::PassedWrapper<T> Passed(T&& scoper) { inline internal::PassedWrapper<T> Passed(T&& scoper) {
@ -305,21 +337,25 @@ inline internal::PassedWrapper<T> Passed(T* scoper) {
return internal::PassedWrapper<T>(std::move(*scoper)); return internal::PassedWrapper<T>(std::move(*scoper));
} }
// IgnoreResult() is used to adapt a function or callback with a return type to ///
// one with a void return. This is most useful if you have a function with, /// IgnoreResult() is used to adapt a function or callback with a return type to
// say, a pesky ignorable bool return that you want to use with PostTask or /// one with a void return. This is most useful if you have a function with,
// something else that expect a callback with a void return. /// say, a pesky ignorable bool return that you want to use with PostTask or
// /// something else that expect a callback with a void return.
// EXAMPLE OF IgnoreResult(): ///
// /// EXAMPLE OF IgnoreResult():
// int DoSomething(int arg) { cout << arg << endl; } ///
// /// <pre>
// // Assign to a callback with a void return type. /// int DoSomething(int arg) { cout << arg << endl; }
// OnceCallback<void(int)> cb = BindOnce(IgnoreResult(&DoSomething)); ///
// std::move(cb).Run(1); // Prints "1". /// // Assign to a callback with a void return type.
// /// OnceCallback<void(int)> cb = BindOnce(IgnoreResult(&DoSomething));
// // Prints "2" on |ml|. /// std::move(cb).Run(1); // Prints "1".
// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 2); ///
/// // Prints "2" on |ml|.
/// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 2);
/// </pre>
///
template <typename T> template <typename T>
inline internal::IgnoreResultHelper<T> IgnoreResult(T data) { inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
return internal::IgnoreResultHelper<T>(std::move(data)); return internal::IgnoreResultHelper<T>(std::move(data));
@ -327,16 +363,20 @@ inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc) #if defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
// RetainBlock() is used to adapt an Objective-C block when Automated Reference ///
// Counting (ARC) is disabled. This is unnecessary when ARC is enabled, as the /// RetainBlock() is used to adapt an Objective-C block when Automated Reference
// BindOnce and BindRepeating already support blocks then. /// Counting (ARC) is disabled. This is unnecessary when ARC is enabled, as the
// /// BindOnce and BindRepeating already support blocks then.
// EXAMPLE OF RetainBlock(): ///
// /// EXAMPLE OF RetainBlock():
// // Wrap the block and bind it to a callback. ///
// OnceCallback<void(int)> cb = /// <pre>
// BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); })); /// // Wrap the block and bind it to a callback.
// std::move(cb).Run(1); // Logs "1". /// OnceCallback<void(int)> cb =
/// BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); }));
/// std::move(cb).Run(1); // Logs "1".
/// </pre>
///
template <typename R, typename... Args> template <typename R, typename... Args>
base::mac::ScopedBlock<R (^)(Args...)> RetainBlock(R (^block)(Args...)) { base::mac::ScopedBlock<R (^)(Args...)> RetainBlock(R (^block)(Args...)) {
return base::mac::ScopedBlock<R (^)(Args...)>(block, return base::mac::ScopedBlock<R (^)(Args...)>(block,

View File

@ -27,36 +27,40 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file adds defines about the platform we're currently building on. /// \file
// /// This file adds defines about the platform we're currently building on.
// Operating System: ///
// OS_AIX / OS_ANDROID / OS_ASMJS / OS_FREEBSD / OS_FUCHSIA / OS_IOS / /// <pre>
// OS_LINUX / OS_MAC / OS_NACL (SFI or NONSFI) / OS_NETBSD / OS_OPENBSD / /// Operating System:
// OS_QNX / OS_SOLARIS / OS_WIN /// OS_AIX / OS_ANDROID / OS_ASMJS / OS_FREEBSD / OS_FUCHSIA / OS_IOS /
// Operating System family: /// OS_LINUX / OS_MAC / OS_NACL (SFI or NONSFI) / OS_NETBSD / OS_OPENBSD /
// OS_APPLE: IOS or MAC /// OS_QNX / OS_SOLARIS / OS_WIN
// OS_BSD: FREEBSD or NETBSD or OPENBSD /// Operating System family:
// OS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX /// OS_APPLE: IOS or MAC
// or MAC or NACL or NETBSD or OPENBSD or QNX or SOLARIS /// OS_BSD: FREEBSD or NETBSD or OPENBSD
// /// OS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX
// /!\ Note: OS_CHROMEOS is set by the build system, not this file /// or MAC or NACL or NETBSD or OPENBSD or QNX or SOLARIS
// ///
// Compiler: /// /!\ Note: OS_CHROMEOS is set by the build system, not this file
// COMPILER_MSVC / COMPILER_GCC ///
// /// Compiler:
// Processor: /// COMPILER_MSVC / COMPILER_GCC
// ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_MIPS / ARCH_CPU_MIPS64 / ///
// ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL / ARCH_CPU_PPC64 / ARCH_CPU_S390 / /// Processor:
// ARCH_CPU_S390X / ARCH_CPU_X86 / ARCH_CPU_X86_64 /// ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_MIPS / ARCH_CPU_MIPS64 /
// Processor family: /// ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL / ARCH_CPU_PPC64 / ARCH_CPU_S390 /
// ARCH_CPU_ARM_FAMILY: ARMEL or ARM64 /// ARCH_CPU_S390X / ARCH_CPU_X86 / ARCH_CPU_X86_64
// ARCH_CPU_MIPS_FAMILY: MIPS64EL or MIPSEL or MIPS64 or MIPS /// Processor family:
// ARCH_CPU_PPC64_FAMILY: PPC64 /// ARCH_CPU_ARM_FAMILY: ARMEL or ARM64
// ARCH_CPU_S390_FAMILY: S390 or S390X /// ARCH_CPU_MIPS_FAMILY: MIPS64EL or MIPSEL or MIPS64 or MIPS
// ARCH_CPU_X86_FAMILY: X86 or X86_64 /// ARCH_CPU_PPC64_FAMILY: PPC64
// Processor features: /// ARCH_CPU_S390_FAMILY: S390 or S390X
// ARCH_CPU_31_BITS / ARCH_CPU_32_BITS / ARCH_CPU_64_BITS /// ARCH_CPU_X86_FAMILY: X86 or X86_64
// ARCH_CPU_BIG_ENDIAN / ARCH_CPU_LITTLE_ENDIAN /// Processor features:
/// ARCH_CPU_31_BITS / ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
/// ARCH_CPU_BIG_ENDIAN / ARCH_CPU_LITTLE_ENDIAN
/// </pre>
///
#ifndef CEF_INCLUDE_BASE_CEF_BUILD_H_ #ifndef CEF_INCLUDE_BASE_CEF_BUILD_H_
#define CEF_INCLUDE_BASE_CEF_BUILD_H_ #define CEF_INCLUDE_BASE_CEF_BUILD_H_

View File

@ -28,40 +28,38 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------- /// \file
// Usage documentation /// A callback is similar in concept to a function pointer: it wraps a runnable
// ----------------------------------------------------------------------------- /// object such as a function, method, lambda, or even another callback,
// /// allowing the runnable object to be invoked later via the callback object.
// Overview: ///
// A callback is similar in concept to a function pointer: it wraps a runnable /// Unlike function pointers, callbacks are created with base::BindOnce() or
// object such as a function, method, lambda, or even another callback, allowing /// base::BindRepeating() and support partial function application.
// the runnable object to be invoked later via the callback object. ///
// /// A base::OnceCallback may be Run() at most once; a base::RepeatingCallback
// Unlike function pointers, callbacks are created with base::BindOnce() or /// may be Run() any number of times. |is_null()| is guaranteed to return true
// base::BindRepeating() and support partial function application. /// for a moved-from callback.
// ///
// A base::OnceCallback may be Run() at most once; a base::RepeatingCallback may /// <pre>
// be Run() any number of times. |is_null()| is guaranteed to return true for a /// // The lambda takes two arguments, but the first argument |x| is bound at
// moved-from callback. /// // callback creation.
// /// base::OnceCallback<int(int)> cb = base::BindOnce([] (int x, int y) {
// // The lambda takes two arguments, but the first argument |x| is bound at /// return x + y;
// // callback creation. /// }, 1);
// base::OnceCallback<int(int)> cb = base::BindOnce([] (int x, int y) { /// // Run() only needs the remaining unbound argument |y|.
// return x + y; /// printf("1 + 2 = %d\n", std::move(cb).Run(2)); // Prints 3
// }, 1); /// printf("cb is null? %s\n",
// // Run() only needs the remaining unbound argument |y|. /// cb.is_null() ? "true" : "false"); // Prints true
// printf("1 + 2 = %d\n", std::move(cb).Run(2)); // Prints 3 /// std::move(cb).Run(2); // Crashes since |cb| has already run.
// printf("cb is null? %s\n", /// </pre>
// cb.is_null() ? "true" : "false"); // Prints true ///
// std::move(cb).Run(2); // Crashes since |cb| has already run. /// Callbacks also support cancellation. A common use is binding the receiver
// /// object as a WeakPtr<T>. If that weak pointer is invalidated, calling Run()
// Callbacks also support cancellation. A common use is binding the receiver /// will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct:
// object as a WeakPtr<T>. If that weak pointer is invalidated, calling Run() /// simply cancelling a callback will not also make it null.
// will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct: ///
// simply cancelling a callback will not also make it null. /// See https://chromium.googlesource.com/chromium/src/+/lkgr/docs/callback.md
// /// for the full documentation.
// See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md
// for the full documentation.
#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_H_ #ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_H_
#define CEF_INCLUDE_BASE_CEF_CALLBACK_H_ #define CEF_INCLUDE_BASE_CEF_CALLBACK_H_

View File

@ -48,9 +48,11 @@ class OnceCallback;
template <typename Signature> template <typename Signature>
class RepeatingCallback; class RepeatingCallback;
// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()> ///
// easier to declare since they will be used in a lot of APIs with delayed /// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()>
// execution. /// easier to declare since they will be used in a lot of APIs with delayed
/// execution.
///
using OnceClosure = OnceCallback<void()>; using OnceClosure = OnceCallback<void()>;
using RepeatingClosure = RepeatingCallback<void()>; using RepeatingClosure = RepeatingCallback<void()>;

View File

@ -75,24 +75,32 @@ struct IsOnceCallbackImpl<OnceCallback<R(Args...)>> : std::true_type {};
} // namespace internal } // namespace internal
// IsBaseCallback<T>::value is true when T is any of the Closure or Callback ///
// family of types. /// IsBaseCallback<T>::value is true when T is any of the Closure or Callback
/// family of types.
///
template <typename T> template <typename T>
using IsBaseCallback = internal::IsBaseCallbackImpl<std::decay_t<T>>; using IsBaseCallback = internal::IsBaseCallbackImpl<std::decay_t<T>>;
// IsOnceCallback<T>::value is true when T is a OnceClosure or OnceCallback ///
// type. /// IsOnceCallback<T>::value is true when T is a OnceClosure or OnceCallback
/// type.
///
template <typename T> template <typename T>
using IsOnceCallback = internal::IsOnceCallbackImpl<std::decay_t<T>>; using IsOnceCallback = internal::IsOnceCallbackImpl<std::decay_t<T>>;
// SFINAE friendly enabler allowing to overload methods for both Repeating and ///
// OnceCallbacks. /// SFINAE friendly enabler allowing to overload methods for both Repeating and
// /// OnceCallbacks.
// Usage: ///
// template <template <typename> class CallbackType, /// Usage:
// ... other template args ..., /// <pre>
// typename = EnableIfIsBaseCallback<CallbackType>> /// template <template <typename> class CallbackType,
// void DoStuff(CallbackType<...> cb, ...); /// ... other template args ...,
/// typename = EnableIfIsBaseCallback<CallbackType>>
/// void DoStuff(CallbackType<...> cb, ...);
/// </pre>
///
template <template <typename> class CallbackType> template <template <typename> class CallbackType>
using EnableIfIsBaseCallback = using EnableIfIsBaseCallback =
std::enable_if_t<IsBaseCallback<CallbackType<void()>>::value>; std::enable_if_t<IsBaseCallback<CallbackType<void()>>::value>;
@ -129,13 +137,16 @@ class OnceCallbackHolder final {
} // namespace internal } // namespace internal
// Wraps the given OnceCallback into a RepeatingCallback that relays its ///
// invocation to the original OnceCallback on the first invocation. The /// Wraps the given OnceCallback into a RepeatingCallback that relays its
// following invocations are just ignored. /// invocation to the original OnceCallback on the first invocation. The
// /// following invocations are just ignored.
// Note that this deliberately subverts the Once/Repeating paradigm of Callbacks ///
// but helps ease the migration from old-style Callbacks. Avoid if possible; use /// Note that this deliberately subverts the Once/Repeating paradigm of
// if necessary for migration. TODO(tzik): Remove it. https://crbug.com/730593 /// Callbacks but helps ease the migration from old-style Callbacks. Avoid if
/// possible; use if necessary for migration.
///
// TODO(tzik): Remove it. https://crbug.com/730593
template <typename... Args> template <typename... Args>
RepeatingCallback<void(Args...)> AdaptCallbackForRepeating( RepeatingCallback<void(Args...)> AdaptCallbackForRepeating(
OnceCallback<void(Args...)> callback) { OnceCallback<void(Args...)> callback) {
@ -145,9 +156,11 @@ RepeatingCallback<void(Args...)> AdaptCallbackForRepeating(
/*ignore_extra_runs=*/true)); /*ignore_extra_runs=*/true));
} }
// Wraps the given OnceCallback and returns two OnceCallbacks with an identical ///
// signature. On first invokation of either returned callbacks, the original /// Wraps the given OnceCallback and returns two OnceCallbacks with an identical
// callback is invoked. Invoking the remaining callback results in a crash. /// signature. On first invokation of either returned callbacks, the original
/// callback is invoked. Invoking the remaining callback results in a crash.
///
template <typename... Args> template <typename... Args>
std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>> std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>>
SplitOnceCallback(OnceCallback<void(Args...)> callback) { SplitOnceCallback(OnceCallback<void(Args...)> callback) {
@ -158,10 +171,12 @@ SplitOnceCallback(OnceCallback<void(Args...)> callback) {
return std::make_pair(wrapped_once, wrapped_once); return std::make_pair(wrapped_once, wrapped_once);
} }
// ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures ///
// that the Closure is executed no matter how the current scope exits. /// ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures
// If you are looking for "ScopedCallback", "CallbackRunner", or /// that the Closure is executed no matter how the current scope exits.
// "CallbackScoper" this is the class you want. /// If you are looking for "ScopedCallback", "CallbackRunner", or
/// "CallbackScoper" this is the class you want.
///
class ScopedClosureRunner { class ScopedClosureRunner {
public: public:
ScopedClosureRunner(); ScopedClosureRunner();
@ -189,7 +204,9 @@ class ScopedClosureRunner {
OnceClosure closure_; OnceClosure closure_;
}; };
// Creates a null callback. ///
/// Creates a null callback.
///
class NullCallback { class NullCallback {
public: public:
template <typename R, typename... Args> template <typename R, typename... Args>
@ -202,7 +219,9 @@ class NullCallback {
} }
}; };
// Creates a callback that does nothing when called. ///
/// Creates a callback that does nothing when called.
///
class DoNothing { class DoNothing {
public: public:
template <typename... Args> template <typename... Args>
@ -225,9 +244,11 @@ class DoNothing {
} }
}; };
// Useful for creating a Closure that will delete a pointer when invoked. Only ///
// use this when necessary. In most cases MessageLoop::DeleteSoon() is a better /// Useful for creating a Closure that will delete a pointer when invoked. Only
// fit. /// use this when necessary. In most cases MessageLoop::DeleteSoon() is a better
/// fit.
///
template <typename T> template <typename T>
void DeletePointer(T* obj) { void DeletePointer(T* obj) {
delete obj; delete obj;

View File

@ -28,54 +28,57 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// OVERVIEW: ///
// /// \file
// A container for a list of callbacks. Provides callers the ability to manually /// A container for a list of callbacks. Provides callers the ability to
// or automatically unregister callbacks at any time, including during callback /// manually or automatically unregister callbacks at any time, including during
// notification. /// callback notification.
// ///
// TYPICAL USAGE: /// TYPICAL USAGE:
// ///
// class MyWidget { /// <pre>
// public: /// class MyWidget {
// using CallbackList = base::RepeatingCallbackList<void(const Foo&)>; /// public:
// /// using CallbackList = base::RepeatingCallbackList<void(const Foo&)>;
// // Registers |cb| to be called whenever NotifyFoo() is executed. ///
// CallbackListSubscription RegisterCallback(CallbackList::CallbackType cb) { /// // Registers |cb| to be called whenever NotifyFoo() is executed.
// return callback_list_.Add(std::move(cb)); /// CallbackListSubscription RegisterCallback(CallbackList::CallbackType cb) {
// } /// return callback_list_.Add(std::move(cb));
// /// }
// private: ///
// // Calls all registered callbacks, with |foo| as the supplied arg. /// private:
// void NotifyFoo(const Foo& foo) { /// // Calls all registered callbacks, with |foo| as the supplied arg.
// callback_list_.Notify(foo); /// void NotifyFoo(const Foo& foo) {
// } /// callback_list_.Notify(foo);
// /// }
// CallbackList callback_list_; ///
// }; /// CallbackList callback_list_;
// /// };
// ///
// class MyWidgetListener { ///
// private: /// class MyWidgetListener {
// void OnFoo(const Foo& foo) { /// private:
// // Called whenever MyWidget::NotifyFoo() is executed, unless /// void OnFoo(const Foo& foo) {
// // |foo_subscription_| has been destroyed. /// // Called whenever MyWidget::NotifyFoo() is executed, unless
// } /// // |foo_subscription_| has been destroyed.
// /// }
// // Automatically deregisters the callback when deleted (e.g. in ///
// // ~MyWidgetListener()). Unretained(this) is safe here since the /// // Automatically deregisters the callback when deleted (e.g. in
// // ScopedClosureRunner does not outlive |this|. /// // ~MyWidgetListener()). Unretained(this) is safe here since the
// CallbackListSubscription foo_subscription_ = /// // ScopedClosureRunner does not outlive |this|.
// MyWidget::Get()->RegisterCallback( /// CallbackListSubscription foo_subscription_ =
// base::BindRepeating(&MyWidgetListener::OnFoo, /// MyWidget::Get()->RegisterCallback(
// base::Unretained(this))); /// base::BindRepeating(&MyWidgetListener::OnFoo,
// }; /// base::Unretained(this)));
// /// };
// UNSUPPORTED: /// </pre>
// ///
// * Destroying the CallbackList during callback notification. /// UNSUPPORTED:
// ///
// This is possible to support, but not currently necessary. /// * Destroying the CallbackList during callback notification.
///
/// This is possible to support, but not currently necessary.
///
#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_ #ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
#define CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_ #define CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
@ -381,9 +384,9 @@ class RepeatingCallbackList
} }
}; };
// Syntactic sugar to parallel that used for Callbacks. ///
// ClosureList explicitly not provided since it is not used, and CallbackList /// Syntactic sugar to parallel that used for Callbacks.
// is deprecated. {Once,Repeating}ClosureList should instead be used. ///
using OnceClosureList = OnceCallbackList<void()>; using OnceClosureList = OnceCallbackList<void()>;
using RepeatingClosureList = RepeatingCallbackList<void()>; using RepeatingClosureList = RepeatingCallbackList<void()>;

View File

@ -28,44 +28,51 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// CancelableCallback is a wrapper around base::Callback that allows ///
// cancellation of a callback. CancelableCallback takes a reference on the /// \file
// wrapped callback until this object is destroyed or Reset()/Cancel() are /// CancelableCallback is a wrapper around base::Callback that allows
// called. /// cancellation of a callback. CancelableCallback takes a reference on the
// /// wrapped callback until this object is destroyed or Reset()/Cancel() are
// NOTE: /// called.
// ///
// Calling CancelableCallback::Cancel() brings the object back to its natural, /// NOTE:
// default-constructed state, i.e., CancelableCallback::callback() will return ///
// a null callback. /// Calling CancelableCallback::Cancel() brings the object back to its natural,
// /// default-constructed state, i.e., CancelableCallback::callback() will return
// THREAD-SAFETY: /// a null callback.
// ///
// CancelableCallback objects must be created on, posted to, cancelled on, and /// THREAD-SAFETY:
// destroyed on the same thread. ///
// /// CancelableCallback objects must be created on, posted to, cancelled on, and
// /// destroyed on the same thread.
// EXAMPLE USAGE: ///
// ///
// In the following example, the test is verifying that RunIntensiveTest() /// EXAMPLE USAGE:
// Quit()s the message loop within 4 seconds. The cancelable callback is posted ///
// to the message loop, the intensive test runs, the message loop is run, /// In the following example, the test is verifying that RunIntensiveTest()
// then the callback is cancelled. /// Quit()s the message loop within 4 seconds. The cancelable callback is posted
// /// to the message loop, the intensive test runs, the message loop is run,
// RunLoop run_loop; /// then the callback is cancelled.
// ///
// void TimeoutCallback(const std::string& timeout_message) { /// <pre>
// FAIL() << timeout_message; /// RunLoop run_loop;
// run_loop.QuitWhenIdle(); ///
// } /// void TimeoutCallback(const std::string& timeout_message) {
// /// FAIL() << timeout_message;
// CancelableOnceClosure timeout( /// run_loop.QuitWhenIdle();
// base::BindOnce(&TimeoutCallback, "Test timed out.")); /// }
// ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, timeout.callback(), ///
// TimeDelta::FromSeconds(4)); /// CancelableOnceClosure timeout(
// RunIntensiveTest(); /// base::BindOnce(&TimeoutCallback, "Test timed out."));
// run_loop.Run(); /// ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE,
// timeout.Cancel(); // Hopefully this is hit before the timeout callback runs. /// timeout.callback(),
/// TimeDelta::FromSeconds(4));
/// RunIntensiveTest();
/// run_loop.Run();
/// // Hopefully this is hit before the timeout callback runs.
/// timeout.Cancel();
/// </pre>
///
#ifndef CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_ #ifndef CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_
#define CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_ #define CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_
@ -166,8 +173,10 @@ class CancelableCallbackImpl {
} // namespace internal } // namespace internal
// Consider using base::WeakPtr directly instead of base::CancelableCallback for ///
// the task cancellation. /// Consider using base::WeakPtr directly instead of base::CancelableCallback
/// for the task cancellation.
///
template <typename Signature> template <typename Signature>
using CancelableOnceCallback = using CancelableOnceCallback =
internal::CancelableCallbackImpl<OnceCallback<Signature>>; internal::CancelableCallbackImpl<OnceCallback<Signature>>;

View File

@ -47,9 +47,11 @@
namespace base { namespace base {
namespace cef_internal { namespace cef_internal {
// A convenient wrapper for an OS specific critical section. The only real ///
// intelligence in this class is in debug mode for the support for the /// A convenient wrapper for an OS specific critical section. The only real
// AssertAcquired() method. /// intelligence in this class is in debug mode for the support for the
/// AssertAcquired() method.
///
class Lock { class Lock {
public: public:
#if !DCHECK_IS_ON() // Optimized wrapper implementation #if !DCHECK_IS_ON() // Optimized wrapper implementation
@ -62,10 +64,12 @@ class Lock {
void Acquire() { lock_.Lock(); } void Acquire() { lock_.Lock(); }
void Release() { lock_.Unlock(); } void Release() { lock_.Unlock(); }
// If the lock is not held, take it and return true. If the lock is already ///
// held by another thread, immediately return false. This must not be called /// If the lock is not held, take it and return true. If the lock is already
// by a thread already holding the lock (what happens is undefined and an /// held by another thread, immediately return false. This must not be called
// assertion may fail). /// by a thread already holding the lock (what happens is undefined and an
/// assertion may fail).
///
bool Try() { return lock_.Try(); } bool Try() { return lock_.Try(); }
// Null implementation if not debug. // Null implementation if not debug.
@ -116,7 +120,9 @@ class Lock {
LockImpl lock_; LockImpl lock_;
}; };
// A helper class that acquires the given Lock while the AutoLock is in scope. ///
/// A helper class that acquires the given Lock while the AutoLock is in scope.
///
class AutoLock { class AutoLock {
public: public:
struct AlreadyAcquired {}; struct AlreadyAcquired {};
@ -139,8 +145,10 @@ class AutoLock {
Lock& lock_; Lock& lock_;
}; };
// AutoUnlock is a helper that will Release() the |lock| argument in the ///
// constructor, and re-Acquire() it in the destructor. /// AutoUnlock is a helper that will Release() the |lock| argument in the
/// constructor, and re-Acquire() it in the destructor.
///
class AutoUnlock { class AutoUnlock {
public: public:
explicit AutoUnlock(Lock& lock) : lock_(lock) { explicit AutoUnlock(Lock& lock) : lock_(lock) {

View File

@ -27,110 +27,130 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// --------------------------------------------------------------------------- ///
// /// \file
// The contents of this file are only available to applications that link /// A bunch of macros for logging.
// against the libcef_dll_wrapper target. ///
// /// NOTE: The contents of this file are only available to applications that link
// WARNING: Logging macros should not be used in the main/browser process before /// against the libcef_dll_wrapper target.
// calling CefInitialize or in sub-processes before calling CefExecuteProcess. ///
// /// WARNING: Logging macros should not be used in the main/browser process
// Instructions /// before calling CefInitialize or in sub-processes before calling
// ------------ /// CefExecuteProcess.
// ///
// Make a bunch of macros for logging. The way to log things is to stream /// INSTRUCTIONS:
// things to LOG(<a particular severity level>). E.g., ///
// /// The way to log things is to stream things to LOG(<a particular severity
// LOG(INFO) << "Found " << num_cookies << " cookies"; /// level>). E.g.,
// ///
// You can also do conditional logging: /// <pre>
// /// LOG(INFO) << "Found " << num_cookies << " cookies";
// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; /// </pre>
// ///
// The CHECK(condition) macro is active in both debug and release builds and /// You can also do conditional logging:
// effectively performs a LOG(FATAL) which terminates the process and ///
// generates a crashdump unless a debugger is attached. /// <pre>
// /// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
// There are also "debug mode" logging macros like the ones above: /// </pre>
// ///
// DLOG(INFO) << "Found cookies"; /// The CHECK(condition) macro is active in both debug and release builds and
// /// effectively performs a LOG(FATAL) which terminates the process and
// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; /// generates a crashdump unless a debugger is attached.
// ///
// All "debug mode" logging is compiled away to nothing for non-debug mode /// There are also "debug mode" logging macros like the ones above:
// compiles. LOG_IF and development flags also work well together ///
// because the code can be compiled away sometimes. /// <pre>
// /// DLOG(INFO) << "Found cookies";
// We also have ///
// /// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
// LOG_ASSERT(assertion); /// </pre>
// DLOG_ASSERT(assertion); ///
// /// All "debug mode" logging is compiled away to nothing for non-debug mode
// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; /// compiles. LOG_IF and development flags also work well together
// /// because the code can be compiled away sometimes.
// There are "verbose level" logging macros. They look like ///
// /// We also have
// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; ///
// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; /// <pre>
// /// LOG_ASSERT(assertion);
// These always log at the INFO log level (when they log at all). /// DLOG_ASSERT(assertion);
// The verbose logging can also be turned on module-by-module. For instance, /// </pre>
// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0 ///
// will cause: /// which is syntactic sugar for "{,D}LOG_IF(FATAL, assert fails) << assertion;"
// a. VLOG(2) and lower messages to be printed from profile.{h,cc} ///
// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc} /// There are "verbose level" logging macros. They look like
// c. VLOG(3) and lower messages to be printed from files prefixed with ///
// "browser" /// <pre>
// d. VLOG(4) and lower messages to be printed from files under a /// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
// "chromeos" directory. /// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
// e. VLOG(0) and lower messages to be printed from elsewhere /// </pre>
// ///
// The wildcarding functionality shown by (c) supports both '*' (match /// These always log at the INFO log level (when they log at all).
// 0 or more characters) and '?' (match any single character) /// The verbose logging can also be turned on module-by-module. For instance,
// wildcards. Any pattern containing a forward or backward slash will /// <pre>
// be tested against the whole pathname and not just the module. /// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
// E.g., "*/foo/bar/*=2" would change the logging level for all code /// </pre>
// in source files under a "foo/bar" directory. /// will cause:
// /// 1. VLOG(2) and lower messages to be printed from profile.{h,cc}
// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as /// 2. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
// /// 3. VLOG(3) and lower messages to be printed from files prefixed with
// if (VLOG_IS_ON(2)) { /// "browser"
// // do some logging preparation and logging /// 4. VLOG(4) and lower messages to be printed from files under a
// // that can't be accomplished with just VLOG(2) << ...; /// "chromeos" directory.
// } /// 5. VLOG(0) and lower messages to be printed from elsewhere
// ///
// There is also a VLOG_IF "verbose level" condition macro for sample /// The wildcarding functionality shown by (c) supports both '*' (match
// cases, when some extra computation and preparation for logs is not /// 0 or more characters) and '?' (match any single character)
// needed. /// wildcards. Any pattern containing a forward or backward slash will
// /// be tested against the whole pathname and not just the module.
// VLOG_IF(1, (size > 1024)) /// E.g., "*/foo/bar/*=2" would change the logging level for all code
// << "I'm printed when size is more than 1024 and when you run the " /// in source files under a "foo/bar" directory.
// "program with --v=1 or more"; ///
// /// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
// We also override the standard 'assert' to use 'DLOG_ASSERT'. ///
// /// <pre>
// Lastly, there is: /// if (VLOG_IS_ON(2)) {
// /// // do some logging preparation and logging
// PLOG(ERROR) << "Couldn't do foo"; /// // that can't be accomplished with just VLOG(2) << ...;
// DPLOG(ERROR) << "Couldn't do foo"; /// }
// PLOG_IF(ERROR, cond) << "Couldn't do foo"; /// </pre>
// DPLOG_IF(ERROR, cond) << "Couldn't do foo"; ///
// PCHECK(condition) << "Couldn't do foo"; /// There is also a VLOG_IF "verbose level" condition macro for sample
// DPCHECK(condition) << "Couldn't do foo"; /// cases, when some extra computation and preparation for logs is not
// /// needed.
// which append the last system error to the message in string form (taken from ///
// GetLastError() on Windows and errno on POSIX). /// <pre>
// /// VLOG_IF(1, (size > 1024))
// The supported severity levels for macros that allow you to specify one /// << "I'm printed when size is more than 1024 and when you run the "
// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. /// "program with --v=1 or more";
// /// </pre>
// Very important: logging a message at the FATAL severity level causes ///
// the program to terminate (after the message is logged). /// We also override the standard 'assert' to use 'DLOG_ASSERT'.
// ///
// There is the special severity of DFATAL, which logs FATAL in debug mode, /// Lastly, there is:
// ERROR in normal mode. ///
// /// <pre>
/// PLOG(ERROR) << "Couldn't do foo";
/// DPLOG(ERROR) << "Couldn't do foo";
/// PLOG_IF(ERROR, cond) << "Couldn't do foo";
/// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
/// PCHECK(condition) << "Couldn't do foo";
/// DPCHECK(condition) << "Couldn't do foo";
/// </pre>
///
/// which append the last system error to the message in string form (taken from
/// GetLastError() on Windows and errno on POSIX).
///
/// The supported severity levels for macros that allow you to specify one
/// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
///
/// Very important: logging a message at the FATAL severity level causes
/// the program to terminate (after the message is logged).
///
/// There is the special severity of DFATAL, which logs FATAL in debug mode,
/// ERROR in normal mode.
///
#ifndef CEF_INCLUDE_BASE_CEF_LOGGING_H_ #ifndef CEF_INCLUDE_BASE_CEF_LOGGING_H_
#define CEF_INCLUDE_BASE_CEF_LOGGING_H_ #define CEF_INCLUDE_BASE_CEF_LOGGING_H_

View File

@ -38,8 +38,8 @@
// updated to match. // updated to match.
// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE. // ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
// Use explicit deletions instead. See the section on copyability/movability in // Use explicit deletions instead. For more information see
// //styleguide/c++/c++-dos-and-donts.md for more information. // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++-dos-and-donts.md#explicitly-declare-class-copyability_movability
// DEPRECATED: See above. Makes a class uncopyable. // DEPRECATED: See above. Makes a class uncopyable.
#define DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete #define DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete

View File

@ -49,17 +49,21 @@
namespace base { namespace base {
// Used for logging. Always an integer value. ///
/// Used for logging. Always an integer value.
///
typedef cef_platform_thread_id_t PlatformThreadId; typedef cef_platform_thread_id_t PlatformThreadId;
// Used for thread checking and debugging. ///
// Meant to be as fast as possible. /// Used for thread checking and debugging.
// These are produced by PlatformThread::CurrentRef(), and used to later /// Meant to be as fast as possible.
// check if we are on the same thread or not by using ==. These are safe /// These are produced by PlatformThread::CurrentRef(), and used to later
// to copy between threads, but can't be copied to another process as they /// check if we are on the same thread or not by using ==. These are safe
// have no meaning there. Also, the internal identifier can be re-used /// to copy between threads, but can't be copied to another process as they
// after a thread dies, so a PlatformThreadRef cannot be reliably used /// have no meaning there. Also, the internal identifier can be re-used
// to distinguish a new thread from an old, dead thread. /// after a thread dies, so a PlatformThreadRef cannot be reliably used
/// to distinguish a new thread from an old, dead thread.
///
class PlatformThreadRef { class PlatformThreadRef {
public: public:
typedef cef_platform_thread_handle_t RefType; typedef cef_platform_thread_handle_t RefType;
@ -76,18 +80,24 @@ class PlatformThreadRef {
RefType id_; RefType id_;
}; };
// A namespace for low-level thread functions. ///
// Chromium uses a class with static methods but CEF uses an actual namespace /// A namespace for low-level thread functions.
// to avoid linker problems with the sandbox libaries on Windows. /// Chromium uses a class with static methods but CEF uses an actual namespace
/// to avoid linker problems with the sandbox libaries on Windows.
///
namespace PlatformThread { namespace PlatformThread {
// Gets the current thread id, which may be useful for logging purposes. ///
/// Gets the current thread id, which may be useful for logging purposes.
///
inline PlatformThreadId CurrentId() { inline PlatformThreadId CurrentId() {
return cef_get_current_platform_thread_id(); return cef_get_current_platform_thread_id();
} }
// Gets the current thread reference, which can be used to check if ///
// we're on the right thread quickly. /// Gets the current thread reference, which can be used to check if
/// we're on the right thread quickly.
///
inline PlatformThreadRef CurrentRef() { inline PlatformThreadRef CurrentRef() {
return PlatformThreadRef(cef_get_current_platform_thread_handle()); return PlatformThreadRef(cef_get_current_platform_thread_handle());
} }

View File

@ -45,9 +45,11 @@
namespace base { namespace base {
// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>. ///
// Note that std::unique_ptr<T> has very different semantics from /// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
// std::unique_ptr<T[]>: do not use this helper for array allocations. /// Note that std::unique_ptr<T> has very different semantics from
/// std::unique_ptr<T[]>: do not use this helper for array allocations.
///
template <typename T> template <typename T>
std::unique_ptr<T> WrapUnique(T* ptr) { std::unique_ptr<T> WrapUnique(T* ptr) {
return std::unique_ptr<T>(ptr); return std::unique_ptr<T>(ptr);

View File

@ -290,52 +290,26 @@ class ScopedAllowCrossThreadRefCountAccess final {
using ScopedAllowCrossThreadRefCountAccess = using ScopedAllowCrossThreadRefCountAccess =
cef_subtle::ScopedAllowCrossThreadRefCountAccess; cef_subtle::ScopedAllowCrossThreadRefCountAccess;
// ///
// A base class for reference counted classes. Otherwise, known as a cheap /// The reference count starts from zero by default, and we intended to migrate
// knock-off of WebKit's RefCounted<T> class. To use this, just extend your /// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
// class from it like so: /// the ref counted class to opt-in.
// ///
// class MyFoo : public base::RefCounted<MyFoo> { /// If an object has start-from-one ref count, the first scoped_refptr need to
// ... /// be created by base::AdoptRef() or base::MakeRefCounted(). We can use
// private: /// base::MakeRefCounted() to create create both type of ref counted object.
// friend class base::RefCounted<MyFoo>; ///
// ~MyFoo(); /// The motivations to use start-from-one ref count are:
// }; /// - Start-from-one ref count doesn't need the ref count increment for the
// /// first reference.
// Usage Notes: /// - It can detect an invalid object acquisition for a being-deleted object
// 1. You should always make your destructor non-public, to avoid any code /// that has zero ref count. That tends to happen on custom deleter that
// deleting the object accidentally while there are references to it. /// delays the deletion.
// 2. You should always make the ref-counted base class a friend of your class, /// TODO(tzik): Implement invalid acquisition detection.
// so that it can access the destructor. /// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
// /// And start-from-one ref count is a step to merge WTF::RefCounted into
// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs /// base::RefCounted.
// to trap unsafe cross thread usage. A subclass instance of RefCounted can be ///
// passed to another execution thread only when its ref count is 1. If the ref
// count is more than 1, the RefCounted class verifies the ref updates are made
// on the same execution thread as the previous ones. The subclass can also
// manually call IsOnValidThread to trap other non-thread-safe accesses; see
// the documentation for that method.
//
//
// The reference count starts from zero by default, and we intended to migrate
// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
// the ref counted class to opt-in.
//
// If an object has start-from-one ref count, the first scoped_refptr need to be
// created by base::AdoptRef() or base::MakeRefCounted(). We can use
// base::MakeRefCounted() to create create both type of ref counted object.
//
// The motivations to use start-from-one ref count are:
// - Start-from-one ref count doesn't need the ref count increment for the
// first reference.
// - It can detect an invalid object acquisition for a being-deleted object
// that has zero ref count. That tends to happen on custom deleter that
// delays the deletion.
// TODO(tzik): Implement invalid acquisition detection.
// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
// And start-from-one ref count is a step to merge WTF::RefCounted into
// base::RefCounted.
//
#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
static constexpr ::base::cef_subtle::StartRefCountFromOneTag \ static constexpr ::base::cef_subtle::StartRefCountFromOneTag \
kRefCountPreference = ::base::cef_subtle::kStartRefCountFromOneTag kRefCountPreference = ::base::cef_subtle::kStartRefCountFromOneTag
@ -343,6 +317,10 @@ using ScopedAllowCrossThreadRefCountAccess =
template <class T, typename Traits> template <class T, typename Traits>
class RefCounted; class RefCounted;
///
/// Default traits for RefCounted<T>. Deletes the object when its ref count
/// reaches 0. Overload to delete it on a different thread etc.
///
template <typename T> template <typename T>
struct DefaultRefCountedTraits { struct DefaultRefCountedTraits {
static void Destruct(const T* x) { static void Destruct(const T* x) {
@ -350,6 +328,34 @@ struct DefaultRefCountedTraits {
} }
}; };
///
/// A base class for reference counted classes. Otherwise, known as a cheap
/// knock-off of WebKit's RefCounted<T> class. To use this, just extend your
/// class from it like so:
///
/// <pre>
/// class MyFoo : public base::RefCounted<MyFoo> {
/// ...
/// private:
/// friend class base::RefCounted<MyFoo>;
/// ~MyFoo();
/// };
/// </pre>
///
/// Usage Notes:
/// 1. You should always make your destructor non-public, to avoid any code
/// deleting the object accidentally while there are references to it.
/// 2. You should always make the ref-counted base class a friend of your class,
/// so that it can access the destructor.
///
/// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
/// to trap unsafe cross thread usage. A subclass instance of RefCounted can be
/// passed to another execution thread only when its ref count is 1. If the ref
/// count is more than 1, the RefCounted class verifies the ref updates are made
/// on the same execution thread as the previous ones. The subclass can also
/// manually call IsOnValidThread to trap other non-thread-safe accesses; see
/// the documentation for that method.
///
template <class T, typename Traits = DefaultRefCountedTraits<T>> template <class T, typename Traits = DefaultRefCountedTraits<T>>
class RefCounted : public cef_subtle::RefCountedBase { class RefCounted : public cef_subtle::RefCountedBase {
public: public:
@ -389,8 +395,10 @@ class RefCounted : public cef_subtle::RefCountedBase {
template <class T, typename Traits> template <class T, typename Traits>
class RefCountedThreadSafe; class RefCountedThreadSafe;
// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref ///
// count reaches 0. Overload to delete it on a different thread etc. /// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
/// count reaches 0. Overload to delete it on a different thread etc.
///
template <typename T> template <typename T>
struct DefaultRefCountedThreadSafeTraits { struct DefaultRefCountedThreadSafeTraits {
static void Destruct(const T* x) { static void Destruct(const T* x) {
@ -402,21 +410,26 @@ struct DefaultRefCountedThreadSafeTraits {
} }
}; };
// ///
// A thread-safe variant of RefCounted<T> /// A thread-safe variant of RefCounted<T>
// ///
// class MyFoo : public base::RefCountedThreadSafe<MyFoo> { /// <pre>
// ... /// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
// }; /// ...
// /// };
// If you're using the default trait, then you should add compile time /// </pre>
// asserts that no one else is deleting your object. i.e. ///
// private: /// If you're using the default trait, then you should add compile time
// friend class base::RefCountedThreadSafe<MyFoo>; /// asserts that no one else is deleting your object. i.e.
// ~MyFoo(); /// <pre>
// /// private:
// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe /// friend class base::RefCountedThreadSafe<MyFoo>;
// too. See the comment above the RefCounted definition for details. /// ~MyFoo();
/// </pre>
///
/// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
/// too. See the comment above the RefCounted definition for details.
///
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>> template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
class RefCountedThreadSafe : public cef_subtle::RefCountedThreadSafeBase { class RefCountedThreadSafe : public cef_subtle::RefCountedThreadSafeBase {
public: public:
@ -457,10 +470,10 @@ class RefCountedThreadSafe : public cef_subtle::RefCountedThreadSafeBase {
} }
}; };
// ///
// A thread-safe wrapper for some piece of data so we can place other /// A thread-safe wrapper for some piece of data so we can place other
// things in scoped_refptrs<>. /// things in scoped_refptrs<>.
// ///
template <typename T> template <typename T>
class RefCountedData class RefCountedData
: public base::RefCountedThreadSafe<base::RefCountedData<T>> { : public base::RefCountedThreadSafe<base::RefCountedData<T>> {

View File

@ -142,68 +142,76 @@ scoped_refptr<T> WrapRefCounted(T* t) {
} // namespace base } // namespace base
// ///
// A smart pointer class for reference counted objects. Use this class instead /// A smart pointer class for reference counted objects. Use this class instead
// of calling AddRef and Release manually on a reference counted object to /// of calling AddRef and Release manually on a reference counted object to
// avoid common memory leaks caused by forgetting to Release an object /// avoid common memory leaks caused by forgetting to Release an object
// reference. Sample usage: /// reference. Sample usage:
// ///
// class MyFoo : public RefCounted<MyFoo> { /// <pre>
// ... /// class MyFoo : public RefCounted<MyFoo> {
// private: /// ...
// friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>. /// private:
// ~MyFoo(); // Destructor must be private/protected. /// friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
// }; /// ~MyFoo(); // Destructor must be
// /// private/protected.
// void some_function() { /// };
// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>(); ///
// foo->Method(param); /// void some_function() {
// // |foo| is released when this function returns /// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
// } /// foo->Method(param);
// /// // |foo| is released when this function returns
// void some_other_function() { /// }
// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>(); ///
// ... /// void some_other_function() {
// foo.reset(); // explicitly releases |foo| /// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
// ... /// ...
// if (foo) /// foo.reset(); // explicitly releases |foo|
// foo->Method(param); /// ...
// } /// if (foo)
// /// foo->Method(param);
// The above examples show how scoped_refptr<T> acts like a pointer to T. /// }
// Given two scoped_refptr<T> classes, it is also possible to exchange /// </pre>
// references between the two objects, like so: ///
// /// The above examples show how scoped_refptr<T> acts like a pointer to T.
// { /// Given two scoped_refptr<T> classes, it is also possible to exchange
// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>(); /// references between the two objects, like so:
// scoped_refptr<MyFoo> b; ///
// /// <pre>
// b.swap(a); /// {
// // now, |b| references the MyFoo object, and |a| references nullptr. /// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
// } /// scoped_refptr<MyFoo> b;
// ///
// To make both |a| and |b| in the above example reference the same MyFoo /// b.swap(a);
// object, simply use the assignment operator: /// // now, |b| references the MyFoo object, and |a| references nullptr.
// /// }
// { /// </pre>
// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>(); ///
// scoped_refptr<MyFoo> b; /// To make both |a| and |b| in the above example reference the same MyFoo
// /// object, simply use the assignment operator:
// b = a; ///
// // now, |a| and |b| each own a reference to the same MyFoo object. /// <pre>
// } /// {
// /// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
// Also see Chromium's ownership and calling conventions: /// scoped_refptr<MyFoo> b;
// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions ///
// Specifically: /// b = a;
// If the function (at least sometimes) takes a ref on a refcounted object, /// // now, |a| and |b| each own a reference to the same MyFoo object.
// declare the param as scoped_refptr<T>. The caller can decide whether it /// }
// wishes to transfer ownership (by calling std::move(t) when passing t) or /// </pre>
// retain its ref (by simply passing t directly). ///
// In other words, use scoped_refptr like you would a std::unique_ptr except /// Also see Chromium's ownership and calling conventions:
// in the odd case where it's required to hold on to a ref while handing one /// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
// to another component (if a component merely needs to use t on the stack /// Specifically:
// without keeping a ref: pass t as a raw T*). /// If the function (at least sometimes) takes a ref on a refcounted object,
/// declare the param as scoped_refptr<T>. The caller can decide whether it
/// wishes to transfer ownership (by calling std::move(t) when passing t) or
/// retain its ref (by simply passing t directly).
/// In other words, use scoped_refptr like you would a std::unique_ptr except
/// in the odd case where it's required to hold on to a ref while handing one
/// to another component (if a component merely needs to use t on the stack
/// without keeping a ref: pass t as a raw T*).
///
template <class T> template <class T>
class TRIVIAL_ABI scoped_refptr { class TRIVIAL_ABI scoped_refptr {
public: public:

View File

@ -28,40 +28,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains ownership
// of a reference to any type that is maintained by Retain and Release methods.
//
// The Traits structure must provide the Retain and Release methods for type T.
// A default ScopedTypeRefTraits is used but not defined, and should be defined
// for each type to use this interface. For example, an appropriate definition
// of ScopedTypeRefTraits for CGLContextObj would be:
//
// template<>
// struct ScopedTypeRefTraits<CGLContextObj> {
// static CGLContextObj InvalidValue() { return nullptr; }
// static CGLContextObj Retain(CGLContextObj object) {
// CGLContextRetain(object);
// return object;
// }
// static void Release(CGLContextObj object) { CGLContextRelease(object); }
// };
//
// For the many types that have pass-by-pointer create functions, the function
// InitializeInto() is provided to allow direct initialization and assumption
// of ownership of the object. For example, continuing to use the above
// CGLContextObj specialization:
//
// base::ScopedTypeRef<CGLContextObj> context;
// CGLCreateContext(pixel_format, share_group, context.InitializeInto());
//
// For initialization with an existing object, the caller may specify whether
// the ScopedTypeRef<> being initialized is assuming the caller's existing
// ownership of the object (and should not call Retain in initialization) or if
// it should not assume this ownership and must create its own (by calling
// Retain in initialization). This behavior is based on the |policy| parameter,
// with |ASSUME| for the former and |RETAIN| for the latter. The default policy
// is to |ASSUME|.
#ifndef CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_ #ifndef CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_
#define CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_ #define CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_
#pragma once #pragma once
@ -82,6 +48,46 @@ namespace base {
template <typename T> template <typename T>
struct ScopedTypeRefTraits; struct ScopedTypeRefTraits;
///
/// ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains
/// ownership of a reference to any type that is maintained by Retain and
/// Release methods.
///
/// The Traits structure must provide the Retain and Release methods for type T.
/// A default ScopedTypeRefTraits is used but not defined, and should be defined
/// for each type to use this interface. For example, an appropriate definition
/// of ScopedTypeRefTraits for CGLContextObj would be:
///
/// <pre>
/// template<>
/// struct ScopedTypeRefTraits<CGLContextObj> {
/// static CGLContextObj InvalidValue() { return nullptr; }
/// static CGLContextObj Retain(CGLContextObj object) {
/// CGLContextRetain(object);
/// return object;
/// }
/// static void Release(CGLContextObj object) { CGLContextRelease(object); }
/// };
/// </pre>
///
/// For the many types that have pass-by-pointer create functions, the function
/// InitializeInto() is provided to allow direct initialization and assumption
/// of ownership of the object. For example, continuing to use the above
/// CGLContextObj specialization:
///
/// <pre>
/// base::ScopedTypeRef<CGLContextObj> context;
/// CGLCreateContext(pixel_format, share_group, context.InitializeInto());
/// </pre>
///
/// For initialization with an existing object, the caller may specify whether
/// the ScopedTypeRef<> being initialized is assuming the caller's existing
/// ownership of the object (and should not call Retain in initialization) or if
/// it should not assume this ownership and must create its own (by calling
/// Retain in initialization). This behavior is based on the |policy| parameter,
/// with |ASSUME| for the former and |RETAIN| for the latter. The default policy
/// is to |ASSUME|.
///
template <typename T, typename Traits = ScopedTypeRefTraits<T>> template <typename T, typename Traits = ScopedTypeRefTraits<T>>
class ScopedTypeRef { class ScopedTypeRef {
public: public:

View File

@ -43,10 +43,12 @@
#include "include/base/cef_logging.h" #include "include/base/cef_logging.h"
#include "include/base/internal/cef_thread_checker_impl.h" #include "include/base/internal/cef_thread_checker_impl.h"
// Apart from debug builds, we also enable the thread checker in ///
// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots /// Apart from debug builds, we also enable the thread checker in
// with this define will get the same level of thread checking as /// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
// debug bots. /// with this define will get the same level of thread checking as
/// debug bots.
///
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
#define ENABLE_THREAD_CHECKER 1 #define ENABLE_THREAD_CHECKER 1
#else #else
@ -57,10 +59,12 @@ namespace base {
namespace cef_internal { namespace cef_internal {
// Do nothing implementation, for use in release mode. ///
// /// Do nothing implementation, for use in release mode.
// Note: You should almost always use the ThreadChecker class to get the ///
// right version for your build configuration. /// Note: You should almost always use the ThreadChecker class to get the
/// right version for your build configuration.
///
class ThreadCheckerDoNothing { class ThreadCheckerDoNothing {
public: public:
bool CalledOnValidThread() const { return true; } bool CalledOnValidThread() const { return true; }
@ -70,37 +74,42 @@ class ThreadCheckerDoNothing {
} // namespace cef_internal } // namespace cef_internal
// ThreadChecker is a helper class used to help verify that some methods of a ///
// class are called from the same thread. It provides identical functionality to /// ThreadChecker is a helper class used to help verify that some methods of a
// base::NonThreadSafe, but it is meant to be held as a member variable, rather /// class are called from the same thread. It provides identical functionality
// than inherited from base::NonThreadSafe. /// to base::NonThreadSafe, but it is meant to be held as a member variable,
// /// rather than inherited from base::NonThreadSafe.
// While inheriting from base::NonThreadSafe may give a clear indication about ///
// the thread-safety of a class, it may also lead to violations of the style /// While inheriting from base::NonThreadSafe may give a clear indication about
// guide with regard to multiple inheritance. The choice between having a /// the thread-safety of a class, it may also lead to violations of the style
// ThreadChecker member and inheriting from base::NonThreadSafe should be based /// guide with regard to multiple inheritance. The choice between having a
// on whether: /// ThreadChecker member and inheriting from base::NonThreadSafe should be based
// - Derived classes need to know the thread they belong to, as opposed to /// on whether:
// having that functionality fully encapsulated in the base class. /// - Derived classes need to know the thread they belong to, as opposed to
// - Derived classes should be able to reassign the base class to another /// having that functionality fully encapsulated in the base class.
// thread, via DetachFromThread. /// - Derived classes should be able to reassign the base class to another
// /// thread, via DetachFromThread.
// If neither of these are true, then having a ThreadChecker member and calling ///
// CalledOnValidThread is the preferable solution. /// If neither of these are true, then having a ThreadChecker member and calling
// /// CalledOnValidThread is the preferable solution.
// Example: ///
// class MyClass { /// Example:
// public: ///
// void Foo() { /// <pre>
// DCHECK(thread_checker_.CalledOnValidThread()); /// class MyClass {
// ... (do stuff) ... /// public:
// } /// void Foo() {
// /// DCHECK(thread_checker_.CalledOnValidThread());
// private: /// ... (do stuff) ...
// ThreadChecker thread_checker_; /// }
// } ///
// /// private:
// In Release mode, CalledOnValidThread will always return true. /// ThreadChecker thread_checker_;
/// }
/// </pre>
///
/// In Release mode, CalledOnValidThread will always return true.
///
#if ENABLE_THREAD_CHECKER #if ENABLE_THREAD_CHECKER
class ThreadChecker : public cef_internal::ThreadCheckerImpl {}; class ThreadChecker : public cef_internal::ThreadCheckerImpl {};
#else #else

View File

@ -29,111 +29,133 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/// ///
// Trace events are for tracking application performance and resource usage. /// \file
// Macros are provided to track: /// Trace events are for tracking application performance and resource usage.
// Begin and end of function calls /// Macros are provided to track:
// Counters /// Begin and end of function calls
// /// Counters
// Events are issued against categories. Whereas LOG's categories are statically ///
// defined, TRACE categories are created implicitly with a string. For example: /// Events are issued against categories. Whereas LOG's categories are
// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") /// statically defined, TRACE categories are created implicitly with a string.
// /// For example: <pre>
// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: /// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") /// </pre>
// doSomethingCostly() ///
// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") /// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
// Note: Our tools can't always determine the correct BEGIN/END pairs unless /// <pre>
// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you /// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
// need them to be in separate scopes. /// doSomethingCostly()
// /// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
// A common use case is to trace entire function scopes. This issues a trace /// </pre>
// BEGIN and END automatically: /// Note: Our tools can't always determine the correct BEGIN/END pairs unless
// void doSomethingCostly() { /// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); /// need them to be in separate scopes.
// ... ///
// } /// A common use case is to trace entire function scopes. This issues a trace
// /// BEGIN and END automatically:
// Additional parameters can be associated with an event: /// <pre>
// void doSomethingCostly2(int howMuch) { /// void doSomethingCostly() {
// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", /// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
// "howMuch", howMuch); /// ...
// ... /// }
// } /// </pre>
// ///
// The trace system will automatically add to this information the current /// Additional parameters can be associated with an event:
// process id, thread id, and a timestamp in microseconds. /// <pre>
// /// void doSomethingCostly2(int howMuch) {
// To trace an asynchronous procedure such as an IPC send/receive, use /// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
// ASYNC_BEGIN and ASYNC_END: /// "howMuch", howMuch);
// [single threaded sender code] /// ...
// static int send_count = 0; /// }
// ++send_count; /// </pre>
// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); ///
// Send(new MyMessage(send_count)); /// The trace system will automatically add to this information the current
// [receive code] /// process id, thread id, and a timestamp in microseconds.
// void OnMyMessage(send_count) { ///
// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); /// To trace an asynchronous procedure such as an IPC send/receive, use
// } /// ASYNC_BEGIN and ASYNC_END:
// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. /// <pre>
// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. /// [single threaded sender code]
// Pointers can be used for the ID parameter, and they will be mangled /// static int send_count = 0;
// internally so that the same pointer on two different processes will not /// ++send_count;
// match. For example: /// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
// class MyTracedClass { /// Send(new MyMessage(send_count));
// public: /// [receive code]
// MyTracedClass() { /// void OnMyMessage(send_count) {
// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); /// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
// } /// }
// ~MyTracedClass() { /// </pre>
// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); /// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
// } /// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
// } /// Pointers can be used for the ID parameter, and they will be mangled
// /// internally so that the same pointer on two different processes will not
// The trace event also supports counters, which is a way to track a quantity /// match. For example:
// as it varies over time. Counters are created with the following macro: /// <pre>
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); /// class MyTracedClass {
// /// public:
// Counters are process-specific. The macro itself can be issued from any /// MyTracedClass() {
// thread, however. /// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
// /// }
// Sometimes, you want to track two counters at once. You can do this with two /// ~MyTracedClass() {
// counter macros: /// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); /// }
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); /// }
// Or you can do it with a combined macro: /// </pre>
// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", ///
// "bytesPinned", g_myCounterValue[0], /// The trace event also supports counters, which is a way to track a quantity
// "bytesAllocated", g_myCounterValue[1]); /// as it varies over time. Counters are created with the following macro:
// This indicates to the tracing UI that these counters should be displayed /// <pre>
// in a single graph, as a summed area chart. /// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
// /// </pre>
// Since counters are in a global namespace, you may want to disembiguate with a ///
// unique ID, by using the TRACE_COUNTER_ID* variations. /// Counters are process-specific. The macro itself can be issued from any
// /// thread, however.
// By default, trace collection is compiled in, but turned off at runtime. ///
// Collecting trace data is the responsibility of the embedding application. In /// Sometimes, you want to track two counters at once. You can do this with two
// CEF's case, calling BeginTracing will turn on tracing on all active /// counter macros:
// processes. /// <pre>
// /// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
// /// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
// Memory scoping note: /// </pre>
// Tracing copies the pointers, not the string content, of the strings passed /// Or you can do it with a combined macro:
// in for category, name, and arg_names. Thus, the following code will cause /// <pre>
// problems: /// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
// char* str = strdup("impprtantName"); /// "bytesPinned", g_myCounterValue[0],
// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! /// "bytesAllocated", g_myCounterValue[1]);
// free(str); // Trace system now has dangling pointer /// </pre>
// /// This indicates to the tracing UI that these counters should be displayed
// To avoid this issue with the |name| and |arg_name| parameters, use the /// in a single graph, as a summed area chart.
// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime ///
// overhead. /// Since counters are in a global namespace, you may want to disembiguate with
// Notes: The category must always be in a long-lived char* (i.e. static const). /// a unique ID, by using the TRACE_COUNTER_ID* variations.
// The |arg_values|, when used, are always deep copied with the _COPY ///
// macros. /// By default, trace collection is compiled in, but turned off at runtime.
// /// Collecting trace data is the responsibility of the embedding application. In
// /// CEF's case, calling BeginTracing will turn on tracing on all active
// Thread Safety: /// processes.
// All macros are thread safe and can be used from any process. ///
///
/// Memory scoping note:
/// Tracing copies the pointers, not the string content, of the strings passed
/// in for category, name, and arg_names. Thus, the following code will cause
/// problems:
/// <pre>
/// char* str = strdup("impprtantName");
/// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD!
/// free(str); // Trace system now has dangling pointer
/// </pre>
///
/// To avoid this issue with the |name| and |arg_name| parameters, use the
/// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime
/// overhead.
///
/// Notes: The category must always be in a long-lived char* (i.e. static
/// const). The |arg_values|, when used, are always deep copied with
/// the _COPY macros.
///
///
/// Thread Safety:
/// All macros are thread safe and can be used from any process.
/// ///
#ifndef CEF_INCLUDE_BASE_CEF_TRACE_EVENT_H_ #ifndef CEF_INCLUDE_BASE_CEF_TRACE_EVENT_H_
@ -141,7 +163,7 @@
#pragma once #pragma once
#if defined(USING_CHROMIUM_INCLUDES) #if defined(USING_CHROMIUM_INCLUDES)
// When building CEF include the Chromium header directly. /// When building CEF include the Chromium header directly.
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#else // !USING_CHROMIUM_INCLUDES #else // !USING_CHROMIUM_INCLUDES
// The following is substantially similar to the Chromium implementation. // The following is substantially similar to the Chromium implementation.
@ -150,11 +172,13 @@
#include "include/internal/cef_trace_event_internal.h" #include "include/internal/cef_trace_event_internal.h"
// Records a pair of begin and end events called "name" for the current ///
// scope, with 0, 1 or 2 associated arguments. If the category is not /// Records a pair of begin and end events called "name" for the current
// enabled, then this does nothing. /// scope, with 0, 1 or 2 associated arguments. If the category is not
// - category and name strings must have application lifetime (statics or /// enabled, then this does nothing.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_EVENT0(category, name) \ #define TRACE_EVENT0(category, name) \
cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false); \ cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false); \
CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name) CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name)
@ -179,11 +203,13 @@
cef_trace_event::CefTraceEndOnScopeClose CEF_INTERNAL_TRACE_EVENT_UID( \ cef_trace_event::CefTraceEndOnScopeClose CEF_INTERNAL_TRACE_EVENT_UID( \
profileScope)(category, name) profileScope)(category, name)
// Records a single event called "name" immediately, with 0, 1 or 2 ///
// associated arguments. If the category is not enabled, then this /// Records a single event called "name" immediately, with 0, 1 or 2
// does nothing. /// associated arguments. If the category is not enabled, then this
// - category and name strings must have application lifetime (statics or /// does nothing.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_EVENT_INSTANT0(category, name) \ #define TRACE_EVENT_INSTANT0(category, name) \
cef_trace_event_instant(category, name, NULL, 0, NULL, 0, false) cef_trace_event_instant(category, name, NULL, 0, NULL, 0, false)
#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ #define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
@ -201,11 +227,13 @@
cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \ cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \
arg2_val, true) arg2_val, true)
// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 ///
// associated arguments. If the category is not enabled, then this /// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
// does nothing. /// associated arguments. If the category is not enabled, then this
// - category and name strings must have application lifetime (statics or /// does nothing.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_EVENT_BEGIN0(category, name) \ #define TRACE_EVENT_BEGIN0(category, name) \
cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false) cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false)
#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ #define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \
@ -223,10 +251,12 @@
cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \ cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \
arg2_val, true) arg2_val, true)
// Records a single END event for "name" immediately. If the category ///
// is not enabled, then this does nothing. /// Records a single END event for "name" immediately. If the category
// - category and name strings must have application lifetime (statics or /// is not enabled, then this does nothing.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_EVENT_END0(category, name) \ #define TRACE_EVENT_END0(category, name) \
cef_trace_event_end(category, name, NULL, 0, NULL, 0, false) cef_trace_event_end(category, name, NULL, 0, NULL, 0, false)
#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ #define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \
@ -244,20 +274,24 @@
cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \ cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \
arg2_val, true) arg2_val, true)
// Records the value of a counter called "name" immediately. Value ///
// must be representable as a 32 bit integer. /// Records the value of a counter called "name" immediately. Value
// - category and name strings must have application lifetime (statics or /// must be representable as a 32 bit integer.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_COUNTER1(category, name, value) \ #define TRACE_COUNTER1(category, name, value) \
cef_trace_counter(category, name, NULL, value, NULL, 0, false) cef_trace_counter(category, name, NULL, value, NULL, 0, false)
#define TRACE_COPY_COUNTER1(category, name, value) \ #define TRACE_COPY_COUNTER1(category, name, value) \
cef_trace_counter(category, name, NULL, value, NULL, 0, true) cef_trace_counter(category, name, NULL, value, NULL, 0, true)
// Records the values of a multi-parted counter called "name" immediately. ///
// The UI will treat value1 and value2 as parts of a whole, displaying their /// Records the values of a multi-parted counter called "name" immediately.
// values as a stacked-bar chart. /// The UI will treat value1 and value2 as parts of a whole, displaying their
// - category and name strings must have application lifetime (statics or /// values as a stacked-bar chart.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
/// literals). They may not include " chars.
///
#define TRACE_COUNTER2(category, name, value1_name, value1_val, value2_name, \ #define TRACE_COUNTER2(category, name, value1_name, value1_val, value2_name, \
value2_val) \ value2_val) \
cef_trace_counter(category, name, value1_name, value1_val, value2_name, \ cef_trace_counter(category, name, value1_name, value1_val, value2_name, \
@ -267,28 +301,32 @@
cef_trace_counter(category, name, value1_name, value1_val, value2_name, \ cef_trace_counter(category, name, value1_name, value1_val, value2_name, \
value2_val, true) value2_val, true)
// Records the value of a counter called "name" immediately. Value ///
// must be representable as a 32 bit integer. /// Records the value of a counter called "name" immediately. Value
// - category and name strings must have application lifetime (statics or /// must be representable as a 32 bit integer.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
// - |id| is used to disambiguate counters with the same name. It must either /// literals). They may not include " chars.
// be a pointer or an integer value up to 64 bits. If it's a pointer, the /// - |id| is used to disambiguate counters with the same name. It must either
// bits will be xored with a hash of the process ID so that the same pointer /// be a pointer or an integer value up to 64 bits. If it's a pointer, the
// on two different processes will not collide. /// bits will be xored with a hash of the process ID so that the same pointer
/// on two different processes will not collide.
///
#define TRACE_COUNTER_ID1(category, name, id, value) \ #define TRACE_COUNTER_ID1(category, name, id, value) \
cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, false) cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, false)
#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ #define TRACE_COPY_COUNTER_ID1(category, name, id, value) \
cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, true) cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, true)
// Records the values of a multi-parted counter called "name" immediately. ///
// The UI will treat value1 and value2 as parts of a whole, displaying their /// Records the values of a multi-parted counter called "name" immediately.
// values as a stacked-bar chart. /// The UI will treat value1 and value2 as parts of a whole, displaying their
// - category and name strings must have application lifetime (statics or /// values as a stacked-bar chart.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
// - |id| is used to disambiguate counters with the same name. It must either /// literals). They may not include " chars.
// be a pointer or an integer value up to 64 bits. If it's a pointer, the /// - |id| is used to disambiguate counters with the same name. It must either
// bits will be xored with a hash of the process ID so that the same pointer /// be a pointer or an integer value up to 64 bits. If it's a pointer, the
// on two different processes will not collide. /// bits will be xored with a hash of the process ID so that the same pointer
/// on two different processes will not collide.
///
#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ #define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \
value2_name, value2_val) \ value2_name, value2_val) \
cef_trace_counter_id(category, name, id, value1_name, value1_val, \ cef_trace_counter_id(category, name, id, value1_name, value1_val, \
@ -298,22 +336,24 @@
cef_trace_counter_id(category, name, id, value1_name, value1_val, \ cef_trace_counter_id(category, name, id, value1_name, value1_val, \
value2_name, value2_val, true) value2_name, value2_val, true)
// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 ///
// associated arguments. If the category is not enabled, then this /// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
// does nothing. /// associated arguments. If the category is not enabled, then this
// - category and name strings must have application lifetime (statics or /// does nothing.
// literals). They may not include " chars. /// - category and name strings must have application lifetime (statics or
// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. /// literals). They may not include " chars.
// ASYNC events are considered to match if their category, name and id values /// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event.
// all match. |id| must either be a pointer or an integer value up to 64 /// ASYNC events are considered to match if their category, name and id values
// bits. If it's a pointer, the bits will be xored with a hash of the process /// all match. |id| must either be a pointer or an integer value up to 64
// ID sothat the same pointer on two different processes will not collide. /// bits. If it's a pointer, the bits will be xored with a hash of the process
// An asynchronous operation can consist of multiple phases. The first phase is /// ID sothat the same pointer on two different processes will not collide.
// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the /// An asynchronous operation can consist of multiple phases. The first phase is
// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END. /// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
// An async operation can span threads and processes, but all events in that /// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END.
// operation must use the same |name| and |id|. Each event can have its own /// An async operation can span threads and processes, but all events in that
// args. /// operation must use the same |name| and |id|. Each event can have its own
/// args.
///
#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ #define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \
cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, false) cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, false)
#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ #define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
@ -333,12 +373,14 @@
cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \ cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val, true) arg2_name, arg2_val, true)
// Records a single ASYNC_STEP_INTO event for |step| immediately. If the ///
// category is not enabled, then this does nothing. The |name| and |id| must /// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
// match the ASYNC_BEGIN event above. The |step| param identifies this step /// category is not enabled, then this does nothing. The |name| and |id| must
// within the async event. This should be called at the beginning of the next /// match the ASYNC_BEGIN event above. The |step| param identifies this step
// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any /// within the async event. This should be called at the beginning of the next
// ASYNC_STEP_PAST events. /// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
/// ASYNC_STEP_PAST events.
///
#define TRACE_EVENT_ASYNC_STEP_INTO0(category, name, id, step) \ #define TRACE_EVENT_ASYNC_STEP_INTO0(category, name, id, step) \
cef_trace_event_async_step_into(category, name, id, step, NULL, 0, false) cef_trace_event_async_step_into(category, name, id, step, NULL, 0, false)
#define TRACE_EVENT_ASYNC_STEP_INTO1(category, name, id, step, arg1_name, \ #define TRACE_EVENT_ASYNC_STEP_INTO1(category, name, id, step, arg1_name, \
@ -352,12 +394,14 @@
cef_trace_event_async_step_into(category, name, id, step, arg1_name, \ cef_trace_event_async_step_into(category, name, id, step, arg1_name, \
arg1_val, true) arg1_val, true)
// Records a single ASYNC_STEP_PAST event for |step| immediately. If the ///
// category is not enabled, then this does nothing. The |name| and |id| must /// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
// match the ASYNC_BEGIN event above. The |step| param identifies this step /// category is not enabled, then this does nothing. The |name| and |id| must
// within the async event. This should be called at the beginning of the next /// match the ASYNC_BEGIN event above. The |step| param identifies this step
// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any /// within the async event. This should be called at the beginning of the next
// ASYNC_STEP_INTO events. /// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
/// ASYNC_STEP_INTO events.
///
#define TRACE_EVENT_ASYNC_STEP_PAST0(category, name, id, step) \ #define TRACE_EVENT_ASYNC_STEP_PAST0(category, name, id, step) \
cef_trace_event_async_step_past(category, name, id, step, NULL, 0, false) cef_trace_event_async_step_past(category, name, id, step, NULL, 0, false)
#define TRACE_EVENT_ASYNC_STEP_PAST1(category, name, id, step, arg1_name, \ #define TRACE_EVENT_ASYNC_STEP_PAST1(category, name, id, step, arg1_name, \
@ -371,8 +415,10 @@
cef_trace_event_async_step_past(category, name, id, step, arg1_name, \ cef_trace_event_async_step_past(category, name, id, step, arg1_name, \
arg1_val, true) arg1_val, true)
// Records a single ASYNC_END event for "name" immediately. If the category ///
// is not enabled, then this does nothing. /// Records a single ASYNC_END event for "name" immediately. If the category
/// is not enabled, then this does nothing.
///
#define TRACE_EVENT_ASYNC_END0(category, name, id) \ #define TRACE_EVENT_ASYNC_END0(category, name, id) \
cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, false) cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, false)
#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ #define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
@ -394,7 +440,9 @@
namespace cef_trace_event { namespace cef_trace_event {
// Used by TRACE_EVENTx macro. Do not use directly. ///
/// Used by TRACE_EVENTx macro. Do not use directly.
///
class CefTraceEndOnScopeClose { class CefTraceEndOnScopeClose {
public: public:
CefTraceEndOnScopeClose(const char* category, const char* name) CefTraceEndOnScopeClose(const char* category, const char* name)
@ -408,7 +456,7 @@ class CefTraceEndOnScopeClose {
const char* name_; const char* name_;
}; };
} // cef_trace_event } // namespace cef_trace_event
#endif // !USING_CHROMIUM_INCLUDES #endif // !USING_CHROMIUM_INCLUDES

View File

@ -28,25 +28,30 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Use std::tuple as tuple type. This file contains helper functions for ///
// working with std::tuples. /// \file
// The functions DispatchToMethod and DispatchToFunction take a function pointer /// Use std::tuple as tuple type. This file contains helper functions for
// or instance and method pointer, and unpack a tuple into arguments to the /// working with std::tuples.
// call. /// The functions DispatchToMethod and DispatchToFunction take a function
// /// pointer or instance and method pointer, and unpack a tuple into arguments to
// Example usage: /// the call.
// // These two methods of creating a Tuple are identical. ///
// std::tuple<int, const char*> tuple_a(1, "wee"); /// Example usage:
// std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee"); /// <pre>
// /// // These two methods of creating a Tuple are identical.
// void SomeFunc(int a, const char* b) { } /// std::tuple<int, const char*> tuple_a(1, "wee");
// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee") /// std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee");
// DispatchToFunction( ///
// &SomeFunc, std::make_tuple(10, "foo")); // SomeFunc(10, "foo") /// void SomeFunc(int a, const char* b) { }
// /// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
// struct { void SomeMeth(int a, int b, int c) { } } foo; /// DispatchToFunction(
// DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3)); /// &SomeFunc, std::make_tuple(10, "foo")); // SomeFunc(10, "foo")
// // foo->SomeMeth(1, 2, 3); ///
/// struct { void SomeMeth(int a, int b, int c) { } } foo;
/// DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3));
/// // foo->SomeMeth(1, 2, 3);
/// </pre>
///
#ifndef CEF_INCLUDE_BASE_CEF_TUPLE_H_ #ifndef CEF_INCLUDE_BASE_CEF_TUPLE_H_
#define CEF_INCLUDE_BASE_CEF_TUPLE_H_ #define CEF_INCLUDE_BASE_CEF_TUPLE_H_
@ -88,9 +93,7 @@ inline void DispatchToMethodImpl(const ObjT& obj,
} }
template <typename ObjT, typename Method, typename Tuple> template <typename ObjT, typename Method, typename Tuple>
inline void DispatchToMethod(const ObjT& obj, inline void DispatchToMethod(const ObjT& obj, Method method, Tuple&& args) {
Method method,
Tuple&& args) {
constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value; constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
DispatchToMethodImpl(obj, method, std::forward<Tuple>(args), DispatchToMethodImpl(obj, method, std::forward<Tuple>(args),
std::make_index_sequence<size>()); std::make_index_sequence<size>());

View File

@ -28,69 +28,73 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Weak pointers are pointers to an object that do not affect its lifetime, ///
// and which may be invalidated (i.e. reset to nullptr) by the object, or its /// \file
// owner, at any time, most commonly when the object is about to be deleted. /// Weak pointers are pointers to an object that do not affect its lifetime.
/// They may be invalidated (i.e. reset to nullptr) by the object, or its
// Weak pointers are useful when an object needs to be accessed safely by one /// owner, at any time, most commonly when the object is about to be deleted.
// or more objects other than its owner, and those callers can cope with the ///
// object vanishing and e.g. tasks posted to it being silently dropped. /// Weak pointers are useful when an object needs to be accessed safely by one
// Reference-counting such an object would complicate the ownership graph and /// or more objects other than its owner, and those callers can cope with the
// make it harder to reason about the object's lifetime. /// object vanishing and e.g. tasks posted to it being silently dropped.
/// Reference-counting such an object would complicate the ownership graph and
// EXAMPLE: /// make it harder to reason about the object's lifetime.
// ///
// class Controller { /// EXAMPLE:
// public: ///
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } /// <pre>
// void WorkComplete(const Result& result) { ... } /// class Controller {
// private: /// public:
// // Member variables should appear before the WeakPtrFactory, to ensure /// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// // that any WeakPtrs to Controller are invalidated before its members /// void WorkComplete(const Result& result) { ... }
// // variable's destructors are executed, rendering them invalid. /// private:
// WeakPtrFactory<Controller> weak_factory_{this}; /// // Member variables should appear before the WeakPtrFactory, to ensure
// }; /// // that any WeakPtrs to Controller are invalidated before its members
// /// // variable's destructors are executed, rendering them invalid.
// class Worker { /// WeakPtrFactory<Controller> weak_factory_{this};
// public: /// };
// static void StartNew(WeakPtr<Controller> controller) { ///
// Worker* worker = new Worker(std::move(controller)); /// class Worker {
// // Kick off asynchronous processing... /// public:
// } /// static void StartNew(WeakPtr<Controller> controller) {
// private: /// Worker* worker = new Worker(std::move(controller));
// Worker(WeakPtr<Controller> controller) /// // Kick off asynchronous processing...
// : controller_(std::move(controller)) {} /// }
// void DidCompleteAsynchronousProcessing(const Result& result) { /// private:
// if (controller_) /// Worker(WeakPtr<Controller> controller)
// controller_->WorkComplete(result); /// : controller_(std::move(controller)) {}
// } /// void DidCompleteAsynchronousProcessing(const Result& result) {
// WeakPtr<Controller> controller_; /// if (controller_)
// }; /// controller_->WorkComplete(result);
// /// }
// With this implementation a caller may use SpawnWorker() to dispatch multiple /// WeakPtr<Controller> controller_;
// Workers and subsequently delete the Controller, without waiting for all /// };
// Workers to have completed. /// </pre>
///
// ------------------------- IMPORTANT: Thread-safety ------------------------- /// With this implementation a caller may use SpawnWorker() to dispatch multiple
/// Workers and subsequently delete the Controller, without waiting for all
// Weak pointers may be passed safely between threads, but must always be /// Workers to have completed.
// dereferenced and invalidated on the same ThreaddTaskRunner otherwise ///
// checking the pointer would be racey. /// <b>IMPORTANT: Thread-safety</b>
// ///
// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory /// Weak pointers may be passed safely between threads, but must always be
// is dereferenced, the factory and its WeakPtrs become bound to the calling /// dereferenced and invalidated on the same ThreaddTaskRunner otherwise
// thread or current ThreaddWorkerPool token, and cannot be dereferenced or /// checking the pointer would be racey.
// invalidated on any other task runner. Bound WeakPtrs can still be handed ///
// off to other task runners, e.g. to use to post tasks back to object on the /// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
// bound thread. /// is dereferenced, the factory and its WeakPtrs become bound to the calling
// /// thread or current ThreaddWorkerPool token, and cannot be dereferenced or
// If all WeakPtr objects are destroyed or invalidated then the factory is /// invalidated on any other task runner. Bound WeakPtrs can still be handed
// unbound from the ThreaddTaskRunner/Thread. The WeakPtrFactory may then be /// off to other task runners, e.g. to use to post tasks back to object on the
// destroyed, or new WeakPtr objects may be used, from a different thread. /// bound thread.
// ///
// Thus, at least one WeakPtr object must exist and have been dereferenced on /// If all WeakPtr objects are destroyed or invalidated then the factory is
// the correct thread to enforce that other WeakPtr objects will enforce they /// unbound from the ThreadedTaskRunner/Thread. The WeakPtrFactory may then be
// are used on the desired thread. /// destroyed, or new WeakPtr objects may be used, from a different thread.
///
/// Thus, at least one WeakPtr object must exist and have been dereferenced on
/// the correct thread to enforce that other WeakPtr objects will enforce they
/// are used on the desired thread.
#ifndef CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_ #ifndef CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_
#define CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_ #define CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_
@ -243,27 +247,32 @@ class SupportsWeakPtrBase {
template <typename T> template <typename T>
class WeakPtrFactory; class WeakPtrFactory;
// The WeakPtr class holds a weak reference to |T*|. ///
// /// The WeakPtr class holds a weak reference to |T*|.
// This class is designed to be used like a normal pointer. You should always ///
// null-test an object of this class before using it or invoking a method that /// This class is designed to be used like a normal pointer. You should always
// may result in the underlying object being destroyed. /// null-test an object of this class before using it or invoking a method that
// /// may result in the underlying object being destroyed.
// EXAMPLE: ///
// /// EXAMPLE:
// class Foo { ... }; ///
// WeakPtr<Foo> foo; /// <pre>
// if (foo) /// class Foo { ... };
// foo->method(); /// WeakPtr<Foo> foo;
// /// if (foo)
/// foo->method();
/// </pre>
///
template <typename T> template <typename T>
class WeakPtr : public internal::WeakPtrBase { class WeakPtr : public internal::WeakPtrBase {
public: public:
WeakPtr() = default; WeakPtr() = default;
WeakPtr(std::nullptr_t) {} WeakPtr(std::nullptr_t) {}
// Allow conversion from U to T provided U "is a" T. Note that this ///
// is separate from the (implicit) copy and move constructors. /// Allow conversion from U to T provided U "is a" T. Note that this
/// is separate from the (implicit) copy and move constructors.
///
template <typename U> template <typename U>
WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other) { WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other) {
// Need to cast from U* to T* to do pointer adjustment in case of multiple // Need to cast from U* to T* to do pointer adjustment in case of multiple
@ -292,21 +301,27 @@ class WeakPtr : public internal::WeakPtrBase {
return get(); return get();
} }
// Allow conditionals to test validity, e.g. if (weak_ptr) {...}; ///
/// Allow conditionals to test validity, e.g. `if (weak_ptr) {...}`;
///
explicit operator bool() const { return get() != nullptr; } explicit operator bool() const { return get() != nullptr; }
// Returns false if the WeakPtr is confirmed to be invalid. This call is safe ///
// to make from any thread, e.g. to optimize away unnecessary work, but /// Returns false if the WeakPtr is confirmed to be invalid. This call is safe
// operator bool() must always be called, on the correct thread, before /// to make from any thread, e.g. to optimize away unnecessary work, but
// actually using the pointer. /// operator bool() must always be called, on the correct thread, before
// /// actually using the pointer.
// Warning: as with any object, this call is only thread-safe if the WeakPtr ///
// instance isn't being re-assigned or reset() racily with this call. /// Warning: as with any object, this call is only thread-safe if the WeakPtr
/// instance isn't being re-assigned or reset() racily with this call.
///
bool MaybeValid() const { return ref_.MaybeValid(); } bool MaybeValid() const { return ref_.MaybeValid(); }
// Returns whether the object |this| points to has been invalidated. This can ///
// be used to distinguish a WeakPtr to a destroyed object from one that has /// Returns whether the object |this| points to has been invalidated. This can
// been explicitly set to null. /// be used to distinguish a WeakPtr to a destroyed object from one that has
/// been explicitly set to null.
///
bool WasInvalidated() const { return ptr_ && !ref_.IsValid(); } bool WasInvalidated() const { return ptr_ && !ref_.IsValid(); }
private: private:
@ -320,7 +335,9 @@ class WeakPtr : public internal::WeakPtrBase {
: WeakPtrBase(ref, reinterpret_cast<uintptr_t>(ptr)) {} : WeakPtrBase(ref, reinterpret_cast<uintptr_t>(ptr)) {}
}; };
// Allow callers to compare WeakPtrs against nullptr to test validity. ///
/// Allow callers to compare WeakPtrs against nullptr to test validity.
///
template <class T> template <class T>
bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) { bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
return !(weak_ptr == nullptr); return !(weak_ptr == nullptr);
@ -348,11 +365,14 @@ class WeakPtrFactoryBase {
}; };
} // namespace internal } // namespace internal
// A class may be composed of a WeakPtrFactory and thereby ///
// control how it exposes weak pointers to itself. This is helpful if you only /// A class may be composed of a WeakPtrFactory and thereby control how it
// need weak pointers within the implementation of a class. This class is also /// exposes weak pointers to itself. This is helpful if you only need weak
// useful when working with primitive types. For example, you could have a /// pointers within the implementation of a class. This class is also useful
// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool. /// when working with primitive types. For example, you could have a
/// WeakPtrFactory<bool> that is used to pass around a weak reference to a
/// bool.
///
template <class T> template <class T>
class WeakPtrFactory : public internal::WeakPtrFactoryBase { class WeakPtrFactory : public internal::WeakPtrFactoryBase {
public: public:
@ -371,24 +391,30 @@ class WeakPtrFactory : public internal::WeakPtrFactoryBase {
reinterpret_cast<T*>(ptr_)); reinterpret_cast<T*>(ptr_));
} }
// Call this method to invalidate all existing weak pointers. ///
/// Call this method to invalidate all existing weak pointers.
///
void InvalidateWeakPtrs() { void InvalidateWeakPtrs() {
DCHECK(ptr_); DCHECK(ptr_);
weak_reference_owner_.Invalidate(); weak_reference_owner_.Invalidate();
} }
// Call this method to determine if any weak pointers exist. ///
/// Call this method to determine if any weak pointers exist.
///
bool HasWeakPtrs() const { bool HasWeakPtrs() const {
DCHECK(ptr_); DCHECK(ptr_);
return weak_reference_owner_.HasRefs(); return weak_reference_owner_.HasRefs();
} }
}; };
// A class may extend from SupportsWeakPtr to let others take weak pointers to ///
// it. This avoids the class itself implementing boilerplate to dispense weak /// A class may extend from SupportsWeakPtr to let others take weak pointers to
// pointers. However, since SupportsWeakPtr's destructor won't invalidate /// it. This avoids the class itself implementing boilerplate to dispense weak
// weak pointers to the class until after the derived class' members have been /// pointers. However, since SupportsWeakPtr's destructor won't invalidate
// destroyed, its use can lead to subtle use-after-destroy issues. /// weak pointers to the class until after the derived class' members have been
/// destroyed, its use can lead to subtle use-after-destroy issues.
///
template <class T> template <class T>
class SupportsWeakPtr : public internal::SupportsWeakPtrBase { class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
public: public:
@ -408,24 +434,29 @@ class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
internal::WeakReferenceOwner weak_reference_owner_; internal::WeakReferenceOwner weak_reference_owner_;
}; };
// Helper function that uses type deduction to safely return a WeakPtr<Derived> ///
// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it /// Helper function that uses type deduction to safely return a WeakPtr<Derived>
// extends a Base that extends SupportsWeakPtr<Base>. /// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
// /// extends a Base that extends SupportsWeakPtr<Base>.
// EXAMPLE: ///
// class Base : public base::SupportsWeakPtr<Producer> {}; /// EXAMPLE:
// class Derived : public Base {}; /// <pre>
// /// class Base : public base::SupportsWeakPtr<Producer> {};
// Derived derived; /// class Derived : public Base {};
// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived); ///
// /// Derived derived;
// Note that the following doesn't work (invalid type conversion) since /// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(), /// </pre>
// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at ///
// the caller. /// Note that the following doesn't work (invalid type conversion) since
// /// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails. /// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
/// the caller.
///
/// <pre>
/// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails.
/// </pre>
///
template <typename Derived> template <typename Derived>
WeakPtr<Derived> AsWeakPtr(Derived* t) { WeakPtr<Derived> AsWeakPtr(Derived* t) {
return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t); return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);