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

Unified Diff: base/callback.h

Issue 2042223002: Introduce OnceClosure and BindOnce (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 3 months 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 side-by-side diff with in-line comments
Download patch
Index: base/callback.h
diff --git a/base/callback.h b/base/callback.h
index d173a3c7b6b47b564e698d02fe60a7b3d1947ca2..ff8d6f9aad30322eb084fc2ad639ae9ab08437fa 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -19,15 +19,76 @@
namespace base {
-template <typename R, typename... Args, internal::CopyMode copy_mode>
-class Callback<R(Args...), copy_mode>
- : public internal::CallbackBase<copy_mode> {
+namespace internal {
+
+// RunMixin provides different variant of `Run()` function to `Callback<>` based
dcheng 2016/09/08 04:09:01 Nit: "different variants" or "a different variant"
tzik 2016/09/12 11:00:34 Done.
+// on the type of callback.
+template <typename CallbackType>
+class RunMixin;
+
+// Specialization for RepeatingCallback.
+template <typename R, typename... Args, CopyMode copy_mode>
+class RunMixin<Callback<R(Args...), copy_mode, RepeatMode::Repeating>> {
+ private:
+ using CallbackType = Callback<R(Args...), copy_mode, RepeatMode::Repeating>;
+
+ public:
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...);
+
+ R Run(Args... args) const {
+ const CallbackType& cb = static_cast<const CallbackType&>(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...);
+ }
+};
+
+// Specialization for OnceCallback.
+template <typename R, typename... Args>
+class RunMixin<Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>> {
+ private:
+ using CallbackType =
+ Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>;
+
public:
- using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...);
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...);
- // MSVC 2013 doesn't support Type Alias of function types.
- // Revisit this after we update it to newer version.
- typedef R RunType(Args...);
+ R Run(Args... args) && {
+ // Move the callback instance into a local variable before the invocation,
+ // that ensures the internal state is cleared after the invocation.
+ // It's not safe to touch |this| after the invocation, since running the
+ // bound function may destroy |this|.
+ CallbackType cb = static_cast<CallbackType&&>(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...);
+ }
+};
+
+template <typename From, typename To>
+struct IsCallbackConvertible : std::false_type {};
+
+template <typename Signature>
+struct IsCallbackConvertible<
+ Callback<Signature, CopyMode::Copyable, RepeatMode::Repeating>,
+ Callback<Signature, CopyMode::MoveOnly, RepeatMode::Once>> : std::true_type {
+};
+
+} // namespace internal
+
+template <typename R,
+ typename... Args,
+ internal::CopyMode copy_mode,
+ internal::RepeatMode repeat_mode>
+class Callback<R(Args...), copy_mode, repeat_mode>
+ : public internal::CallbackBase<copy_mode>,
+ public internal::RunMixin<Callback<R(Args...), copy_mode, repeat_mode>> {
+ public:
+ static_assert(repeat_mode != internal::RepeatMode::Once ||
+ copy_mode == internal::CopyMode::MoveOnly,
+ "OnceCallback must be MoveOnly.");
+
+ using RunType = R(Args...);
Callback() : internal::CallbackBase<copy_mode>(nullptr) {}
@@ -35,26 +96,27 @@ class Callback<R(Args...), copy_mode>
: internal::CallbackBase<copy_mode>(bind_state) {
}
+ template <typename OtherCallback,
+ typename = typename std::enable_if<
+ internal::IsCallbackConvertible<OtherCallback, Callback>::value
+ >::type>
+ Callback(OtherCallback other)
+ : internal::CallbackBase<copy_mode>(std::move(other)) {}
+
+ template <typename OtherCallback,
+ typename = typename std::enable_if<
+ internal::IsCallbackConvertible<OtherCallback, Callback>::value
+ >::type>
+ Callback& operator=(OtherCallback other) {
+ static_cast<internal::CallbackBase<copy_mode>&>(*this) = std::move(other);
+ return *this;
+ }
+
bool Equals(const Callback& other) const {
return this->EqualsInternal(other);
}
- // 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>(this->polymorphic_invoke());
- return f(this->bind_state_.get(), std::forward<Args>(args)...);
- }
+ friend class internal::RunMixin<Callback>;
};
} // namespace base
« no previous file with comments | « base/bind_unittest.cc ('k') | base/callback_forward.h » ('j') | base/callback_forward.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698