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