YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
future.hpp
Go to the documentation of this file.
1#pragma once
2
7#include <yaclib/fwd.hpp>
10
11namespace yaclib {
12
13/**
14 * Provides a mechanism to access the result of async operations
15 *
16 * Future and \ref Promise are like a Single Producer/Single Consumer one-shot one-element channel.
17 * Use the \ref Promise to fulfill the \ref Future.
18 */
19template <typename V, typename E>
21 public:
22 static_assert(Check<V>(), "V should be valid");
23 static_assert(Check<E>(), "E should be valid");
24 static_assert(!std::is_same_v<V, E>, "Future cannot be instantiated with same V and E, because it's ambiguous");
25
26 FutureBase(const FutureBase&) = delete;
27 FutureBase& operator=(const FutureBase&) = delete;
28
29 FutureBase(FutureBase&& other) noexcept = default;
30 FutureBase& operator=(FutureBase&& other) noexcept = default;
31
32 /**
33 * The default constructor creates not a \ref Valid Future
34 *
35 * Needed only for usability, e.g. instead of std::optional<Future<T>> in containers.
36 */
38
39 /**
40 * If Future is \ref Valid then call \ref Stop
41 */
43 if (Valid()) {
44 std::move(*this).Detach();
45 }
46 }
47
48 /**
49 * Check if this \ref Future has \ref Promise
50 *
51 * \return false if this \ref Future is default-constructed or moved to, otherwise true
52 */
54 return _core != nullptr;
55 }
56
57 /**
58 * Check that \ref Result that corresponds to this \ref Future is computed
59 *
60 * \return false if the \ref Result of this \ref Future is not computed yet, otherwise true
61 */
64 return !_core->Empty();
65 }
66
67 void Get() & = delete;
68 void Get() const&& = delete;
69 void Touch() & = delete;
70 void Touch() const&& = delete;
71
72 /**
73 * Return copy of \ref Result from \ref Future
74 *
75 * If \ref Ready is false return an empty \ref Result. This method is thread-safe and can be called multiple times.
76 * \note The behavior is undefined if \ref Valid is false before the call to this function.
77 * \return \ref Result stored in the shared state
78 */
80 if (Ready()) { // TODO(MBkkt) Maybe we want likely
81 return &_core->Get();
82 }
83 return nullptr;
84 }
85
86 /**
87 * Wait until \def Ready is true and move \ref Result from Future
88 *
89 * \note The behavior is undefined if \ref Valid is false before the call to this function.
90 * \return The \ref Result that Future received
91 */
92 [[nodiscard]] Result<V, E> Get() && noexcept {
93 Wait(*this);
94 auto core = std::exchange(_core, nullptr);
95 return std::move(core->Get());
96 }
97
98 /**
99 * Assume \def Ready is true and return copy reference to \ref Result from Future
100 *
101 * Assume Ready is true. This method is NOT thread-safe and can be called multiple
102 * \note The behavior is undefined if \ref Valid or Ready is false before the call to this function.
103 * \return The \ref Result stored in the shared state
104 */
107 return _core->Get();
108 }
109
110 /**
111 * Assume \def Ready is true and move \ref Result from Future
112 *
113 * \note The behavior is undefined if \ref Valid or Ready is false before the call to this function.
114 * \return The \ref Result that Future received
115 */
116 [[nodiscard]] Result<V, E> Touch() && noexcept {
118 auto core = std::exchange(_core, nullptr);
119 return std::move(core->Get());
120 }
121
122 /**
123 * Attach the continuation func to *this
124 *
125 * The func will be executed on the specified executor.
126 * \note The behavior is undefined if \ref Valid is false before the call to this function.
127 * \param e Executor which will \ref Execute the continuation
128 * \param f A continuation to be attached
129 * \return New \ref FutureOn object associated with the func result
130 */
131 template <typename Func>
132 [[nodiscard]] /*FutureOn*/ auto Then(IExecutor& e, Func&& f) && {
134 "better way is use ThenInline(...) instead of Then(MakeInline(), ...)");
135 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::On>(_core, &e, std::forward<Func>(f));
136 }
137
138 /**
139 * Disable calling \ref Stop in destructor
140 */
141 void Detach() && noexcept {
142 auto* core = _core.Release();
143 // TODO(MBkkt) if use SetCallback it will single virtual call instead of two
144 core->CallInline(detail::MakeDrop());
145 }
146
147 /**
148 * Attach the final continuation func to *this and \ref Detach *this
149 *
150 * The func will be executed on \ref Inline executor.
151 * \note The behavior is undefined if \ref Valid is false before the call to this function.
152 * \param f A continuation to be attached
153 */
154 template <typename Func>
155 void DetachInline(Func&& f) && {
156 detail::SetCallback<detail::CoreType::Detach, detail::CallbackType::Inline>(_core, nullptr, std::forward<Func>(f));
157 }
158
159 /**
160 * Attach the final continuation func to *this and \ref Detach *this
161 *
162 * The func will be executed on the specified executor.
163 * \note The behavior is undefined if \ref Valid is false before the call to this function.
164 * \param e Executor which will \ref Execute the continuation
165 * \param f A continuation to be attached
166 */
167 template <typename Func>
168 void Detach(IExecutor& e, Func&& f) && {
170 "better way is use DetachInline(...) instead of Detach(MakeInline(), ...)");
171 detail::SetCallback<detail::CoreType::Detach, detail::CallbackType::On>(_core, &e, std::forward<Func>(f));
172 }
173
174 /**
175 * Method that get internal Core state
176 *
177 * \return internal Core state ptr
178 */
182
186
187 protected:
188 explicit FutureBase(detail::UniqueCorePtr<V, E> core) noexcept : _core{std::move(core)} {
189 }
190
192};
193
194extern template class FutureBase<void, StopError>;
195
196/**
197 * Provides a mechanism to access the result of async operations
198 *
199 * Future and \ref Promise are like a Single Producer/Single Consumer one-shot one-element channel.
200 * Use the \ref Promise to fulfill the \ref Future.
201 */
202template <typename V, typename E>
204 using Base = FutureBase<V, E>;
205
206 public:
207 using Base::Base;
208
210 }
211
212 /**
213 * Attach the continuation func to *this
214 *
215 * The func will be executed on \ref Inline executor.
216 * \note The behavior is undefined if \ref Valid is false before the call to this function.
217 * \param f A continuation to be attached
218 * \return New \ref Future object associated with the func result
219 */
220 template <typename Func>
221 [[nodiscard]] /*Future*/ auto ThenInline(Func&& f) && {
222 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::Inline>(this->_core, nullptr,
223 std::forward<Func>(f));
224 }
225};
226
227extern template class Future<>;
228
229/**
230 * Provides a mechanism to access the result of async operations
231 *
232 * Future and \ref Promise are like a Single Producer/Single Consumer one-shot one-element channel.
233 * Use the \ref Promise to fulfill the \ref Future.
234 */
235template <typename V, typename E>
237 using Base = FutureBase<V, E>;
238
239 public:
240 using Base::Base;
241 using Base::Detach;
242 using Base::Then;
243
245 }
246
247 /**
248 * Specify executor for continuation.
249 * Make FutureOn -- Future with executor
250 */
251 [[nodiscard]] Future<V, E> On(std::nullptr_t) && noexcept {
252 return {std::move(this->_core)};
253 }
254
255 /**
256 * Attach the continuation func to *this
257 *
258 * The func will be executed on \ref Inline executor.
259 * \note The behavior is undefined if \ref Valid is false before the call to this function.
260 * \param f A continuation to be attached
261 * \return New \ref FutureOn object associated with the func result
262 */
263 template <typename Func>
264 [[nodiscard]] /*FutureOn*/ auto ThenInline(Func&& f) && {
265 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::InlineOn>(this->_core, nullptr,
266 std::forward<Func>(f));
267 }
268
269 /**
270 * Attach the continuation func to *this
271 *
272 * \note The behavior is undefined if \ref Valid is false before the call to this function.
273 * \param f A continuation to be attached
274 * \return New \ref FutureOn object associated with the func result
275 */
276 template <typename Func>
277 [[nodiscard]] /*FutureOn*/ auto Then(Func&& f) && {
278 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::On>(this->_core, nullptr,
279 std::forward<Func>(f));
280 }
281
282 /**
283 * Attach the final continuation func to *this and \ref Detach *this
284 *
285 * \note Func must return void type.
286 * \param f A continuation to be attached
287 */
288 template <typename Func>
289 void Detach(Func&& f) && {
290 detail::SetCallback<detail::CoreType::Detach, detail::CallbackType::On>(this->_core, nullptr,
291 std::forward<Func>(f));
292 }
293};
294
295extern template class FutureOn<>;
296
297} // namespace yaclib
Provides a mechanism to access the result of async operations.
Definition future.hpp:20
detail::UniqueHandle GetBaseHandle() noexcept
Definition future.hpp:183
void DetachInline(Func &&f) &&
Attach the final continuation func to *this and Detach *this.
Definition future.hpp:155
Result< V, E > Get() &&noexcept
Definition future.hpp:92
FutureBase & operator=(const FutureBase &)=delete
detail::UniqueCorePtr< V, E > _core
Definition future.hpp:191
FutureBase(detail::UniqueCorePtr< V, E > core) noexcept
Definition future.hpp:188
bool Valid() const &noexcept
Check if this Future has Promise.
Definition future.hpp:53
void Touch() &=delete
Result< V, E > Touch() &&noexcept
Definition future.hpp:116
FutureBase(FutureBase &&other) noexcept=default
void Get() &=delete
void Detach() &&noexcept
Disable calling Stop in destructor.
Definition future.hpp:141
FutureBase() noexcept=default
The default constructor creates not a Valid Future.
void Detach(IExecutor &e, Func &&f) &&
Attach the final continuation func to *this and Detach *this.
Definition future.hpp:168
auto Then(IExecutor &e, Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:132
detail::UniqueCorePtr< V, E > & GetCore() noexcept
Method that get internal Core state.
Definition future.hpp:179
FutureBase(const FutureBase &)=delete
FutureBase & operator=(FutureBase &&other) noexcept=default
const Result< V, E > & Touch() const &noexcept
Definition future.hpp:105
bool Ready() const &noexcept
Check that Result that corresponds to this Future is computed.
Definition future.hpp:62
void Get() const &&=delete
Provides a mechanism to access the result of async operations.
Definition future.hpp:236
Future< V, E > On(std::nullptr_t) &&noexcept
Specify executor for continuation.
Definition future.hpp:251
void Detach(Func &&f) &&
Attach the final continuation func to *this and Detach *this.
Definition future.hpp:289
FutureOn(detail::UniqueCorePtr< V, E > core) noexcept
Definition future.hpp:244
auto ThenInline(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:264
auto Then(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:277
Provides a mechanism to access the result of async operations.
Definition future.hpp:203
auto ThenInline(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:221
Future(detail::UniqueCorePtr< V, E > core) noexcept
Definition future.hpp:209
A intrusive pointer to objects with an embedded reference count.
Encapsulated return value from caller.
Definition result.hpp:90
#define YACLIB_WARN(cond, message)
Definition log.hpp:74
#define YACLIB_ASSERT(cond)
Definition log.hpp:85
InlineCore & MakeDrop() noexcept
Definition drop_core.cpp:27
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
YACLIB_INLINE std::enable_if_t<(... &&is_waitable_v< Waited >), void > Wait(Waited &... fs) noexcept
Wait until Ready becomes true.
Definition wait.hpp:18