Commit 3e6d120b authored by sergeyu@chromium.org's avatar sergeyu@chromium.org

Revert 113722 - Add Pass(), which implements move semantics, to scoped_ptr,...

Revert 113722 - Add Pass(), which implements move semantics, to scoped_ptr, scoped_array, and scoped_ptr_malloc.

This modification to the scopers implements the "moveable but not copyable" semantics that were introduced in C++11's unique_ptr<>.

With this, is now possible to use scopers as an argument type or a return type.  This signifies, in the type system, transfer of ownership into a function or out of a function respectively.  Calling, or returning such a function MUST use the temporary resulting from the scoper's Pass() function. You CANNOT just pass the scoper by copy as there is still no copy constructor or assignment operator; trying to do so will yield a compilation error.

This distinction makes it possible to avoid the implicit ownership transfer issues of auto_ptr, but still allow us to have compiler enforced ownership transfer.

Also adds a Passed() helper that allows using a scoper with Bind().

BUG=96118
TEST=new unittests

Review URL: http://codereview.chromium.org/8774032

TBR=ajwong@chromium.org
Review URL: http://codereview.chromium.org/8890060

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113738 0039d316-1c4b-4281-b951-d872f2087c98
parent d17d2fcf
...@@ -6,29 +6,19 @@ ...@@ -6,29 +6,19 @@
// can be used specify the refcounting and reference semantics of arguments // can be used specify the refcounting and reference semantics of arguments
// that are bound by the Bind() function in base/bind.h. // that are bound by the Bind() function in base/bind.h.
// //
// The public functions are base::Unretained(), base::Owned(), bass::Passed(), // The public functions are base::Unretained(), base::Owned(),
// base::ConstRef(), and base::IgnoreResult(). // base::ConstRef(), and base::IgnoreReturn().
// //
// Unretained() allows Bind() to bind a non-refcounted class, and to disable // Unretained() allows Bind() to bind a non-refcounted class, and to disable
// refcounting on arguments that are refcounted objects. // refcounting on arguments that are refcounted objects.
//
// Owned() transfers ownership of an object to the Callback resulting from // Owned() transfers ownership of an object to the Callback resulting from
// bind; the object will be deleted when the Callback is deleted. // bind; the object will be deleted when the Callback is deleted.
//
// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
// through a Callback. Logically, this signifies a destructive transfer of
// the state of the argument into the target function. Invoking
// Callback::Run() twice on a Callback that was created with a Passed()
// argument will CHECK() because the first invocation would have already
// transferred ownership to the target function.
//
// ConstRef() allows binding a constant reference to an argument rather // ConstRef() allows binding a constant reference to an argument rather
// than a copy. // than a copy.
// IgnoreReturn() is used to adapt a 0-argument Callback with a return type to
// a Closure. This is useful if you need to PostTask with a function that has
// a return value that you don't care about.
// //
// IgnoreResult() is used to adapt a function or Callback with a return type to
// one with a void return. This is most useful if you have a function with,
// say, a pesky ignorable bool return that you want to use with PostTask or
// something else that expect a Callback with a void return.
// //
// EXAMPLE OF Unretained(): // EXAMPLE OF Unretained():
// //
...@@ -85,45 +75,13 @@ ...@@ -85,45 +75,13 @@
// its bound callbacks. // its bound callbacks.
// //
// //
// EXAMPLE OF IgnoreResult(): // EXAMPLE OF IgnoreReturn():
// //
// int DoSomething(int arg) { cout << arg << endl; } // int DoSomething(int arg) { cout << arg << endl; }
// // Callback<int(void)> cb = Bind(&DoSomething, 1);
// // Assign to a Callback with a void return type. // Closure c = IgnoreReturn(cb); // Prints "1"
// Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething)); // or
// cb->Run(1); // Prints "1". // ml->PostTask(FROM_HERE, IgnoreReturn(cb)); // Prints "1" on |ml|
//
// // Prints "1" on |ml|.
// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
//
//
// EXAMPLE OF Passed():
//
// void TakesOwnership(scoped_ptr<Foo> arg) { }
// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
//
// scoped_ptr<Foo> f(new Foo());
//
// // |cb| is given ownership of Foo(). |f| is now NULL.
// // You can use f.Pass() in place of &f, but it's more verbose.
// Closure cb = Bind(&TakesOwnership, Passed(&f));
//
// // Run was never called so |cb| still owns Foo() and deletes
// // it on Reset().
// cb.Reset();
//
// // |cb| is given a new Foo created by CreateFoo().
// cb = Bind(&TakesOwnership, Passed(CreateFoo()));
//
// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
// // no longer owns Foo() and, if reset, would not delete Foo().
// cb.Run(); // Foo() is now transferred to |arg| and deleted.
// cb.Run(); // This CHECK()s since Foo() already been used once.
//
// Passed() is particularly useful with PostTask() when you are transferring
// ownership of an argument into a task, but don't necessarily know if the
// task will always be executed. This can happen if the task is cancellable
// or if it is posted to a MessageLoopProxy.
#ifndef BASE_BIND_HELPERS_H_ #ifndef BASE_BIND_HELPERS_H_
#define BASE_BIND_HELPERS_H_ #define BASE_BIND_HELPERS_H_
...@@ -329,45 +287,6 @@ class OwnedWrapper { ...@@ -329,45 +287,6 @@ class OwnedWrapper {
mutable T* ptr_; mutable T* ptr_;
}; };
// PassedWrapper is a copyable adapter for a scoper that ignores const.
//
// It is needed to get around the fact that Bind() takes a const reference to
// all its arguments. Because Bind() takes a const reference to avoid
// unnecessary copies, it is incompatible with movable-but-not-copyable
// types; doing a destructive "move" of the type into Bind() would violate
// the const correctness.
//
// This conundrum cannot be solved without either C++11 rvalue references or
// a O(2^n) blowup of Bind() templates to handle each combination of regular
// types and movable-but-not-copyable types. Thus we introduce a wrapper type
// that is copyable to transmit the correct type information down into
// BindState<>. Ignoring const in this type makes sense because it is only
// created when we are explicitly trying to do a destructive move.
//
// Two notes:
// 1) PassedWrapper supports any type that has a "Pass()" function.
// This is intentional. The whitelisting of which specific types we
// support is maintained by CallbackParamTraits<>.
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
// scoper to a Callback and allow the Callback to execute once.
template <typename T>
class PassedWrapper {
public:
explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
PassedWrapper(const PassedWrapper& other)
: is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
}
T Pass() const {
CHECK(is_valid_);
is_valid_ = false;
return scoper_.Pass();
}
private:
mutable bool is_valid_;
mutable T scoper_;
};
// Unwrap the stored parameters for the wrappers above. // Unwrap the stored parameters for the wrappers above.
template <typename T> template <typename T>
struct UnwrapTraits { struct UnwrapTraits {
...@@ -411,17 +330,9 @@ struct UnwrapTraits<OwnedWrapper<T> > { ...@@ -411,17 +330,9 @@ struct UnwrapTraits<OwnedWrapper<T> > {
} }
}; };
template <typename T>
struct UnwrapTraits<PassedWrapper<T> > {
typedef T ForwardType;
static T Unwrap(PassedWrapper<T>& o) {
return o.Pass();
}
};
// Utility for handling different refcounting semantics in the Bind() // Utility for handling different refcounting semantics in the Bind()
// function. // function.
template <bool is_method, typename T> template <bool, typename T>
struct MaybeRefcount; struct MaybeRefcount;
template <typename T> template <typename T>
...@@ -436,18 +347,24 @@ struct MaybeRefcount<false, T[n]> { ...@@ -436,18 +347,24 @@ struct MaybeRefcount<false, T[n]> {
static void Release(const T*) {} static void Release(const T*) {}
}; };
template <typename T>
struct MaybeRefcount<true, T> {
static void AddRef(const T&) {}
static void Release(const T&) {}
};
template <typename T> template <typename T>
struct MaybeRefcount<true, T*> { struct MaybeRefcount<true, T*> {
static void AddRef(T* o) { o->AddRef(); } static void AddRef(T* o) { o->AddRef(); }
static void Release(T* o) { o->Release(); } static void Release(T* o) { o->Release(); }
}; };
template <typename T>
struct MaybeRefcount<true, UnretainedWrapper<T> > {
static void AddRef(const UnretainedWrapper<T>&) {}
static void Release(const UnretainedWrapper<T>&) {}
};
template <typename T>
struct MaybeRefcount<true, OwnedWrapper<T> > {
static void AddRef(const OwnedWrapper<T>&) {}
static void Release(const OwnedWrapper<T>&) {}
};
// No need to additionally AddRef() and Release() since we are storing a // No need to additionally AddRef() and Release() since we are storing a
// scoped_refptr<> inside the storage object already. // scoped_refptr<> inside the storage object already.
template <typename T> template <typename T>
...@@ -462,13 +379,19 @@ struct MaybeRefcount<true, const T*> { ...@@ -462,13 +379,19 @@ struct MaybeRefcount<true, const T*> {
static void Release(const T* o) { o->Release(); } static void Release(const T* o) { o->Release(); }
}; };
template <typename T>
struct MaybeRefcount<true, WeakPtr<T> > {
static void AddRef(const WeakPtr<T>&) {}
static void Release(const WeakPtr<T>&) {}
};
template <typename R> template <typename R>
void VoidReturnAdapter(Callback<R(void)> callback) { void VoidReturnAdapter(Callback<R(void)> callback) {
callback.Run(); callback.Run();
} }
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a // 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 // method. It is unsed internally by Bind() to select the correct
// InvokeHelper that will no-op itself in the event the WeakPtr<> for // InvokeHelper that will no-op itself in the event the WeakPtr<> for
// the target object is invalidated. // the target object is invalidated.
// //
...@@ -499,20 +422,6 @@ static inline internal::OwnedWrapper<T> Owned(T* o) { ...@@ -499,20 +422,6 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(o); return internal::OwnedWrapper<T>(o);
} }
// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
// is best suited for use with the return value of a function. The second
// takes a pointer to the scoper and is just syntactic sugar to avoid having
// to write Passed(scoper.Pass()).
template <typename T>
static inline internal::PassedWrapper<T> Passed(T scoper) {
return internal::PassedWrapper<T>(scoper.Pass());
}
template <typename T>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
return internal::PassedWrapper<T>(scoper->Pass());
}
// -- DEPRECATED -- Use IgnoreResult instead.
template <typename R> template <typename R>
static inline Closure IgnoreReturn(Callback<R(void)> callback) { static inline Closure IgnoreReturn(Callback<R(void)> callback) {
return Bind(&internal::VoidReturnAdapter<R>, callback); return Bind(&internal::VoidReturnAdapter<R>, callback);
...@@ -529,6 +438,7 @@ IgnoreResult(const Callback<T>& data) { ...@@ -529,6 +438,7 @@ IgnoreResult(const Callback<T>& data) {
return internal::IgnoreResultHelper<Callback<T> >(data); return internal::IgnoreResultHelper<Callback<T> >(data);
} }
} // namespace base } // namespace base
#endif // BASE_BIND_HELPERS_H_ #endif // BASE_BIND_HELPERS_H_
This diff is collapsed.
...@@ -82,6 +82,7 @@ namespace internal { ...@@ -82,6 +82,7 @@ namespace internal {
// into the Bind() system, doing most of the type resolution. // into the Bind() system, doing most of the type resolution.
// There are ARITY BindState types. // There are ARITY BindState types.
// RunnableAdapter<> // RunnableAdapter<>
// //
// The RunnableAdapter<> templates provide a uniform interface for invoking // The RunnableAdapter<> templates provide a uniform interface for invoking
...@@ -120,7 +121,7 @@ class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> { ...@@ -120,7 +121,7 @@ class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> {
} }
R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
return function_($for ARG , [[CallbackForward(a$(ARG))]]); return function_($for ARG , [[a$(ARG)]]);
} }
private: private:
...@@ -142,7 +143,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); ...@@ -142,7 +143,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
R Run(T* object[[]] R Run(T* object[[]]
$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { $if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); return (object->*method_)($for ARG , [[a$(ARG)]]);
} }
private: private:
...@@ -164,7 +165,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); ...@@ -164,7 +165,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
R Run(const T* object[[]] R Run(const T* object[[]]
$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { $if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); return (object->*method_)($for ARG , [[a$(ARG)]]);
} }
private: private:
...@@ -290,7 +291,7 @@ struct InvokeHelper<false, ReturnType, Runnable, ...@@ -290,7 +291,7 @@ struct InvokeHelper<false, ReturnType, Runnable,
void($for ARG , [[A$(ARG)]])> { void($for ARG , [[A$(ARG)]])> {
static ReturnType MakeItSo(Runnable runnable[[]] static ReturnType MakeItSo(Runnable runnable[[]]
$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { $if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
return runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); return runnable.Run($for ARG , [[a$(ARG)]]);
} }
}; };
...@@ -300,7 +301,7 @@ struct InvokeHelper<false, void, Runnable, ...@@ -300,7 +301,7 @@ struct InvokeHelper<false, void, Runnable,
void($for ARG , [[A$(ARG)]])> { void($for ARG , [[A$(ARG)]])> {
static void MakeItSo(Runnable runnable[[]] static void MakeItSo(Runnable runnable[[]]
$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { $if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); runnable.Run($for ARG , [[a$(ARG)]]);
} }
}; };
...@@ -315,7 +316,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { ...@@ -315,7 +316,7 @@ $if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
return; return;
} }
runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); runnable.Run($for ARG , [[a$(ARG)]]);
} }
}; };
...@@ -403,7 +404,7 @@ typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG) ...@@ -403,7 +404,7 @@ typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)
]] ]]
)> )>
::MakeItSo(storage->runnable_ ::MakeItSo(storage->runnable_
$if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]); $if ARITY > 0[[, ]] $for ARG , [[x$(ARG)]]);
} }
}; };
......
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -105,7 +102,7 @@ class CopyCounter { ...@@ -105,7 +102,7 @@ class CopyCounter {
(*copies_)++; (*copies_)++;
} }
// Probing for copies from coercion. // Probing for copies from coerscion.
CopyCounter(const DerivedCopyCounter& other) CopyCounter(const DerivedCopyCounter& other)
: copies_(other.copies_), : copies_(other.copies_),
assigns_(other.assigns_) { assigns_(other.assigns_) {
...@@ -152,11 +149,6 @@ class DeleteCounter { ...@@ -152,11 +149,6 @@ class DeleteCounter {
int* deletes_; int* deletes_;
}; };
template <typename T>
T PassThru(T scoper) {
return scoper.Pass();
}
// Some test functions that we can Bind to. // Some test functions that we can Bind to.
template <typename T> template <typename T>
T PolymorphicIdentity(T t) { T PolymorphicIdentity(T t) {
...@@ -649,8 +641,8 @@ TEST_F(BindTest, Owned) { ...@@ -649,8 +641,8 @@ TEST_F(BindTest, Owned) {
// return the same value. // return the same value.
Callback<DeleteCounter*(void)> no_capture_cb = Callback<DeleteCounter*(void)> no_capture_cb =
Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter)); Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
ASSERT_EQ(counter, no_capture_cb.Run()); EXPECT_EQ(counter, no_capture_cb.Run());
ASSERT_EQ(counter, no_capture_cb.Run()); EXPECT_EQ(counter, no_capture_cb.Run());
EXPECT_EQ(0, deletes); EXPECT_EQ(0, deletes);
no_capture_cb.Reset(); // This should trigger a delete. no_capture_cb.Reset(); // This should trigger a delete.
EXPECT_EQ(1, deletes); EXPECT_EQ(1, deletes);
...@@ -665,60 +657,11 @@ TEST_F(BindTest, Owned) { ...@@ -665,60 +657,11 @@ TEST_F(BindTest, Owned) {
EXPECT_EQ(1, deletes); EXPECT_EQ(1, deletes);
} }
// 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) {
int deletes = 0;
// Tests the Passed() function's support for pointers.
scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
Bind(&PassThru<scoped_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<scoped_ptr<DeleteCounter>(void)> callback =
Bind(&PassThru<scoped_ptr<DeleteCounter> >,
Passed(scoped_ptr<DeleteCounter>(counter)));
EXPECT_FALSE(ptr.get());
EXPECT_EQ(0, deletes);
// Check that ownership can be transferred back out.
scoped_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);
// 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(ptr.Pass());
}
// Argument Copy-constructor usage for non-reference parameters. // Argument Copy-constructor usage for non-reference parameters.
// - Bound arguments are only copied once. // - Bound arguments are only copied once.
// - Forwarded arguments are only copied once. // - Forwarded arguments are only copied once.
// - Forwarded arguments with coercions are only copied twice (once for the // - Forwarded arguments with coerscions are only copied twice (once for the
// coercion, and one for the final dispatch). // coerscion, and one for the final dispatch).
TEST_F(BindTest, ArgumentCopies) { TEST_F(BindTest, ArgumentCopies) {
int copies = 0; int copies = 0;
int assigns = 0; int assigns = 0;
......
...@@ -312,7 +312,7 @@ class Callback<R(A1)> : public internal::CallbackBase { ...@@ -312,7 +312,7 @@ class Callback<R(A1)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1)); return f(bind_state_.get(), a1);
} }
private: private:
...@@ -355,8 +355,8 @@ class Callback<R(A1, A2)> : public internal::CallbackBase { ...@@ -355,8 +355,8 @@ class Callback<R(A1, A2)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2)); a2);
} }
private: private:
...@@ -401,9 +401,9 @@ class Callback<R(A1, A2, A3)> : public internal::CallbackBase { ...@@ -401,9 +401,9 @@ class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2), a2,
internal::CallbackForward(a3)); a3);
} }
private: private:
...@@ -450,10 +450,10 @@ class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase { ...@@ -450,10 +450,10 @@ class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2), a2,
internal::CallbackForward(a3), a3,
internal::CallbackForward(a4)); a4);
} }
private: private:
...@@ -503,11 +503,11 @@ class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase { ...@@ -503,11 +503,11 @@ class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2), a2,
internal::CallbackForward(a3), a3,
internal::CallbackForward(a4), a4,
internal::CallbackForward(a5)); a5);
} }
private: private:
...@@ -559,12 +559,12 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase { ...@@ -559,12 +559,12 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2), a2,
internal::CallbackForward(a3), a3,
internal::CallbackForward(a4), a4,
internal::CallbackForward(a5), a5,
internal::CallbackForward(a6)); a6);
} }
private: private:
...@@ -618,13 +618,13 @@ class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase { ...@@ -618,13 +618,13 @@ class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
PolymorphicInvoke f = PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1), return f(bind_state_.get(), a1,
internal::CallbackForward(a2), a2,
internal::CallbackForward(a3), a3,
internal::CallbackForward(a4), a4,
internal::CallbackForward(a5), a5,
internal::CallbackForward(a6), a6,
internal::CallbackForward(a7)); a7);
} }
private: private:
......
...@@ -291,7 +291,7 @@ class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase { ...@@ -291,7 +291,7 @@ class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase {
return f(bind_state_.get()[[]] return f(bind_state_.get()[[]]
$if ARITY != 0 [[, ]] $if ARITY != 0 [[, ]]
$for ARG , $for ARG ,
[[internal::CallbackForward(a$(ARG))]]); [[a$(ARG)]]);
} }
private: private:
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
namespace base { namespace base {
namespace internal { namespace internal {
...@@ -131,64 +130,6 @@ struct CallbackParamTraits<T[]> { ...@@ -131,64 +130,6 @@ struct CallbackParamTraits<T[]> {
typedef const T* StorageType; typedef const T* StorageType;
}; };
// Parameter traits for movable-but-not-copyable scopers.
//
// Callback<>/Bind() understands movable-but-not-copyable semantics where
// the type cannot be copied but can still have its state destructively
// transferred (aka. moved) to another instance of the same type by calling a
// helper function. When used with Bind(), this signifies transferal of the
// object's state to the target function.
//
// For these types, the ForwardType must not be a const reference, or a
// reference. A const reference is inappropriate, and would break const
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
//
// TODO(ajwong): We might be able to use SFINAE to search for the existence of
// a Pass() function in the type and avoid the whitelist in CallbackParamTraits
// and CallbackForward.
template <typename T>
struct CallbackParamTraits<scoped_ptr<T> > {
typedef scoped_ptr<T> ForwardType;
typedef scoped_ptr<T> StorageType;
};
template <typename T>
struct CallbackParamTraits<scoped_array<T> > {
typedef scoped_array<T> ForwardType;
typedef scoped_array<T> StorageType;
};
template <typename T>
struct CallbackParamTraits<scoped_ptr_malloc<T> > {
typedef scoped_ptr_malloc<T> ForwardType;
typedef scoped_ptr_malloc<T> StorageType;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
// used by the Callback/Bind system for a set of movable-but-not-copyable
// types. It is needed because forwarding a movable-but-not-copyable
// argument to another function requires us to invoke the proper move
// operator to create a rvalue version of the type. The supported types are
// whitelisted below as overloads of the CallbackForward() function. The
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward with C++11 due to a lack
// of rvalue references.
template <typename T>
T& CallbackForward(T& t) { return t; }
template <typename T>
scoped_ptr<T> CallbackForward(scoped_ptr<T>& p) { return p.Pass(); }
template <typename T>
scoped_ptr<T> CallbackForward(scoped_array<T>& p) { return p.Pass(); }
template <typename T>
scoped_ptr<T> CallbackForward(scoped_ptr_malloc<T>& p) { return p.Pass(); }
} // namespace internal } // namespace internal
} // namespace base } // namespace base
......
...@@ -32,41 +32,6 @@ ...@@ -32,41 +32,6 @@
// foo.get()->Method(); // Foo::Method on the 0th element. // foo.get()->Method(); // Foo::Method on the 0th element.
// foo[10].Method(); // Foo::Method on the 10th element. // foo[10].Method(); // Foo::Method on the 10th element.
// } // }
//
// 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
// in to and out of a function. When calling a function that has a scoper
// as the argument type, it must be called with the result of an analogous
// scoper's Pass() function or another function that generates a temporary;
// passing by copy will NOT work. Here is an example using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
// // Do something with arg
// }
// scoped_ptr<Foo> CreateFoo() {
// // No need for calling Pass() because we are constructing a temporary
// // for the return value.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
// return arg.Pass();
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay)"
// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL.
// }
//
// Notice that if you do not call Pass() when returning from PassThru(), or
// when invoking TakesOwnership(), the code will not compile because scopers
// are not copyable; they only implement move semantics which require calling
// the Pass() function to signify a destructive transfer of state. CreateFoo()
// is different though because we are constructing a temporary on the return
// line and thus can avoid needing to call Pass().
#ifndef BASE_MEMORY_SCOPED_PTR_H_ #ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_ #define BASE_MEMORY_SCOPED_PTR_H_
...@@ -82,35 +47,12 @@ ...@@ -82,35 +47,12 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
// Macro with the boilerplate C++03 move emulation for a class.
//
// In C++11, this is done via rvalue references. Here, we use C++03 move
// emulation to fake an rvalue reference. For a more thorough explanation
// of the technique, see:
//
// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
//
#define CPP_03_MOVE_EMULATION(scoper, field) \
private: \
struct RValue { \
explicit RValue(scoper& obj) : obj_(obj) {} \
scoper& obj_; \
}; \
public: \
operator RValue() { return RValue(*this); } \
scoper(RValue proxy) : field(proxy.obj_.release()) { } \
scoper& operator=(RValue proxy) { \
swap(proxy.obj_); \
return *this; \
} \
scoper Pass() { return scoper(RValue(*this)); }
// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> // A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
// automatically deletes the pointer it holds (if any). // automatically deletes the pointer it holds (if any).
// That is, scoped_ptr<T> owns the T object that it points to. // That is, scoped_ptr<T> owns the T object that it points to.
// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object. // Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
// Also like T*, scoped_ptr<T> is thread-compatible, and once you // Also like T*, scoped_ptr<T> is thread-compatible, and once you
// dereference it, you get the thread safety guarantees of T. // dereference it, you get the threadsafety guarantees of T.
// //
// The size of a scoped_ptr is small: // The size of a scoped_ptr is small:
// sizeof(scoped_ptr<C>) == sizeof(C*) // sizeof(scoped_ptr<C>) == sizeof(C*)
...@@ -180,8 +122,6 @@ class scoped_ptr { ...@@ -180,8 +122,6 @@ class scoped_ptr {
return retVal; return retVal;
} }
CPP_03_MOVE_EMULATION(scoped_ptr, ptr_);
private: private:
C* ptr_; C* ptr_;
...@@ -191,10 +131,9 @@ class scoped_ptr { ...@@ -191,10 +131,9 @@ class scoped_ptr {
template <class C2> bool operator==(scoped_ptr<C2> const& p2) const; template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const; template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
// Disallow evil constructors. Note that MUST NOT take a const& because we // Disallow evil constructors
// are implementing move semantics. See the CPP_03_MOVE_EMULATION macro. scoped_ptr(const scoped_ptr&);
scoped_ptr(scoped_ptr&); void operator=(const scoped_ptr&);
void operator=(scoped_ptr&);
}; };
// Free functions // Free functions
...@@ -219,7 +158,7 @@ bool operator!=(C* p1, const scoped_ptr<C>& p2) { ...@@ -219,7 +158,7 @@ bool operator!=(C* p1, const scoped_ptr<C>& p2) {
// As with scoped_ptr<C>, a scoped_array<C> either points to an object // As with scoped_ptr<C>, a scoped_array<C> either points to an object
// or is NULL. A scoped_array<C> owns the object that it points to. // or is NULL. A scoped_array<C> owns the object that it points to.
// scoped_array<T> is thread-compatible, and once you index into it, // scoped_array<T> is thread-compatible, and once you index into it,
// the returned objects have only the thread safety guarantees of T. // the returned objects have only the threadsafety guarantees of T.
// //
// Size: sizeof(scoped_array<C>) == sizeof(C*) // Size: sizeof(scoped_array<C>) == sizeof(C*)
template <class C> template <class C>
...@@ -229,7 +168,7 @@ class scoped_array { ...@@ -229,7 +168,7 @@ class scoped_array {
// The element type // The element type
typedef C element_type; typedef C element_type;
// Constructor. Defaults to initializing with NULL. // Constructor. Defaults to intializing with NULL.
// There is no way to create an uninitialized scoped_array. // There is no way to create an uninitialized scoped_array.
// The input parameter must be allocated with new []. // The input parameter must be allocated with new [].
explicit scoped_array(C* p = NULL) : array_(p) { } explicit scoped_array(C* p = NULL) : array_(p) { }
...@@ -290,8 +229,6 @@ class scoped_array { ...@@ -290,8 +229,6 @@ class scoped_array {
return retVal; return retVal;
} }
CPP_03_MOVE_EMULATION(scoped_array, array_);
private: private:
C* array_; C* array_;
...@@ -299,10 +236,9 @@ class scoped_array { ...@@ -299,10 +236,9 @@ class scoped_array {
template <class C2> bool operator==(scoped_array<C2> const& p2) const; template <class C2> bool operator==(scoped_array<C2> const& p2) const;
template <class C2> bool operator!=(scoped_array<C2> const& p2) const; template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
// Disallow evil constructors. Note that MUST NOT take a const& because we // Disallow evil constructors
// are implementing move semantics. See the CPP_03_MOVE_EMULATION macro. scoped_array(const scoped_array&);
scoped_array(scoped_array&); void operator=(const scoped_array&);
void operator=(scoped_array&);
}; };
// Free functions // Free functions
...@@ -411,8 +347,6 @@ class scoped_ptr_malloc { ...@@ -411,8 +347,6 @@ class scoped_ptr_malloc {
return tmp; return tmp;
} }
CPP_03_MOVE_EMULATION(scoped_ptr_malloc, ptr_);
private: private:
C* ptr_; C* ptr_;
...@@ -422,14 +356,11 @@ class scoped_ptr_malloc { ...@@ -422,14 +356,11 @@ class scoped_ptr_malloc {
template <class C2, class GP> template <class C2, class GP>
bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const; bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
// Disallow evil constructors. Note that MUST NOT take a const& because we // Disallow evil constructors
// are implementing move semantics. See the CPP_03_MOVE_EMULATION macro. scoped_ptr_malloc(const scoped_ptr_malloc&);
scoped_ptr_malloc(scoped_ptr_malloc&); void operator=(const scoped_ptr_malloc&);
void operator=(scoped_ptr_malloc&);
}; };
#undef CPP_03_MOVE_EMULATION
template<class C, class FP> inline template<class C, class FP> inline
void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) { void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
a.swap(b); a.swap(b);
......
...@@ -23,19 +23,6 @@ class ConDecLogger { ...@@ -23,19 +23,6 @@ class ConDecLogger {
DISALLOW_COPY_AND_ASSIGN(ConDecLogger); DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
}; };
scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
return logger.Pass();
}
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 } // namespace
TEST(ScopedPtrTest, ScopedPtr) { TEST(ScopedPtrTest, ScopedPtr) {
...@@ -179,83 +166,4 @@ TEST(ScopedPtrTest, ScopedArray) { ...@@ -179,83 +166,4 @@ TEST(ScopedPtrTest, ScopedArray) {
EXPECT_EQ(0, constructed); EXPECT_EQ(0, constructed);
} }
TEST(ScopedPtrTest, PassBehavior) {
int constructed = 0;
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
// Test Pass() with constructor;
scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
EXPECT_EQ(1, constructed);
// Test Pass() with assignment;
scoped_ptr<ConDecLogger> scoper3;
scoper3 = scoper2.Pass();
EXPECT_EQ(1, constructed);
EXPECT_FALSE(scoper.get());
EXPECT_FALSE(scoper2.get());
EXPECT_TRUE(scoper3.get());
}
// Test uncaught Pass() 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.
scoper.Pass();
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
// 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(scoper.Pass());
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(scoper.Pass());
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(scoper.Pass());
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);
}
// TODO scoped_ptr_malloc // TODO scoped_ptr_malloc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment