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
183 protected:
186
188};
189
190extern template class FutureBase<void, StopError>;
191
192/**
193 * Provides a mechanism to access the result of async operations
194 *
195 * Future and \ref Promise are like a Single Producer/Single Consumer one-shot one-element channel.
196 * Use the \ref Promise to fulfill the \ref Future.
197 */
198template <typename V, typename E>
200 using Base = FutureBase<V, E>;
201
202 public:
203 using Base::Base;
204
207
208 /**
209 * Attach the continuation func to *this
210 *
211 * The func will be executed on \ref Inline executor.
212 * \note The behavior is undefined if \ref Valid is false before the call to this function.
213 * \param f A continuation to be attached
214 * \return New \ref Future object associated with the func result
215 */
216 template <typename Func>
217 [[nodiscard]] /*Future*/ auto ThenInline(Func&& f) && {
218 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::Inline>(this->_core, nullptr,
219 std::forward<Func>(f));
220 }
221};
222
223extern template class Future<>;
224
225/**
226 * Provides a mechanism to access the result of async operations
227 *
228 * Future and \ref Promise are like a Single Producer/Single Consumer one-shot one-element channel.
229 * Use the \ref Promise to fulfill the \ref Future.
230 */
231template <typename V, typename E>
233 using Base = FutureBase<V, E>;
234
235 public:
236 using Base::Base;
237 using Base::Detach;
238 using Base::Then;
239
242
243 /**
244 * Specify executor for continuation.
245 * Make FutureOn -- Future with executor
246 */
247 [[nodiscard]] Future<V, E> On(std::nullptr_t) && noexcept {
248 return {std::move(this->_core)};
249 }
250
251 /**
252 * Attach the continuation func to *this
253 *
254 * The func will be executed on \ref Inline executor.
255 * \note The behavior is undefined if \ref Valid is false before the call to this function.
256 * \param f A continuation to be attached
257 * \return New \ref FutureOn object associated with the func result
258 */
259 template <typename Func>
260 [[nodiscard]] /*FutureOn*/ auto ThenInline(Func&& f) && {
261 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::InlineOn>(this->_core, nullptr,
262 std::forward<Func>(f));
263 }
264
265 /**
266 * Attach the continuation func to *this
267 *
268 * \note The behavior is undefined if \ref Valid is false before the call to this function.
269 * \param f A continuation to be attached
270 * \return New \ref FutureOn object associated with the func result
271 */
272 template <typename Func>
273 [[nodiscard]] /*FutureOn*/ auto Then(Func&& f) && {
274 return detail::SetCallback<detail::CoreType::Then, detail::CallbackType::On>(this->_core, nullptr,
275 std::forward<Func>(f));
276 }
277
278 /**
279 * Attach the final continuation func to *this and \ref Detach *this
280 *
281 * \note Func must return void type.
282 * \param f A continuation to be attached
283 */
284 template <typename Func>
285 void Detach(Func&& f) && {
286 detail::SetCallback<detail::CoreType::Detach, detail::CallbackType::On>(this->_core, nullptr,
287 std::forward<Func>(f));
288 }
289};
290
291extern template class FutureOn<>;
292
293} // namespace yaclib
Provides a mechanism to access the result of async operations.
Definition future.hpp:20
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::ResultCorePtr< V, E > & GetCore() noexcept
Method that get internal Core state.
Definition future.hpp:179
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(detail::ResultCorePtr< V, E > core) noexcept
Definition future.hpp:184
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::ResultCorePtr< V, E > _core
Definition future.hpp:187
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:232
Future< V, E > On(std::nullptr_t) &&noexcept
Specify executor for continuation.
Definition future.hpp:247
void Detach(Func &&f) &&
Attach the final continuation func to *this and Detach *this.
Definition future.hpp:285
auto ThenInline(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:260
auto Then(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:273
FutureOn(detail::ResultCorePtr< V, E > core) noexcept
Definition future.hpp:240
Provides a mechanism to access the result of async operations.
Definition future.hpp:199
Future(detail::ResultCorePtr< V, E > core) noexcept
Definition future.hpp:205
auto ThenInline(Func &&f) &&
Attach the continuation func to *this.
Definition future.hpp:217
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
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
YACLIB_INLINE void Wait(FutureBase< V, E > &... fs) noexcept
Wait until Ready becomes true.
Definition wait.hpp:18