fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // This defines helpful methods for dealing with Callbacks. Because Callbacks |
| 6 | // are implemented using templates, with a class per callback signature, adding |
| 7 | // methods to Callback<> itself is unattractive (lots of extra code gets |
| 8 | // generated). Instead, consider adding methods here. |
| 9 | // |
| 10 | // ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a |
michaelpg | edf640b | 2017-03-18 11:49:09 +0900 | [diff] [blame] | 11 | // move or copy) after the original callback is Reset(). This can be handy if |
| 12 | // Run() reads/writes the variable holding the Callback. |
fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 13 | |
| 14 | #ifndef BASE_CALLBACK_HELPERS_H_ |
| 15 | #define BASE_CALLBACK_HELPERS_H_ |
| 16 | |
tzik | 2c9ac66 | 2017-04-20 21:19:50 +0900 | [diff] [blame] | 17 | #include <utility> |
| 18 | |
| 19 | #include "base/atomicops.h" |
| 20 | #include "base/bind.h" |
fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 21 | #include "base/callback.h" |
avi@chromium.org | b74bab8 | 2013-08-30 11:04:04 +0900 | [diff] [blame] | 22 | #include "base/compiler_specific.h" |
avi | a6a6a68 | 2015-12-27 07:15:14 +0900 | [diff] [blame] | 23 | #include "base/macros.h" |
tzik | 2c9ac66 | 2017-04-20 21:19:50 +0900 | [diff] [blame] | 24 | #include "base/memory/ptr_util.h" |
fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 25 | |
| 26 | namespace base { |
| 27 | |
tzik | 14e09b8 | 2017-01-28 06:20:14 +0900 | [diff] [blame] | 28 | template <typename Signature, |
| 29 | internal::CopyMode copy_mode, |
| 30 | internal::RepeatMode repeat_mode> |
tzik | 2c9ac66 | 2017-04-20 21:19:50 +0900 | [diff] [blame] | 31 | Callback<Signature, copy_mode, repeat_mode> ResetAndReturn( |
| 32 | Callback<Signature, copy_mode, repeat_mode>* cb) { |
| 33 | Callback<Signature, copy_mode, repeat_mode> ret(std::move(*cb)); |
tzik | cd0e2ce | 2017-02-22 18:13:19 +0900 | [diff] [blame] | 34 | DCHECK(!*cb); |
fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 35 | return ret; |
| 36 | } |
| 37 | |
tzik | 2c9ac66 | 2017-04-20 21:19:50 +0900 | [diff] [blame] | 38 | namespace internal { |
| 39 | |
| 40 | template <typename... Args> |
| 41 | class AdaptCallbackForRepeatingHelper final { |
| 42 | public: |
| 43 | explicit AdaptCallbackForRepeatingHelper(OnceCallback<void(Args...)> callback) |
| 44 | : callback_(std::move(callback)) { |
| 45 | DCHECK(callback_); |
| 46 | } |
| 47 | |
| 48 | void Run(Args... args) { |
| 49 | if (subtle::NoBarrier_AtomicExchange(&has_run_, 1)) |
| 50 | return; |
| 51 | DCHECK(callback_); |
| 52 | std::move(callback_).Run(std::forward<Args>(args)...); |
| 53 | } |
| 54 | |
| 55 | private: |
| 56 | volatile subtle::Atomic32 has_run_ = 0; |
| 57 | base::OnceCallback<void(Args...)> callback_; |
| 58 | |
| 59 | DISALLOW_COPY_AND_ASSIGN(AdaptCallbackForRepeatingHelper); |
| 60 | }; |
| 61 | |
| 62 | } // namespace internal |
| 63 | |
| 64 | // Wraps the given OnceCallback into a RepeatingCallback that relays its |
| 65 | // invocation to the original OnceCallback on the first invocation. The |
| 66 | // following invocations are just ignored. |
| 67 | template <typename... Args> |
| 68 | RepeatingCallback<void(Args...)> AdaptCallbackForRepeating( |
| 69 | OnceCallback<void(Args...)> callback) { |
| 70 | using Helper = internal::AdaptCallbackForRepeatingHelper<Args...>; |
| 71 | return base::BindRepeating(&Helper::Run, |
| 72 | base::MakeUnique<Helper>(std::move(callback))); |
| 73 | } |
| 74 | |
sergeyu | f9cf281 | 2016-06-25 09:51:09 +0900 | [diff] [blame] | 75 | // ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures |
| 76 | // that the Closure is executed no matter how the current scope exits. |
avi@chromium.org | b74bab8 | 2013-08-30 11:04:04 +0900 | [diff] [blame] | 77 | class BASE_EXPORT ScopedClosureRunner { |
| 78 | public: |
| 79 | ScopedClosureRunner(); |
| 80 | explicit ScopedClosureRunner(const Closure& closure); |
| 81 | ~ScopedClosureRunner(); |
| 82 | |
sergeyu | f9cf281 | 2016-06-25 09:51:09 +0900 | [diff] [blame] | 83 | ScopedClosureRunner(ScopedClosureRunner&& other); |
| 84 | |
sergeyu | 93396d1 | 2016-07-08 09:34:27 +0900 | [diff] [blame] | 85 | // Releases the current closure if it's set and replaces it with the closure |
| 86 | // from |other|. |
sergeyu | f9cf281 | 2016-06-25 09:51:09 +0900 | [diff] [blame] | 87 | ScopedClosureRunner& operator=(ScopedClosureRunner&& other); |
| 88 | |
| 89 | // Calls the current closure and resets it, so it wont be called again. |
sergeyu | 93396d1 | 2016-07-08 09:34:27 +0900 | [diff] [blame] | 90 | void RunAndReset(); |
sergeyu | f9cf281 | 2016-06-25 09:51:09 +0900 | [diff] [blame] | 91 | |
sergeyu | 93396d1 | 2016-07-08 09:34:27 +0900 | [diff] [blame] | 92 | // Replaces closure with the new one releasing the old one without calling it. |
| 93 | void ReplaceClosure(const Closure& closure); |
sergeyu | f9cf281 | 2016-06-25 09:51:09 +0900 | [diff] [blame] | 94 | |
| 95 | // Releases the Closure without calling. |
avi@chromium.org | b74bab8 | 2013-08-30 11:04:04 +0900 | [diff] [blame] | 96 | Closure Release() WARN_UNUSED_RESULT; |
| 97 | |
| 98 | private: |
| 99 | Closure closure_; |
| 100 | |
| 101 | DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner); |
| 102 | }; |
| 103 | |
fischman@chromium.org | dc221a7 | 2012-03-25 05:37:27 +0900 | [diff] [blame] | 104 | } // namespace base |
| 105 | |
| 106 | #endif // BASE_CALLBACK_HELPERS_H_ |