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
9#if defined(__cplusplus) && __cplusplus >= 201103L
10
11# include <libzth/macros.h>
12
13# include <libzth/sync.h>
14# include <libzth/time.h>
15
16# include <future>
17# include <stdexcept>
18# include <type_traits>
19
20
21
23// std::promise and std::future
24//
25
26namespace zth {
27template <typename T>
28struct type {};
29
30template <typename T>
31using promise = ::std::promise<zth::type<T>>;
32
33template <typename T>
34using future = ::std::future<zth::type<T>>;
35
36template <typename T>
37using shared_future = ::std::shared_future<zth::type<T>>;
38
39namespace impl {
40template <typename T>
42public:
43 using value_type = T;
45
46protected:
47 std_shared_future_base() noexcept = default;
48
50 : m_future{std::move(future)}
51 {}
52
53public:
54 bool valid() const noexcept
55 {
56 return m_future;
57 }
58
59 void wait() const
60 {
62 m_future->wait();
63 }
64
65 template <class Rep, class Period>
66 std::future_status
67 wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
68 {
70 return m_future->block(timeout_duration) ? std::future_status::ready
71 : std::future_status::timeout;
72 }
73
74 template <class Clock, class Duration>
75 std::future_status
76 wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const
77 {
79 return m_future->block(timeout_time) ? std::future_status::ready
80 : std::future_status::timeout;
81 }
82
83protected:
84 T value() const
85 {
87 return m_future->value();
88 }
89
90 void check_valid() const
91 {
92 if(!valid())
93 zth_throw(std::future_error(std::future_errc::no_state));
94 }
95
97};
98
99template <typename T>
101public:
103
104protected:
105 std_future_base() noexcept = default;
106
108 : base{std::move(future)}
109 {}
110
112 {
113 *this = std::move(other);
114 }
115
116public:
118 {
119 this->m_future = std::move(other.m_future);
120 return *this;
121 }
122
125
126 std::shared_future<zth::type<T>> share() const
127 {
128 auto f = std::shared_future<zth::type<T>>(std::move(this->m_future));
129 return f;
130 }
131};
132
133template <typename T>
135public:
136 using value_type = T;
138
139protected:
141 : m_future{new Future_type{}}
142 {}
143
145 : m_future{std::move(future)}
146 {}
147
149 {
150 *this = std::move(other);
151 }
152
153public:
155 {
156 this->m_future = std::move(other.m_future);
157 return *this;
158 }
159
162
163 void swap(std_promise_base& other) noexcept
164 {
165 std::swap(m_future, other.m_future);
166 }
167
168 std::future<zth::type<T>> get_future()
169 {
170 check_valid();
171
172 if(m_got_future)
173 zth_throw(std::future_error(std::future_errc::future_already_retrieved));
174
175 m_got_future = true;
176 return m_future;
177 }
178
179 template <typename U>
180 void set_value(U&& value)
181 {
183 m_future->set(std::forward<U>(value));
184 }
185
187 {
189 m_future->set();
190 }
191
192 void set_exception(std::exception_ptr exception)
193 {
195 m_future->set(std::move(exception));
196 }
197
198protected:
199 void check_valid() const
200 {
201 if(!m_future)
202 zth_throw(std::future_error(std::future_errc::no_state));
203 }
204
206 {
207 check_valid();
208
209 if(m_future->valid())
210 zth_throw(std::future_error(std::future_errc::promise_already_satisfied));
211 }
212
213private:
215 bool m_got_future = false;
216};
217
218} // namespace impl
219} // namespace zth
220
221namespace std {
222template <typename T>
223class future<zth::type<T>> : public zth::impl::std_future_base<T> {
225public:
226 using value_type = T;
228
229 future() noexcept = default;
230
231 // cppcheck-suppress noExplicitConstructor
232 future(zth::SharedPointer<typename base::Future_type> f) noexcept
233 : base{std::move(f)}
234 {}
235
236 value_type get()
237 {
238 return base::value();
239 }
240};
241
242template <typename T>
243class future<zth::type<T&>> : public zth::impl::std_future_base<T*> {
245public:
246 using value_type = T&;
248
249 future() noexcept = default;
250
251 // cppcheck-suppress noExplicitConstructor
252 future(zth::SharedPointer<typename base::Future_type> f) noexcept
253 : base{std::move(f)}
254 {}
255
256 value_type get()
257 {
258 return *base::value();
259 }
260};
261
262template <>
263class future<zth::type<void>> : public zth::impl::std_future_base<void> {
265public:
266 using value_type = void;
268
269 future() noexcept = default;
270
271 // cppcheck-suppress noExplicitConstructor
272 future(zth::SharedPointer<typename base::Future_type> f) noexcept
273 : base{std::move(f)}
274 {}
275
276 void get()
277 {
278 wait();
279 }
280};
281
282template <typename T>
283class shared_future<zth::type<T>> : public zth::impl::std_shared_future_base<T> {
284 ZTH_CLASS_NEW_DELETE(shared_future)
285public:
286 using value_type = T;
288
289 value_type get()
290 {
291 return base::value();
292 }
293};
294
295template <typename T>
296class shared_future<zth::type<T&>> : public zth::impl::std_shared_future_base<T*> {
297 ZTH_CLASS_NEW_DELETE(shared_future)
298public:
299 using value_type = T&;
301
302 value_type get()
303 {
304 return *base::value();
305 }
306};
307
308template <>
309class shared_future<zth::type<void>> : public zth::impl::std_shared_future_base<void> {
310 ZTH_CLASS_NEW_DELETE(shared_future)
311public:
312 using value_type = void;
314
315 void get()
316 {
317 wait();
318 }
319};
320
321template <typename T>
322class promise<zth::type<T>> : public zth::impl::std_promise_base<T> {
323 ZTH_CLASS_NEW_DELETE(promise)
324public:
325 using value_type = T;
327
328 promise() = default;
329
330 // cppcheck-suppress noExplicitConstructor
332 : base{std::move(future)}
333 {}
334};
335
336template <typename T>
337class promise<zth::type<T&>> : public zth::impl::std_promise_base<T*> {
338public:
339 using value_type = T&;
341
342 promise() = default;
343
344 // cppcheck-suppress noExplicitConstructor
346 : base{std::move(future)}
347 {}
348};
349
350template <>
351class promise<zth::type<void>> : public zth::impl::std_promise_base<void> {
352public:
354
355 promise() = default;
356
357 // cppcheck-suppress noExplicitConstructor
359 : base{std::move(future)}
360 {}
361};
362
363} // namespace std
364
365
366
368// std::async
369//
370
371namespace zth {
372enum class launch { detached = 1, awaitable = 2 };
373
374namespace impl {
375# if __cplusplus < 201703L
376template <typename Func, typename... Args>
377using invoke_result = typename std::result_of<Func(Args...)>::type;
378# else
379template <typename Func, typename... Args>
380using invoke_result = typename std::invoke_result_t<Func, Args...>;
381# endif
382} // namespace impl
383
384template <typename Func, typename... Args>
385zth::future<zth::impl::invoke_result<Func, Args...>> async(Func&& f, Args&&... args)
386{
387 return async(zth::launch::detached, std::forward<Func>(f), std::forward<Args>(args)...);
388}
389
390template <typename Func, typename... Args>
392async(zth::launch policy, Func&& f, Args&&... args)
393{
394 auto& fib = zth::fiber(f)(std::forward<Args>(args)...);
395 switch(policy) {
397 return {};
399 return fib.withFuture();
400 default:
401 zth_throw(std::invalid_argument("policy"));
402 }
403}
404} // namespace zth
405
406namespace std {
407template <typename Func, typename... Args>
409async(zth::launch policy, Func&& f, Args&&... args)
410{
411 return zth::async(policy, std::forward<Func>(f), std::forward<Args>(args)...);
412}
413} // namespace std
414
415
416#endif // C++11
417#endif // ZTH_FUTURE_H
Fiber-aware future.
Definition sync.h:598
type & value() &
Definition sync.h:717
void wait()
Definition sync.h:648
void block()
Definition sync.h:185
std_future_base(std_future_base &&other) noexcept
Definition future.h:111
std_future_base() noexcept=default
std_future_base & operator=(std_future_base &&other)
Definition future.h:117
std_future_base & operator=(std_future_base const &)=delete
std::shared_future< zth::type< T > > share() const
Definition future.h:126
std_future_base(std_future_base const &)=delete
std_promise_base(SharedPointer< Future_type > future) noexcept
Definition future.h:144
void check_not_satisfied() const
Definition future.h:205
void check_valid() const
Definition future.h:199
std::future< zth::type< T > > get_future()
Definition future.h:168
std_promise_base & operator=(std_promise_base &&other) noexcept
Definition future.h:154
std_promise_base(std_promise_base const &)=delete
void swap(std_promise_base &other) noexcept
Definition future.h:163
void set_exception(std::exception_ptr exception)
Definition future.h:192
std_promise_base(std_promise_base &&other) noexcept
Definition future.h:148
void set_value(U &&value)
Definition future.h:180
std_promise_base & operator=(std_promise_base const &)=delete
zth::SharedPointer< zth::Future< T > > m_future
Definition future.h:96
bool valid() const noexcept
Definition future.h:54
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
Definition future.h:76
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition future.h:67
std_shared_future_base() noexcept=default
fiber_type< F >::factory fiber(F f, char const *name=nullptr)
Create a new fiber.
Definition async.h:754
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition allocator.h:143
#define zth_throw(...)
Definition macros.h:229
STL namespace.
zth::future< zth::impl::invoke_result< Func, Args... > > async(zth::launch policy, Func &&f, Args &&... args)
Definition future.h:409
typename std::invoke_result_t< Func, Args... > invoke_result
Definition future.h:380
zth::future< zth::impl::invoke_result< Func, Args... > > async(Func &&f, Args &&... args)
Definition future.h:385
::std::future< zth::type< T > > future
Definition future.h:34
launch
Definition future.h:372
::std::shared_future< zth::type< T > > shared_future
Definition future.h:37
::std::promise< zth::type< T > > promise
Definition future.h:31