Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(756)

Side by Side Diff: base/bind_helpers.h

Issue 1496403002: base: Stop using Pass() on move-only types in Bind and Callback. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/callback_internal.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This defines a set of argument wrappers and related factory methods that 5 // This defines a set of argument wrappers and related factory methods that
6 // can be used specify the refcounting and reference semantics of arguments 6 // can be used specify the refcounting and reference semantics of arguments
7 // that are bound by the Bind() function in base/bind.h. 7 // that are bound by the Bind() function in base/bind.h.
8 // 8 //
9 // It also defines a set of simple functions and utilities that people want 9 // It also defines a set of simple functions and utilities that people want
10 // when using Callback<> and Bind(). 10 // when using Callback<> and Bind().
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 // 104 //
105 // 105 //
106 // EXAMPLE OF Passed(): 106 // EXAMPLE OF Passed():
107 // 107 //
108 // void TakesOwnership(scoped_ptr<Foo> arg) { } 108 // void TakesOwnership(scoped_ptr<Foo> arg) { }
109 // scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); } 109 // scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
110 // 110 //
111 // scoped_ptr<Foo> f(new Foo()); 111 // scoped_ptr<Foo> f(new Foo());
112 // 112 //
113 // // |cb| is given ownership of Foo(). |f| is now NULL. 113 // // |cb| is given ownership of Foo(). |f| is now NULL.
114 // // You can use f.Pass() in place of &f, but it's more verbose. 114 // // You can use std::move(f) in place of &f, but it's more verbose.
115 // Closure cb = Bind(&TakesOwnership, Passed(&f)); 115 // Closure cb = Bind(&TakesOwnership, Passed(&f));
116 // 116 //
117 // // Run was never called so |cb| still owns Foo() and deletes 117 // // Run was never called so |cb| still owns Foo() and deletes
118 // // it on Reset(). 118 // // it on Reset().
119 // cb.Reset(); 119 // cb.Reset();
120 // 120 //
121 // // |cb| is given a new Foo created by CreateFoo(). 121 // // |cb| is given a new Foo created by CreateFoo().
122 // cb = Bind(&TakesOwnership, Passed(CreateFoo())); 122 // cb = Bind(&TakesOwnership, Passed(CreateFoo()));
123 // 123 //
124 // // |arg| in TakesOwnership() is given ownership of Foo(). |cb| 124 // // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
(...skipping 11 matching lines...) Expand all
136 // 136 //
137 // DoNothing() - Useful for creating a Closure that does nothing when called. 137 // DoNothing() - Useful for creating a Closure that does nothing when called.
138 // DeletePointer<T>() - Useful for creating a Closure that will delete a 138 // DeletePointer<T>() - Useful for creating a Closure that will delete a
139 // pointer when invoked. Only use this when necessary. 139 // pointer when invoked. Only use this when necessary.
140 // In most cases MessageLoop::DeleteSoon() is a better 140 // In most cases MessageLoop::DeleteSoon() is a better
141 // fit. 141 // fit.
142 142
143 #ifndef BASE_BIND_HELPERS_H_ 143 #ifndef BASE_BIND_HELPERS_H_
144 #define BASE_BIND_HELPERS_H_ 144 #define BASE_BIND_HELPERS_H_
145 145
146 #include <type_traits>
147 #include <utility>
148
146 #include "base/basictypes.h" 149 #include "base/basictypes.h"
147 #include "base/callback.h" 150 #include "base/callback.h"
148 #include "base/memory/weak_ptr.h" 151 #include "base/memory/weak_ptr.h"
149 #include "base/template_util.h" 152 #include "base/template_util.h"
150 153
151 namespace base { 154 namespace base {
152 namespace internal { 155 namespace internal {
153 156
154 // Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T 157 // Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
155 // for the existence of AddRef() and Release() functions of the correct 158 // for the existence of AddRef() and Release() functions of the correct
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 // the const correctness. 355 // the const correctness.
353 // 356 //
354 // This conundrum cannot be solved without either C++11 rvalue references or 357 // This conundrum cannot be solved without either C++11 rvalue references or
355 // a O(2^n) blowup of Bind() templates to handle each combination of regular 358 // a O(2^n) blowup of Bind() templates to handle each combination of regular
356 // types and movable-but-not-copyable types. Thus we introduce a wrapper type 359 // types and movable-but-not-copyable types. Thus we introduce a wrapper type
357 // that is copyable to transmit the correct type information down into 360 // that is copyable to transmit the correct type information down into
358 // BindState<>. Ignoring const in this type makes sense because it is only 361 // BindState<>. Ignoring const in this type makes sense because it is only
359 // created when we are explicitly trying to do a destructive move. 362 // created when we are explicitly trying to do a destructive move.
360 // 363 //
361 // Two notes: 364 // Two notes:
362 // 1) PassedWrapper supports any type that has a "Pass()" function. 365 // 1) PassedWrapper supports any type that has a move constructor, however
363 // This is intentional. The whitelisting of which specific types we 366 // the type will need to be specifically whitelisted in order for it to be
364 // support is maintained by CallbackParamTraits<>. 367 // bound to a Callback. We guard this explicitly at the call of Passed()
368 // to make for clear errors. Things not given to Passed() will be forwarded
369 // and stored by value which will not work for general move-only types.
365 // 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL" 370 // 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
366 // scoper to a Callback and allow the Callback to execute once. 371 // scoper to a Callback and allow the Callback to execute once.
367 template <typename T> 372 template <typename T>
368 class PassedWrapper { 373 class PassedWrapper {
369 public: 374 public:
370 explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {} 375 explicit PassedWrapper(T&& scoper)
danakj 2015/12/04 20:46:13 This take a T&&, but the T is a class template typ
376 : is_valid_(true), scoper_(std::move(scoper)) {}
371 PassedWrapper(const PassedWrapper& other) 377 PassedWrapper(const PassedWrapper& other)
372 : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) { 378 : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
373 }
374 T Pass() const { 379 T Pass() const {
375 CHECK(is_valid_); 380 CHECK(is_valid_);
376 is_valid_ = false; 381 is_valid_ = false;
377 return scoper_.Pass(); 382 return std::move(scoper_);
378 } 383 }
379 384
380 private: 385 private:
381 mutable bool is_valid_; 386 mutable bool is_valid_;
382 mutable T scoper_; 387 mutable T scoper_;
383 }; 388 };
384 389
385 // Unwrap the stored parameters for the wrappers above. 390 // Unwrap the stored parameters for the wrappers above.
386 template <typename T> 391 template <typename T>
387 struct UnwrapTraits { 392 struct UnwrapTraits {
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 static inline internal::ConstRefWrapper<T> ConstRef(const T& o) { 565 static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
561 return internal::ConstRefWrapper<T>(o); 566 return internal::ConstRefWrapper<T>(o);
562 } 567 }
563 568
564 template <typename T> 569 template <typename T>
565 static inline internal::OwnedWrapper<T> Owned(T* o) { 570 static inline internal::OwnedWrapper<T> Owned(T* o) {
566 return internal::OwnedWrapper<T>(o); 571 return internal::OwnedWrapper<T>(o);
567 } 572 }
568 573
569 // We offer 2 syntaxes for calling Passed(). The first takes a temporary and 574 // We offer 2 syntaxes for calling Passed(). The first takes a temporary and
570 // is best suited for use with the return value of a function. The second 575 // is best suited for use with the return value of a function. The second takes
571 // takes a pointer to the scoper and is just syntactic sugar to avoid having 576 // a pointer to the scoper and is just syntactic sugar to avoid having to write
572 // to write Passed(scoper.Pass()). 577 // Passed(std::move(scoper)).
573 template <typename T> 578 //
574 static inline internal::PassedWrapper<T> Passed(T scoper) { 579 // Both versions of Passed() prevent T from being an lvalue reference. The first
575 return internal::PassedWrapper<T>(scoper.Pass()); 580 // via use of enable_if (to prevent reference collapsing from occuring), and the
581 // second takes a T* which makes it illegal for T to be a reference.
582 template <typename T,
583 typename std::enable_if<!std::is_lvalue_reference<T>::value &&
584 internal::IsMoveOnlyType<T>::value>::type* =
585 nullptr>
586 static inline internal::PassedWrapper<T> Passed(T&& scoper) {
danakj 2015/12/04 20:46:13 This one doesn't prevent any move constructors (I
danakj 2015/12/04 20:50:16 I thought about this some more and I don't think I
dcheng 2015/12/04 20:59:08 I think what you're seeing is copy elision. Is the
danakj 2015/12/04 21:05:25 Oh, nope. It saves a move constructor to use T&& h
587 return internal::PassedWrapper<T>(std::move(scoper));
576 } 588 }
577 template <typename T> 589 template <typename T,
590 typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
591 nullptr>
578 static inline internal::PassedWrapper<T> Passed(T* scoper) { 592 static inline internal::PassedWrapper<T> Passed(T* scoper) {
579 return internal::PassedWrapper<T>(scoper->Pass()); 593 return internal::PassedWrapper<T>(std::move(*scoper));
580 } 594 }
581 595
582 template <typename T> 596 template <typename T>
583 static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) { 597 static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
584 return internal::IgnoreResultHelper<T>(data); 598 return internal::IgnoreResultHelper<T>(data);
585 } 599 }
586 600
587 template <typename T> 601 template <typename T>
588 static inline internal::IgnoreResultHelper<Callback<T> > 602 static inline internal::IgnoreResultHelper<Callback<T> >
589 IgnoreResult(const Callback<T>& data) { 603 IgnoreResult(const Callback<T>& data) {
590 return internal::IgnoreResultHelper<Callback<T> >(data); 604 return internal::IgnoreResultHelper<Callback<T> >(data);
591 } 605 }
592 606
593 BASE_EXPORT void DoNothing(); 607 BASE_EXPORT void DoNothing();
594 608
595 template<typename T> 609 template<typename T>
596 void DeletePointer(T* obj) { 610 void DeletePointer(T* obj) {
597 delete obj; 611 delete obj;
598 } 612 }
599 613
600 } // namespace base 614 } // namespace base
601 615
602 #endif // BASE_BIND_HELPERS_H_ 616 #endif // BASE_BIND_HELPERS_H_
OLDNEW
« no previous file with comments | « no previous file | base/callback_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698