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