Zth (libzth)
Loading...
Searching...
No Matches
future.h
Go to the documentation of this file.
1#ifndef ZTH_FUTURE_H
2#define ZTH_FUTURE_H
3/*
4 * SPDX-FileCopyrightText: 2019-2026 Jochem Rutgers
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 */
8
15#if defined(__cplusplus) && __cplusplus >= 201103L
16
17# include <libzth/macros.h>
18
19# include <libzth/sync.h>
20# include <libzth/time.h>
21
22# include <future>
23# include <stdexcept>
24# include <type_traits>
25
26
27
29// std::promise and std::future
30//
31
32namespace zth {
33template <typename T>
34struct type {};
35
36template <typename T>
37using promise = ::std::promise<zth::type<T>>;
38
39template <typename T>
40using future = ::std::future<zth::type<T>>;
41
42template <typename T>
43using shared_future = ::std::shared_future<zth::type<T>>;
44
45namespace impl {
46template <typename T>
48public:
49 using value_type = T;
50
51protected:
53 std_shared_future_base() noexcept = default;
54
57 {}
58
60 : m_future{std::move(future)}
61 {}
62
64 : m_future{future.valid() ? &future.get() : nullptr}
65 {}
66
68 : m_future{static_cast<SharedPointer<Future_type>&&>(std::move(future))}
69 {}
70
71 // cppcheck-suppress-macro noExplicitConstructor
72# define ZTH_FUTURE_CTORS(future_class_type) \
73 using Future_type = typename base::Future_type; \
74 \
75 future_class_type() noexcept = default; \
76 \
77 future_class_type(zth::SharedPointer<Future_type> const& f) noexcept \
78 : base{f} \
79 {} \
80 \
81 future_class_type(zth::SharedReference<Future_type> const& f) noexcept \
82 : base{f} \
83 {}
84
85public:
87
89 {
90 m_future = std::move(other);
91 return *this;
92 }
93
95 {
96 m_future = static_cast<SharedPointer<Future_type>&&>(std::move(other));
97 return *this;
98 }
99
100 // cppcheck-suppress-macro noExplicitConstructor
101# define ZTH_FUTURE_MOVE(future_class_type) \
102 future_class_type(future_class_type&& other) noexcept = default; \
103 \
104 future_class_type(zth::SharedPointer<Future_type>&& f) noexcept \
105 : base{std::move(f)} \
106 {} \
107 \
108 future_class_type(zth::SharedReference<Future_type>&& f) noexcept \
109 : base{std::move(f)} \
110 {} \
111 \
112 future_class_type& operator=(future_class_type&& other) noexcept = default; \
113 \
114 future_class_type& operator=(zth::SharedPointer<Future_type>&& other) noexcept \
115 { \
116 this->base::operator=(std::move(other)); \
117 return *this; \
118 } \
119 \
120 future_class_type& operator=(zth::SharedReference<Future_type>&& other) noexcept \
121 { \
122 this->base::operator=(std::move(other)); \
123 return *this; \
124 }
125
126 std_shared_future_base& operator=(std_shared_future_base const& other) noexcept = default;
127
129 {
130 m_future = other;
131 return *this;
132 }
133
135 {
136 m_future = other.valid() ? &other.get() : nullptr;
137 return *this;
138 }
139
140# define ZTH_FUTURE_COPY(future_class_type) \
141 future_class_type(future_class_type const& other) noexcept = default; \
142 \
143 future_class_type& operator=(future_class_type const& other) noexcept = default; \
144 \
145 future_class_type& operator=(zth::SharedPointer<Future_type> const& other) noexcept \
146 { \
147 this->base::operator=(other); \
148 return *this; \
149 } \
150 \
151 future_class_type& operator=(zth::SharedReference<Future_type> const& other) noexcept \
152 { \
153 this->base::operator=(other); \
154 return *this; \
155 }
156
157 bool valid() const noexcept
158 {
159 return m_future;
160 }
161
162 void wait() const
163 {
164 check_valid();
165 m_future->wait();
166 }
167
168 template <class Rep, class Period>
169 std::future_status
170 wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
171 {
172 check_valid();
173 return m_future->block(timeout_duration) ? std::future_status::ready
174 : std::future_status::timeout;
175 }
176
177 template <class Clock, class Duration>
178 std::future_status
179 wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const
180 {
181 check_valid();
182 return m_future->block(timeout_time) ? std::future_status::ready
183 : std::future_status::timeout;
184 }
185
186 operator SharedPointer<Future_type> const&() const& noexcept
187 {
188 return m_future;
189 }
190
191 operator SharedPointer<Future_type>&&() && noexcept
192 {
193 return std::move(m_future);
194 }
195
196protected:
198 {
199 check_valid();
200 return *m_future;
201 }
202
203 // The inline attribute fixes a false-positive warning about null dereference in value().
204 __attribute__((always_inline)) inline void check_valid() const
205 {
206 if(!valid())
207 zth_throw(std::future_error(std::future_errc::no_state));
208 }
209
211};
212
213template <typename T>
215public:
217 using value_type = typename base::value_type;
218
219protected:
222
223public:
226
227 std::shared_future<zth::type<T>> share() const noexcept
228 {
229 auto f = std::shared_future<zth::type<T>>(std::move(this->m_future));
230 return f;
231 }
232};
233
234template <typename T>
236public:
237 using value_type = T;
239
240protected:
242 : m_future{new Future_type{}}
243 {}
244
246 : m_future{std::move(future)}
247 {}
248
249 std_promise_base(std_promise_base&& other) noexcept = default;
250
251public:
253 {
254 this->m_future = std::move(other.m_future);
255 return *this;
256 }
257
260
261 void swap(std_promise_base& other) noexcept
262 {
263 std::swap(m_future, other.m_future);
264 }
265
266 std::future<zth::type<T>> get_future()
267 {
268 check_valid();
269
270 if(m_got_future)
271 zth_throw(std::future_error(std::future_errc::future_already_retrieved));
272
273 m_got_future = true;
274 return m_future;
275 }
276
277 template <typename U>
278 void set_value(U&& value)
279 {
281 m_future->set(std::forward<U>(value));
282 }
283
285 {
287 m_future->set();
288 }
289
290 void set_exception(std::exception_ptr exception)
291 {
293 m_future->set(std::move(exception));
294 }
295
296protected:
297 void check_valid() const
298 {
299 if(!m_future)
300 zth_throw(std::future_error(std::future_errc::no_state));
301 }
302
304 {
305 check_valid();
306
307 if(m_future->valid())
308 zth_throw(std::future_error(std::future_errc::promise_already_satisfied));
309 }
310
311private:
313 bool m_got_future = false;
314};
315
316} // namespace impl
317} // namespace zth
318
319namespace std {
320template <typename T>
321class future<zth::type<T>> : public zth::impl::std_future_base<T> {
323public:
325 using value_type = typename base::value_type;
326
327 ZTH_FUTURE_CTORS(future)
328 ZTH_FUTURE_MOVE(future)
329
330 future(future const&) = delete;
331 future& operator=(future const&) = delete;
332
333 value_type const& get()
334 {
335 return *base::value();
336 }
337};
338
339template <typename T>
340class future<zth::type<T&>> : public zth::impl::std_future_base<T*> {
342public:
343 using value_type = T&;
345
346 ZTH_FUTURE_CTORS(future)
347 ZTH_FUTURE_MOVE(future)
348
349 future(future const&) = delete;
350 future& operator=(future const&) = delete;
351
352 value_type& get()
353 {
354 return **base::value();
355 }
356};
357
358template <>
359class future<zth::type<void>> : public zth::impl::std_future_base<void> {
361public:
363 using value_type = void;
364
365 ZTH_FUTURE_CTORS(future)
366 ZTH_FUTURE_MOVE(future)
367
368 future(future const&) = delete;
369 future& operator=(future const&) = delete;
370
371 void get()
372 {
373 wait();
374 }
375};
376
377template <typename T>
378class shared_future<zth::type<T>> : public zth::impl::std_shared_future_base<T> {
379 ZTH_CLASS_NEW_DELETE(shared_future)
380public:
381 using value_type = T;
383
384 ZTH_FUTURE_CTORS(shared_future)
385 ZTH_FUTURE_MOVE(shared_future)
386 ZTH_FUTURE_COPY(shared_future)
387
388 value_type const& get()
389 {
390 return *base::value();
391 }
392};
393
394template <typename T>
395class shared_future<zth::type<T&>> : public zth::impl::std_shared_future_base<T*> {
396 ZTH_CLASS_NEW_DELETE(shared_future)
397public:
398 using value_type = T&;
400
401 ZTH_FUTURE_CTORS(shared_future)
402 ZTH_FUTURE_MOVE(shared_future)
403 ZTH_FUTURE_COPY(shared_future)
404
405 value_type& get()
406 {
407 return **base::value();
408 }
409};
410
411template <>
412class shared_future<zth::type<void>> : public zth::impl::std_shared_future_base<void> {
413 ZTH_CLASS_NEW_DELETE(shared_future)
414public:
415 using value_type = void;
417
418 ZTH_FUTURE_CTORS(shared_future)
419 ZTH_FUTURE_MOVE(shared_future)
420 ZTH_FUTURE_COPY(shared_future)
421
422 void get()
423 {
424 wait();
425 }
426};
427
428template <typename T>
429class promise<zth::type<T>> : public zth::impl::std_promise_base<T> {
430 ZTH_CLASS_NEW_DELETE(promise)
431public:
432 using value_type = T;
434
435 promise() = default;
436
437 // cppcheck-suppress noExplicitConstructor
439 : base{std::move(future)}
440 {}
441};
442
443template <typename T>
444class promise<zth::type<T&>> : public zth::impl::std_promise_base<T*> {
445public:
446 using value_type = T&;
448
449 promise() = default;
450
451 // cppcheck-suppress noExplicitConstructor
453 : base{std::move(future)}
454 {}
455};
456
457template <>
458class promise<zth::type<void>> : public zth::impl::std_promise_base<void> {
459public:
461
462 promise() = default;
463
464 // cppcheck-suppress noExplicitConstructor
466 : base{std::move(future)}
467 {}
468};
469
470} // namespace std
471
472# undef ZTH_FUTURE_CTORS
473# undef ZTH_FUTURE_MOVE
474# undef ZTH_FUTURE_COPY
475
476
477
479// std::async
480//
481
482namespace zth {
483
489enum class launch {
490 detached = 1,
491 awaitable = 2,
492};
493
494namespace impl {
495# if __cplusplus < 201703L
496template <typename Func, typename... Args>
497using invoke_result = typename std::result_of<Func(Args...)>::type;
498# else
499template <typename Func, typename... Args>
500using invoke_result = typename std::invoke_result_t<Func, Args...>;
501# endif
502} // namespace impl
503
504template <typename Func, typename... Args>
505zth::future<zth::impl::invoke_result<Func, Args...>> async(Func&& f, Args&&... args)
506{
507 return async(zth::launch::detached, std::forward<Func>(f), std::forward<Args>(args)...);
508}
509
510template <typename Func, typename... Args>
512async(zth::launch policy, Func&& f, Args&&... args)
513{
514 auto fib = zth::fiber(std::forward<Func>(f), std::forward<Args>(args)...);
515 switch(policy) {
517 return {};
519 return fib << zth::asFuture();
520 default:
521 zth_throw(std::invalid_argument("policy"));
522 }
523}
524} // namespace zth
525
526namespace std {
527template <typename Func, typename... Args>
529async(zth::launch policy, Func&& f, Args&&... args)
530{
531 return zth::async(policy, std::forward<Func>(f), std::forward<Args>(args)...);
532}
533} // namespace std
534
535
536#endif // C++11
537#endif // ZTH_FUTURE_H
Fiber-aware future.
Definition sync.h:1068
constexpr type * get() const noexcept
Definition sync.h:134
typename base::value_type value_type
Definition future.h:217
std::shared_future< zth::type< T > > share() const noexcept
Definition future.h:227
std_future_base & operator=(std_future_base const &)=delete
std_future_base(std_future_base const &)=delete
std_promise_base(SharedPointer< Future_type > future) noexcept
Definition future.h:245
void check_not_satisfied() const
Definition future.h:303
void check_valid() const
Definition future.h:297
std::future< zth::type< T > > get_future()
Definition future.h:266
std_promise_base & operator=(std_promise_base &&other) noexcept
Definition future.h:252
std_promise_base(std_promise_base const &)=delete
void swap(std_promise_base &other) noexcept
Definition future.h:261
void set_exception(std::exception_ptr exception)
Definition future.h:290
std_promise_base(std_promise_base &&other) noexcept=default
void set_value(U &&value)
Definition future.h:278
std_promise_base & operator=(std_promise_base const &)=delete
zth::SharedPointer< zth::Future< T > > m_future
Definition future.h:210
bool valid() const noexcept
Definition future.h:157
std_shared_future_base & operator=(std_shared_future_base &&other) noexcept=default
std_shared_future_base(SharedReference< Future_type > const &future) noexcept
Definition future.h:63
std_shared_future_base & operator=(SharedPointer< Future_type > const &other) noexcept
Definition future.h:128
std_shared_future_base(SharedPointer< Future_type > &&future) noexcept
Definition future.h:59
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
Definition future.h:179
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition future.h:170
std_shared_future_base() noexcept=default
std_shared_future_base & operator=(SharedReference< Future_type > &&other) noexcept
Definition future.h:94
Future_type & value() const
Definition future.h:197
std_shared_future_base & operator=(SharedPointer< Future_type > &&other) noexcept
Definition future.h:88
std_shared_future_base(SharedReference< Future_type > &&future) noexcept
Definition future.h:67
std_shared_future_base & operator=(std_shared_future_base const &other) noexcept=default
std_shared_future_base & operator=(SharedReference< Future_type > const &other) noexcept
Definition future.h:134
#define ZTH_FUTURE_CTORS(future_class_type)
Definition future.h:72
#define ZTH_FUTURE_COPY(future_class_type)
Definition future.h:140
#define ZTH_FUTURE_MOVE(future_class_type)
Definition future.h:101
fiber_type< F >::fiber fiber(F &&f, Args &&... args)
Create and start a new fiber.
Definition async.h:1192
launch
Launch policies for std::async to start fibers instead of threads.
Definition future.h:489
@ awaitable
Start fiber, returning a future to await.
@ detached
Start fiber, without a future to await.
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition allocator.h:159
#define zth_throw(...)
Definition macros.h:365
STL namespace.
zth::future< zth::impl::invoke_result< Func, Args... > > async(zth::launch policy, Func &&f, Args &&... args)
Definition future.h:529
typename std::invoke_result_t< Func, Args... > invoke_result
Definition future.h:500
zth::future< zth::impl::invoke_result< Func, Args... > > async(Func &&f, Args &&... args)
Definition future.h:505
::std::future< zth::type< T > > future
Definition future.h:40
::std::shared_future< zth::type< T > > shared_future
Definition future.h:43
::std::promise< zth::type< T > > promise
Definition future.h:37
Forces the fiber to have a future that outlives the fiber.
Definition async.h:310
Base exception class for Zth exceptions.
Definition exception.h:16