libweave: Port base/ changes from Chromium project
Now this makes the state of base/ match libchrome's implementation
on Brillo and Chrome OS.
Change-Id: I1c1eb30d2669aeb58a77f332f8c69f130d00878c
Reviewed-on: https://weave-review.googlesource.com/3065
Reviewed-by: Robert Ginda <rginda@google.com>
diff --git a/file_lists.mk b/file_lists.mk
index e13553f..6345939 100644
--- a/file_lists.mk
+++ b/file_lists.mk
@@ -130,7 +130,6 @@
third_party/chromium/base/json/string_escape_unittest.cc \
third_party/chromium/base/logging_unittest.cc \
third_party/chromium/base/memory/ref_counted_unittest.cc \
- third_party/chromium/base/memory/scoped_ptr_unittest.cc \
third_party/chromium/base/memory/weak_ptr_unittest.cc \
third_party/chromium/base/numerics/safe_numerics_unittest.cc \
third_party/chromium/base/observer_list_unittest.cc \
diff --git a/third_party/chromium/base/bind.h b/third_party/chromium/base/bind.h
index 770e457..46dbb91 100644
--- a/third_party/chromium/base/bind.h
+++ b/third_party/chromium/base/bind.h
@@ -6,7 +6,6 @@
#define BASE_BIND_H_
#include "base/bind_internal.h"
-#include "base/callback_internal.h"
// -----------------------------------------------------------------------------
// Usage documentation
@@ -47,14 +46,27 @@
namespace base {
+namespace internal {
+
+// Don't use Alias Template directly here to avoid a compile error on MSVC2013.
template <typename Functor, typename... Args>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- typename internal::CallbackParamTraits<Args>::StorageType...>
- ::UnboundRunType>
-Bind(Functor functor, const Args&... args) {
+struct MakeUnboundRunTypeImpl {
+ using Type =
+ typename BindState<
+ typename FunctorTraits<Functor>::RunnableType,
+ typename FunctorTraits<Functor>::RunType,
+ Args...>::UnboundRunType;
+};
+
+} // namespace internal
+
+template <typename Functor, typename... Args>
+using MakeUnboundRunType =
+ typename internal::MakeUnboundRunTypeImpl<Functor, Args...>::Type;
+
+template <typename Functor, typename... Args>
+base::Callback<MakeUnboundRunType<Functor, Args...>>
+Bind(Functor functor, Args&&... args) {
// Type aliases for how to store and run the functor.
using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
using RunType = typename internal::FunctorTraits<Functor>::RunType;
@@ -88,12 +100,11 @@
!internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
"a parameter is a refcounted type and needs scoped_refptr");
- using BindState = internal::BindState<
- RunnableType, RunType,
- typename internal::CallbackParamTraits<Args>::StorageType...>;
+ using BindState = internal::BindState<RunnableType, RunType, Args...>;
return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), args...));
+ new BindState(internal::MakeRunnable(functor),
+ std::forward<Args>(args)...));
}
} // namespace base
diff --git a/third_party/chromium/base/bind_helpers.h b/third_party/chromium/base/bind_helpers.h
index 23e2cc9..5a4524a 100644
--- a/third_party/chromium/base/bind_helpers.h
+++ b/third_party/chromium/base/bind_helpers.h
@@ -153,7 +153,6 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
-#include "base/template_util.h"
#include "build/build_config.h"
namespace base {
@@ -381,7 +380,7 @@
: is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(const PassedWrapper& other)
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
- T Pass() const {
+ T Take() const {
CHECK(is_valid_);
is_valid_ = false;
return std::move(scoper_);
@@ -394,98 +393,39 @@
// Unwrap the stored parameters for the wrappers above.
template <typename T>
-struct UnwrapTraits {
- using ForwardType = const T&;
- static ForwardType Unwrap(const T& o) { return o; }
-};
+const T& Unwrap(const T& o) {
+ return o;
+}
template <typename T>
-struct UnwrapTraits<UnretainedWrapper<T> > {
- using ForwardType = T*;
- static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
- return unretained.get();
- }
-};
+T* Unwrap(UnretainedWrapper<T> unretained) {
+ return unretained.get();
+}
template <typename T>
-struct UnwrapTraits<ConstRefWrapper<T> > {
- using ForwardType = const T&;
- static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
- return const_ref.get();
- }
-};
+const T& Unwrap(ConstRefWrapper<T> const_ref) {
+ return const_ref.get();
+}
template <typename T>
-struct UnwrapTraits<scoped_refptr<T> > {
- using ForwardType = T*;
- static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
-};
+T* Unwrap(const scoped_refptr<T>& o) {
+ return o.get();
+}
template <typename T>
-struct UnwrapTraits<WeakPtr<T> > {
- using ForwardType = const WeakPtr<T>&;
- static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
-};
+const WeakPtr<T>& Unwrap(const WeakPtr<T>& o) {
+ return o;
+}
template <typename T>
-struct UnwrapTraits<OwnedWrapper<T> > {
- using ForwardType = T*;
- static ForwardType Unwrap(const OwnedWrapper<T>& o) {
- return o.get();
- }
-};
+T* Unwrap(const OwnedWrapper<T>& o) {
+ return o.get();
+}
template <typename T>
-struct UnwrapTraits<PassedWrapper<T> > {
- using ForwardType = T;
- static T Unwrap(PassedWrapper<T>& o) {
- return o.Pass();
- }
-};
-
-// Utility for handling different refcounting semantics in the Bind()
-// function.
-template <bool is_method, typename... T>
-struct MaybeScopedRefPtr;
-
-template <bool is_method>
-struct MaybeScopedRefPtr<is_method> {
- MaybeScopedRefPtr() {}
-};
-
-template <typename T, typename... Rest>
-struct MaybeScopedRefPtr<false, T, Rest...> {
- MaybeScopedRefPtr(const T&, const Rest&...) {}
-};
-
-template <typename T, size_t n, typename... Rest>
-struct MaybeScopedRefPtr<false, T[n], Rest...> {
- MaybeScopedRefPtr(const T*, const Rest&...) {}
-};
-
-template <typename T, typename... Rest>
-struct MaybeScopedRefPtr<true, T, Rest...> {
- MaybeScopedRefPtr(const T& /* o */, const Rest&...) {}
-};
-
-template <typename T, typename... Rest>
-struct MaybeScopedRefPtr<true, T*, Rest...> {
- MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
- scoped_refptr<T> ref_;
-};
-
-// No need to additionally AddRef() and Release() since we are storing a
-// scoped_refptr<> inside the storage object already.
-template <typename T, typename... Rest>
-struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
- MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
-};
-
-template <typename T, typename... Rest>
-struct MaybeScopedRefPtr<true, const T*, Rest...> {
- MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
- scoped_refptr<const T> ref_;
-};
+T Unwrap(PassedWrapper<T>& o) {
+ return o.Take();
+}
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
// method. It is used internally by Bind() to select the correct
@@ -625,15 +565,12 @@
// 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,
- typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
- !std::is_lvalue_reference<T>::value>::type* =
+ typename std::enable_if<!std::is_lvalue_reference<T>::value>::type* =
nullptr>
static inline internal::PassedWrapper<T> Passed(T&& scoper) {
return internal::PassedWrapper<T>(std::move(scoper));
}
-template <typename T,
- typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
- nullptr>
+template <typename T>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
return internal::PassedWrapper<T>(std::move(*scoper));
}
diff --git a/third_party/chromium/base/bind_internal.h b/third_party/chromium/base/bind_internal.h
index 50c3e24..199467c 100644
--- a/third_party/chromium/base/bind_internal.h
+++ b/third_party/chromium/base/bind_internal.h
@@ -104,7 +104,8 @@
struct BindsArrayToFirstArg : std::false_type {};
template <typename T, typename... Args>
-struct BindsArrayToFirstArg<true, T, Args...> : std::is_array<T> {};
+struct BindsArrayToFirstArg<true, T, Args...>
+ : std::is_array<typename std::remove_reference<T>::type> {};
// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
@@ -153,8 +154,9 @@
: function_(function) {
}
- R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
- return function_(CallbackForward(args)...);
+ template <typename... RunArgs>
+ R Run(RunArgs&&... args) {
+ return function_(std::forward<RunArgs>(args)...);
}
private:
@@ -174,8 +176,9 @@
: method_(method) {
}
- R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
- return (object->*method_)(CallbackForward(args)...);
+ template <typename... RunArgs>
+ R Run(T* object, RunArgs&&... args) {
+ return (object->*method_)(std::forward<RunArgs>(args)...);
}
private:
@@ -193,9 +196,9 @@
: method_(method) {
}
- R Run(const T* object,
- typename CallbackParamTraits<Args>::ForwardType... args) {
- return (object->*method_)(CallbackForward(args)...);
+ template <typename... RunArgs>
+ R Run(const T* object, RunArgs&&... args) {
+ return (object->*method_)(std::forward<RunArgs>(args)...);
}
private:
@@ -280,38 +283,42 @@
//
// WeakCalls similarly need special syntax that is applied to the first
// argument to check if they should no-op themselves.
-template <bool IsWeakCall, typename ReturnType, typename Runnable,
- typename ArgsType>
+template <bool IsWeakCall, typename ReturnType, typename Runnable>
struct InvokeHelper;
-template <typename ReturnType, typename Runnable, typename... Args>
-struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
- static ReturnType MakeItSo(Runnable runnable, Args... args) {
- return runnable.Run(CallbackForward(args)...);
+template <typename ReturnType, typename Runnable>
+struct InvokeHelper<false, ReturnType, Runnable> {
+ template <typename... RunArgs>
+ static ReturnType MakeItSo(Runnable runnable, RunArgs&&... args) {
+ return runnable.Run(std::forward<RunArgs>(args)...);
}
};
-template <typename Runnable, typename... Args>
-struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
- static void MakeItSo(Runnable runnable, Args... args) {
- runnable.Run(CallbackForward(args)...);
+template <typename Runnable>
+struct InvokeHelper<false, void, Runnable> {
+ template <typename... RunArgs>
+ static void MakeItSo(Runnable runnable, RunArgs&&... args) {
+ runnable.Run(std::forward<RunArgs>(args)...);
}
};
-template <typename Runnable, typename BoundWeakPtr, typename... Args>
-struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
+template <typename Runnable>
+struct InvokeHelper<true, void, Runnable> {
+ template <typename BoundWeakPtr, typename... RunArgs>
+ static void MakeItSo(Runnable runnable,
+ BoundWeakPtr weak_ptr,
+ RunArgs&&... args) {
if (!weak_ptr.get()) {
return;
}
- runnable.Run(weak_ptr.get(), CallbackForward(args)...);
+ runnable.Run(weak_ptr.get(), std::forward<RunArgs>(args)...);
}
};
#if !defined(_MSC_VER)
-template <typename ReturnType, typename Runnable, typename ArgsType>
-struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
+template <typename ReturnType, typename Runnable>
+struct InvokeHelper<true, ReturnType, Runnable> {
// WeakCalls are only supported for functions with a void return type.
// Otherwise, the function result would be undefined if the the WeakPtr<>
// is invalidated.
@@ -324,33 +331,48 @@
// Invoker<>
//
// See description at the top of the file.
-template <typename BoundIndices,
- typename StorageType, typename Unwrappers,
+template <typename BoundIndices, typename StorageType,
typename InvokeHelperType, typename UnboundForwardRunType>
struct Invoker;
template <size_t... bound_indices,
typename StorageType,
- typename... Unwrappers,
typename InvokeHelperType,
typename R,
- typename... UnboundForwardArgs>
+ typename... UnboundArgs>
struct Invoker<IndexSequence<bound_indices...>,
- StorageType, TypeList<Unwrappers...>,
- InvokeHelperType, R(UnboundForwardArgs...)> {
- static R Run(BindStateBase* base,
- UnboundForwardArgs... unbound_args) {
+ StorageType,
+ InvokeHelperType,
+ R(UnboundArgs...)> {
+ static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) {
StorageType* storage = static_cast<StorageType*>(base);
// Local references to make debugger stepping easier. If in a debugger,
// you really want to warp ahead and step through the
// InvokeHelper<>::MakeItSo() call below.
return InvokeHelperType::MakeItSo(
- storage->runnable_,
- Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
- CallbackForward(unbound_args)...);
+ storage->runnable_, Unwrap(get<bound_indices>(storage->bound_args_))...,
+ std::forward<UnboundArgs>(unbound_args)...);
}
};
+// Used to implement MakeArgsStorage.
+template <bool is_method, typename... BoundArgs>
+struct MakeArgsStorageImpl {
+ using Type = std::tuple<BoundArgs...>;
+};
+
+template <typename Obj, typename... BoundArgs>
+struct MakeArgsStorageImpl<true, Obj*, BoundArgs...> {
+ using Type = std::tuple<scoped_refptr<Obj>, BoundArgs...>;
+};
+
+// Constructs a tuple type to store BoundArgs into BindState.
+// This wraps the first argument into a scoped_refptr if |is_method| is true and
+// the first argument is a raw pointer.
+// Other arguments are adjusted for store and packed into a tuple.
+template <bool is_method, typename... BoundArgs>
+using MakeArgsStorage = typename MakeArgsStorageImpl<
+ is_method, typename std::decay<BoundArgs>::type...>::Type;
// BindState<>
//
@@ -376,40 +398,31 @@
using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
using RunnableType = Runnable;
+ enum { is_method = HasIsMethodTag<Runnable>::value };
+
// true_type if Runnable is a method invocation and the first bound argument
// is a WeakPtr.
using IsWeakCall =
- IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
+ IsWeakMethod<is_method, typename std::decay<BoundArgs>::type...>;
using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
- using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
- using UnboundForwardArgs = DropTypeListItem<
- sizeof...(BoundArgs),
- TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
- using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
-
- using InvokeHelperArgs = ConcatTypeLists<
- TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
- UnboundForwardArgs>;
- using InvokeHelperType =
- InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
+ using InvokeHelperType = InvokeHelper<IsWeakCall::value, R, Runnable>;
using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
public:
- using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
- InvokeHelperType, UnboundForwardRunType>;
using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
+ using InvokerType =
+ Invoker<BoundIndices, StorageType, InvokeHelperType, UnboundRunType>;
- BindState(const Runnable& runnable, const BoundArgs&... bound_args)
+ template <typename... ForwardArgs>
+ BindState(const Runnable& runnable, ForwardArgs&&... bound_args)
: BindStateBase(&Destroy),
runnable_(runnable),
- ref_(bound_args...),
- bound_args_(bound_args...) {}
+ bound_args_(std::forward<ForwardArgs>(bound_args)...) {}
RunnableType runnable_;
- MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
- Tuple<BoundArgs...> bound_args_;
+ MakeArgsStorage<is_method, BoundArgs...> bound_args_;
private:
~BindState() {}
diff --git a/third_party/chromium/base/bind_unittest.cc b/third_party/chromium/base/bind_unittest.cc
index f3a1211..76d158b 100644
--- a/third_party/chromium/base/bind_unittest.cc
+++ b/third_party/chromium/base/bind_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <utility>
+#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -93,43 +94,87 @@
void NonVirtualSet() { value = kChildValue; }
};
-// Used for probing the number of copies that occur if a type must be coerced
-// during argument forwarding in the Run() methods.
-struct DerivedCopyCounter {
- DerivedCopyCounter(int* copies, int* assigns)
- : copies_(copies), assigns_(assigns) {
- }
+// Used for probing the number of copies and moves that occur if a type must be
+// coerced during argument forwarding in the Run() methods.
+struct DerivedCopyMoveCounter {
+ DerivedCopyMoveCounter(int* copies,
+ int* assigns,
+ int* move_constructs,
+ int* move_assigns)
+ : copies_(copies),
+ assigns_(assigns),
+ move_constructs_(move_constructs),
+ move_assigns_(move_assigns) {}
int* copies_;
int* assigns_;
+ int* move_constructs_;
+ int* move_assigns_;
};
-// Used for probing the number of copies in an argument.
-class CopyCounter {
+// Used for probing the number of copies and moves in an argument.
+class CopyMoveCounter {
public:
- CopyCounter(int* copies, int* assigns)
- : copies_(copies), assigns_(assigns) {
+ CopyMoveCounter(int* copies,
+ int* assigns,
+ int* move_constructs,
+ int* move_assigns)
+ : copies_(copies),
+ assigns_(assigns),
+ move_constructs_(move_constructs),
+ move_assigns_(move_assigns) {}
+
+ CopyMoveCounter(const CopyMoveCounter& other)
+ : copies_(other.copies_),
+ assigns_(other.assigns_),
+ move_constructs_(other.move_constructs_),
+ move_assigns_(other.move_assigns_) {
+ (*copies_)++;
}
- CopyCounter(const CopyCounter& other)
+ CopyMoveCounter(CopyMoveCounter&& other)
: copies_(other.copies_),
- assigns_(other.assigns_) {
- (*copies_)++;
+ assigns_(other.assigns_),
+ move_constructs_(other.move_constructs_),
+ move_assigns_(other.move_assigns_) {
+ (*move_constructs_)++;
}
// Probing for copies from coercion.
- explicit CopyCounter(const DerivedCopyCounter& other)
+ explicit CopyMoveCounter(const DerivedCopyMoveCounter& other)
: copies_(other.copies_),
- assigns_(other.assigns_) {
+ assigns_(other.assigns_),
+ move_constructs_(other.move_constructs_),
+ move_assigns_(other.move_assigns_) {
(*copies_)++;
}
- const CopyCounter& operator=(const CopyCounter& rhs) {
+ // Probing for moves from coercion.
+ explicit CopyMoveCounter(DerivedCopyMoveCounter&& other)
+ : copies_(other.copies_),
+ assigns_(other.assigns_),
+ move_constructs_(other.move_constructs_),
+ move_assigns_(other.move_assigns_) {
+ (*move_constructs_)++;
+ }
+
+ const CopyMoveCounter& operator=(const CopyMoveCounter& rhs) {
copies_ = rhs.copies_;
assigns_ = rhs.assigns_;
+ move_constructs_ = rhs.move_constructs_;
+ move_assigns_ = rhs.move_assigns_;
- if (assigns_) {
- (*assigns_)++;
- }
+ (*assigns_)++;
+
+ return *this;
+ }
+
+ const CopyMoveCounter& operator=(CopyMoveCounter&& rhs) {
+ copies_ = rhs.copies_;
+ assigns_ = rhs.assigns_;
+ move_constructs_ = rhs.move_constructs_;
+ move_assigns_ = rhs.move_assigns_;
+
+ (*move_assigns_)++;
return *this;
}
@@ -141,6 +186,47 @@
private:
int* copies_;
int* assigns_;
+ int* move_constructs_;
+ int* move_assigns_;
+};
+
+// Used for probing the number of copies in an argument. The instance is a
+// copyable and non-movable type.
+class CopyCounter {
+ public:
+ CopyCounter(int* copies, int* assigns)
+ : counter_(copies, assigns, nullptr, nullptr) {}
+ CopyCounter(const CopyCounter& other) : counter_(other.counter_) {}
+ CopyCounter& operator=(const CopyCounter& other) {
+ counter_ = other.counter_;
+ return *this;
+ }
+
+ explicit CopyCounter(const DerivedCopyMoveCounter& other) : counter_(other) {}
+
+ int copies() const { return counter_.copies(); }
+
+ private:
+ CopyMoveCounter counter_;
+};
+
+// Used for probing the number of moves in an argument. The instance is a
+// non-copyable and movable type.
+class MoveCounter {
+ public:
+ MoveCounter(int* move_constructs, int* move_assigns)
+ : counter_(nullptr, nullptr, move_constructs, move_assigns) {}
+ MoveCounter(MoveCounter&& other) : counter_(std::move(other.counter_)) {}
+ MoveCounter& operator=(MoveCounter&& other) {
+ counter_ = std::move(other.counter_);
+ return *this;
+ }
+
+ explicit MoveCounter(DerivedCopyMoveCounter&& other)
+ : counter_(std::move(other)) {}
+
+ private:
+ CopyMoveCounter counter_;
};
class DeleteCounter {
@@ -191,7 +277,7 @@
return s;
}
-int GetCopies(const CopyCounter& counter) {
+int GetCopies(const CopyMoveCounter& counter) {
return counter.copies();
}
@@ -339,8 +425,8 @@
// preserve virtual dispatch).
TEST_F(BindTest, FunctionTypeSupport) {
EXPECT_CALL(static_func_mock_, VoidMethod0());
- EXPECT_CALL(has_ref_, AddRef()).Times(5);
- EXPECT_CALL(has_ref_, Release()).Times(5);
+ EXPECT_CALL(has_ref_, AddRef()).Times(4);
+ EXPECT_CALL(has_ref_, Release()).Times(4);
EXPECT_CALL(has_ref_, VoidMethod0()).Times(2);
EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
@@ -670,12 +756,16 @@
int copies = 0;
int assigns = 0;
- CopyCounter counter(&copies, &assigns);
+ int move_constructs = 0;
+ int move_assigns = 0;
+ CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns);
Callback<int()> all_const_ref_cb =
Bind(&GetCopies, ConstRef(counter));
EXPECT_EQ(0, all_const_ref_cb.Run());
EXPECT_EQ(0, copies);
EXPECT_EQ(0, assigns);
+ EXPECT_EQ(0, move_constructs);
+ EXPECT_EQ(0, move_assigns);
}
TEST_F(BindTest, ScopedRefptr) {
@@ -718,37 +808,57 @@
EXPECT_EQ(1, deletes);
}
-// Passed() wrapper support.
+// Tests for Passed() wrapper support:
// - Passed() can be constructed from a pointer to scoper.
// - Passed() can be constructed from a scoper rvalue.
// - Using Passed() gives Callback Ownership.
// - Ownership is transferred from Callback to callee on the first Run().
// - Callback supports unbound arguments.
-TEST_F(BindTest, ScopedPtr) {
+template <typename T>
+class BindMoveOnlyTypeTest : public ::testing::Test {
+};
+
+struct CustomDeleter {
+ void operator()(DeleteCounter* c) { delete c; }
+};
+
+using MoveOnlyTypesToTest =
+ ::testing::Types<scoped_ptr<DeleteCounter>,
+ std::unique_ptr<DeleteCounter>,
+ std::unique_ptr<DeleteCounter, CustomDeleter>>;
+TYPED_TEST_CASE(BindMoveOnlyTypeTest, MoveOnlyTypesToTest);
+
+TYPED_TEST(BindMoveOnlyTypeTest, PassedToBoundCallback) {
int deletes = 0;
- // Tests the Passed() function's support for pointers.
- scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
- Callback<scoped_ptr<DeleteCounter>()> unused_callback =
- Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
+ TypeParam ptr(new DeleteCounter(&deletes));
+ Callback<TypeParam()> callback = Bind(&PassThru<TypeParam>, Passed(&ptr));
EXPECT_FALSE(ptr.get());
EXPECT_EQ(0, deletes);
// If we never invoke the Callback, it retains ownership and deletes.
- unused_callback.Reset();
+ callback.Reset();
EXPECT_EQ(1, deletes);
+}
- // Tests the Passed() function's support for rvalues.
- deletes = 0;
- DeleteCounter* counter = new DeleteCounter(&deletes);
- Callback<scoped_ptr<DeleteCounter>()> callback =
- Bind(&PassThru<scoped_ptr<DeleteCounter> >,
- Passed(scoped_ptr<DeleteCounter>(counter)));
- EXPECT_FALSE(ptr.get());
+TYPED_TEST(BindMoveOnlyTypeTest, PassedWithRvalue) {
+ int deletes = 0;
+ Callback<TypeParam()> callback = Bind(
+ &PassThru<TypeParam>, Passed(TypeParam(new DeleteCounter(&deletes))));
EXPECT_EQ(0, deletes);
- // Check that ownership can be transferred back out.
- scoped_ptr<DeleteCounter> result = callback.Run();
+ // If we never invoke the Callback, it retains ownership and deletes.
+ callback.Reset();
+ EXPECT_EQ(1, deletes);
+}
+
+// Check that ownership can be transferred back out.
+TYPED_TEST(BindMoveOnlyTypeTest, ReturnMoveOnlyType) {
+ int deletes = 0;
+ DeleteCounter* counter = new DeleteCounter(&deletes);
+ Callback<TypeParam()> callback =
+ Bind(&PassThru<TypeParam>, Passed(TypeParam(counter)));
+ TypeParam result = callback.Run();
ASSERT_EQ(counter, result.get());
EXPECT_EQ(0, deletes);
@@ -759,58 +869,49 @@
// Ensure that we actually did get ownership.
result.reset();
EXPECT_EQ(1, deletes);
-
- // Test unbound argument forwarding.
- Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
- Bind(&PassThru<scoped_ptr<DeleteCounter> >);
- ptr.reset(new DeleteCounter(&deletes));
- cb_unbound.Run(std::move(ptr));
}
-TEST_F(BindTest, UniquePtr) {
+TYPED_TEST(BindMoveOnlyTypeTest, UnboundForwarding) {
int deletes = 0;
-
- // Tests the Passed() function's support for pointers.
- std::unique_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
- Callback<std::unique_ptr<DeleteCounter>()> unused_callback =
- Bind(&PassThru<std::unique_ptr<DeleteCounter>>, Passed(&ptr));
- EXPECT_FALSE(ptr.get());
- EXPECT_EQ(0, deletes);
-
- // If we never invoke the Callback, it retains ownership and deletes.
- unused_callback.Reset();
- EXPECT_EQ(1, deletes);
-
- // Tests the Passed() function's support for rvalues.
- deletes = 0;
- DeleteCounter* counter = new DeleteCounter(&deletes);
- Callback<std::unique_ptr<DeleteCounter>()> callback =
- Bind(&PassThru<std::unique_ptr<DeleteCounter>>,
- Passed(std::unique_ptr<DeleteCounter>(counter)));
- EXPECT_FALSE(ptr.get());
- EXPECT_EQ(0, deletes);
-
- // Check that ownership can be transferred back out.
- std::unique_ptr<DeleteCounter> result = callback.Run();
- ASSERT_EQ(counter, result.get());
- EXPECT_EQ(0, deletes);
-
- // Resetting does not delete since ownership was transferred.
- callback.Reset();
- EXPECT_EQ(0, deletes);
-
- // Ensure that we actually did get ownership.
- result.reset();
- EXPECT_EQ(1, deletes);
-
+ TypeParam ptr(new DeleteCounter(&deletes));
// Test unbound argument forwarding.
- Callback<std::unique_ptr<DeleteCounter>(std::unique_ptr<DeleteCounter>)>
- cb_unbound = Bind(&PassThru<std::unique_ptr<DeleteCounter>>);
- ptr.reset(new DeleteCounter(&deletes));
+ Callback<TypeParam(TypeParam)> cb_unbound = Bind(&PassThru<TypeParam>);
cb_unbound.Run(std::move(ptr));
+ EXPECT_EQ(1, deletes);
}
-// Argument Copy-constructor usage for non-reference parameters.
+void VerifyVector(const std::vector<scoped_ptr<int>>& v) {
+ ASSERT_EQ(1u, v.size());
+ EXPECT_EQ(12345, *v[0]);
+}
+
+std::vector<scoped_ptr<int>> AcceptAndReturnMoveOnlyVector(
+ std::vector<scoped_ptr<int>> v) {
+ VerifyVector(v);
+ return v;
+}
+
+// Test that a vector containing move-only types can be used with Callback.
+TEST_F(BindTest, BindMoveOnlyVector) {
+ using MoveOnlyVector = std::vector<scoped_ptr<int>>;
+
+ MoveOnlyVector v;
+ v.push_back(make_scoped_ptr(new int(12345)));
+
+ // Early binding should work:
+ base::Callback<MoveOnlyVector()> bound_cb =
+ base::Bind(&AcceptAndReturnMoveOnlyVector, Passed(&v));
+ MoveOnlyVector intermediate_result = bound_cb.Run();
+ VerifyVector(intermediate_result);
+
+ // As should passing it as an argument to Run():
+ base::Callback<MoveOnlyVector(MoveOnlyVector)> unbound_cb =
+ base::Bind(&AcceptAndReturnMoveOnlyVector);
+ MoveOnlyVector final_result = unbound_cb.Run(std::move(intermediate_result));
+ VerifyVector(final_result);
+}
+
+// Argument copy-constructor usage for non-reference copy-only parameters.
// - Bound arguments are only copied once.
// - Forwarded arguments are only copied once.
// - Forwarded arguments with coercions are only copied twice (once for the
@@ -820,28 +921,148 @@
int assigns = 0;
CopyCounter counter(&copies, &assigns);
-
- Callback<void()> copy_cb =
- Bind(&VoidPolymorphic<CopyCounter>::Run, counter);
- EXPECT_GE(1, copies);
+ Bind(&VoidPolymorphic<CopyCounter>::Run, counter);
+ EXPECT_EQ(1, copies);
EXPECT_EQ(0, assigns);
copies = 0;
assigns = 0;
- Callback<void(CopyCounter)> forward_cb =
- Bind(&VoidPolymorphic<CopyCounter>::Run);
- forward_cb.Run(counter);
- EXPECT_GE(1, copies);
+ Bind(&VoidPolymorphic<CopyCounter>::Run, CopyCounter(&copies, &assigns));
+ EXPECT_EQ(1, copies);
EXPECT_EQ(0, assigns);
copies = 0;
assigns = 0;
- DerivedCopyCounter derived(&copies, &assigns);
- Callback<void(CopyCounter)> coerce_cb =
- Bind(&VoidPolymorphic<CopyCounter>::Run);
- coerce_cb.Run(CopyCounter(derived));
- EXPECT_GE(2, copies);
+ Bind(&VoidPolymorphic<CopyCounter>::Run).Run(counter);
+ EXPECT_EQ(2, copies);
EXPECT_EQ(0, assigns);
+
+ copies = 0;
+ assigns = 0;
+ Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(&copies, &assigns));
+ EXPECT_EQ(1, copies);
+ EXPECT_EQ(0, assigns);
+
+ copies = 0;
+ assigns = 0;
+ DerivedCopyMoveCounter derived(&copies, &assigns, nullptr, nullptr);
+ Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(derived));
+ EXPECT_EQ(2, copies);
+ EXPECT_EQ(0, assigns);
+
+ copies = 0;
+ assigns = 0;
+ Bind(&VoidPolymorphic<CopyCounter>::Run)
+ .Run(CopyCounter(
+ DerivedCopyMoveCounter(&copies, &assigns, nullptr, nullptr)));
+ EXPECT_EQ(2, copies);
+ EXPECT_EQ(0, assigns);
+}
+
+// Argument move-constructor usage for move-only parameters.
+// - Bound arguments passed by move are not copied.
+TEST_F(BindTest, ArgumentMoves) {
+ int move_constructs = 0;
+ int move_assigns = 0;
+
+ Bind(&VoidPolymorphic<const MoveCounter&>::Run,
+ MoveCounter(&move_constructs, &move_assigns));
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ // TODO(tzik): Support binding move-only type into a non-reference parameter
+ // of a variant of Callback.
+
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<MoveCounter>::Run)
+ .Run(MoveCounter(&move_constructs, &move_assigns));
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<MoveCounter>::Run)
+ .Run(MoveCounter(DerivedCopyMoveCounter(
+ nullptr, nullptr, &move_constructs, &move_assigns)));
+ EXPECT_EQ(2, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+}
+
+// Argument constructor usage for non-reference movable-copyable
+// parameters.
+// - Bound arguments passed by move are not copied.
+// - Forwarded arguments are only copied once.
+// - Forwarded arguments with coercions are only copied once and moved once.
+TEST_F(BindTest, ArgumentCopiesAndMoves) {
+ int copies = 0;
+ int assigns = 0;
+ int move_constructs = 0;
+ int move_assigns = 0;
+
+ CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns);
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run, counter);
+ EXPECT_EQ(1, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(0, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ copies = 0;
+ assigns = 0;
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run,
+ CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns));
+ EXPECT_EQ(0, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ copies = 0;
+ assigns = 0;
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run).Run(counter);
+ EXPECT_EQ(1, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ copies = 0;
+ assigns = 0;
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+ .Run(CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns));
+ EXPECT_EQ(0, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ DerivedCopyMoveCounter derived_counter(&copies, &assigns, &move_constructs,
+ &move_assigns);
+ copies = 0;
+ assigns = 0;
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+ .Run(CopyMoveCounter(derived_counter));
+ EXPECT_EQ(1, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(1, move_constructs);
+ EXPECT_EQ(0, move_assigns);
+
+ copies = 0;
+ assigns = 0;
+ move_constructs = 0;
+ move_assigns = 0;
+ Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+ .Run(CopyMoveCounter(DerivedCopyMoveCounter(
+ &copies, &assigns, &move_constructs, &move_assigns)));
+ EXPECT_EQ(0, copies);
+ EXPECT_EQ(0, assigns);
+ EXPECT_EQ(2, move_constructs);
+ EXPECT_EQ(0, move_assigns);
}
// Callback construction and assignment tests.
diff --git a/third_party/chromium/base/callback.h b/third_party/chromium/base/callback.h
index 3bf0008..c04e90d 100644
--- a/third_party/chromium/base/callback.h
+++ b/third_party/chromium/base/callback.h
@@ -7,7 +7,6 @@
#include "base/callback_forward.h"
#include "base/callback_internal.h"
-#include "base/template_util.h"
// NOTE: Header files that do not require the full definition of Callback or
// Closure should #include "base/callback_forward.h" instead of this file.
@@ -341,63 +340,65 @@
// void Bar(char* ptr);
// Bind(&Foo, "test");
// Bind(&Bar, "test"); // This fails because ptr is not const.
-
-namespace base {
-
-// First, we forward declare the Callback class template. This informs the
-// compiler that the template only has 1 type parameter which is the function
-// signature that the Callback is representing.
-//
-// After this, create template specializations for 0-7 parameters. Note that
-// even though the template typelist grows, the specialization still
-// only has one type: the function signature.
//
// If you are thinking of forward declaring Callback in your own header file,
// please include "base/callback_forward.h" instead.
+namespace base {
namespace internal {
template <typename Runnable, typename RunType, typename... BoundArgsType>
struct BindState;
} // namespace internal
-template <typename R, typename... Args>
-class Callback<R(Args...)> : public internal::CallbackBase {
+template <typename R, typename... Args, internal::CopyMode copy_mode>
+class Callback<R(Args...), copy_mode>
+ : public internal::CallbackBase<copy_mode> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(Args...);
- Callback() : CallbackBase(nullptr) { }
+ Callback() : internal::CallbackBase<copy_mode>(nullptr) {}
- template <typename Runnable, typename BindRunType, typename... BoundArgsType>
+ template <typename Runnable, typename BindRunType, typename... BoundArgs>
explicit Callback(
- internal::BindState<Runnable, BindRunType, BoundArgsType...>* bind_state)
- : CallbackBase(bind_state) {
+ internal::BindState<Runnable, BindRunType, BoundArgs...>* bind_state)
+ : internal::CallbackBase<copy_mode>(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType...>
+ &internal::BindState<Runnable, BindRunType, BoundArgs...>
::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+ using InvokeFuncStorage =
+ typename internal::CallbackBase<copy_mode>::InvokeFuncStorage;
+ this->polymorphic_invoke_ =
+ reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
+ return this->EqualsInternal(other);
}
- R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
- const {
+ // Run() makes an extra copy compared to directly calling the bound function
+ // if an argument is passed-by-value and is copyable-but-not-movable:
+ // i.e. below copies CopyableNonMovableType twice.
+ // void F(CopyableNonMovableType) {}
+ // Bind(&F).Run(CopyableNonMovableType());
+ //
+ // We can not fully apply Perfect Forwarding idiom to the callchain from
+ // Callback::Run() to the target function. Perfect Forwarding requires
+ // knowing how the caller will pass the arguments. However, the signature of
+ // InvokerType::Run() needs to be fixed in the callback constructor, so Run()
+ // cannot template its arguments based on how it's called.
+ R Run(Args... args) const {
PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(args)...);
+ reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke_);
+ return f(this->bind_state_.get(), std::forward<Args>(args)...);
}
private:
- using PolymorphicInvoke =
- R(*)(internal::BindStateBase*,
- typename internal::CallbackParamTraits<Args>::ForwardType...);
+ using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...);
};
} // namespace base
diff --git a/third_party/chromium/base/callback_forward.h b/third_party/chromium/base/callback_forward.h
index a9a263a..8b9b89c 100644
--- a/third_party/chromium/base/callback_forward.h
+++ b/third_party/chromium/base/callback_forward.h
@@ -6,8 +6,19 @@
#define BASE_CALLBACK_FORWARD_H_
namespace base {
+namespace internal {
-template <typename Sig>
+// CopyMode is used to control the copyablity of a Callback.
+// MoveOnly indicates the Callback is not copyable but movable, and Copyable
+// indicates it is copyable and movable.
+enum class CopyMode {
+ MoveOnly, Copyable,
+};
+
+} // namespace internal
+
+template <typename Signature,
+ internal::CopyMode copy_mode = internal::CopyMode::Copyable>
class Callback;
// Syntactic sugar to make Callback<void()> easier to declare since it
diff --git a/third_party/chromium/base/callback_internal.cc b/third_party/chromium/base/callback_internal.cc
index f0d16bb..932d36c 100644
--- a/third_party/chromium/base/callback_internal.cc
+++ b/third_party/chromium/base/callback_internal.cc
@@ -18,29 +18,66 @@
destructor_(this);
}
-CallbackBase::CallbackBase(const CallbackBase& c) = default;
-CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
-
-void CallbackBase::Reset() {
- polymorphic_invoke_ = NULL;
- // NULL the bind_state_ last, since it may be holding the last ref to whatever
- // object owns us, and we may be deleted after that.
- bind_state_ = NULL;
+CallbackBase<CopyMode::MoveOnly>::CallbackBase(CallbackBase&& c)
+ : bind_state_(std::move(c.bind_state_)),
+ polymorphic_invoke_(c.polymorphic_invoke_) {
+ c.polymorphic_invoke_ = nullptr;
}
-bool CallbackBase::Equals(const CallbackBase& other) const {
+CallbackBase<CopyMode::MoveOnly>&
+CallbackBase<CopyMode::MoveOnly>::operator=(CallbackBase&& c) {
+ bind_state_ = std::move(c.bind_state_);
+ polymorphic_invoke_ = c.polymorphic_invoke_;
+ c.polymorphic_invoke_ = nullptr;
+ return *this;
+}
+
+void CallbackBase<CopyMode::MoveOnly>::Reset() {
+ polymorphic_invoke_ = nullptr;
+ // NULL the bind_state_ last, since it may be holding the last ref to whatever
+ // object owns us, and we may be deleted after that.
+ bind_state_ = nullptr;
+}
+
+bool CallbackBase<CopyMode::MoveOnly>::EqualsInternal(
+ const CallbackBase& other) const {
return bind_state_.get() == other.bind_state_.get() &&
polymorphic_invoke_ == other.polymorphic_invoke_;
}
-CallbackBase::CallbackBase(BindStateBase* bind_state)
- : bind_state_(bind_state),
- polymorphic_invoke_(NULL) {
+CallbackBase<CopyMode::MoveOnly>::CallbackBase(
+ BindStateBase* bind_state)
+ : bind_state_(bind_state) {
DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
}
-CallbackBase::~CallbackBase() {
+CallbackBase<CopyMode::MoveOnly>::~CallbackBase() {}
+
+CallbackBase<CopyMode::Copyable>::CallbackBase(
+ const CallbackBase& c)
+ : CallbackBase<CopyMode::MoveOnly>(nullptr) {
+ bind_state_ = c.bind_state_;
+ polymorphic_invoke_ = c.polymorphic_invoke_;
}
+CallbackBase<CopyMode::Copyable>::CallbackBase(CallbackBase&& c)
+ : CallbackBase<CopyMode::MoveOnly>(std::move(c)) {}
+
+CallbackBase<CopyMode::Copyable>&
+CallbackBase<CopyMode::Copyable>::operator=(const CallbackBase& c) {
+ bind_state_ = c.bind_state_;
+ polymorphic_invoke_ = c.polymorphic_invoke_;
+ return *this;
+}
+
+CallbackBase<CopyMode::Copyable>&
+CallbackBase<CopyMode::Copyable>::operator=(CallbackBase&& c) {
+ *static_cast<CallbackBase<CopyMode::MoveOnly>*>(this) = std::move(c);
+ return *this;
+}
+
+template class CallbackBase<CopyMode::MoveOnly>;
+template class CallbackBase<CopyMode::Copyable>;
+
} // namespace internal
} // namespace base
diff --git a/third_party/chromium/base/callback_internal.h b/third_party/chromium/base/callback_internal.h
index 6339437..3682bf9 100644
--- a/third_party/chromium/base/callback_internal.h
+++ b/third_party/chromium/base/callback_internal.h
@@ -15,13 +15,14 @@
#include <vector>
#include "base/base_export.h"
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/template_util.h"
namespace base {
namespace internal {
+template <CopyMode copy_mode>
class CallbackBase;
// BindStateBase is used to provide an opaque handle that the Callback
@@ -43,6 +44,7 @@
private:
friend class scoped_refptr<BindStateBase>;
+ template <CopyMode copy_mode>
friend class CallbackBase;
void AddRef();
@@ -58,10 +60,13 @@
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
-class BASE_EXPORT CallbackBase {
+// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
+// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
+template <>
+class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> {
public:
- CallbackBase(const CallbackBase& c);
- CallbackBase& operator=(const CallbackBase& c);
+ CallbackBase(CallbackBase&& c);
+ CallbackBase& operator=(CallbackBase&& c);
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const { return bind_state_.get() == NULL; }
@@ -77,7 +82,7 @@
using InvokeFuncStorage = void(*)();
// Returns true if this callback equals |other|. |other| may be null.
- bool Equals(const CallbackBase& other) const;
+ bool EqualsInternal(const CallbackBase& other) const;
// Allow initializing of |bind_state_| via the constructor to avoid default
// initialization of the scoped_refptr. We do not also initialize
@@ -91,9 +96,27 @@
~CallbackBase();
scoped_refptr<BindStateBase> bind_state_;
- InvokeFuncStorage polymorphic_invoke_;
+ InvokeFuncStorage polymorphic_invoke_ = nullptr;
};
+// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
+template <>
+class BASE_EXPORT CallbackBase<CopyMode::Copyable>
+ : public CallbackBase<CopyMode::MoveOnly> {
+ public:
+ CallbackBase(const CallbackBase& c);
+ CallbackBase(CallbackBase&& c);
+ CallbackBase& operator=(const CallbackBase& c);
+ CallbackBase& operator=(CallbackBase&& c);
+ protected:
+ explicit CallbackBase(BindStateBase* bind_state)
+ : CallbackBase<CopyMode::MoveOnly>(bind_state) {}
+ ~CallbackBase() {}
+};
+
+extern template class CallbackBase<CopyMode::MoveOnly>;
+extern template class CallbackBase<CopyMode::Copyable>;
+
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via std::move() in a
// destructive way. Types are considered to be move-only if they have a
@@ -103,7 +126,13 @@
// confuses template deduction in VS2013 with certain types such as
// std::unique_ptr.
// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
+
template <typename T> struct IsMoveOnlyType {
+ // Types YesType and NoType are guaranteed such that sizeof(YesType) <
+ // sizeof(NoType).
+ using YesType = char;
+ struct NoType { YesType dummy[2]; };
+
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
@@ -116,8 +145,14 @@
// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
// move-only, even without the sentinel member.
-template <typename T>
-struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
+template <typename T, typename D>
+struct IsMoveOnlyType<std::unique_ptr<T, D>> : std::true_type {};
+
+// Specialization of std::vector, so that it's considered move-only if the
+// element type is move-only. Allocator is explicitly ignored when determining
+// move-only status of the std::vector.
+template <typename T, typename Allocator>
+struct IsMoveOnlyType<std::vector<T, Allocator>> : IsMoveOnlyType<T> {};
template <typename>
struct CallbackParamTraitsForMoveOnlyType;
@@ -130,16 +165,7 @@
// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
//
// This is a typetraits object that's used to take an argument type, and
-// extract a suitable type for storing and forwarding arguments.
-//
-// In particular, it strips off references, and converts arrays to
-// pointers for storage; and it avoids accidentally trying to create a
-// "reference of a reference" if the argument is a reference type.
-//
-// This array type becomes an issue for storage because we are passing bound
-// parameters by const reference. In this case, we end up passing an actual
-// array type in the initializer list which C++ does not allow. This will
-// break passing of C-string literals.
+// extract a suitable type for forwarding arguments.
template <typename T>
struct CallbackParamTraits
: std::conditional<IsMoveOnlyType<T>::value,
@@ -150,18 +176,6 @@
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType {
using ForwardType = const T&;
- using StorageType = T;
-};
-
-// The Storage should almost be impossible to trigger unless someone manually
-// specifies type of the bind parameters. However, in case they do,
-// this will guard against us accidentally storing a reference parameter.
-//
-// The ForwardType should only be used for unbound arguments.
-template <typename T>
-struct CallbackParamTraitsForNonMoveOnlyType<T&> {
- using ForwardType = T&;
- using StorageType = T;
};
// Note that for array types, we implicitly add a const in the conversion. This
@@ -172,14 +186,12 @@
template <typename T, size_t n>
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
using ForwardType = const T*;
- using StorageType = const T*;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
using ForwardType = const T*;
- using StorageType = const T*;
};
// Parameter traits for movable-but-not-copyable scopers.
@@ -198,7 +210,6 @@
template <typename T>
struct CallbackParamTraitsForMoveOnlyType {
using ForwardType = T;
- using StorageType = T;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
diff --git a/third_party/chromium/base/logging.cc b/third_party/chromium/base/logging.cc
index 6306f47..ab97073 100644
--- a/third_party/chromium/base/logging.cc
+++ b/third_party/chromium/base/logging.cc
@@ -233,7 +233,7 @@
}
void RawLog(int level, const char* message) {
- if (level >= g_min_log_level) {
+ if (level >= g_min_log_level && message) {
size_t bytes_written = 0;
const size_t message_len = strlen(message);
int rv;
diff --git a/third_party/chromium/base/logging.h b/third_party/chromium/base/logging.h
index ee10ae2..1290bfe 100644
--- a/third_party/chromium/base/logging.h
+++ b/third_party/chromium/base/logging.h
@@ -342,9 +342,6 @@
#define LOG_IF(severity, condition) \
LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
-#define SYSLOG(severity) LOG(severity)
-#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
-
// The VLOG macros log with negative verbosities.
#define VLOG_STREAM(verbose_level) \
logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
@@ -358,8 +355,6 @@
#define LOG_ASSERT(condition) \
LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
-#define SYSLOG_ASSERT(condition) \
- SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
// The actual stream used isn't important.
#define EAT_STREAM_PARAMETERS \
@@ -656,12 +651,6 @@
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
-// A non-macro interface to the log facility; (useful
-// when the logging level is not a compile-time constant).
-inline void LogAtLevel(int log_level, const std::string& msg) {
- LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
-}
-
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
diff --git a/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h b/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
index 33bacba..5dbc183 100644
--- a/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -5,10 +5,10 @@
#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#include <tuple>
+#include <type_traits>
+
#include "base/memory/ref_counted.h"
-#include "base/template_util.h"
-#include "base/tuple.h"
-#include "build/build_config.h"
// It is dangerous to post a task with a T* argument where T is a subtype of
// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
@@ -25,11 +25,6 @@
template <typename T>
struct NeedsScopedRefptrButGetsRawPtr {
-#if defined(OS_WIN)
- enum {
- value = base::false_type::value
- };
-#else
enum {
// Human readable translation: you needed to be a scoped_refptr if you are a
// raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
@@ -38,7 +33,6 @@
(std::is_convertible<T, subtle::RefCountedBase*>::value ||
std::is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
};
-#endif
};
template <typename Params>
@@ -47,14 +41,14 @@
};
template <>
-struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
+struct ParamsUseScopedRefptrCorrectly<std::tuple<>> {
enum { value = 1 };
};
template <typename Head, typename... Tail>
-struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+struct ParamsUseScopedRefptrCorrectly<std::tuple<Head, Tail...>> {
enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
- ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
+ ParamsUseScopedRefptrCorrectly<std::tuple<Tail...>>::value };
};
} // namespace internal
diff --git a/third_party/chromium/base/memory/ref_counted.h b/third_party/chromium/base/memory/ref_counted.h
index 95fa565..a480eb0 100644
--- a/third_party/chromium/base/memory/ref_counted.h
+++ b/third_party/chromium/base/memory/ref_counted.h
@@ -347,15 +347,25 @@
private:
template <typename U> friend class scoped_refptr;
- // Allow scoped_refptr<T> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
+ // Implement "Safe Bool Idiom"
+ // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
//
- // Note that this trick is only safe when the == and != operators
- // are declared explicitly, as otherwise "refptr1 == refptr2"
- // will compile but do the wrong thing (i.e., convert to Testable
- // and then do the comparison).
+ // Allow scoped_refptr<T> to be used in boolean expressions such as
+ // if (ref_ptr_instance)
+ // But do not become convertible to a real bool (which is dangerous).
+ // Implementation requires:
+ // typedef Testable
+ // operator Testable() const
+ // operator==
+ // operator!=
+ //
+ // == and != operators must be declared explicitly or dissallowed, as
+ // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert
+ // to Testable and then do the comparison).
+ //
+ // C++11 provides for "explicit operator bool()", however it is currently
+ // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist
typedef T* scoped_refptr::*Testable;
-
public:
operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
@@ -403,8 +413,6 @@
return scoped_refptr<T>(t);
}
-// Temporary operator overloads to facilitate the transition. See
-// https://crbug.com/110610.
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
return lhs.get() == rhs;
diff --git a/third_party/chromium/base/memory/ref_counted_unittest.cc b/third_party/chromium/base/memory/ref_counted_unittest.cc
index 88ee981..739b45f 100644
--- a/third_party/chromium/base/memory/ref_counted_unittest.cc
+++ b/third_party/chromium/base/memory/ref_counted_unittest.cc
@@ -139,10 +139,31 @@
}
TEST(RefCountedUnitTest, BooleanTesting) {
- scoped_refptr<SelfAssign> p;
- EXPECT_FALSE(p);
- p = new SelfAssign;
- EXPECT_TRUE(p);
+ scoped_refptr<SelfAssign> ptr_to_an_instance = new SelfAssign;
+ EXPECT_TRUE(ptr_to_an_instance);
+ EXPECT_FALSE(!ptr_to_an_instance);
+
+ if (ptr_to_an_instance) {
+ } else {
+ ADD_FAILURE() << "Pointer to an instance should result in true.";
+ }
+
+ if (!ptr_to_an_instance) { // check for operator!().
+ ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+ }
+
+ scoped_refptr<SelfAssign> null_ptr;
+ EXPECT_FALSE(null_ptr);
+ EXPECT_TRUE(!null_ptr);
+
+ if (null_ptr) {
+ ADD_FAILURE() << "Null pointer should result in false.";
+ }
+
+ if (!null_ptr) { // check for operator!().
+ } else {
+ ADD_FAILURE() << "Null pointer should result in !x being true.";
+ }
}
TEST(RefCountedUnitTest, Equality) {
diff --git a/third_party/chromium/base/memory/scoped_ptr.h b/third_party/chromium/base/memory/scoped_ptr.h
index d68604e..2d2c0ec 100644
--- a/third_party/chromium/base/memory/scoped_ptr.h
+++ b/third_party/chromium/base/memory/scoped_ptr.h
@@ -33,6 +33,15 @@
// foo[10].Method(); // Foo::Method on the 10th element.
// }
//
+// Scopers are testable as booleans:
+// {
+// scoped_ptr<Foo> foo;
+// if (!foo)
+// foo.reset(new Foo());
+// if (foo)
+// LOG(INFO) << "This code is reached."
+// }
+//
// These scopers also implement part of the functionality of C++11 unique_ptr
// in that they are "movable but not copyable." You can use the scopers in
// the parameter and return types of functions to signify ownership transfer
@@ -81,7 +90,8 @@
// This is an implementation designed to match the anticipated future TR2
// implementation of the scoped_ptr class.
-#include <assert.h>
+// TODO(dcheng): Clean up these headers, but there are likely lots of existing
+// IWYU violations.
#include <stddef.h>
#include <stdlib.h>
@@ -91,17 +101,13 @@
#include <utility>
#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/move.h"
-#include "base/template_util.h"
+#include "build/build_config.h"
namespace base {
-namespace subtle {
-class RefCountedBase;
-class RefCountedThreadSafeBase;
-} // namespace subtle
-
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
//
@@ -113,485 +119,10 @@
}
};
-namespace internal {
-
-template <typename T> struct IsNotRefCounted {
- enum {
- value = !std::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
- !std::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
- value
- };
-};
-
-// Minimal implementation of the core logic of scoped_ptr, suitable for
-// reuse in both scoped_ptr and its specializations.
-template <class T, class D>
-class scoped_ptr_impl {
- public:
- explicit scoped_ptr_impl(T* p) : data_(p) {}
-
- // Initializer for deleters that have data parameters.
- scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
-
- // Templated constructor that destructively takes the value from another
- // scoped_ptr_impl.
- template <typename U, typename V>
- scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
- : data_(other->release(), other->get_deleter()) {
- // We do not support move-only deleters. We could modify our move
- // emulation to have base::subtle::move() and base::subtle::forward()
- // functions that are imperfect emulations of their C++11 equivalents,
- // but until there's a requirement, just assume deleters are copyable.
- }
-
- template <typename U, typename V>
- void TakeState(scoped_ptr_impl<U, V>* other) {
- // See comment in templated constructor above regarding lack of support
- // for move-only deleters.
- reset(other->release());
- get_deleter() = other->get_deleter();
- }
-
- ~scoped_ptr_impl() {
- // Match libc++, which calls reset() in its destructor.
- // Use nullptr as the new value for three reasons:
- // 1. libc++ does it.
- // 2. Avoids infinitely recursing into destructors if two classes are owned
- // in a reference cycle (see ScopedPtrTest.ReferenceCycle).
- // 3. If |this| is accessed in the future, in a use-after-free bug, attempts
- // to dereference |this|'s pointer should cause either a failure or a
- // segfault closer to the problem. If |this| wasn't reset to nullptr,
- // the access would cause the deleted memory to be read or written
- // leading to other more subtle issues.
- reset(nullptr);
- }
-
- void reset(T* p) {
- // Match C++11's definition of unique_ptr::reset(), which requires changing
- // the pointer before invoking the deleter on the old pointer. This prevents
- // |this| from being accessed after the deleter is run, which may destroy
- // |this|.
- T* old = data_.ptr;
- data_.ptr = p;
- if (old != nullptr)
- static_cast<D&>(data_)(old);
- }
-
- T* get() const { return data_.ptr; }
-
- D& get_deleter() { return data_; }
- const D& get_deleter() const { return data_; }
-
- void swap(scoped_ptr_impl& p2) {
- // Standard swap idiom: 'using std::swap' ensures that std::swap is
- // present in the overload set, but we call swap unqualified so that
- // any more-specific overloads can be used, if available.
- using std::swap;
- swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
- swap(data_.ptr, p2.data_.ptr);
- }
-
- T* release() {
- T* old_ptr = data_.ptr;
- data_.ptr = nullptr;
- return old_ptr;
- }
-
- private:
- // Needed to allow type-converting constructor.
- template <typename U, typename V> friend class scoped_ptr_impl;
-
- // Use the empty base class optimization to allow us to have a D
- // member, while avoiding any space overhead for it when D is an
- // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
- // discussion of this technique.
- struct Data : public D {
- explicit Data(T* ptr_in) : ptr(ptr_in) {}
- Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
- T* ptr;
- };
-
- Data data_;
-
- DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
-};
-
-} // namespace internal
-
} // namespace base
-// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
-// automatically deletes the pointer it holds (if any).
-// That is, scoped_ptr<T> owns the T object that it points to.
-// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
-// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
-// dereference it, you get the thread safety guarantees of T.
-//
-// The size of scoped_ptr is small. On most compilers, when using the
-// std::default_delete, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters
-// will increase the size proportional to whatever state they need to have. See
-// comments inside scoped_ptr_impl<> for details.
-//
-// Current implementation targets having a strict subset of C++11's
-// unique_ptr<> features. Known deficiencies include not supporting move-only
-// deleteres, function pointers as deleters, and deleters with reference
-// types.
-template <class T, class D = std::default_delete<T>>
-class scoped_ptr {
- DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
-
- static_assert(!std::is_array<T>::value,
- "scoped_ptr doesn't support array with size");
- static_assert(base::internal::IsNotRefCounted<T>::value,
- "T is a refcounted type and needs a scoped_refptr");
-
- public:
- // The element and deleter types.
- using element_type = T;
- using deleter_type = D;
-
- // Constructor. Defaults to initializing with nullptr.
- scoped_ptr() : impl_(nullptr) {}
-
- // Constructor. Takes ownership of p.
- explicit scoped_ptr(element_type* p) : impl_(p) {}
-
- // Constructor. Allows initialization of a stateful deleter.
- scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
-
- // Constructor. Allows construction from a nullptr.
- scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
-
- // Move constructor.
- //
- // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
- // not just the conversion constructor) in order to warn on pessimizing moves.
- // The requirements for the move constructor are specified in C++11
- // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
- // we don't support reference (or move-only) deleters, the post conditions are
- // trivially true: we always copy construct the deleter from other's deleter.
- scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
-
- // Conversion constructor. Allows construction from a scoped_ptr rvalue for a
- // convertible type and deleter.
- //
- // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
- // participate in overload resolution if all the following are true:
- // - U is implicitly convertible to T: this is important for 2 reasons:
- // 1. So type traits don't incorrectly return true, e.g.
- // std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
- // should be false.
- // 2. To make sure code like this compiles:
- // void F(scoped_ptr<int>);
- // void F(scoped_ptr<Base>);
- // // Ambiguous since both conversion constructors match.
- // F(scoped_ptr<Derived>());
- // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
- // scoped_ptr<T>.
- // - D is a reference type and E is the same type, or D is not a reference
- // type and E is implicitly convertible to D: again, we don't support
- // reference deleters, so we only worry about the latter requirement.
- template <typename U,
- typename E,
- typename std::enable_if<!std::is_array<U>::value &&
- std::is_convertible<U*, T*>::value &&
- std::is_convertible<E, D>::value>::type* =
- nullptr>
- scoped_ptr(scoped_ptr<U, E>&& other)
- : impl_(&other.impl_) {}
-
- // operator=.
- //
- // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
- // require a move assignment operator to trigger the pessimizing move warning:
- // in this case, the warning triggers when moving a temporary. For consistency
- // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
- // defines several requirements around this: like the move constructor, the
- // requirements are simplified by the fact that we don't support move-only or
- // reference deleters.
- scoped_ptr& operator=(scoped_ptr&& rhs) {
- impl_.TakeState(&rhs.impl_);
- return *this;
- }
-
- // operator=. Allows assignment from a scoped_ptr rvalue for a convertible
- // type and deleter.
- //
- // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
- // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
- // requirement for this operator, but like the conversion constructor, the
- // requirements are greatly simplified by not supporting move-only or
- // reference deleters.
- template <typename U,
- typename E,
- typename std::enable_if<!std::is_array<U>::value &&
- std::is_convertible<U*, T*>::value &&
- // Note that this really should be
- // std::is_assignable, but <type_traits>
- // appears to be missing this on some
- // platforms. This is close enough (though
- // it's not the same).
- std::is_convertible<D, E>::value>::type* =
- nullptr>
- scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
- impl_.TakeState(&rhs.impl_);
- return *this;
- }
-
- // operator=. Allows assignment from a nullptr. Deletes the currently owned
- // object, if any.
- scoped_ptr& operator=(std::nullptr_t) {
- reset();
- return *this;
- }
-
- // Reset. Deletes the currently owned object, if any.
- // Then takes ownership of a new object, if given.
- void reset(element_type* p = nullptr) { impl_.reset(p); }
-
- // Accessors to get the owned object.
- // operator* and operator-> will assert() if there is no current object.
- element_type& operator*() const {
- assert(impl_.get() != nullptr);
- return *impl_.get();
- }
- element_type* operator->() const {
- assert(impl_.get() != nullptr);
- return impl_.get();
- }
- element_type* get() const { return impl_.get(); }
-
- // Access to the deleter.
- deleter_type& get_deleter() { return impl_.get_deleter(); }
- const deleter_type& get_deleter() const { return impl_.get_deleter(); }
-
- // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- //
- // Note that this trick is only safe when the == and != operators
- // are declared explicitly, as otherwise "scoped_ptr1 ==
- // scoped_ptr2" will compile but do the wrong thing (i.e., convert
- // to Testable and then do the comparison).
- private:
- typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
- scoped_ptr::*Testable;
-
- public:
- operator Testable() const {
- return impl_.get() ? &scoped_ptr::impl_ : nullptr;
- }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- impl_.swap(p2.impl_);
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object. If this object
- // holds a nullptr, the return value is nullptr. After this operation, this
- // object will hold a nullptr, and will not own the object any more.
- element_type* release() WARN_UNUSED_RESULT {
- return impl_.release();
- }
-
- private:
- // Needed to reach into |impl_| in the constructor.
- template <typename U, typename V> friend class scoped_ptr;
- base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
-
- // Forbidden for API compatibility with std::unique_ptr.
- explicit scoped_ptr(int disallow_construction_from_null);
-};
-
-template <class T, class D>
-class scoped_ptr<T[], D> {
- DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
-
- public:
- // The element and deleter types.
- using element_type = T;
- using deleter_type = D;
-
- // Constructor. Defaults to initializing with nullptr.
- scoped_ptr() : impl_(nullptr) {}
-
- // Constructor. Stores the given array. Note that the argument's type
- // must exactly match T*. In particular:
- // - it cannot be a pointer to a type derived from T, because it is
- // inherently unsafe in the general case to access an array through a
- // pointer whose dynamic type does not match its static type (eg., if
- // T and the derived types had different sizes access would be
- // incorrectly calculated). Deletion is also always undefined
- // (C++98 [expr.delete]p3). If you're doing this, fix your code.
- // - it cannot be const-qualified differently from T per unique_ptr spec
- // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
- // to work around this may use const_cast<const T*>().
- explicit scoped_ptr(element_type* array) : impl_(array) {}
-
- // Constructor. Allows construction from a nullptr.
- scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
-
- // Constructor. Allows construction from a scoped_ptr rvalue.
- scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
-
- // operator=. Allows assignment from a scoped_ptr rvalue.
- scoped_ptr& operator=(scoped_ptr&& rhs) {
- impl_.TakeState(&rhs.impl_);
- return *this;
- }
-
- // operator=. Allows assignment from a nullptr. Deletes the currently owned
- // array, if any.
- scoped_ptr& operator=(std::nullptr_t) {
- reset();
- return *this;
- }
-
- // Reset. Deletes the currently owned array, if any.
- // Then takes ownership of a new object, if given.
- void reset(element_type* array = nullptr) { impl_.reset(array); }
-
- // Accessors to get the owned array.
- element_type& operator[](size_t i) const {
- assert(impl_.get() != nullptr);
- return impl_.get()[i];
- }
- element_type* get() const { return impl_.get(); }
-
- // Access to the deleter.
- deleter_type& get_deleter() { return impl_.get_deleter(); }
- const deleter_type& get_deleter() const { return impl_.get_deleter(); }
-
- // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- private:
- typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
- scoped_ptr::*Testable;
-
- public:
- operator Testable() const {
- return impl_.get() ? &scoped_ptr::impl_ : nullptr;
- }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- impl_.swap(p2.impl_);
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object. If this object
- // holds a nullptr, the return value is nullptr. After this operation, this
- // object will hold a nullptr, and will not own the object any more.
- element_type* release() WARN_UNUSED_RESULT {
- return impl_.release();
- }
-
- private:
- // Force element_type to be a complete type.
- enum { type_must_be_complete = sizeof(element_type) };
-
- // Actually hold the data.
- base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
-
- // Disable initialization from any type other than element_type*, by
- // providing a constructor that matches such an initialization, but is
- // private and has no definition. This is disabled because it is not safe to
- // call delete[] on an array whose static type does not match its dynamic
- // type.
- template <typename U> explicit scoped_ptr(U* array);
- explicit scoped_ptr(int disallow_construction_from_null);
-
- // Disable reset() from any type other than element_type*, for the same
- // reasons as the constructor above.
- template <typename U> void reset(U* array);
- void reset(int disallow_reset_from_null);
-};
-
-// Free functions
-template <class T, class D>
-void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
- p1.swap(p2);
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return p1.get() == p2.get();
-}
-template <class T, class D>
-bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
- return p.get() == nullptr;
-}
-template <class T, class D>
-bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
- return p.get() == nullptr;
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return !(p1 == p2);
-}
-template <class T, class D>
-bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
- return !(p == nullptr);
-}
-template <class T, class D>
-bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
- return !(p == nullptr);
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return p1.get() < p2.get();
-}
-template <class T, class D>
-bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
- auto* ptr = p.get();
- return ptr < static_cast<decltype(ptr)>(nullptr);
-}
-template <class T, class D>
-bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
- auto* ptr = p.get();
- return static_cast<decltype(ptr)>(nullptr) < ptr;
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return p2 < p1;
-}
-template <class T, class D>
-bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
- return nullptr < p;
-}
-template <class T, class D>
-bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
- return p < nullptr;
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return !(p1 > p2);
-}
-template <class T, class D>
-bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
- return !(p > nullptr);
-}
-template <class T, class D>
-bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
- return !(nullptr > p);
-}
-
-template <class T1, class D1, class T2, class D2>
-bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
- return !(p1 < p2);
-}
-template <class T, class D>
-bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
- return !(p < nullptr);
-}
-template <class T, class D>
-bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
- return !(nullptr < p);
-}
+template <typename T, typename D = std::default_delete<T>>
+using scoped_ptr = std::unique_ptr<T, D>;
// A function to convert T* into scoped_ptr<T>
// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
@@ -601,9 +132,4 @@
return scoped_ptr<T>(ptr);
}
-template <typename T>
-std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
- return out << p.get();
-}
-
#endif // BASE_MEMORY_SCOPED_PTR_H_
diff --git a/third_party/chromium/base/memory/scoped_ptr_unittest.cc b/third_party/chromium/base/memory/scoped_ptr_unittest.cc
deleted file mode 100644
index c1eb469..0000000
--- a/third_party/chromium/base/memory/scoped_ptr_unittest.cc
+++ /dev/null
@@ -1,843 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/scoped_ptr.h"
-
-#include <stddef.h>
-
-#include <sstream>
-
-#include <gtest/gtest.h>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-
-namespace {
-
-// Used to test depth subtyping.
-class ConDecLoggerParent {
- public:
- virtual ~ConDecLoggerParent() {}
-
- virtual void SetPtr(int* ptr) = 0;
-
- virtual int SomeMeth(int x) const = 0;
-};
-
-class ConDecLogger : public ConDecLoggerParent {
- public:
- ConDecLogger() : ptr_(NULL) { }
- explicit ConDecLogger(int* ptr) { SetPtr(ptr); }
- ~ConDecLogger() override { --*ptr_; }
-
- void SetPtr(int* ptr) override {
- ptr_ = ptr;
- ++*ptr_;
- }
-
- int SomeMeth(int x) const override { return x; }
-
- private:
- int* ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
-};
-
-struct CountingDeleter {
- explicit CountingDeleter(int* count) : count_(count) {}
- inline void operator()(double* ptr) const {
- (*count_)++;
- }
- int* count_;
-};
-
-// Used to test assignment of convertible deleters.
-struct CountingDeleterChild : public CountingDeleter {
- explicit CountingDeleterChild(int* count) : CountingDeleter(count) {}
-};
-
-class OverloadedNewAndDelete {
- public:
- void* operator new(size_t size) {
- g_new_count++;
- return malloc(size);
- }
-
- void operator delete(void* ptr) {
- g_delete_count++;
- free(ptr);
- }
-
- static void ResetCounters() {
- g_new_count = 0;
- g_delete_count = 0;
- }
-
- static int new_count() { return g_new_count; }
- static int delete_count() { return g_delete_count; }
-
- private:
- static int g_new_count;
- static int g_delete_count;
-};
-
-int OverloadedNewAndDelete::g_new_count = 0;
-int OverloadedNewAndDelete::g_delete_count = 0;
-
-scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
- return logger;
-}
-
-void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
-}
-
-// Do not delete this function! It's existence is to test that you can
-// return a temporarily constructed version of the scoper.
-scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) {
- return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
-}
-
-} // namespace
-
-TEST(ScopedPtrTest, ScopedPtr) {
- int constructed = 0;
-
- // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
- static_assert(sizeof(int*) >= sizeof(scoped_ptr<int>),
- "scoped_ptr shouldn't be larger than the raw pointer");
-
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- EXPECT_EQ(10, scoper->SomeMeth(10));
- EXPECT_EQ(10, scoper.get()->SomeMeth(10));
- EXPECT_EQ(10, (*scoper).SomeMeth(10));
- }
- EXPECT_EQ(0, constructed);
-
- // Test reset() and release()
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoper.reset(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoper.reset();
- EXPECT_EQ(0, constructed);
- EXPECT_FALSE(scoper.get());
-
- scoper.reset(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- ConDecLogger* take = scoper.release();
- EXPECT_EQ(1, constructed);
- EXPECT_FALSE(scoper.get());
- delete take;
- EXPECT_EQ(0, constructed);
-
- scoper.reset(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-
- // Test swap().
- {
- scoped_ptr<ConDecLogger> scoper1;
- scoped_ptr<ConDecLogger> scoper2;
- EXPECT_TRUE(scoper1.get() == scoper2.get());
- EXPECT_FALSE(scoper1.get() != scoper2.get());
-
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoper1.reset(logger);
- EXPECT_EQ(logger, scoper1.get());
- EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
-
- scoper2.swap(scoper1);
- EXPECT_EQ(logger, scoper2.get());
- EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
- }
- EXPECT_EQ(0, constructed);
-}
-
-TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
- int constructed = 0;
-
- // Test construction from a scoped_ptr to a derived class.
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<ConDecLoggerParent> scoper_parent(std::move(scoper));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper_parent.get());
- EXPECT_FALSE(scoper.get());
-
- EXPECT_EQ(10, scoper_parent->SomeMeth(10));
- EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10));
- EXPECT_EQ(10, (*scoper_parent).SomeMeth(10));
- }
- EXPECT_EQ(0, constructed);
-
- // Test assignment from a scoped_ptr to a derived class.
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<ConDecLoggerParent> scoper_parent;
- scoper_parent = std::move(scoper);
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper_parent.get());
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-
- // Test construction of a scoped_ptr with an additional const annotation.
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<const ConDecLogger> scoper_const(std::move(scoper));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper_const.get());
- EXPECT_FALSE(scoper.get());
-
- EXPECT_EQ(10, scoper_const->SomeMeth(10));
- EXPECT_EQ(10, scoper_const.get()->SomeMeth(10));
- EXPECT_EQ(10, (*scoper_const).SomeMeth(10));
- }
- EXPECT_EQ(0, constructed);
-
- // Test assignment to a scoped_ptr with an additional const annotation.
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<const ConDecLogger> scoper_const;
- scoper_const = std::move(scoper);
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper_const.get());
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-
- // Test assignment to a scoped_ptr deleter of parent type.
- {
- // Custom deleters never touch these value.
- double dummy_value, dummy_value2;
- int deletes = 0;
- int alternate_deletes = 0;
- scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
- CountingDeleter(&deletes));
- scoped_ptr<double, CountingDeleterChild> scoper_child(
- &dummy_value2, CountingDeleterChild(&alternate_deletes));
-
- EXPECT_TRUE(scoper);
- EXPECT_TRUE(scoper_child);
- EXPECT_EQ(0, deletes);
- EXPECT_EQ(0, alternate_deletes);
-
- // Test this compiles and correctly overwrites the deleter state.
- scoper = std::move(scoper_child);
- EXPECT_TRUE(scoper);
- EXPECT_FALSE(scoper_child);
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(0, alternate_deletes);
-
- scoper.reset();
- EXPECT_FALSE(scoper);
- EXPECT_FALSE(scoper_child);
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(1, alternate_deletes);
-
- scoper_child.reset(&dummy_value);
- EXPECT_TRUE(scoper_child);
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(1, alternate_deletes);
- scoped_ptr<double, CountingDeleter> scoper_construct(
- std::move(scoper_child));
- EXPECT_TRUE(scoper_construct);
- EXPECT_FALSE(scoper_child);
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(1, alternate_deletes);
-
- scoper_construct.reset();
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(2, alternate_deletes);
- }
-}
-
-TEST(ScopedPtrTest, ScopedPtrWithArray) {
- static const int kNumLoggers = 12;
-
- int constructed = 0;
-
- {
- scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]);
- EXPECT_TRUE(scoper);
- EXPECT_EQ(&scoper[0], scoper.get());
- for (int i = 0; i < kNumLoggers; ++i) {
- scoper[i].SetPtr(&constructed);
- }
- EXPECT_EQ(12, constructed);
-
- EXPECT_EQ(10, scoper.get()->SomeMeth(10));
- EXPECT_EQ(10, scoper[2].SomeMeth(10));
- }
- EXPECT_EQ(0, constructed);
-
- // Test reset() and release()
- {
- scoped_ptr<ConDecLogger[]> scoper;
- EXPECT_FALSE(scoper.get());
- EXPECT_FALSE(scoper.release());
- EXPECT_FALSE(scoper.get());
- scoper.reset();
- EXPECT_FALSE(scoper.get());
-
- scoper.reset(new ConDecLogger[kNumLoggers]);
- for (int i = 0; i < kNumLoggers; ++i) {
- scoper[i].SetPtr(&constructed);
- }
- EXPECT_EQ(12, constructed);
- scoper.reset();
- EXPECT_EQ(0, constructed);
-
- scoper.reset(new ConDecLogger[kNumLoggers]);
- for (int i = 0; i < kNumLoggers; ++i) {
- scoper[i].SetPtr(&constructed);
- }
- EXPECT_EQ(12, constructed);
- ConDecLogger* ptr = scoper.release();
- EXPECT_EQ(12, constructed);
- delete[] ptr;
- EXPECT_EQ(0, constructed);
- }
- EXPECT_EQ(0, constructed);
-
- // Test swap() and type-safe Boolean.
- {
- scoped_ptr<ConDecLogger[]> scoper1;
- scoped_ptr<ConDecLogger[]> scoper2;
- EXPECT_TRUE(scoper1.get() == scoper2.get());
- EXPECT_FALSE(scoper1.get() != scoper2.get());
-
- ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
- for (int i = 0; i < kNumLoggers; ++i) {
- loggers[i].SetPtr(&constructed);
- }
- scoper1.reset(loggers);
- EXPECT_TRUE(scoper1);
- EXPECT_EQ(loggers, scoper1.get());
- EXPECT_FALSE(scoper2);
- EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
-
- scoper2.swap(scoper1);
- EXPECT_EQ(loggers, scoper2.get());
- EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
- }
- EXPECT_EQ(0, constructed);
-
- {
- ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
- scoped_ptr<ConDecLogger[]> scoper(loggers);
- EXPECT_TRUE(scoper);
- for (int i = 0; i < kNumLoggers; ++i) {
- scoper[i].SetPtr(&constructed);
- }
- EXPECT_EQ(kNumLoggers, constructed);
-
- // Test moving with constructor;
- scoped_ptr<ConDecLogger[]> scoper2(std::move(scoper));
- EXPECT_EQ(kNumLoggers, constructed);
-
- // Test moving with assignment;
- scoped_ptr<ConDecLogger[]> scoper3;
- scoper3 = std::move(scoper2);
- EXPECT_EQ(kNumLoggers, constructed);
- EXPECT_FALSE(scoper);
- EXPECT_FALSE(scoper2);
- EXPECT_TRUE(scoper3);
- }
- EXPECT_EQ(0, constructed);
-}
-
-TEST(ScopedPtrTest, MoveBehavior) {
- int constructed = 0;
- {
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoped_ptr<ConDecLogger> scoper(logger);
- EXPECT_EQ(1, constructed);
-
- // Test moving with constructor;
- scoped_ptr<ConDecLogger> scoper2(std::move(scoper));
- EXPECT_EQ(1, constructed);
-
- // Test moving with assignment;
- scoped_ptr<ConDecLogger> scoper3;
- scoper3 = std::move(scoper2);
- EXPECT_EQ(1, constructed);
- EXPECT_FALSE(scoper.get());
- EXPECT_FALSE(scoper2.get());
- EXPECT_TRUE(scoper3.get());
- }
-
-#if !defined(OS_ANDROID) && !defined(OS_LINUX)
- // Test uncaught Pass() does not have side effects, because Pass()
- // is implemented by std::move().
- // TODO(danakj): Remove this test case when we remove Pass().
- {
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoped_ptr<ConDecLogger> scoper(logger);
- EXPECT_EQ(1, constructed);
-
- // Should auto-destruct logger by end of scope.
- scoped_ptr<ConDecLogger>&& rvalue = scoper.Pass();
- // The Pass() function mimics std::move(), which does not have side-effects.
- EXPECT_TRUE(scoper.get());
- EXPECT_TRUE(rvalue);
- }
- EXPECT_EQ(0, constructed);
-#endif
-
- // Test that passing to function which does nothing does not leak.
- {
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoped_ptr<ConDecLogger> scoper(logger);
- EXPECT_EQ(1, constructed);
-
- // Should auto-destruct logger by end of scope.
- GrabAndDrop(std::move(scoper));
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-}
-
-TEST(ScopedPtrTest, ReturnTypeBehavior) {
- int constructed = 0;
-
- // Test that we can return a scoped_ptr.
- {
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoped_ptr<ConDecLogger> scoper(logger);
- EXPECT_EQ(1, constructed);
-
- PassThru(std::move(scoper));
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-
- // Test uncaught return type not leak.
- {
- ConDecLogger* logger = new ConDecLogger(&constructed);
- scoped_ptr<ConDecLogger> scoper(logger);
- EXPECT_EQ(1, constructed);
-
- // Should auto-destruct logger by end of scope.
- PassThru(std::move(scoper));
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-
- // Call TestReturnOfType() so the compiler doesn't warn for an unused
- // function.
- {
- TestReturnOfType(&constructed);
- }
- EXPECT_EQ(0, constructed);
-}
-
-TEST(ScopedPtrTest, CustomDeleter) {
- double dummy_value; // Custom deleter never touches this value.
- int deletes = 0;
- int alternate_deletes = 0;
-
- // Normal delete support.
- {
- deletes = 0;
- scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
- CountingDeleter(&deletes));
- EXPECT_EQ(0, deletes);
- EXPECT_TRUE(scoper.get());
- }
- EXPECT_EQ(1, deletes);
-
- // Test reset() and release().
- deletes = 0;
- {
- scoped_ptr<double, CountingDeleter> scoper(NULL,
- CountingDeleter(&deletes));
- EXPECT_FALSE(scoper.get());
- EXPECT_FALSE(scoper.release());
- EXPECT_FALSE(scoper.get());
- scoper.reset();
- EXPECT_FALSE(scoper.get());
- EXPECT_EQ(0, deletes);
-
- scoper.reset(&dummy_value);
- scoper.reset();
- EXPECT_EQ(1, deletes);
-
- scoper.reset(&dummy_value);
- EXPECT_EQ(&dummy_value, scoper.release());
- }
- EXPECT_EQ(1, deletes);
-
- // Test get_deleter().
- deletes = 0;
- alternate_deletes = 0;
- {
- scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
- CountingDeleter(&deletes));
- // Call deleter manually.
- EXPECT_EQ(0, deletes);
- scoper.get_deleter()(&dummy_value);
- EXPECT_EQ(1, deletes);
-
- // Deleter is still there after reset.
- scoper.reset();
- EXPECT_EQ(2, deletes);
- scoper.get_deleter()(&dummy_value);
- EXPECT_EQ(3, deletes);
-
- // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
- scoper.get_deleter() = CountingDeleter(&alternate_deletes);
- scoper.reset(&dummy_value);
- EXPECT_EQ(0, alternate_deletes);
-
- }
- EXPECT_EQ(3, deletes);
- EXPECT_EQ(1, alternate_deletes);
-
- // Test operator= deleter support.
- deletes = 0;
- alternate_deletes = 0;
- {
- double dummy_value2;
- scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
- CountingDeleter(&deletes));
- scoped_ptr<double, CountingDeleter> scoper2(
- &dummy_value2,
- CountingDeleter(&alternate_deletes));
- EXPECT_EQ(0, deletes);
- EXPECT_EQ(0, alternate_deletes);
-
- // Pass the second deleter through a constructor and an operator=. Then
- // reinitialize the empty scopers to ensure that each one is deleting
- // properly.
- scoped_ptr<double, CountingDeleter> scoper3(std::move(scoper2));
- scoper = std::move(scoper3);
- EXPECT_EQ(1, deletes);
-
- scoper2.reset(&dummy_value2);
- scoper3.reset(&dummy_value2);
- EXPECT_EQ(0, alternate_deletes);
-
- }
- EXPECT_EQ(1, deletes);
- EXPECT_EQ(3, alternate_deletes);
-
- // Test swap(), and type-safe Boolean.
- {
- scoped_ptr<double, CountingDeleter> scoper1(NULL,
- CountingDeleter(&deletes));
- scoped_ptr<double, CountingDeleter> scoper2(NULL,
- CountingDeleter(&deletes));
- EXPECT_TRUE(scoper1.get() == scoper2.get());
- EXPECT_FALSE(scoper1.get() != scoper2.get());
-
- scoper1.reset(&dummy_value);
- EXPECT_TRUE(scoper1);
- EXPECT_EQ(&dummy_value, scoper1.get());
- EXPECT_FALSE(scoper2);
- EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
-
- scoper2.swap(scoper1);
- EXPECT_EQ(&dummy_value, scoper2.get());
- EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1.get() == scoper2.get());
- EXPECT_TRUE(scoper1.get() != scoper2.get());
- }
-}
-
-// Sanity check test for overloaded new and delete operators. Does not do full
-// coverage of reset/release/move operations as that is redundant with the
-// above.
-TEST(ScopedPtrTest, OverloadedNewAndDelete) {
- {
- OverloadedNewAndDelete::ResetCounters();
- scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<OverloadedNewAndDelete> scoper2(std::move(scoper));
- }
- EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
- EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
-}
-
-scoped_ptr<int> NullIntReturn() {
- return nullptr;
-}
-
-TEST(ScopedPtrTest, Nullptr) {
- scoped_ptr<int> scoper1(nullptr);
- scoped_ptr<int> scoper2(new int);
- scoper2 = nullptr;
- scoped_ptr<int> scoper3(NullIntReturn());
- scoped_ptr<int> scoper4 = NullIntReturn();
- EXPECT_EQ(nullptr, scoper1.get());
- EXPECT_EQ(nullptr, scoper2.get());
- EXPECT_EQ(nullptr, scoper3.get());
- EXPECT_EQ(nullptr, scoper4.get());
-}
-
-scoped_ptr<int[]> NullIntArrayReturn() {
- return nullptr;
-}
-
-TEST(ScopedPtrTest, NullptrArray) {
- scoped_ptr<int[]> scoper1(nullptr);
- scoped_ptr<int[]> scoper2(new int[3]);
- scoper2 = nullptr;
- scoped_ptr<int[]> scoper3(NullIntArrayReturn());
- scoped_ptr<int[]> scoper4 = NullIntArrayReturn();
- EXPECT_EQ(nullptr, scoper1.get());
- EXPECT_EQ(nullptr, scoper2.get());
- EXPECT_EQ(nullptr, scoper3.get());
- EXPECT_EQ(nullptr, scoper4.get());
-}
-
-class Super {};
-class Sub : public Super {};
-
-scoped_ptr<Sub> SubClassReturn() {
- return make_scoped_ptr(new Sub);
-}
-
-TEST(ScopedPtrTest, Conversion) {
- scoped_ptr<Sub> sub1(new Sub);
- scoped_ptr<Sub> sub2(new Sub);
-
- // Upcast with move works.
- scoped_ptr<Super> super1 = std::move(sub1);
- super1 = std::move(sub2);
-
- // Upcast with an rvalue works.
- scoped_ptr<Super> super2 = SubClassReturn();
- super2 = SubClassReturn();
-}
-
-// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
-// value first.
-TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
- scoped_ptr<int> x(new int);
- std::stringstream s1;
- s1 << x;
-
- std::stringstream s2;
- s2 << x.get();
-
- EXPECT_EQ(s2.str(), s1.str());
-}
-
-TEST(ScopedPtrTest, ReferenceCycle) {
- struct StructB;
- struct StructA {
- scoped_ptr<StructB> b;
- };
-
- struct StructB {
- scoped_ptr<StructA> a;
- };
-
- // Create a reference cycle.
- StructA* a = new StructA;
- a->b.reset(new StructB);
- a->b->a.reset(a);
-
- // Break the cycle by calling reset(). This will cause |a| (and hence, |a->b|)
- // to be deleted before the call to reset() returns. This tests that the
- // implementation of scoped_ptr::reset() doesn't access |this| after it
- // deletes the underlying pointer. This behaviour is consistent with the
- // definition of unique_ptr::reset in C++11.
- a->b.reset();
-
- // Go again, but this time, break the cycle by invoking |a|'s destructor. This
- // tests that the implementation of ~scoped_ptr doesn't infinitely recurse
- // into the destructors of |a| and |a->b|. Note, deleting |a| instead will
- // cause |a| to be double-free'd because |a->b| owns |a| and deletes it via
- // its destructor.
- a = new StructA;
- a->b.reset(new StructB);
- a->b->a.reset(a);
- a->~StructA();
-}
-
-TEST(ScopedPtrTest, Operators) {
- struct Parent {};
- struct Child : public Parent {};
-
- scoped_ptr<Parent> p(new Parent);
- scoped_ptr<Parent> p2(new Parent);
- scoped_ptr<Child> c(new Child);
- scoped_ptr<Parent> pnull;
-
- // Operator==.
- EXPECT_TRUE(p == p);
- EXPECT_FALSE(p == c);
- EXPECT_FALSE(p == p2);
- EXPECT_FALSE(p == pnull);
-
- EXPECT_FALSE(p == nullptr);
- EXPECT_FALSE(nullptr == p);
- EXPECT_TRUE(pnull == nullptr);
- EXPECT_TRUE(nullptr == pnull);
-
- // Operator!=.
- EXPECT_FALSE(p != p);
- EXPECT_TRUE(p != c);
- EXPECT_TRUE(p != p2);
- EXPECT_TRUE(p != pnull);
-
- EXPECT_TRUE(p != nullptr);
- EXPECT_TRUE(nullptr != p);
- EXPECT_FALSE(pnull != nullptr);
- EXPECT_FALSE(nullptr != pnull);
-
- // Compare two scoped_ptr<T>.
- EXPECT_EQ(p.get() < p2.get(), p < p2);
- EXPECT_EQ(p.get() <= p2.get(), p <= p2);
- EXPECT_EQ(p.get() > p2.get(), p > p2);
- EXPECT_EQ(p.get() >= p2.get(), p >= p2);
- EXPECT_EQ(p2.get() < p.get(), p2 < p);
- EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
- EXPECT_EQ(p2.get() > p.get(), p2 > p);
- EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
-
- // And convertible scoped_ptr<T> and scoped_ptr<U>.
- EXPECT_EQ(p.get() < c.get(), p < c);
- EXPECT_EQ(p.get() <= c.get(), p <= c);
- EXPECT_EQ(p.get() > c.get(), p > c);
- EXPECT_EQ(p.get() >= c.get(), p >= c);
- EXPECT_EQ(c.get() < p.get(), c < p);
- EXPECT_EQ(c.get() <= p.get(), c <= p);
- EXPECT_EQ(c.get() > p.get(), c > p);
- EXPECT_EQ(c.get() >= p.get(), c >= p);
-
- // Compare to nullptr.
- EXPECT_TRUE(p > nullptr);
- EXPECT_FALSE(nullptr > p);
- EXPECT_FALSE(pnull > nullptr);
- EXPECT_FALSE(nullptr > pnull);
-
- EXPECT_TRUE(p >= nullptr);
- EXPECT_FALSE(nullptr >= p);
- EXPECT_TRUE(pnull >= nullptr);
- EXPECT_TRUE(nullptr >= pnull);
-
- EXPECT_FALSE(p < nullptr);
- EXPECT_TRUE(nullptr < p);
- EXPECT_FALSE(pnull < nullptr);
- EXPECT_FALSE(nullptr < pnull);
-
- EXPECT_FALSE(p <= nullptr);
- EXPECT_TRUE(nullptr <= p);
- EXPECT_TRUE(pnull <= nullptr);
- EXPECT_TRUE(nullptr <= pnull);
-};
-
-TEST(ScopedPtrTest, ArrayOperators) {
- struct Parent {};
- struct Child : public Parent {};
-
- scoped_ptr<Parent[]> p(new Parent[1]);
- scoped_ptr<Parent[]> p2(new Parent[1]);
- scoped_ptr<Child[]> c(new Child[1]);
- scoped_ptr<Parent[]> pnull;
-
- // Operator==.
- EXPECT_TRUE(p == p);
- EXPECT_FALSE(p == c);
- EXPECT_FALSE(p == p2);
- EXPECT_FALSE(p == pnull);
-
- EXPECT_FALSE(p == nullptr);
- EXPECT_FALSE(nullptr == p);
- EXPECT_TRUE(pnull == nullptr);
- EXPECT_TRUE(nullptr == pnull);
-
- // Operator!=.
- EXPECT_FALSE(p != p);
- EXPECT_TRUE(p != c);
- EXPECT_TRUE(p != p2);
- EXPECT_TRUE(p != pnull);
-
- EXPECT_TRUE(p != nullptr);
- EXPECT_TRUE(nullptr != p);
- EXPECT_FALSE(pnull != nullptr);
- EXPECT_FALSE(nullptr != pnull);
-
- // Compare two scoped_ptr<T>.
- EXPECT_EQ(p.get() < p2.get(), p < p2);
- EXPECT_EQ(p.get() <= p2.get(), p <= p2);
- EXPECT_EQ(p.get() > p2.get(), p > p2);
- EXPECT_EQ(p.get() >= p2.get(), p >= p2);
- EXPECT_EQ(p2.get() < p.get(), p2 < p);
- EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
- EXPECT_EQ(p2.get() > p.get(), p2 > p);
- EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
-
- // And convertible scoped_ptr<T> and scoped_ptr<U>.
- EXPECT_EQ(p.get() < c.get(), p < c);
- EXPECT_EQ(p.get() <= c.get(), p <= c);
- EXPECT_EQ(p.get() > c.get(), p > c);
- EXPECT_EQ(p.get() >= c.get(), p >= c);
- EXPECT_EQ(c.get() < p.get(), c < p);
- EXPECT_EQ(c.get() <= p.get(), c <= p);
- EXPECT_EQ(c.get() > p.get(), c > p);
- EXPECT_EQ(c.get() >= p.get(), c >= p);
-
- // Compare to nullptr.
- EXPECT_TRUE(p > nullptr);
- EXPECT_FALSE(nullptr > p);
- EXPECT_FALSE(pnull > nullptr);
- EXPECT_FALSE(nullptr > pnull);
-
- EXPECT_TRUE(p >= nullptr);
- EXPECT_FALSE(nullptr >= p);
- EXPECT_TRUE(pnull >= nullptr);
- EXPECT_TRUE(nullptr >= pnull);
-
- EXPECT_FALSE(p < nullptr);
- EXPECT_TRUE(nullptr < p);
- EXPECT_FALSE(pnull < nullptr);
- EXPECT_FALSE(nullptr < pnull);
-
- EXPECT_FALSE(p <= nullptr);
- EXPECT_TRUE(nullptr <= p);
- EXPECT_TRUE(pnull <= nullptr);
- EXPECT_TRUE(nullptr <= pnull);
-}
diff --git a/third_party/chromium/base/memory/weak_ptr.cc b/third_party/chromium/base/memory/weak_ptr.cc
index 0f91ef3..7c9ced0 100644
--- a/third_party/chromium/base/memory/weak_ptr.cc
+++ b/third_party/chromium/base/memory/weak_ptr.cc
@@ -24,6 +24,8 @@
WeakReference::WeakReference() {
}
+WeakReference::WeakReference(const WeakReference& other) = default;
+
WeakReference::WeakReference(const Flag* flag) : flag_(flag) {
}
diff --git a/third_party/chromium/base/memory/weak_ptr.h b/third_party/chromium/base/memory/weak_ptr.h
index c1c52ee..601c379 100644
--- a/third_party/chromium/base/memory/weak_ptr.h
+++ b/third_party/chromium/base/memory/weak_ptr.h
@@ -70,6 +70,8 @@
#ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_
+#include <type_traits>
+
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -104,6 +106,7 @@
};
WeakReference();
+ WeakReference(const WeakReference& other);
explicit WeakReference(const Flag* flag);
~WeakReference();
@@ -156,10 +159,9 @@
// function that makes calling this easier.
template<typename Derived>
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
- typedef std::is_convertible<Derived*, internal::SupportsWeakPtrBase*>
- convertible;
- static_assert(convertible::value,
- "AsWeakPtr argument must inherit from SupportsWeakPtr");
+ static_assert(
+ std::is_base_of<internal::SupportsWeakPtrBase, Derived>::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
return AsWeakPtrImpl<Derived>(t, *t);
}
@@ -215,27 +217,38 @@
return get();
}
- // Allow WeakPtr<element_type> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
+ void reset() {
+ ref_ = internal::WeakReference();
+ ptr_ = NULL;
+ }
+
+ // Implement "Safe Bool Idiom"
+ // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
//
- // Note that this trick is only safe when the == and != operators
- // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2"
- // will compile but do the wrong thing (i.e., convert to Testable
- // and then do the comparison).
+ // Allow WeakPtr<element_type> to be used in boolean expressions such as
+ // if (weak_ptr_instance)
+ // But do not become convertible to a real bool (which is dangerous).
+ // Implementation requires:
+ // typedef Testable
+ // operator Testable() const
+ // operator==
+ // operator!=
+ //
+ // == and != operators must be declared explicitly or dissallowed, as
+ // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert
+ // to Testable and then do the comparison).
+ //
+ // C++11 provides for "explicit operator bool()", however it is currently
+ // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist
private:
typedef T* WeakPtr::*Testable;
public:
operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
- void reset() {
- ref_ = internal::WeakReference();
- ptr_ = NULL;
- }
-
private:
- // Explicitly declare comparison operators as required by the bool
- // trick, but keep them private.
+ // Explicitly declare comparison operators as required by the "Safe Bool
+ // Idiom", but keep them private.
template <class U> bool operator==(WeakPtr<U> const&) const;
template <class U> bool operator!=(WeakPtr<U> const&) const;
diff --git a/third_party/chromium/base/memory/weak_ptr_unittest.cc b/third_party/chromium/base/memory/weak_ptr_unittest.cc
index 8d4057c..fdbb280 100644
--- a/third_party/chromium/base/memory/weak_ptr_unittest.cc
+++ b/third_party/chromium/base/memory/weak_ptr_unittest.cc
@@ -119,6 +119,37 @@
EXPECT_EQ(&target, ptr.get());
}
+TEST(WeakPtrFactoryTest, BooleanTesting) {
+ int data;
+ WeakPtrFactory<int> factory(&data);
+
+ WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
+ EXPECT_TRUE(ptr_to_an_instance);
+ EXPECT_FALSE(!ptr_to_an_instance);
+
+ if (ptr_to_an_instance) {
+ } else {
+ ADD_FAILURE() << "Pointer to an instance should result in true.";
+ }
+
+ if (!ptr_to_an_instance) { // check for operator!().
+ ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+ }
+
+ WeakPtr<int> null_ptr;
+ EXPECT_FALSE(null_ptr);
+ EXPECT_TRUE(!null_ptr);
+
+ if (null_ptr) {
+ ADD_FAILURE() << "Null pointer should result in false.";
+ }
+
+ if (!null_ptr) { // check for operator!().
+ } else {
+ ADD_FAILURE() << "Null pointer should result in !x being true.";
+ }
+}
+
TEST(WeakPtrTest, InvalidateWeakPtrs) {
int data;
WeakPtrFactory<int> factory(&data);
diff --git a/third_party/chromium/base/move.h b/third_party/chromium/base/move.h
index 24bf9d7..42242b4 100644
--- a/third_party/chromium/base/move.h
+++ b/third_party/chromium/base/move.h
@@ -5,6 +5,7 @@
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
+// TODO(dcheng): Remove this header.
#include <utility>
#include "base/compiler_specific.h"
@@ -25,13 +26,11 @@
// into a scoped_ptr. The class must define a move constructor and move
// assignment operator to make this work.
//
-// This version of the macro adds a Pass() function and a cryptic
-// MoveOnlyTypeForCPP03 typedef for the base::Callback implementation to use.
-// See IsMoveOnlyType template and its usage in base/callback_internal.h
-// for more details.
+// This version of the macro adds a cryptic MoveOnlyTypeForCPP03 typedef for the
+// base::Callback implementation to use. See IsMoveOnlyType template and its
+// usage in base/callback_internal.h for more details.
// TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN
// everywhere instead.
-#if defined(OS_ANDROID) || defined(OS_LINUX)
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
private: \
type(const type&) = delete; \
@@ -41,17 +40,5 @@
typedef void MoveOnlyTypeForCPP03; \
\
private:
-#else
-#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
- private: \
- type(const type&) = delete; \
- void operator=(const type&) = delete; \
- \
- public: \
- type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
- typedef void MoveOnlyTypeForCPP03; \
- \
- private:
-#endif
#endif // BASE_MOVE_H_
diff --git a/third_party/chromium/base/numerics/safe_conversions_impl.h b/third_party/chromium/base/numerics/safe_conversions_impl.h
index e1d376a..03e7ee6 100644
--- a/third_party/chromium/base/numerics/safe_conversions_impl.h
+++ b/third_party/chromium/base/numerics/safe_conversions_impl.h
@@ -8,8 +8,6 @@
#include <limits.h>
#include <stdint.h>
-#include <limits>
-
namespace base {
namespace internal {
diff --git a/third_party/chromium/base/numerics/safe_math.h b/third_party/chromium/base/numerics/safe_math.h
index ddffb6e..9757f1c 100644
--- a/third_party/chromium/base/numerics/safe_math.h
+++ b/third_party/chromium/base/numerics/safe_math.h
@@ -6,6 +6,7 @@
#define BASE_NUMERICS_SAFE_MATH_H_
#include <stddef.h>
+#include <type_traits>
#include "base/numerics/safe_math_impl.h"
diff --git a/third_party/chromium/base/numerics/safe_numerics_unittest.cc b/third_party/chromium/base/numerics/safe_numerics_unittest.cc
index 8ac7b0c..de93e49 100644
--- a/third_party/chromium/base/numerics/safe_numerics_unittest.cc
+++ b/third_party/chromium/base/numerics/safe_numerics_unittest.cc
@@ -13,7 +13,6 @@
#include "base/compiler_specific.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
-#include "base/template_util.h"
using std::numeric_limits;
using base::CheckedNumeric;
diff --git a/third_party/chromium/base/rand_util.cc b/third_party/chromium/base/rand_util.cc
index c02c875..fab6c66 100644
--- a/third_party/chromium/base/rand_util.cc
+++ b/third_party/chromium/base/rand_util.cc
@@ -68,8 +68,8 @@
std::string RandBytesAsString(size_t length) {
DCHECK_GT(length, 0u);
- std::string result(length, ' ');
- RandBytes(&result[0], length);
+ std::string result;
+ RandBytes(WriteInto(&result, length + 1), length);
return result;
}
diff --git a/third_party/chromium/base/strings/string_number_conversions.cc b/third_party/chromium/base/strings/string_number_conversions.cc
index ac0fd46..529e913 100644
--- a/third_party/chromium/base/strings/string_number_conversions.cc
+++ b/third_party/chromium/base/strings/string_number_conversions.cc
@@ -136,6 +136,7 @@
if (begin != end && *begin == '-') {
if (!std::numeric_limits<value_type>::is_signed) {
+ *output = 0;
valid = false;
} else if (!Negative::Invoke(begin + 1, end, output)) {
valid = false;
diff --git a/third_party/chromium/base/strings/string_number_conversions_unittest.cc b/third_party/chromium/base/strings/string_number_conversions_unittest.cc
index 1cfb2c8..d570c08 100644
--- a/third_party/chromium/base/strings/string_number_conversions_unittest.cc
+++ b/third_party/chromium/base/strings/string_number_conversions_unittest.cc
@@ -133,7 +133,7 @@
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- int output = 0;
+ int output = cases[i].output ^ 1; // Ensure StringToInt wrote something.
EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -182,7 +182,8 @@
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- unsigned output = 0;
+ unsigned output =
+ cases[i].output ^ 1; // Ensure StringToUint wrote something.
EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
diff --git a/third_party/chromium/base/strings/string_piece.h b/third_party/chromium/base/strings/string_piece.h
index c79d9fa..b68b1f2 100644
--- a/third_party/chromium/base/strings/string_piece.h
+++ b/third_party/chromium/base/strings/string_piece.h
@@ -143,6 +143,8 @@
}
value_type operator[](size_type i) const { return ptr_[i]; }
+ value_type front() const { return ptr_[0]; }
+ value_type back() const { return ptr_[length_ - 1]; }
void remove_prefix(size_type n) {
ptr_ += n;
diff --git a/third_party/chromium/base/strings/string_util.cc b/third_party/chromium/base/strings/string_util.cc
index eb0c546..50f7a23 100644
--- a/third_party/chromium/base/strings/string_util.cc
+++ b/third_party/chromium/base/strings/string_util.cc
@@ -242,4 +242,17 @@
return true;
}
+
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(string_type* str,
+ size_t length_with_null) {
+ DCHECK_GT(length_with_null, 1u);
+ str->reserve(length_with_null);
+ str->resize(length_with_null - 1);
+ return &((*str)[0]);
+}
+
+char* WriteInto(std::string* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
+}
} // namespace base
diff --git a/third_party/chromium/base/strings/string_util.h b/third_party/chromium/base/strings/string_util.h
index d6b6e10..f505bb6 100644
--- a/third_party/chromium/base/strings/string_util.h
+++ b/third_party/chromium/base/strings/string_util.h
@@ -173,6 +173,28 @@
bool IsStringUTF8(const StringPiece& str);
bool IsStringASCII(const StringPiece& str);
+// Reserves enough memory in |str| to accommodate |length_with_null| characters,
+// sets the size of |str| to |length_with_null - 1| characters, and returns a
+// pointer to the underlying contiguous array of characters. This is typically
+// used when calling a function that writes results into a character array, but
+// the caller wants the data to be managed by a string-like object. It is
+// convenient in that is can be used inline in the call, and fast in that it
+// avoids copying the results of the call from a char* into a string.
+//
+// |length_with_null| must be at least 2, since otherwise the underlying string
+// would have size 0, and trying to access &((*str)[0]) in that case can result
+// in a number of problems.
+//
+// Internally, this takes linear time because the resize() call 0-fills the
+// underlying array for potentially all
+// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes. Ideally we
+// could avoid this aspect of the resize() call, as we expect the caller to
+// immediately write over this memory, but there is no other way to set the size
+// of the string, and not doing that will mean people who access |str| rather
+// than str.c_str() will get back a string of whatever size |str| had on entry
+// to this function (probably 0).
+char* WriteInto(std::string* str, size_t length_with_null);
+
} // namespace base
#if defined(OS_WIN)
diff --git a/third_party/chromium/base/strings/string_util_unittest.cc b/third_party/chromium/base/strings/string_util_unittest.cc
index 451fbd8..8d77d36 100644
--- a/third_party/chromium/base/strings/string_util_unittest.cc
+++ b/third_party/chromium/base/strings/string_util_unittest.cc
@@ -147,4 +147,39 @@
}
}
+class WriteIntoTest : public testing::Test {
+ protected:
+ static void WritesCorrectly(size_t num_chars) {
+ std::string buffer;
+ char kOriginal[] = "supercali";
+ strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars);
+ // Using std::string(buffer.c_str()) instead of |buffer| truncates the
+ // string at the first \0.
+ EXPECT_EQ(std::string(kOriginal,
+ std::min(num_chars, arraysize(kOriginal) - 1)),
+ std::string(buffer.c_str()));
+ EXPECT_EQ(num_chars, buffer.size());
+ }
+};
+
+TEST_F(WriteIntoTest, WriteInto) {
+ // Validate that WriteInto reserves enough space and
+ // sizes a string correctly.
+ WritesCorrectly(1);
+ WritesCorrectly(2);
+ WritesCorrectly(5000);
+
+ // Validate that WriteInto doesn't modify other strings
+ // when using a Copy-on-Write implementation.
+ const char kLive[] = "live";
+ const char kDead[] = "dead";
+ const std::string live = kLive;
+ std::string dead = live;
+ strncpy(WriteInto(&dead, 5), kDead, 4);
+ EXPECT_EQ(kDead, dead);
+ EXPECT_EQ(4u, dead.size());
+ EXPECT_EQ(kLive, live);
+ EXPECT_EQ(4u, live.size());
+}
+
} // namespace base
diff --git a/third_party/chromium/base/template_util.h b/third_party/chromium/base/template_util.h
index 7b61d24..0c3cac2 100644
--- a/third_party/chromium/base/template_util.h
+++ b/third_party/chromium/base/template_util.h
@@ -5,7 +5,6 @@
#ifndef BASE_TEMPLATE_UTIL_H_
#define BASE_TEMPLATE_UTIL_H_
-#include <stddef.h>
#include <type_traits>
#include "build/build_config.h"
@@ -16,18 +15,6 @@
template <class T> struct is_non_const_reference<T&> : std::true_type {};
template <class T> struct is_non_const_reference<const T&> : std::false_type {};
-namespace internal {
-
-// Types YesType and NoType are guaranteed such that sizeof(YesType) <
-// sizeof(NoType).
-typedef char YesType;
-
-struct NoType {
- YesType dummy[2];
-};
-
-} // namespace internal
-
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/third_party/chromium/base/template_util_unittest.cc b/third_party/chromium/base/template_util_unittest.cc
index ce029af..25f4ba3 100644
--- a/third_party/chromium/base/template_util_unittest.cc
+++ b/third_party/chromium/base/template_util_unittest.cc
@@ -10,106 +10,11 @@
namespace base {
namespace {
-struct AStruct {};
-class AClass {};
-enum AnEnum {};
-
-class Parent {};
-class Child : public Parent {};
-
-using std::is_pointer;
-using std::is_array;
-using std::is_convertible;
-using std::is_same;
-using std::is_class;
-using std::is_member_function_pointer;
-
-// is_pointer<Type>
-static_assert(!is_pointer<int>::value, "IsPointer");
-static_assert(!is_pointer<int&>::value, "IsPointer");
-static_assert(is_pointer<int*>::value, "IsPointer");
-static_assert(is_pointer<const int*>::value, "IsPointer");
-
-// is_array<Type>
-static_assert(!is_array<int>::value, "IsArray");
-static_assert(!is_array<int*>::value, "IsArray");
-static_assert(!is_array<int (*)[3]>::value, "IsArray");
-static_assert(is_array<int[]>::value, "IsArray");
-static_assert(is_array<const int[]>::value, "IsArray");
-static_assert(is_array<int[3]>::value, "IsArray");
-
// is_non_const_reference<Type>
static_assert(!is_non_const_reference<int>::value, "IsNonConstReference");
static_assert(!is_non_const_reference<const int&>::value,
"IsNonConstReference");
static_assert(is_non_const_reference<int&>::value, "IsNonConstReference");
-// is_convertible<From, To>
-
-// Extra parens needed to make preprocessor macro parsing happy. Otherwise,
-// it sees the equivalent of:
-//
-// (is_convertible < Child), (Parent > ::value)
-//
-// Silly C++.
-static_assert((is_convertible<Child, Parent>::value), "IsConvertible");
-static_assert(!(is_convertible<Parent, Child>::value), "IsConvertible");
-static_assert(!(is_convertible<Parent, AStruct>::value), "IsConvertible");
-static_assert((is_convertible<int, double>::value), "IsConvertible");
-static_assert((is_convertible<int*, void*>::value), "IsConvertible");
-static_assert(!(is_convertible<void*, int*>::value), "IsConvertible");
-
-// Array types are an easy corner case. Make sure to test that
-// it does indeed compile.
-static_assert(!(is_convertible<int[10], double>::value), "IsConvertible");
-static_assert(!(is_convertible<double, int[10]>::value), "IsConvertible");
-static_assert((is_convertible<int[10], int*>::value), "IsConvertible");
-
-// is_same<Type1, Type2>
-static_assert(!(is_same<Child, Parent>::value), "IsSame");
-static_assert(!(is_same<Parent, Child>::value), "IsSame");
-static_assert((is_same<Parent, Parent>::value), "IsSame");
-static_assert((is_same<int*, int*>::value), "IsSame");
-static_assert((is_same<int, int>::value), "IsSame");
-static_assert((is_same<void, void>::value), "IsSame");
-static_assert(!(is_same<int, double>::value), "IsSame");
-
-// is_class<Type>
-static_assert(is_class<AStruct>::value, "IsClass");
-static_assert(is_class<AClass>::value, "IsClass");
-static_assert(!is_class<AnEnum>::value, "IsClass");
-static_assert(!is_class<int>::value, "IsClass");
-static_assert(!is_class<char*>::value, "IsClass");
-static_assert(!is_class<int&>::value, "IsClass");
-static_assert(!is_class<char[3]>::value, "IsClass");
-
-static_assert(!is_member_function_pointer<int>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<int*>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<void*>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<AStruct>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<AStruct*>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<void (*)()>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<int (*)(int)>::value,
- "IsMemberFunctionPointer");
-static_assert(!is_member_function_pointer<int (*)(int, int)>::value,
- "IsMemberFunctionPointer");
-
-static_assert(is_member_function_pointer<void (AStruct::*)()>::value,
- "IsMemberFunctionPointer");
-static_assert(is_member_function_pointer<void (AStruct::*)(int)>::value,
- "IsMemberFunctionPointer");
-static_assert(is_member_function_pointer<int (AStruct::*)(int)>::value,
- "IsMemberFunctionPointer");
-static_assert(is_member_function_pointer<int (AStruct::*)(int) const>::value,
- "IsMemberFunctionPointer");
-static_assert(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
- "IsMemberFunctionPointer");
-
} // namespace
} // namespace base
diff --git a/third_party/chromium/base/tuple.h b/third_party/chromium/base/tuple.h
index e5872cc..78dfd75 100644
--- a/third_party/chromium/base/tuple.h
+++ b/third_party/chromium/base/tuple.h
@@ -29,6 +29,7 @@
#define BASE_TUPLE_H_
#include <stddef.h>
+#include <tuple>
#include "base/bind_helpers.h"
#include "build/build_config.h"
@@ -109,28 +110,6 @@
template <size_t N>
using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
-// Traits ----------------------------------------------------------------------
-//
-// A simple traits class for tuple arguments.
-//
-// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
-// RefType: the ref version of a type (same as the type for refs).
-// ParamType: what type to pass to functions (refs should not be constified).
-
-template <class P>
-struct TupleTraits {
- typedef P ValueType;
- typedef P& RefType;
- typedef const P& ParamType;
-};
-
-template <class P>
-struct TupleTraits<P&> {
- typedef P ValueType;
- typedef P& RefType;
- typedef P& ParamType;
-};
-
// Tuple -----------------------------------------------------------------------
//
// This set of classes is useful for bundling 0 or more heterogeneous data types
@@ -145,75 +124,10 @@
// want filled by the dispatchee, and the tuple is merely a container for that
// output (a "tier"). See MakeRefTuple and its usages.
-template <typename IxSeq, typename... Ts>
-struct TupleBaseImpl;
template <typename... Ts>
-using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
-template <size_t N, typename T>
-struct TupleLeaf;
+using Tuple = std::tuple<Ts...>;
-template <typename... Ts>
-struct Tuple final : TupleBase<Ts...> {
- Tuple() : TupleBase<Ts...>() {}
- explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
- : TupleBase<Ts...>(args...) {}
-};
-
-// Avoids ambiguity between Tuple's two constructors.
-template <>
-struct Tuple<> final {};
-
-template <size_t... Ns, typename... Ts>
-struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
- TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
- explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
- : TupleLeaf<Ns, Ts>(args)... {}
-};
-
-template <size_t N, typename T>
-struct TupleLeaf {
- TupleLeaf() {}
- explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
-
- T& get() { return x; }
- const T& get() const { return x; }
-
- T x;
-};
-
-// Tuple getters --------------------------------------------------------------
-//
-// Allows accessing an arbitrary tuple element by index.
-//
-// Example usage:
-// base::Tuple<int, double> t2;
-// base::get<0>(t2) = 42;
-// base::get<1>(t2) = 3.14;
-
-template <size_t I, typename T>
-T& get(TupleLeaf<I, T>& leaf) {
- return leaf.get();
-}
-
-template <size_t I, typename T>
-const T& get(const TupleLeaf<I, T>& leaf) {
- return leaf.get();
-}
-
-// Tuple types ----------------------------------------------------------------
-//
-// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
-// definitions of class types the tuple takes as parameters.
-
-template <typename T>
-struct TupleTypes;
-
-template <typename... Ts>
-struct TupleTypes<Tuple<Ts...>> {
- using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>;
- using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>;
- using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>;
-};
+using std::get;
// Tuple creators -------------------------------------------------------------
//
@@ -245,15 +159,15 @@
// Non-Static Dispatchers with no out params.
template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
-inline void DispatchToMethodImpl(ObjT* obj,
+inline void DispatchToMethodImpl(const ObjT& obj,
Method method,
const Tuple<Ts...>& arg,
IndexSequence<Ns...>) {
- (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+ (obj->*method)(internal::Unwrap(get<Ns>(arg))...);
}
template <typename ObjT, typename Method, typename... Ts>
-inline void DispatchToMethod(ObjT* obj,
+inline void DispatchToMethod(const ObjT& obj,
Method method,
const Tuple<Ts...>& arg) {
DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
@@ -265,7 +179,7 @@
inline void DispatchToFunctionImpl(Function function,
const Tuple<Ts...>& arg,
IndexSequence<Ns...>) {
- (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+ (*function)(internal::Unwrap(get<Ns>(arg))...);
}
template <typename Function, typename... Ts>
@@ -281,18 +195,17 @@
typename... OutTs,
size_t... InNs,
size_t... OutNs>
-inline void DispatchToMethodImpl(ObjT* obj,
+inline void DispatchToMethodImpl(const ObjT& obj,
Method method,
const Tuple<InTs...>& in,
Tuple<OutTs...>* out,
IndexSequence<InNs...>,
IndexSequence<OutNs...>) {
- (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))...,
- &get<OutNs>(*out)...);
+ (obj->*method)(internal::Unwrap(get<InNs>(in))..., &get<OutNs>(*out)...);
}
template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
-inline void DispatchToMethod(ObjT* obj,
+inline void DispatchToMethod(const ObjT& obj,
Method method,
const Tuple<InTs...>& in,
Tuple<OutTs...>* out) {
diff --git a/third_party/chromium/base/values.cc b/third_party/chromium/base/values.cc
index 55719da..29f0301 100644
--- a/third_party/chromium/base/values.cc
+++ b/third_party/chromium/base/values.cc
@@ -794,6 +794,8 @@
: target_(target),
it_(target.dictionary_.begin()) {}
+DictionaryValue::Iterator::Iterator(const Iterator& other) = default;
+
DictionaryValue::Iterator::~Iterator() {}
DictionaryValue* DictionaryValue::DeepCopy() const {
diff --git a/third_party/chromium/base/values.h b/third_party/chromium/base/values.h
index 25d2a79..36e24cc 100644
--- a/third_party/chromium/base/values.h
+++ b/third_party/chromium/base/values.h
@@ -348,6 +348,7 @@
class BASE_EXPORT Iterator {
public:
explicit Iterator(const DictionaryValue& target);
+ Iterator(const Iterator& other);
~Iterator();
bool IsAtEnd() const { return it_ == target_.dictionary_.end(); }