Google Cloud C++ Client  2.1.0
C++ Client Library for Google Cloud Platform
future_generic.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_GENERIC_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_FUTURE_GENERIC_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 #include "absl/meta/type_traits.h"
29 
30 namespace google {
31 namespace cloud {
33 /**
34  * Implement ISO/IEC TS 19571:2016 `future<T>`.
35  */
36 template <typename T>
37 class future final : private internal::future_base<T> {
38  public:
39  using shared_state_type =
40  typename internal::future_base<T>::shared_state_type;
41 
42  // workaround Apple Clang-7xx series bug, if we use `= default` here, the
43  // compiler believes there is no default constructor defined. :shrug:
44  future() noexcept {} // NOLINT(modernize-use-equals-default)
45 
46  /**
47  * Creates a new future that unwraps @p rhs.
48  *
49  * This constructor creates a new shared state that becomes satisfied when
50  * both `rhs` and `rhs.get()` become satisfied. If `rhs` is satisfied, but
51  * `rhs.get()` returns an invalid future then the newly created future becomes
52  * satisfied with a `std::future_error` exception, and the exception error
53  * code is `std::future_errc::broken_promise`.
54  *
55  * @note The technical specification requires this to be a `noexcept`
56  * constructor I (coryan) believe this is a defect in the technical
57  * specification, as this *creates* a new shared state: shared states are
58  * dynamically allocated, and the allocator (which might be the default
59  * `operator new`) may raise.
60  */
61  // NOLINTNEXTLINE(google-explicit-constructor)
62  future(future<future<T>>&& rhs) noexcept(false);
63 
64  /**
65  * Creates a future from a future whose result type is convertible to this
66  * future's result type.
67  */
68  template <class U, typename Enable =
69  absl::enable_if_t<std::is_constructible<T, U>::value>>
70  explicit future(future<U>&& rhs)
71  : future<T>(rhs.then([](future<U> other) { return T(other.get()); })) {}
72 
73  /**
74  * Waits until the shared state becomes ready, then retrieves the value stored
75  * in the shared state.
76  *
77  * @note This operation invalidates the future, subsequent calls will fail,
78  * the application should capture the returned value because it would.
79  *
80  * @throws any exceptions stored in the shared state.
81  * @throws std::future_error with std::no_state if the future does not have
82  * a shared state.
83  */
84  T get() {
85  this->check_valid();
86  std::shared_ptr<shared_state_type> tmp;
87  tmp.swap(this->shared_state_);
88  return tmp->get();
89  }
90 
91  using internal::future_base<T>::cancel;
92  using internal::future_base<T>::is_ready;
93  using internal::future_base<T>::valid;
94  using internal::future_base<T>::wait;
95  using internal::future_base<T>::wait_for;
96  using internal::future_base<T>::wait_until;
97 
98  /**
99  * Attach a continuation to the future.
100  *
101  * Attach a callable @a func to be invoked when the future is
102  * ready. The return type is a future wrapping the return type of
103  * @a func.
104  *
105  * @return `future<T>` where T is `std::result_of_t<F, R>` (basically).
106  * If T matches `future<U>` then it returns `future<U>`. The returned
107  * future will contain the result of @a func.
108  * @param func a Callable to be invoked when the future is ready.
109  * The function might be called immediately, e.g., if the future is
110  * ready.
111  *
112  * Side effects: `valid() == false` if the operation is successful.
113  */
114  template <typename F>
115  typename internal::then_helper<F, T>::future_t then(F&& func) {
116  this->check_valid();
117  using requires_unwrap_t =
118  typename internal::then_helper<F, T>::requires_unwrap_t;
119  return then_impl(std::forward<F>(func), requires_unwrap_t{});
120  }
121 
122  explicit future(std::shared_ptr<shared_state_type> state)
123  : internal::future_base<T>(std::move(state)) {}
124 
125  private:
126  /// Implement `then()` if the result does not require unwrapping.
127  template <typename F>
128  typename internal::then_helper<F, T>::future_t then_impl(F&& functor,
129  std::false_type);
130 
131  /// Implement `then()` if the result requires unwrapping.
132  template <typename F>
133  typename internal::then_helper<F, T>::future_t then_impl(F&& functor,
134  std::true_type);
135 
136  template <typename U>
137  friend class future;
138  friend class future<void>;
139 
140  friend struct internal::CoroutineSupport;
141 };
142 
143 /**
144  * Implement `promise<T>` as defined in ISO/IEC TS 19571:2016.
145  */
146 template <typename T>
147 class promise final : private internal::promise_base<T> {
148  public:
149  /// Creates a promise with an unsatisfied shared state.
150  promise() : internal::promise_base<T>([] {}) {}
151 
152  /// Creates a promise with an unsatisfied shared state.
153  explicit promise(std::function<void()> cancellation_callback)
154  : internal::promise_base<T>(std::move(cancellation_callback)) {}
155 
156  /// Creates a promise *without* a shared state.
157  explicit promise(null_promise_t x)
158  : internal::promise_base<T>(std::move(x)) {}
159 
160  /// Constructs a new promise and transfer any shared state from @p rhs.
161  // NOLINTNEXTLINE(performance-noexcept-move-constructor)
162  promise(promise&&) = default;
163 
164  /// Abandons the shared state in `*this`, if any, and transfers the shared
165  /// state from @p rhs.
166  promise& operator=(promise&& rhs) noexcept {
167  promise tmp(std::move(rhs));
168  this->swap(tmp);
169  return *this;
170  }
171 
172  /**
173  * Abandons any shared state.
174  *
175  * If the shared state was not already satisfied it becomes satisfied with
176  * a `std::future_error` exception. The error code in this exception is
177  * `std::future_errc::broken_promise`.
178  */
179  ~promise() = default;
180 
181  promise(promise const&) = delete;
182  promise& operator=(promise const&) = delete;
183 
184  /// Swaps the shared state in `*this` with @p rhs.
185  void swap(promise& other) noexcept {
186  std::swap(this->shared_state_, other.shared_state_);
187  }
188 
189  /**
190  * Creates the `future<T>` using the same shared state as `*this`.
191  */
193  internal::future_shared_state<T>::mark_retrieved(this->shared_state_);
194  return future<T>(this->shared_state_);
195  }
196 
197  /**
198  * Satisfies the shared state.
199  *
200  * @throws std::future_error with std::future_errc::promise_already_satisfied
201  * if the shared state is already satisfied.
202  * @throws std::future_error with std::no_state if the promise does not have
203  * a shared state.
204  */
205  void set_value(T value) {
206  if (!this->shared_state_) {
207  internal::ThrowFutureError(std::future_errc::no_state, __func__);
208  }
209  this->shared_state_->set_value(std::move(value));
210  }
211 
212  using internal::promise_base<T>::set_exception;
213 };
214 
215 /// Create a future<void> that is immediately ready.
216 template <typename T>
217 inline future<typename internal::make_ready_return<T>::type> make_ready_future(
218  T&& t) {
219  using V = typename internal::make_ready_return<T>::type;
220  // TODO(#1410) - Implement specializations of future<R&> and promise<R&>.
221  static_assert(!std::is_reference<V>::value, "future<R&> is not implemented");
222  promise<V> p;
223  p.set_value(std::forward<T>(t));
224  return p.get_future();
225 }
226 
228 } // namespace cloud
229 } // namespace google
230 
231 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_FUTURE_GENERIC_H