dispenso 1.4.1
A library for task parallelism
Loading...
Searching...
No Matches
future.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
17#pragma once
18
19#include <functional>
20#include <vector>
21
22#include <dispenso/detail/future_impl.h>
23#include <dispenso/detail/result_of.h>
25
26namespace dispenso {
27
28// See https://en.cppreference.com/w/cpp/experimental/future for details on the API.
29
30// TODO(bbudge): Implement when_any(), ?unwrapping constructor? functionality.
31
36constexpr std::launch kNotAsync = static_cast<std::launch>(0);
42constexpr std::launch kNotDeferred = static_cast<std::launch>(0);
43
69template <typename Result>
70class Future : detail::FutureBase<Result> {
71 using Base = detail::FutureBase<Result>;
72
73 public:
77 Future() noexcept : Base() {}
78
84 Future(Future&& f) noexcept : Base(std::move(f)) {}
85 Future(Base&& f) noexcept : Base(std::move(f)) {}
86
93 Future(const Future& f) noexcept : Base(f) {}
94 Future(const Base& f) noexcept : Base(f) {}
95
110 template <typename F, typename Schedulable>
112 F&& f,
113 Schedulable& schedulable,
114 std::launch asyncPolicy = kNotAsync,
115 std::launch deferredPolicy = std::launch::deferred)
116 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
117
123 Future& operator=(Future&& f) noexcept {
124 Base::move(reinterpret_cast<Base&&>(f));
125 return *this;
126 }
133 Base::copy(f);
134 return *this;
135 }
136
141 ~Future() = default;
142
151 bool valid() const noexcept {
152 return Base::valid();
153 }
154
162 bool is_ready() const {
163 return Base::is_ready();
164 }
165
171 void wait() const {
172 Base::wait();
173 }
174
186 template <class Rep, class Period>
187 std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeoutDuration) const {
188 return Base::wait_for(timeoutDuration);
189 }
190
201 template <class Clock, class Duration>
202 std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeoutTime) const {
203 return Base::wait_until(timeoutTime);
204 }
205
211 return std::move(*this);
212 }
213
219 const Result& get() const {
220 wait();
221 return this->impl_->result();
222 }
223
239 template <typename F, typename Schedulable>
241 F&& f,
242 Schedulable& sched,
243 std::launch asyncPolicy = kNotAsync,
244 std::launch deferredPolicy = std::launch::deferred) {
246 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<Result>&&>>(
247 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
248 return retFuture;
249 }
250 template <typename F>
252 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
253 }
254
255 private:
256 template <typename T>
257 Future(T&& t, detail::ReadyTag) {
258 this->impl_ = detail::createValueFutureImplReady<Result>(std::forward<T>(t));
259 }
260
261 template <typename T>
262 friend Future<std::decay_t<T>> make_ready_future(T&& t);
263
264 template <typename R>
265 friend class Future;
266};
267
268template <typename Result>
269class Future<Result&> : detail::FutureBase<Result&> {
270 using Base = detail::FutureBase<Result&>;
271
272 public:
273 Future() noexcept : Base() {}
274 Future(Future&& f) noexcept : Base(std::move(f)) {}
275 Future(Base&& f) noexcept : Base(std::move(f)) {}
276 Future(const Future& f) noexcept : Base(f) {}
277 Future(const Base& f) noexcept : Base(f) {}
278 template <typename F, typename Schedulable>
279 Future(
280 F&& f,
281 Schedulable& schedulable,
282 std::launch asyncPolicy = kNotAsync,
283 std::launch deferredPolicy = std::launch::deferred)
284 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
285 Future& operator=(Future&& f) noexcept {
286 Base::move(reinterpret_cast<Base&&>(f));
287 return *this;
288 }
289 Future& operator=(const Future& f) {
290 Base::copy(f);
291 return *this;
292 }
293 ~Future() = default;
294 using Base::is_ready;
295 using Base::valid;
296 using Base::wait;
297 using Base::wait_for;
298 using Base::wait_until;
299
300 Future share() {
301 return std::move(*this);
302 }
303
309 Result& get() const {
310 wait();
311 return this->impl_->result();
312 }
313
314 template <typename F, typename Schedulable>
316 F&& f,
317 Schedulable& sched,
318 std::launch asyncPolicy = kNotAsync,
319 std::launch deferredPolicy = std::launch::deferred) {
321 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<Result&>&&>>(
322 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
323 return retFuture;
324 }
325 template <typename F>
326 Future<detail::ResultOf<F, Future<Result&>&&>> then(F&& f) {
327 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
328 }
329
330 private:
331 template <typename T>
332 Future(std::reference_wrapper<T> t, detail::ReadyTag) {
333 this->impl_ = detail::createRefFutureImplReady<Result>(t);
334 }
335
336 template <typename X>
337 friend Future<X&> make_ready_future(std::reference_wrapper<X> x);
338
339 template <typename R>
340 friend class Future;
341};
342
343template <>
344class Future<void> : detail::FutureBase<void> {
345 using Base = detail::FutureBase<void>;
346
347 public:
348 Future() noexcept : Base() {}
349 Future(Future&& f) noexcept : Base(std::move(f)) {}
350 Future(Base&& f) noexcept : Base(std::move(f)) {}
351 Future(const Future& f) noexcept : Base(f) {}
352 Future(const Base& f) noexcept : Base(f) {}
353 template <typename F, typename Schedulable>
354 Future(
355 F&& f,
356 Schedulable& schedulable,
357 std::launch asyncPolicy = kNotAsync,
358 std::launch deferredPolicy = std::launch::deferred)
359 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
360 Future& operator=(Future&& f) noexcept {
361 Base::move(reinterpret_cast<Base&&>(f));
362 return *this;
363 }
364 Future& operator=(const Future& f) {
365 Base::copy(f);
366 return *this;
367 }
368 ~Future() = default;
369 using Base::is_ready;
370 using Base::valid;
371 using Base::wait;
372 using Base::wait_for;
373 using Base::wait_until;
374
375 Future share() {
376 return std::move(*this);
377 }
378
382 void get() const {
383 wait();
384 this->impl_->result();
385 }
386
387 template <typename F, typename Schedulable>
389 F&& f,
390 Schedulable& sched,
391 std::launch asyncPolicy = kNotAsync,
392 std::launch deferredPolicy = std::launch::deferred) {
394 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<void>&&>>(
395 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
396 return retFuture;
397 }
398 template <typename F>
399 Future<detail::ResultOf<F, Future<void>&&>> then(F&& f) {
400 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
401 }
402
403 private:
404 Future(detail::ReadyTag) {
405 impl_ = detail::createVoidFutureImplReady();
406 }
407
408 friend Future<void> make_ready_future();
409
410 template <typename R>
411 friend class Future;
412};
413
414// TODO(bbudge): Determine if we should
415// a. Expand launch policies, and logically inherit from std::launch and
416// b. Whether async should truly mean on a new thread.
417// For now we will treat std::launch::async such that we pass ForceQueuingTag
418
429template <class F, class... Args>
430inline Future<detail::ResultOf<F, Args...>> async(std::launch policy, F&& f, Args&&... args) {
431 return Future<detail::ResultOf<F, Args...>>(
432 std::bind(std::forward<F>(f), std::forward<Args>(args)...), globalThreadPool(), policy);
433}
434
441template <class F, class... Args>
442inline Future<detail::ResultOf<F, Args...>> async(F&& f, Args&&... args) {
443 return ::dispenso::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
444}
445
457template <class F, class... Args>
458inline Future<detail::ResultOf<F, Args...>>
459async(ThreadPool& pool, std::launch policy, F&& f, Args&&... args) {
460 return Future<detail::ResultOf<F, Args...>>(
461 std::bind(std::forward<F>(f), std::forward<Args>(args)...), pool, policy);
462}
463
471template <class F, class... Args>
472inline Future<detail::ResultOf<F, Args...>> async(ThreadPool& pool, F&& f, Args&&... args) {
473 return ::dispenso::async(
474 pool, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
475}
476
488template <class F, class... Args>
489inline Future<detail::ResultOf<F, Args...>>
490async(TaskSet& tasks, std::launch policy, F&& f, Args&&... args) {
491 return Future<detail::ResultOf<F, Args...>>(
492 std::bind(std::forward<F>(f), std::forward<Args>(args)...), tasks, policy);
493}
494
502template <class F, class... Args>
503inline Future<detail::ResultOf<F, Args...>> async(TaskSet& tasks, F&& f, Args&&... args) {
504 return ::dispenso::async(
505 tasks, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
506}
507
519template <class F, class... Args>
520inline Future<detail::ResultOf<F, Args...>>
521async(ConcurrentTaskSet& tasks, std::launch policy, F&& f, Args&&... args) {
522 return Future<detail::ResultOf<F, Args...>>(
523 std::bind(std::forward<F>(f), std::forward<Args>(args)...), tasks, policy);
524}
525
533template <class F, class... Args>
534inline Future<detail::ResultOf<F, Args...>> async(ConcurrentTaskSet& tasks, F&& f, Args&&... args) {
535 return ::dispenso::async(
536 tasks, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
537}
538
550template <class F, class... Args>
551inline Future<detail::ResultOf<F, Args...>>
552async(NewThreadInvoker sched, std::launch policy, F&& f, Args&&... args) {
553 return Future<detail::ResultOf<F, Args...>>(
554 std::bind(std::forward<F>(f), std::forward<Args>(args)...), sched, policy);
555}
556
564template <class F, class... Args>
565inline Future<detail::ResultOf<F, Args...>> async(NewThreadInvoker sched, F&& f, Args&&... args) {
566 return ::dispenso::async(
567 sched, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
568}
569
576template <typename T>
578 return Future<std::decay_t<T>>(std::forward<T>(t), detail::ReadyTag());
579}
580
587template <typename X>
588inline Future<X&> make_ready_future(std::reference_wrapper<X> x) {
589 return Future<X&>(x, detail::ReadyTag());
590}
591
597 return Future<void>(detail::ReadyTag());
598}
599
611template <class InputIt>
613 InputIt first,
614 InputIt last);
615
626template <class... Futures>
627auto when_all(Futures&&... futures) -> Future<std::tuple<std::decay_t<Futures>...>>;
628
642template <class InputIt>
644when_all(TaskSet& taskSet, InputIt first, InputIt last);
645template <class InputIt>
647when_all(ConcurrentTaskSet& taskSet, InputIt first, InputIt last);
648
661template <class... Futures>
662auto when_all(TaskSet& taskSet, Futures&&... futures)
664
665template <class... Futures>
666auto when_all(ConcurrentTaskSet& taskSet, Futures&&... futures)
668} // namespace dispenso
669
670#include <dispenso/detail/future_impl2.h>
Result & get() const
Definition future.h:309
bool is_ready() const
Definition future.h:162
~Future()=default
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeoutTime) const
Definition future.h:202
void wait() const
Definition future.h:171
friend Future< std::decay_t< T > > make_ready_future(T &&t)
Definition future.h:577
std::future_status wait_for(const std::chrono::duration< Rep, Period > &timeoutDuration) const
Definition future.h:187
const Result & get() const
Definition future.h:219
Future share()
Definition future.h:210
Future(const Future &f) noexcept
Definition future.h:93
Future< detail::ResultOf< F, Future< Result > && > > then(F &&f, Schedulable &sched, std::launch asyncPolicy=kNotAsync, std::launch deferredPolicy=std::launch::deferred)
Definition future.h:240
Future & operator=(Future &&f) noexcept
Definition future.h:123
Future() noexcept
Definition future.h:77
Future(Future &&f) noexcept
Definition future.h:84
Future & operator=(const Future &f)
Definition future.h:132
bool valid() const noexcept
Definition future.h:151
Future(F &&f, Schedulable &schedulable, std::launch asyncPolicy=kNotAsync, std::launch deferredPolicy=std::launch::deferred)
Definition future.h:111
Future< detail::ResultOf< F, Args... > > async(std::launch policy, F &&f, Args &&... args)
Definition future.h:430
Future< std::decay_t< T > > make_ready_future(T &&t)
Definition future.h:577
Future< std::vector< typename std::iterator_traits< InputIt >::value_type > > when_all(InputIt first, InputIt last)
constexpr std::launch kNotAsync
Definition future.h:36
constexpr std::launch kNotDeferred
Definition future.h:42