WPILibC++  2019.3.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
future.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #ifndef WPIUTIL_WPI_FUTURE_H_
9 #define WPIUTIL_WPI_FUTURE_H_
10 
11 #include <stdint.h>
12 
13 #include <algorithm>
14 #include <atomic>
15 #include <chrono>
16 #include <functional>
17 #include <type_traits>
18 #include <utility>
19 #include <vector>
20 
21 #include "wpi/condition_variable.h"
22 #include "wpi/mutex.h"
23 
24 namespace wpi {
25 
26 template <typename T>
28 
29 template <typename T>
30 class future;
31 
32 template <typename T>
33 class promise;
34 template <>
35 class promise<void>;
36 
37 namespace detail {
38 
40  public:
42 
43  bool IsActive() const { return m_active; }
44 
45  wpi::mutex& GetResultMutex() { return m_resultMutex; }
46 
47  void Notify() { m_resultCv.notify_all(); }
48 
49  // must be called with locked lock == ResultMutex
50  void Wait(std::unique_lock<wpi::mutex>& lock) { m_resultCv.wait(lock); }
51 
52  // returns false if timeout reached
53  template <class Clock, class Duration>
54  bool WaitUntil(std::unique_lock<wpi::mutex>& lock,
55  const std::chrono::time_point<Clock, Duration>& timeout_time) {
56  return m_resultCv.wait_until(lock, timeout_time) ==
57  std::cv_status::no_timeout;
58  }
59 
60  void IgnoreResult(uint64_t request);
61 
62  uint64_t CreateRequest();
63 
64  // returns true if request was pending
65  // must be called with ResultMutex held
66  bool EraseRequest(uint64_t request);
67 
68  // same as doing CreateRequest() followed by EraseRequest()
69  // must be called with ResultMutex held
70  uint64_t CreateErasedRequest() { return ++m_uid; }
71 
72  private:
73  wpi::mutex m_resultMutex;
74  std::atomic_bool m_active{true};
75  wpi::condition_variable m_resultCv;
76 
77  uint64_t m_uid = 0;
78  std::vector<uint64_t> m_requests;
79 };
80 
81 template <typename To, typename From>
82 struct FutureThen {
83  template <typename F>
84  static future<To> Create(PromiseFactory<From>& fromFactory, uint64_t request,
85  PromiseFactory<To>& factory, F&& func);
86 };
87 
88 template <typename From>
89 struct FutureThen<void, From> {
90  template <typename F>
91  static future<void> Create(PromiseFactory<From>& fromFactory,
92  uint64_t request, PromiseFactory<void>& factory,
93  F&& func);
94 };
95 
96 template <typename To>
97 struct FutureThen<To, void> {
98  template <typename F>
99  static future<To> Create(PromiseFactory<void>& fromFactory, uint64_t request,
100  PromiseFactory<To>& factory, F&& func);
101 };
102 
103 template <>
104 struct FutureThen<void, void> {
105  template <typename F>
106  static future<void> Create(PromiseFactory<void>& fromFactory,
107  uint64_t request, PromiseFactory<void>& factory,
108  F&& func);
109 };
110 
111 } // namespace detail
112 
125 template <typename T>
126 class PromiseFactory final : public detail::PromiseFactoryBase {
127  friend class future<T>;
128 
129  public:
130  using detail::PromiseFactoryBase::Notify;
131  using ThenFunction = std::function<void(uint64_t, T)>;
132 
139  future<T> CreateFuture(uint64_t request);
140 
146  future<T> MakeReadyFuture(T&& value);
147 
154  promise<T> CreatePromise(uint64_t request);
155 
163  void SetValue(uint64_t request, const T& value);
164 
172  void SetValue(uint64_t request, T&& value);
173 
174  void SetThen(uint64_t request, uint64_t outRequest, ThenFunction func);
175 
176  bool IsReady(uint64_t request) noexcept;
177  T GetResult(uint64_t request);
178  void WaitResult(uint64_t request);
179  template <class Clock, class Duration>
180  bool WaitResultUntil(
181  uint64_t request,
182  const std::chrono::time_point<Clock, Duration>& timeout_time);
183 
184  static PromiseFactory& GetInstance();
185 
186  private:
187  struct Then {
188  Then(uint64_t request_, uint64_t outRequest_, ThenFunction func_)
189  : request(request_), outRequest(outRequest_), func(std::move(func_)) {}
190  uint64_t request;
191  uint64_t outRequest;
192  ThenFunction func;
193  };
194 
195  std::vector<Then> m_thens;
196  std::vector<std::pair<uint64_t, T>> m_results;
197 };
198 
202 template <>
203 class PromiseFactory<void> final : public detail::PromiseFactoryBase {
204  friend class future<void>;
205 
206  public:
207  using detail::PromiseFactoryBase::Notify;
208  using ThenFunction = std::function<void(uint64_t)>;
209 
216  future<void> CreateFuture(uint64_t request);
217 
224 
231  promise<void> CreatePromise(uint64_t request);
232 
239  void SetValue(uint64_t request);
240 
241  void SetThen(uint64_t request, uint64_t outRequest, ThenFunction func);
242 
243  bool IsReady(uint64_t request) noexcept;
244  void GetResult(uint64_t request);
245  void WaitResult(uint64_t request);
246  template <class Clock, class Duration>
247  bool WaitResultUntil(
248  uint64_t request,
249  const std::chrono::time_point<Clock, Duration>& timeout_time);
250 
251  static PromiseFactory& GetInstance();
252 
253  private:
254  struct Then {
255  Then(uint64_t request_, uint64_t outRequest_, ThenFunction func_)
256  : request(request_), outRequest(outRequest_), func(std::move(func_)) {}
257  uint64_t request;
258  uint64_t outRequest;
259  ThenFunction func;
260  };
261 
262  std::vector<Then> m_thens;
263  std::vector<uint64_t> m_results;
264 };
265 
273 template <typename T>
274 class future final {
275  friend class PromiseFactory<T>;
276  friend class promise<T>;
277 
278  public:
282  future() noexcept = default;
283 
284  future(future&& oth) noexcept {
285  this->m_request = oth.m_request;
286  this->m_promises = oth.m_promises;
287  oth.m_request = 0;
288  oth.m_promises = nullptr;
289  }
290  future(const future&) = delete;
291 
292  template <typename R>
293  future(future<R>&& oth) noexcept
294  : future(oth.then([](R&& val) -> T { return val; })) {}
295 
300  if (m_promises) m_promises->IgnoreResult(m_request);
301  }
302 
303  future& operator=(future&& oth) noexcept {
304  this->m_request = oth.m_request;
305  this->m_promises = oth.m_promises;
306  oth.m_request = 0;
307  oth.m_promises = nullptr;
308  return *this;
309  }
310  future& operator=(const future&) = delete;
311 
318  T get() {
319  if (m_promises)
320  return m_promises->GetResult(m_request);
321  else
322  return T();
323  }
324 
325  template <typename R, typename F>
326  future<R> then(PromiseFactory<R>& factory, F&& func) {
327  if (m_promises) {
328  auto promises = m_promises;
329  m_promises = nullptr;
330  return detail::FutureThen<R, T>::Create(*promises, m_request, factory,
331  func);
332  } else {
333  return future<R>();
334  }
335  }
336 
337  template <typename F, typename R = typename std::result_of<F && (T &&)>::type>
338  future<R> then(F&& func) {
339  return then(PromiseFactory<R>::GetInstance(), std::forward<F>(func));
340  }
341 
342  bool is_ready() const noexcept {
343  return m_promises && m_promises->IsReady(m_request);
344  }
345 
352  bool valid() const noexcept { return m_promises; }
353 
360  void wait() const {
361  if (m_promises) m_promises->WaitResult(m_request);
362  }
363 
370  template <class Clock, class Duration>
372  const std::chrono::time_point<Clock, Duration>& timeout_time) const {
373  return m_promises && m_promises->WaitResultUntil(m_request, timeout_time);
374  }
375 
382  template <class Rep, class Period>
383  bool wait_for(
384  const std::chrono::duration<Rep, Period>& timeout_duration) const {
385  return wait_until(std::chrono::steady_clock::now() + timeout_duration);
386  }
387 
388  private:
389  future(PromiseFactory<T>* promises, uint64_t request) noexcept
390  : m_request(request), m_promises(promises) {}
391 
392  uint64_t m_request = 0;
393  PromiseFactory<T>* m_promises = nullptr;
394 };
395 
399 template <>
400 class future<void> final {
401  friend class PromiseFactory<void>;
402  friend class promise<void>;
403 
404  public:
408  future() noexcept = default;
409 
410  future(future&& oth) noexcept {
411  m_request = oth.m_request;
412  m_promises = oth.m_promises;
413  oth.m_request = 0;
414  oth.m_promises = nullptr;
415  }
416  future(const future&) = delete;
417 
422  if (m_promises) m_promises->IgnoreResult(m_request);
423  }
424 
425  future& operator=(future&& oth) noexcept {
426  m_request = oth.m_request;
427  m_promises = oth.m_promises;
428  oth.m_request = 0;
429  oth.m_promises = nullptr;
430  return *this;
431  }
432  future& operator=(const future&) = delete;
433 
438  void get() {
439  if (m_promises) m_promises->GetResult(m_request);
440  }
441 
442  template <typename R, typename F>
443  future<R> then(PromiseFactory<R>& factory, F&& func) {
444  if (m_promises) {
445  auto promises = m_promises;
446  m_promises = nullptr;
447  return detail::FutureThen<R, void>::Create(*promises, m_request, factory,
448  func);
449  } else {
450  return future<R>();
451  }
452  }
453 
454  template <typename F, typename R = typename std::result_of<F && ()>::type>
455  future<R> then(F&& func) {
456  return then(PromiseFactory<R>::GetInstance(), std::forward<F>(func));
457  }
458 
459  bool is_ready() const noexcept {
460  return m_promises && m_promises->IsReady(m_request);
461  }
462 
469  bool valid() const noexcept { return m_promises; }
470 
476  void wait() const {
477  if (m_promises) m_promises->WaitResult(m_request);
478  }
479 
486  template <class Clock, class Duration>
488  const std::chrono::time_point<Clock, Duration>& timeout_time) const {
489  return m_promises && m_promises->WaitResultUntil(m_request, timeout_time);
490  }
491 
498  template <class Rep, class Period>
499  bool wait_for(
500  const std::chrono::duration<Rep, Period>& timeout_duration) const {
501  return wait_until(std::chrono::steady_clock::now() + timeout_duration);
502  }
503 
504  private:
505  future(PromiseFactory<void>* promises, uint64_t request) noexcept
506  : m_request(request), m_promises(promises) {}
507 
508  uint64_t m_request = 0;
509  PromiseFactory<void>* m_promises = nullptr;
510 };
511 
519 template <typename T>
520 class promise final {
521  friend class PromiseFactory<T>;
522 
523  public:
527  promise() : m_promises(&PromiseFactory<T>::GetInstance()) {
528  m_request = m_promises->CreateRequest();
529  }
530 
531  promise(promise&& oth) noexcept
532  : m_request(oth.m_request), m_promises(oth.m_promises) {
533  oth.m_request = 0;
534  oth.m_promises = nullptr;
535  }
536 
537  promise(const promise&) = delete;
538 
543  if (m_promises) m_promises->SetValue(m_request, T());
544  }
545 
546  promise& operator=(promise&& oth) noexcept {
547  m_request = oth.m_request;
548  m_promises = oth.m_promises;
549  oth.m_request = 0;
550  oth.m_promises = nullptr;
551  return *this;
552  }
553 
554  promise& operator=(const promise&) = delete;
555 
559  void swap(promise& oth) noexcept {
560  std::swap(m_request, oth.m_request);
561  std::swap(m_promises, oth.m_promises);
562  }
563 
569  future<T> get_future() noexcept { return future<T>(m_promises, m_request); }
570 
577  void set_value(const T& value) {
578  if (m_promises) m_promises->SetValue(m_request, value);
579  m_promises = nullptr;
580  }
581 
588  void set_value(T&& value) {
589  if (m_promises) m_promises->SetValue(m_request, std::move(value));
590  m_promises = nullptr;
591  }
592 
593  private:
594  promise(PromiseFactory<T>* promises, uint64_t request) noexcept
595  : m_request(request), m_promises(promises) {}
596 
597  uint64_t m_request = 0;
598  PromiseFactory<T>* m_promises = nullptr;
599 };
600 
604 template <>
605 class promise<void> final {
606  friend class PromiseFactory<void>;
607 
608  public:
612  promise() : m_promises(&PromiseFactory<void>::GetInstance()) {
613  m_request = m_promises->CreateRequest();
614  }
615 
616  promise(promise&& oth) noexcept
617  : m_request(oth.m_request), m_promises(oth.m_promises) {
618  oth.m_request = 0;
619  oth.m_promises = nullptr;
620  }
621 
622  promise(const promise&) = delete;
623 
628  if (m_promises) m_promises->SetValue(m_request);
629  }
630 
631  promise& operator=(promise&& oth) noexcept {
632  m_request = oth.m_request;
633  m_promises = oth.m_promises;
634  oth.m_request = 0;
635  oth.m_promises = nullptr;
636  return *this;
637  }
638 
639  promise& operator=(const promise&) = delete;
640 
644  void swap(promise& oth) noexcept {
645  std::swap(m_request, oth.m_request);
646  std::swap(m_promises, oth.m_promises);
647  }
648 
655  return future<void>(m_promises, m_request);
656  }
657 
662  void set_value() {
663  if (m_promises) m_promises->SetValue(m_request);
664  m_promises = nullptr;
665  }
666 
667  private:
668  promise(PromiseFactory<void>* promises, uint64_t request) noexcept
669  : m_request(request), m_promises(promises) {}
670 
671  uint64_t m_request = 0;
672  PromiseFactory<void>* m_promises = nullptr;
673 };
674 
678 template <typename T>
679 inline future<T> make_ready_future(T&& value) {
681  std::forward<T>(value));
682 }
683 
689 }
690 
691 template <typename T>
692 inline future<T> PromiseFactory<T>::CreateFuture(uint64_t request) {
693  return future<T>{this, request};
694 }
695 
696 template <typename T>
698  std::unique_lock<wpi::mutex> lock(GetResultMutex());
699  uint64_t req = CreateErasedRequest();
700  m_results.emplace_back(std::piecewise_construct, std::forward_as_tuple(req),
701  std::forward_as_tuple(std::move(value)));
702  return future<T>{this, req};
703 }
704 
705 template <typename T>
707  return promise<T>{this, request};
708 }
709 
710 template <typename T>
711 void PromiseFactory<T>::SetValue(uint64_t request, const T& value) {
712  std::unique_lock<wpi::mutex> lock(GetResultMutex());
713  if (!EraseRequest(request)) return;
714  auto it = std::find_if(m_thens.begin(), m_thens.end(),
715  [=](const auto& x) { return x.request == request; });
716  if (it != m_thens.end()) {
717  uint64_t outRequest = it->outRequest;
718  ThenFunction func = std::move(it->func);
719  m_thens.erase(it);
720  lock.unlock();
721  return func(outRequest, value);
722  }
723  m_results.emplace_back(std::piecewise_construct,
724  std::forward_as_tuple(request),
725  std::forward_as_tuple(value));
726  Notify();
727 }
728 
729 template <typename T>
730 void PromiseFactory<T>::SetValue(uint64_t request, T&& value) {
731  std::unique_lock<wpi::mutex> lock(GetResultMutex());
732  if (!EraseRequest(request)) return;
733  auto it = std::find_if(m_thens.begin(), m_thens.end(),
734  [=](const auto& x) { return x.request == request; });
735  if (it != m_thens.end()) {
736  uint64_t outRequest = it->outRequest;
737  ThenFunction func = std::move(it->func);
738  m_thens.erase(it);
739  lock.unlock();
740  return func(outRequest, std::move(value));
741  }
742  m_results.emplace_back(std::piecewise_construct,
743  std::forward_as_tuple(request),
744  std::forward_as_tuple(std::move(value)));
745  Notify();
746 }
747 
748 template <typename T>
749 void PromiseFactory<T>::SetThen(uint64_t request, uint64_t outRequest,
750  ThenFunction func) {
751  std::unique_lock<wpi::mutex> lock(GetResultMutex());
752  auto it = std::find_if(m_results.begin(), m_results.end(),
753  [=](const auto& r) { return r.first == request; });
754  if (it != m_results.end()) {
755  auto val = std::move(it->second);
756  m_results.erase(it);
757  lock.unlock();
758  return func(outRequest, std::move(val));
759  }
760  m_thens.emplace_back(request, outRequest, func);
761 }
762 
763 template <typename T>
764 bool PromiseFactory<T>::IsReady(uint64_t request) noexcept {
765  std::unique_lock<wpi::mutex> lock(GetResultMutex());
766  auto it = std::find_if(m_results.begin(), m_results.end(),
767  [=](const auto& r) { return r.first == request; });
768  return it != m_results.end();
769 }
770 
771 template <typename T>
772 T PromiseFactory<T>::GetResult(uint64_t request) {
773  // wait for response
774  std::unique_lock<wpi::mutex> lock(GetResultMutex());
775  while (IsActive()) {
776  // Did we get a response to *our* request?
777  auto it = std::find_if(m_results.begin(), m_results.end(),
778  [=](const auto& r) { return r.first == request; });
779  if (it != m_results.end()) {
780  // Yes, remove it from the vector and we're done.
781  auto rv = std::move(it->second);
782  m_results.erase(it);
783  return rv;
784  }
785  // No, keep waiting for a response
786  Wait(lock);
787  }
788  return T();
789 }
790 
791 template <typename T>
792 void PromiseFactory<T>::WaitResult(uint64_t request) {
793  // wait for response
794  std::unique_lock<wpi::mutex> lock(GetResultMutex());
795  while (IsActive()) {
796  // Did we get a response to *our* request?
797  auto it = std::find_if(m_results.begin(), m_results.end(),
798  [=](const auto& r) { return r.first == request; });
799  if (it != m_results.end()) return;
800  // No, keep waiting for a response
801  Wait(lock);
802  }
803 }
804 
805 template <typename T>
806 template <class Clock, class Duration>
807 bool PromiseFactory<T>::WaitResultUntil(
808  uint64_t request,
809  const std::chrono::time_point<Clock, Duration>& timeout_time) {
810  std::unique_lock<wpi::mutex> lock(GetResultMutex());
811  bool timeout = false;
812  while (IsActive()) {
813  // Did we get a response to *our* request?
814  auto it = std::find_if(m_results.begin(), m_results.end(),
815  [=](const auto& r) { return r.first == request; });
816  if (it != m_results.end()) return true;
817  if (timeout) break;
818  // No, keep waiting for a response
819  if (!WaitUntil(lock, timeout_time)) timeout = true;
820  }
821  return false;
822 }
823 
824 template <typename T>
825 PromiseFactory<T>& PromiseFactory<T>::GetInstance() {
826  static PromiseFactory inst;
827  return inst;
828 }
829 
831  return future<void>{this, request};
832 }
833 
835  return promise<void>{this, request};
836 }
837 
838 template <class Clock, class Duration>
840  uint64_t request,
841  const std::chrono::time_point<Clock, Duration>& timeout_time) {
842  std::unique_lock<wpi::mutex> lock(GetResultMutex());
843  bool timeout = false;
844  while (IsActive()) {
845  // Did we get a response to *our* request?
846  auto it = std::find_if(m_results.begin(), m_results.end(),
847  [=](const auto& r) { return r == request; });
848  if (it != m_results.end()) return true;
849  if (timeout) break;
850  // No, keep waiting for a response
851  if (!WaitUntil(lock, timeout_time)) timeout = true;
852  }
853  return false;
854 }
855 
856 template <typename To, typename From>
857 template <typename F>
858 future<To> detail::FutureThen<To, From>::Create(
859  PromiseFactory<From>& fromFactory, uint64_t request,
860  PromiseFactory<To>& factory, F&& func) {
861  uint64_t req = factory.CreateRequest();
862  fromFactory.SetThen(request, req, [&factory, func](uint64_t r, From value) {
863  factory.SetValue(r, func(std::move(value)));
864  });
865  return factory.CreateFuture(req);
866 }
867 
868 template <typename From>
869 template <typename F>
870 future<void> detail::FutureThen<void, From>::Create(
871  PromiseFactory<From>& fromFactory, uint64_t request,
872  PromiseFactory<void>& factory, F&& func) {
873  uint64_t req = factory.CreateRequest();
874  fromFactory.SetThen(request, req, [&factory, func](uint64_t r, From value) {
875  func(std::move(value));
876  factory.SetValue(r);
877  });
878  return factory.CreateFuture(req);
879 }
880 
881 template <typename To>
882 template <typename F>
883 future<To> detail::FutureThen<To, void>::Create(
884  PromiseFactory<void>& fromFactory, uint64_t request,
885  PromiseFactory<To>& factory, F&& func) {
886  uint64_t req = factory.CreateRequest();
887  fromFactory.SetThen(request, req, [&factory, func](uint64_t r) {
888  factory.SetValue(r, func());
889  });
890  return factory.CreateFuture(req);
891 }
892 
893 template <typename F>
894 future<void> detail::FutureThen<void, void>::Create(
895  PromiseFactory<void>& fromFactory, uint64_t request,
896  PromiseFactory<void>& factory, F&& func) {
897  uint64_t req = factory.CreateRequest();
898  fromFactory.SetThen(request, req, [&factory, func](uint64_t r) {
899  func();
900  factory.SetValue(r);
901  });
902  return factory.CreateFuture(req);
903 }
904 
905 } // namespace wpi
906 
907 #endif // WPIUTIL_WPI_FUTURE_H_
Definition: future.h:39
void wait() const
Waits for the promise to provide a value.
Definition: future.h:360
future() noexcept=default
Constructs an empty (invalid) future.
future< T > get_future() noexcept
Gets a future for this promise.
Definition: future.h:569
promise()
Constructs an empty promise.
Definition: future.h:527
~promise()
Sets the promised value to a default-constructed T if not already set.
Definition: future.h:542
Explicit specialization for PromiseFactory.
Definition: future.h:203
bool valid() const noexcept
Checks if the future is valid.
Definition: future.h:352
Definition: optional.h:885
bool wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
Waits for the promise to provide a value, or the specified time has been reached. ...
Definition: future.h:371
Explicit specialization for future.
Definition: future.h:400
promise()
Constructs an empty promise.
Definition: future.h:612
WPILib C++ utilities (wpiutil) namespace.
Definition: SmallString.h:21
bool wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
Waits for the promise to provide a value, or the specified time has been reached. ...
Definition: future.h:487
~promise()
Sets the promised value if not already set.
Definition: future.h:627
void swap(promise &oth) noexcept
Swaps this promise with another one.
Definition: future.h:559
Explicit specialization for promise.
Definition: future.h:605
bool wait_for(const std::chrono::duration< Rep, Period > &timeout_duration) const
Waits for the promise to provide a value, or the specified amount of time has elapsed.
Definition: future.h:383
future< void > get_future() noexcept
Gets a future for this promise.
Definition: future.h:654
A lightweight version of std::promise.
Definition: future.h:33
void SetValue(uint64_t request, const T &value)
Sets a value directly for a future without creating a promise object.
Definition: future.h:711
void Wait(double seconds)
Pause the task for a specified time.
future< T > MakeReadyFuture(T &&value)
Creates a future and makes it immediately ready.
Definition: future.h:697
void set_value(T &&value)
Sets the promised value.
Definition: future.h:588
void swap(promise &oth) noexcept
Swaps this promise with another one.
Definition: future.h:644
bool valid() const noexcept
Checks if the future is valid.
Definition: future.h:469
Definition: future.h:82
void set_value()
Sets the promised value.
Definition: future.h:662
void set_value(const T &value)
Sets the promised value.
Definition: future.h:577
promise< T > CreatePromise(uint64_t request)
Creates a promise.
Definition: future.h:706
future< T > make_ready_future(T &&value)
Constructs a valid future with the value set.
Definition: future.h:679
void wait() const
Waits for the promise to provide a value.
Definition: future.h:476
A lightweight version of std::future.
Definition: future.h:30
~future()
Ignores the result of the future if it has not been retrieved.
Definition: future.h:421
~future()
Ignores the result of the future if it has not been retrieved.
Definition: future.h:299
future< T > CreateFuture(uint64_t request)
Creates a future.
Definition: future.h:692
A promise factory for lightweight futures.
Definition: future.h:27
bool wait_for(const std::chrono::duration< Rep, Period > &timeout_duration) const
Waits for the promise to provide a value, or the specified amount of time has elapsed.
Definition: future.h:499