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(); }