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)) {}
86 Future(Base&& f) noexcept : Base(std::move(f)) {}
87
94 Future(const Future& f) noexcept : Base(f) {}
96 Future(const Base& f) noexcept : Base(f) {}
97
112 template <typename F, typename Schedulable>
114 F&& f,
115 Schedulable& schedulable,
116 std::launch asyncPolicy = kNotAsync,
117 std::launch deferredPolicy = std::launch::deferred)
118 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
119
125 Future& operator=(Future&& f) noexcept {
126 Base::move(reinterpret_cast<Base&&>(f));
127 return *this;
128 }
134 Future& operator=(const Future& f) {
135 Base::copy(f);
136 return *this;
137 }
138
143 ~Future() = default;
144
153 bool valid() const noexcept {
154 return Base::valid();
155 }
156
164 bool is_ready() const {
165 return Base::is_ready();
166 }
167
173 void wait() const {
174 Base::wait();
175 }
176
188 template <class Rep, class Period>
189 std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeoutDuration) const {
190 return Base::wait_for(timeoutDuration);
191 }
192
203 template <class Clock, class Duration>
204 std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeoutTime) const {
205 return Base::wait_until(timeoutTime);
206 }
207
212 Future share() {
213 return std::move(*this);
214 }
215
221 const Result& get() const {
222 wait();
223 return this->impl_->result();
224 }
225
241 template <typename F, typename Schedulable>
243 F&& f,
244 Schedulable& sched,
245 std::launch asyncPolicy = kNotAsync,
246 std::launch deferredPolicy = std::launch::deferred) {
248 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<Result>&&>>(
249 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
250 return retFuture;
251 }
252 template <typename F>
253 Future<detail::ResultOf<F, Future<Result>&&>> then(F&& f) {
254 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
255 }
256
257 private:
258 template <typename T>
259 Future(T&& t, detail::ReadyTag) {
260 this->impl_ = detail::createValueFutureImplReady<Result>(std::forward<T>(t));
261 }
262
263 template <typename T>
264 friend Future<std::decay_t<T>> make_ready_future(T&& t);
265
266 template <typename R>
267 friend class Future;
268};
269
273template <typename Result>
274class Future<Result&> : detail::FutureBase<Result&> {
275 using Base = detail::FutureBase<Result&>;
276
277 public:
279 Future() noexcept : Base() {}
281 Future(Future&& f) noexcept : Base(std::move(f)) {}
283 Future(Base&& f) noexcept : Base(std::move(f)) {}
285 Future(const Future& f) noexcept : Base(f) {}
287 Future(const Base& f) noexcept : Base(f) {}
290 template <typename F, typename Schedulable>
292 F&& f,
293 Schedulable& schedulable,
294 std::launch asyncPolicy = kNotAsync,
295 std::launch deferredPolicy = std::launch::deferred)
296 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
297 Future& operator=(Future&& f) noexcept {
298 Base::move(reinterpret_cast<Base&&>(f));
299 return *this;
300 }
301 Future& operator=(const Future& f) {
302 Base::copy(f);
303 return *this;
304 }
305 ~Future() = default;
306 using Base::is_ready;
307 using Base::valid;
308 using Base::wait;
309 using Base::wait_for;
310 using Base::wait_until;
311
312 Future share() {
313 return std::move(*this);
314 }
315
321 Result& get() const {
322 wait();
323 return this->impl_->result();
324 }
325
326 template <typename F, typename Schedulable>
328 F&& f,
329 Schedulable& sched,
330 std::launch asyncPolicy = kNotAsync,
331 std::launch deferredPolicy = std::launch::deferred) {
333 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<Result&>&&>>(
334 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
335 return retFuture;
336 }
337 template <typename F>
338 Future<detail::ResultOf<F, Future<Result&>&&>> then(F&& f) {
339 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
340 }
341
342 private:
343 template <typename T>
344 Future(std::reference_wrapper<T> t, detail::ReadyTag) {
345 this->impl_ = detail::createRefFutureImplReady<Result>(t);
346 }
347
348 template <typename X>
349 friend Future<X&> make_ready_future(std::reference_wrapper<X> x);
350
351 template <typename R>
352 friend class Future;
353};
354
358template <>
359class Future<void> : detail::FutureBase<void> {
360 using Base = detail::FutureBase<void>;
361
362 public:
364 Future() noexcept : Base() {}
366 Future(Future&& f) noexcept : Base(std::move(f)) {}
368 Future(Base&& f) noexcept : Base(std::move(f)) {}
370 Future(const Future& f) noexcept : Base(f) {}
372 Future(const Base& f) noexcept : Base(f) {}
375 template <typename F, typename Schedulable>
376 DISPENSO_REQUIRES(OnceCallableFunc<F>)
378 F&& f,
379 Schedulable& schedulable,
380 std::launch asyncPolicy = kNotAsync,
381 std::launch deferredPolicy = std::launch::deferred)
382 : Base(std::forward<F>(f), schedulable, asyncPolicy, deferredPolicy) {}
383 Future& operator=(Future&& f) noexcept {
384 Base::move(reinterpret_cast<Base&&>(f));
385 return *this;
386 }
387 Future& operator=(const Future& f) {
388 Base::copy(f);
389 return *this;
390 }
391 ~Future() = default;
392 using Base::is_ready;
393 using Base::valid;
394 using Base::wait;
395 using Base::wait_for;
396 using Base::wait_until;
397
398 Future share() {
399 return std::move(*this);
400 }
401
405 void get() const {
406 wait();
407 this->impl_->result();
408 }
409
410 template <typename F, typename Schedulable>
412 F&& f,
413 Schedulable& sched,
414 std::launch asyncPolicy = kNotAsync,
415 std::launch deferredPolicy = std::launch::deferred) {
417 retFuture.impl_ = this->template thenImpl<detail::ResultOf<F, Future<void>&&>>(
418 std::forward<F>(f), sched, asyncPolicy, deferredPolicy);
419 return retFuture;
420 }
421 template <typename F>
422 Future<detail::ResultOf<F, Future<void>&&>> then(F&& f) {
423 return then(std::forward<F>(f), globalThreadPool(), kNotAsync, std::launch::deferred);
424 }
425
426 private:
427 Future(detail::ReadyTag) {
428 impl_ = detail::createVoidFutureImplReady();
429 }
430
431 friend Future<void> make_ready_future();
432
433 template <typename R>
434 friend class Future;
435};
436
437// TODO(bbudge): Determine if we should
438// a. Expand launch policies, and logically inherit from std::launch and
439// b. Whether async should truly mean on a new thread.
440// For now we will treat std::launch::async such that we pass ForceQueuingTag
441
452template <class F, class... Args>
453inline Future<detail::ResultOf<F, Args...>> async(std::launch policy, F&& f, Args&&... args) {
454 return Future<detail::ResultOf<F, Args...>>(
455 std::bind(std::forward<F>(f), std::forward<Args>(args)...), globalThreadPool(), policy);
456}
457
464template <class F, class... Args>
465inline Future<detail::ResultOf<F, Args...>> async(F&& f, Args&&... args) {
466 return ::dispenso::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
467}
468
480template <class F, class... Args>
481inline Future<detail::ResultOf<F, Args...>>
482async(ThreadPool& pool, std::launch policy, F&& f, Args&&... args) {
483 return Future<detail::ResultOf<F, Args...>>(
484 std::bind(std::forward<F>(f), std::forward<Args>(args)...), pool, policy);
485}
486
494template <class F, class... Args>
495inline Future<detail::ResultOf<F, Args...>> async(ThreadPool& pool, F&& f, Args&&... args) {
496 return ::dispenso::async(
497 pool, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
498}
499
511template <class F, class... Args>
512inline Future<detail::ResultOf<F, Args...>>
513async(TaskSet& tasks, std::launch policy, F&& f, Args&&... args) {
514 return Future<detail::ResultOf<F, Args...>>(
515 std::bind(std::forward<F>(f), std::forward<Args>(args)...), tasks, policy);
516}
517
525template <class F, class... Args>
526inline Future<detail::ResultOf<F, Args...>> async(TaskSet& tasks, F&& f, Args&&... args) {
527 return ::dispenso::async(
528 tasks, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
529}
530
542template <class F, class... Args>
543inline Future<detail::ResultOf<F, Args...>>
544async(ConcurrentTaskSet& tasks, std::launch policy, F&& f, Args&&... args) {
545 return Future<detail::ResultOf<F, Args...>>(
546 std::bind(std::forward<F>(f), std::forward<Args>(args)...), tasks, policy);
547}
548
556template <class F, class... Args>
557inline Future<detail::ResultOf<F, Args...>> async(ConcurrentTaskSet& tasks, F&& f, Args&&... args) {
558 return ::dispenso::async(
559 tasks, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
560}
561
573template <class F, class... Args>
574inline Future<detail::ResultOf<F, Args...>>
575async(NewThreadInvoker sched, std::launch policy, F&& f, Args&&... args) {
576 return Future<detail::ResultOf<F, Args...>>(
577 std::bind(std::forward<F>(f), std::forward<Args>(args)...), sched, policy);
578}
579
587template <class F, class... Args>
588inline Future<detail::ResultOf<F, Args...>> async(NewThreadInvoker sched, F&& f, Args&&... args) {
589 return ::dispenso::async(
590 sched, std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
591}
592
599template <typename T>
601 return Future<std::decay_t<T>>(std::forward<T>(t), detail::ReadyTag());
602}
603
610template <typename X>
611inline Future<X&> make_ready_future(std::reference_wrapper<X> x) {
612 return Future<X&>(x, detail::ReadyTag());
613}
614
620 return Future<void>(detail::ReadyTag());
621}
622
634template <class InputIt>
636 InputIt first,
637 InputIt last);
638
649template <class... Futures>
650auto when_all(Futures&&... futures) -> Future<std::tuple<std::decay_t<Futures>...>>;
651
665template <class InputIt>
667when_all(TaskSet& taskSet, InputIt first, InputIt last);
669template <class InputIt>
671when_all(ConcurrentTaskSet& taskSet, InputIt first, InputIt last);
672
685template <class... Futures>
686auto when_all(TaskSet& taskSet, Futures&&... futures)
688
690template <class... Futures>
691auto when_all(ConcurrentTaskSet& taskSet, Futures&&... futures)
693} // namespace dispenso
694
695#include <dispenso/detail/future_impl2.h>
Future(const Base &f) noexcept
Definition future.h:287
Future(Base &&f) noexcept
Definition future.h:283
Result & get() const
Definition future.h:321
Future(const Future &f) noexcept
Definition future.h:285
Future(Future &&f) noexcept
Definition future.h:281
Future(F &&f, Schedulable &schedulable, std::launch asyncPolicy=kNotAsync, std::launch deferredPolicy=std::launch::deferred)
Definition future.h:291
Future(const Base &f) noexcept
Definition future.h:372
Future(const Future &f) noexcept
Definition future.h:370
Future(Future &&f) noexcept
Definition future.h:366
Future(Base &&f) noexcept
Definition future.h:368
bool is_ready() const
Definition future.h:164
~Future()=default
Future(Base &&f) noexcept
Definition future.h:86
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeoutTime) const
Definition future.h:204
void wait() const
Definition future.h:173
friend Future< std::decay_t< T > > make_ready_future(T &&t)
Definition future.h:600
std::future_status wait_for(const std::chrono::duration< Rep, Period > &timeoutDuration) const
Definition future.h:189
const Result & get() const
Definition future.h:221
Future(const Future &f) noexcept
Definition future.h:94
Future(const Base &f) noexcept
Definition future.h:96
Future() noexcept
Definition future.h:77
Future(Future &&f) noexcept
Definition future.h:84
bool valid() const noexcept
Definition future.h:153
Future(F &&f, Schedulable &schedulable, std::launch asyncPolicy=kNotAsync, std::launch deferredPolicy=std::launch::deferred)
Definition future.h:113
Future< detail::ResultOf< F, Args... > > async(std::launch policy, F &&f, Args &&... args)
Definition future.h:453
Future< std::decay_t< T > > make_ready_future(T &&t)
Definition future.h:600
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
DISPENSO_DLL_ACCESS ThreadPool & globalThreadPool()