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