Google Cloud C++ Client  2.0.0
C++ Client Library for Google Cloud Platform
future_void.h
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_FUTURE_VOID_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_FUTURE_VOID_H
17 /**
18  * @file
19  *
20  * Fully specialize `future<void>` and `promise<R>` for void.
21  */
22 
23 #include "google/cloud/internal/future_base.h"
24 #include "google/cloud/internal/future_fwd.h"
25 #include "google/cloud/internal/future_impl.h"
26 #include "google/cloud/internal/future_then_meta.h"
27 #include "google/cloud/version.h"
28 
29 namespace google {
30 namespace cloud {
32 /**
33  * Implement ISO/IEC TS 19571:2016 future for void.
34  */
35 template <>
36 class future<void> final : private internal::future_base<void> {
37  public:
38  using shared_state_type =
39  typename internal::future_base<void>::shared_state_type;
40 
41  // workaround Apple Clang-7xx series bug, if we use `= default` here, the
42  // compiler believes there is no default constructor defined. :shrug:
43  future() noexcept {} // NOLINT(modernize-use-equals-default)
44 
45  /**
46  * Creates a new future that unwraps @p rhs.
47  *
48  * This constructor creates a new shared state that becomes satisfied when
49  * both `rhs` and `rhs.get()` become satisfied. If `rhs` is satisfied, but
50  * `rhs.get()` returns an invalid future then the newly created future becomes
51  * satisfied with a `std::future_error` exception, and the exception error
52  * code is `std::future_errc::broken_promise`.
53  *
54  * @note The technical specification requires this to be a `noexcept`
55  * constructor I (coryan) believe this is a defect in the technical
56  * specification, as this *creates* a new shared state: shared states are
57  * dynamically allocated, and the allocator (which might be the default
58  * `operator new`) may raise.
59  */
60  // NOLINTNEXTLINE(google-explicit-constructor)
61  future(future<future<void>>&& rhs) noexcept(false);
62 
63  /**
64  * Creates a future from a future whose result type is convertible to this
65  * future's result type.
66  */
67  template <class T>
68  explicit future(future<T>&& rhs) : future<void>(rhs.then([](future<T>) {})) {}
69 
70  /**
71  * Waits until the shared state becomes ready, then retrieves the value stored
72  * in the shared state.
73  *
74  * @throws any exceptions stored in the shared state.
75  * @throws std::future_error with std::no_state if the future does not have
76  * a shared state.
77  */
78  void get() {
79  check_valid();
80  std::shared_ptr<shared_state_type> tmp;
81  tmp.swap(shared_state_);
82  return tmp->get();
83  }
84 
85  using future_base::cancel;
86  using future_base::is_ready;
87  using future_base::valid;
88  using future_base::wait;
89  using future_base::wait_for;
90  using future_base::wait_until;
91 
92  /**
93  * Attach a continuation to the future.
94  *
95  * Attach a callable @a func to be invoked when the future is
96  * ready. The return type is a future wrapping the return type of
97  * @a func.
98  *
99  * @return `future<T>` where T is `std::result_of_t<F, R>` (basically).
100  * If T matches `future<U>` then it returns `future<U>`. The returned
101  * future will contain the result of @a func.
102  * @param func a Callable to be invoked when the future is ready.
103  * The function might be called immediately, e.g., if the future is
104  * ready.
105  *
106  * Side effects: `valid() == false` if the operation is successful.
107  */
108  template <typename F>
109  typename internal::then_helper<F, void>::future_t then(F&& func) {
110  check_valid();
111  using requires_unwrap_t =
112  typename internal::then_helper<F, void>::requires_unwrap_t;
113  return then_impl(std::forward<F>(func), requires_unwrap_t{});
114  }
115 
116  explicit future(std::shared_ptr<shared_state_type> state)
117  : future_base<void>(std::move(state)) {}
118 
119  private:
120  /// Implement `then()` if the result does not require unwrapping.
121  template <typename F>
122  typename internal::then_helper<F, void>::future_t then_impl(F&& functor,
123  std::false_type);
124 
125  /// Implement `then()` if the result requires unwrapping.
126  template <typename F>
127  typename internal::then_helper<F, void>::future_t then_impl(F&& functor,
128  std::true_type);
129 
130  template <typename U>
131  friend class future;
132 
133  friend struct internal::CoroutineSupport;
134 };
135 
136 /**
137  * Specialize promise as defined in ISO/IEC TS 19571:2016 for void.
138  */
139 template <>
140 class promise<void> final : private internal::promise_base<void> {
141  public:
142  /// Creates a promise with an unsatisfied shared state.
143  promise() : promise_base([] {}) {}
144 
145  /// Creates a promise with an unsatisfied shared state.
146  explicit promise(std::function<void()> cancellation_callback)
147  : promise_base(std::move(cancellation_callback)) {}
148 
149  /// Creates a promise *without* a shared state.
150  explicit promise(null_promise_t x) : promise_base(std::move(x)) {}
151 
152  /// Constructs a new promise and transfer any shared state from @p rhs.
153  promise(promise&&) = default;
154 
155  /// Abandons the shared state in `*this`, if any, and transfers the shared
156  /// state from @p rhs.
157  promise& operator=(promise&& rhs) noexcept {
158  promise tmp(std::move(rhs));
159  tmp.swap(*this);
160  return *this;
161  }
162 
163  /**
164  * Abandons any shared state.
165  *
166  * If the shared state was not already satisfied it becomes satisfied with
167  * a `std::future_error` exception. The error code in this exception is
168  * `std::future_errc::broken_promise`.
169  */
170  ~promise() = default;
171 
172  promise(promise const&) = delete;
173  promise& operator=(promise const&) = delete;
174 
175  /// Swaps the shared state in `*this` with @p rhs.
176  void swap(promise& other) noexcept {
177  std::swap(shared_state_, other.shared_state_);
178  }
179 
180  /**
181  * Creates the `future<void>` using the same shared state as `*this`.
182  */
183  future<void> get_future() {
184  shared_state_type::mark_retrieved(shared_state_);
185  return future<void>(shared_state_);
186  }
187 
188  /**
189  * Satisfies the shared state.
190  *
191  * @throws std::future_error with std::future_errc::promise_already_satisfied
192  * if the shared state is already satisfied.
193  * @throws std::future_error with std::no_state if the promise does not have
194  * a shared state.
195  */
196  void set_value() {
197  if (!shared_state_) {
198  internal::ThrowFutureError(std::future_errc::no_state, __func__);
199  }
200  shared_state_->set_value();
201  }
202 
203  using promise_base<void>::set_exception;
204 };
205 
206 /// Create a future<void> that is immediately ready.
207 inline future<void> make_ready_future() {
208  promise<void> p;
209  p.set_value();
210  return p.get_future();
211 }
212 
214 } // namespace cloud
215 } // namespace google
216 
217 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_FUTURE_VOID_H