8 #ifndef WPIUTIL_WPI_FUTURE_H_
9 #define WPIUTIL_WPI_FUTURE_H_
17 #include <type_traits>
21 #include "wpi/condition_variable.h"
22 #include "wpi/mutex.h"
43 bool IsActive()
const {
return m_active; }
45 wpi::mutex& GetResultMutex() {
return m_resultMutex; }
47 void Notify() { m_resultCv.notify_all(); }
50 void Wait(std::unique_lock<wpi::mutex>& lock) { m_resultCv.wait(lock); }
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;
60 void IgnoreResult(uint64_t request);
62 uint64_t CreateRequest();
66 bool EraseRequest(uint64_t request);
70 uint64_t CreateErasedRequest() {
return ++m_uid; }
73 wpi::mutex m_resultMutex;
74 std::atomic_bool m_active{
true};
75 wpi::condition_variable m_resultCv;
78 std::vector<uint64_t> m_requests;
81 template <
typename To,
typename From>
88 template <
typename From>
96 template <
typename To>
105 template <
typename F>
125 template <
typename T>
130 using detail::PromiseFactoryBase::Notify;
131 using ThenFunction = std::function<void(uint64_t, T)>;
163 void SetValue(uint64_t request,
const T& value);
172 void SetValue(uint64_t request, T&& value);
174 void SetThen(uint64_t request, uint64_t outRequest, ThenFunction func);
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(
182 const std::chrono::time_point<Clock, Duration>& timeout_time);
188 Then(uint64_t request_, uint64_t outRequest_, ThenFunction func_)
189 : request(request_), outRequest(outRequest_), func(
std::move(func_)) {}
195 std::vector<Then> m_thens;
196 std::vector<std::pair<uint64_t, T>> m_results;
204 friend class future<void>;
207 using detail::PromiseFactoryBase::Notify;
208 using ThenFunction = std::function<void(uint64_t)>;
241 void SetThen(uint64_t request, uint64_t outRequest, ThenFunction func);
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(
249 const std::chrono::time_point<Clock, Duration>& timeout_time);
255 Then(uint64_t request_, uint64_t outRequest_, ThenFunction func_)
256 : request(request_), outRequest(outRequest_), func(std::move(func_)) {}
262 std::vector<Then> m_thens;
263 std::vector<uint64_t> m_results;
273 template <
typename T>
282 future() noexcept = default;
285 this->m_request = oth.m_request;
286 this->m_promises = oth.m_promises;
288 oth.m_promises =
nullptr;
292 template <
typename R>
293 future(future<R>&& oth) noexcept
294 :
future(oth.then([](R&& val) -> T {
return val; })) {}
300 if (m_promises) m_promises->IgnoreResult(m_request);
304 this->m_request = oth.m_request;
305 this->m_promises = oth.m_promises;
307 oth.m_promises =
nullptr;
320 return m_promises->GetResult(m_request);
325 template <
typename R,
typename F>
328 auto promises = m_promises;
329 m_promises =
nullptr;
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));
342 bool is_ready() const noexcept {
343 return m_promises && m_promises->IsReady(m_request);
352 bool valid() const noexcept {
return m_promises; }
361 if (m_promises) m_promises->WaitResult(m_request);
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);
382 template <
class Rep,
class Period>
384 const std::chrono::duration<Rep, Period>& timeout_duration)
const {
385 return wait_until(std::chrono::steady_clock::now() + timeout_duration);
390 : m_request(request), m_promises(promises) {}
392 uint64_t m_request = 0;
393 PromiseFactory<T>* m_promises =
nullptr;
408 future() noexcept =
default;
411 m_request = oth.m_request;
412 m_promises = oth.m_promises;
414 oth.m_promises =
nullptr;
422 if (m_promises) m_promises->IgnoreResult(m_request);
426 m_request = oth.m_request;
427 m_promises = oth.m_promises;
429 oth.m_promises =
nullptr;
439 if (m_promises) m_promises->GetResult(m_request);
442 template <
typename R,
typename F>
445 auto promises = m_promises;
446 m_promises =
nullptr;
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));
459 bool is_ready() const noexcept {
460 return m_promises && m_promises->IsReady(m_request);
469 bool valid() const noexcept {
return m_promises; }
477 if (m_promises) m_promises->WaitResult(m_request);
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);
498 template <
class Rep,
class Period>
500 const std::chrono::duration<Rep, Period>& timeout_duration)
const {
501 return wait_until(std::chrono::steady_clock::now() + timeout_duration);
506 : m_request(request), m_promises(promises) {}
508 uint64_t m_request = 0;
509 PromiseFactory<void>* m_promises =
nullptr;
519 template <
typename T>
520 class promise final {
521 friend class PromiseFactory<T>;
528 m_request = m_promises->CreateRequest();
532 : m_request(oth.m_request), m_promises(oth.m_promises) {
534 oth.m_promises =
nullptr;
543 if (m_promises) m_promises->SetValue(m_request, T());
547 m_request = oth.m_request;
548 m_promises = oth.m_promises;
550 oth.m_promises =
nullptr;
560 std::swap(m_request, oth.m_request);
561 std::swap(m_promises, oth.m_promises);
578 if (m_promises) m_promises->SetValue(m_request, value);
579 m_promises =
nullptr;
589 if (m_promises) m_promises->SetValue(m_request, std::move(value));
590 m_promises =
nullptr;
595 : m_request(request), m_promises(promises) {}
597 uint64_t m_request = 0;
598 PromiseFactory<T>* m_promises =
nullptr;
613 m_request = m_promises->CreateRequest();
617 : m_request(oth.m_request), m_promises(oth.m_promises) {
619 oth.m_promises =
nullptr;
628 if (m_promises) m_promises->SetValue(m_request);
632 m_request = oth.m_request;
633 m_promises = oth.m_promises;
635 oth.m_promises =
nullptr;
645 std::swap(m_request, oth.m_request);
646 std::swap(m_promises, oth.m_promises);
663 if (m_promises) m_promises->SetValue(m_request);
664 m_promises =
nullptr;
669 : m_request(request), m_promises(promises) {}
671 uint64_t m_request = 0;
672 PromiseFactory<void>* m_promises =
nullptr;
678 template <
typename T>
681 std::forward<T>(value));
691 template <
typename T>
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)));
705 template <
typename T>
710 template <
typename T>
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);
721 return func(outRequest, value);
723 m_results.emplace_back(std::piecewise_construct,
724 std::forward_as_tuple(request),
725 std::forward_as_tuple(value));
729 template <
typename T>
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);
740 return func(outRequest, std::move(value));
742 m_results.emplace_back(std::piecewise_construct,
743 std::forward_as_tuple(request),
744 std::forward_as_tuple(std::move(value)));
748 template <
typename T>
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);
758 return func(outRequest, std::move(val));
760 m_thens.emplace_back(request, outRequest, func);
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();
771 template <
typename T>
772 T PromiseFactory<T>::GetResult(uint64_t request) {
774 std::unique_lock<wpi::mutex> lock(GetResultMutex());
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()) {
781 auto rv = std::move(it->second);
791 template <
typename T>
792 void PromiseFactory<T>::WaitResult(uint64_t request) {
794 std::unique_lock<wpi::mutex> lock(GetResultMutex());
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;
805 template <
typename T>
806 template <
class Clock,
class Duration>
807 bool PromiseFactory<T>::WaitResultUntil(
809 const std::chrono::time_point<Clock, Duration>& timeout_time) {
810 std::unique_lock<wpi::mutex> lock(GetResultMutex());
811 bool timeout =
false;
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;
819 if (!WaitUntil(lock, timeout_time)) timeout =
true;
824 template <
typename T>
825 PromiseFactory<T>& PromiseFactory<T>::GetInstance() {
826 static PromiseFactory inst;
838 template <
class Clock,
class Duration>
841 const std::chrono::time_point<Clock, Duration>& timeout_time) {
842 std::unique_lock<wpi::mutex> lock(GetResultMutex());
843 bool timeout =
false;
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;
851 if (!WaitUntil(lock, timeout_time)) timeout =
true;
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)));
865 return factory.CreateFuture(req);
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));
878 return factory.CreateFuture(req);
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());
890 return factory.CreateFuture(req);
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) {
902 return factory.CreateFuture(req);
907 #endif // WPIUTIL_WPI_FUTURE_H_
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: SmallVector.h:946
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
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