ajwong@chromium.org | ac4c668 | 2012-01-04 00:57:39 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_CALLBACK_H_ |
| 6 | #define BASE_CALLBACK_H_ |
| 7 | |
erikwright@chromium.org | d7f7524 | 2011-12-07 21:44:06 | [diff] [blame] | 8 | #include "base/callback_forward.h" |
ajwong@chromium.org | 59eff91 | 2011-02-18 23:29:31 | [diff] [blame] | 9 | #include "base/callback_internal.h" |
erikwright@chromium.org | d7f7524 | 2011-12-07 21:44:06 | [diff] [blame] | 10 | |
| 11 | // NOTE: Header files that do not require the full definition of Callback or |
| 12 | // Closure should #include "base/callback_forward.h" instead of this file. |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 13 | |
brettw@chromium.org | 2429264 | 2012-07-12 20:06:40 | [diff] [blame] | 14 | // ----------------------------------------------------------------------------- |
tzik | 703f156 | 2016-09-02 07:36:55 | [diff] [blame] | 15 | // Usage documentation |
brettw@chromium.org | 2429264 | 2012-07-12 20:06:40 | [diff] [blame] | 16 | // ----------------------------------------------------------------------------- |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 17 | // |
tzik | 703f156 | 2016-09-02 07:36:55 | [diff] [blame] | 18 | // See //docs/callback.md for documentation. |
ajwong@chromium.org | 4346ef91 | 2011-02-19 00:52:15 | [diff] [blame] | 19 | |
tzik | 77d41139 | 2016-03-09 09:47:03 | [diff] [blame] | 20 | namespace base { |
ajwong@chromium.org | e24f876 | 2011-12-20 00:10:04 | [diff] [blame] | 21 | |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 22 | namespace internal { |
tzik | caf1d84b | 2016-06-28 12:22:21 | [diff] [blame] | 23 | |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 24 | template <typename CallbackType> |
| 25 | struct IsOnceCallback : std::false_type {}; |
| 26 | |
| 27 | template <typename Signature> |
| 28 | struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {}; |
| 29 | |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 30 | // RunMixin provides different variants of `Run()` function to `Callback<>` |
| 31 | // based on the type of callback. |
| 32 | template <typename CallbackType> |
| 33 | class RunMixin; |
| 34 | |
| 35 | // Specialization for OnceCallback. |
| 36 | template <typename R, typename... Args> |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 37 | class RunMixin<OnceCallback<R(Args...)>> { |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 38 | private: |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 39 | using CallbackType = OnceCallback<R(Args...)>; |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 40 | |
| 41 | public: |
| 42 | using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 43 | |
dcheng | 3f2fd66e | 2016-12-20 23:56:59 | [diff] [blame] | 44 | R Run(Args... args) const & { |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 45 | // Note: even though this static_assert will trivially always fail, it |
| 46 | // cannot be simply replaced with static_assert(false, ...) because: |
| 47 | // - Per [dcl.dcl]/p4, a program is ill-formed if the constant-expression |
| 48 | // argument does not evaluate to true. |
| 49 | // - Per [temp.res]/p8, if no valid specialization can be generated for a |
| 50 | // template definition, and that template is not instantiated, the |
| 51 | // template definition is ill-formed, no diagnostic required. |
| 52 | // These two clauses, taken together, would allow a conforming C++ compiler |
| 53 | // to immediately reject static_assert(false, ...), even inside an |
| 54 | // uninstantiated template. |
| 55 | static_assert(!IsOnceCallback<CallbackType>::value, |
dcheng | 3f2fd66e | 2016-12-20 23:56:59 | [diff] [blame] | 56 | "OnceCallback::Run() may only be invoked on a non-const " |
| 57 | "rvalue, i.e. std::move(callback).Run()."); |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 58 | } |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 59 | |
| 60 | R Run(Args... args) && { |
| 61 | // Move the callback instance into a local variable before the invocation, |
| 62 | // that ensures the internal state is cleared after the invocation. |
| 63 | // It's not safe to touch |this| after the invocation, since running the |
| 64 | // bound function may destroy |this|. |
| 65 | CallbackType cb = static_cast<CallbackType&&>(*this); |
| 66 | PolymorphicInvoke f = |
| 67 | reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke()); |
| 68 | return f(cb.bind_state_.get(), std::forward<Args>(args)...); |
| 69 | } |
| 70 | }; |
| 71 | |
| 72 | // Specialization for RepeatingCallback. |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 73 | template <typename R, typename... Args> |
| 74 | class RunMixin<RepeatingCallback<R(Args...)>> { |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 75 | private: |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 76 | using CallbackType = RepeatingCallback<R(Args...)>; |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 77 | |
| 78 | public: |
| 79 | using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
| 80 | |
| 81 | R Run(Args... args) const { |
| 82 | const CallbackType& cb = static_cast<const CallbackType&>(*this); |
| 83 | PolymorphicInvoke f = |
| 84 | reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke()); |
| 85 | return f(cb.bind_state_.get(), std::forward<Args>(args)...); |
| 86 | } |
| 87 | }; |
| 88 | |
| 89 | template <typename From, typename To> |
| 90 | struct IsCallbackConvertible : std::false_type {}; |
| 91 | |
| 92 | template <typename Signature> |
dcheng | 77172b9 | 2016-11-22 07:46:06 | [diff] [blame] | 93 | struct IsCallbackConvertible<RepeatingCallback<Signature>, |
| 94 | OnceCallback<Signature>> : std::true_type {}; |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 95 | |
| 96 | } // namespace internal |
| 97 | |
| 98 | template <typename R, |
| 99 | typename... Args, |
| 100 | internal::CopyMode copy_mode, |
| 101 | internal::RepeatMode repeat_mode> |
| 102 | class Callback<R(Args...), copy_mode, repeat_mode> |
| 103 | : public internal::CallbackBase<copy_mode>, |
| 104 | public internal::RunMixin<Callback<R(Args...), copy_mode, repeat_mode>> { |
| 105 | public: |
| 106 | static_assert(repeat_mode != internal::RepeatMode::Once || |
| 107 | copy_mode == internal::CopyMode::MoveOnly, |
| 108 | "OnceCallback must be MoveOnly."); |
| 109 | |
| 110 | using RunType = R(Args...); |
ajwong@chromium.org | b38d357 | 2011-02-15 01:27:38 | [diff] [blame] | 111 | |
tzik | 77d41139 | 2016-03-09 09:47:03 | [diff] [blame] | 112 | Callback() : internal::CallbackBase<copy_mode>(nullptr) {} |
ajwong@chromium.org | b38d357 | 2011-02-15 01:27:38 | [diff] [blame] | 113 | |
tzik | 1886c27 | 2016-09-08 05:45:38 | [diff] [blame] | 114 | explicit Callback(internal::BindStateBase* bind_state) |
tzik | 77d41139 | 2016-03-09 09:47:03 | [diff] [blame] | 115 | : internal::CallbackBase<copy_mode>(bind_state) { |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 116 | } |
| 117 | |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 118 | template <typename OtherCallback, |
| 119 | typename = typename std::enable_if< |
| 120 | internal::IsCallbackConvertible<OtherCallback, Callback>::value |
| 121 | >::type> |
| 122 | Callback(OtherCallback other) |
| 123 | : internal::CallbackBase<copy_mode>(std::move(other)) {} |
| 124 | |
| 125 | template <typename OtherCallback, |
| 126 | typename = typename std::enable_if< |
| 127 | internal::IsCallbackConvertible<OtherCallback, Callback>::value |
| 128 | >::type> |
| 129 | Callback& operator=(OtherCallback other) { |
| 130 | static_cast<internal::CallbackBase<copy_mode>&>(*this) = std::move(other); |
| 131 | return *this; |
| 132 | } |
| 133 | |
ajwong@chromium.org | 481915a77 | 2011-09-10 03:14:35 | [diff] [blame] | 134 | bool Equals(const Callback& other) const { |
tzik | 77d41139 | 2016-03-09 09:47:03 | [diff] [blame] | 135 | return this->EqualsInternal(other); |
ajwong@chromium.org | 481915a77 | 2011-09-10 03:14:35 | [diff] [blame] | 136 | } |
| 137 | |
tzik | 27d1e31 | 2016-09-13 05:28:59 | [diff] [blame] | 138 | friend class internal::RunMixin<Callback>; |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 139 | }; |
ajwong@chromium.org | b38d357 | 2011-02-15 01:27:38 | [diff] [blame] | 140 | |
| 141 | } // namespace base |
akalin@chromium.org | 2041cf34 | 2010-02-19 03:15:59 | [diff] [blame] | 142 | |
tzik | c87149e | 2014-11-20 01:08:20 | [diff] [blame] | 143 | #endif // BASE_CALLBACK_H_ |