@@ -68,14 +68,21 @@ class continuation_base {
6868 */
6969class future_shared_state_base {
7070 public:
71- future_shared_state_base () : mu_(), cv_(), current_state_(state::not_ready) {}
72-
71+ future_shared_state_base () : future_shared_state_base([] {}) {}
72+ future_shared_state_base (std::function<void ()> cancellation_callback)
73+ : mu_(),
74+ cv_ (),
75+ current_state_(state::not_ready),
76+ cancellation_callback_(cancellation_callback) {}
7377 // / Return true if the shared state has a value or an exception.
7478 bool is_ready () const {
7579 std::unique_lock<std::mutex> lk (mu_);
7680 return is_ready_unlocked ();
7781 }
7882
83+ // / Return true if the shared state can be cancelled.
84+ bool cancellable () const { return !is_ready () && !cancelled_; }
85+
7986 // / Block until is_ready() returns true ...
8087 void wait () {
8188 std::unique_lock<std::mutex> lk (mu_);
@@ -197,6 +204,19 @@ class future_shared_state_base {
197204 continuation_ = std::move (c);
198205 }
199206
207+ // Try to cancel the task by invoking the cancellation_callback.
208+ bool cancel () {
209+ if (!cancellable ()) {
210+ return false ;
211+ }
212+ cancellation_callback_ ();
213+ // If the callback fails with an exception we assume it had no effect.
214+ // Incidentally this means we provide the strong exception guarantee for
215+ // this function.
216+ cancelled_ = true ;
217+ return true ;
218+ }
219+
200220 protected:
201221 bool is_ready_unlocked () const { return current_state_ != state::not_ready; }
202222
@@ -279,6 +299,10 @@ class future_shared_state_base {
279299 * member variable and does not satisfy the shared state.
280300 */
281301 std::unique_ptr<continuation_base> continuation_;
302+
303+ // Allow users "cancel" the future with the given callback.
304+ std::atomic<bool > cancelled_ = ATOMIC_VAR_INIT(false );
305+ std::function<void ()> cancellation_callback_;
282306};
283307
284308/* *
@@ -306,6 +330,8 @@ template <typename T>
306330class future_shared_state final : private future_shared_state_base {
307331 public:
308332 future_shared_state () : future_shared_state_base(), buffer_() {}
333+ future_shared_state (std::function<void ()> cancellation_callback)
334+ : future_shared_state_base(cancellation_callback), buffer_() {}
309335 ~future_shared_state () {
310336 if (current_state_ == state::has_value) {
311337 // Recall that state::has_value is a terminal state, once a value is
@@ -318,6 +344,7 @@ class future_shared_state final : private future_shared_state_base {
318344 }
319345
320346 using future_shared_state_base::abandon;
347+ using future_shared_state_base::cancel;
321348 using future_shared_state_base::is_ready;
322349 using future_shared_state_base::set_continuation;
323350 using future_shared_state_base::set_exception;
@@ -441,8 +468,11 @@ template <>
441468class future_shared_state <void > final : private future_shared_state_base {
442469 public:
443470 future_shared_state () : future_shared_state_base() {}
471+ future_shared_state (std::function<void ()> cancellation_callback)
472+ : future_shared_state_base(cancellation_callback) {}
444473
445474 using future_shared_state_base::abandon;
475+ using future_shared_state_base::cancel;
446476 using future_shared_state_base::is_ready;
447477 using future_shared_state_base::set_continuation;
448478 using future_shared_state_base::set_exception;
0 commit comments