blob: 109eeb93ca3ef3d703287e4e527e5309a7eda2e2 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "wpi/future.h"
6
7namespace wpi {
8namespace detail {
9
10PromiseFactoryBase::~PromiseFactoryBase() {
11 m_active = false;
12 m_resultCv.notify_all(); // wake up any waiters
13}
14
15void PromiseFactoryBase::IgnoreResult(uint64_t request) {
16 std::unique_lock lock(m_resultMutex);
17 EraseRequest(request);
18}
19
20uint64_t PromiseFactoryBase::CreateRequest() {
21 std::unique_lock lock(m_resultMutex);
22 uint64_t req = ++m_uid;
23 m_requests.push_back(req);
24 return req;
25}
26
27bool PromiseFactoryBase::EraseRequest(uint64_t request) {
Austin Schuh812d0d12021-11-04 20:16:48 -070028 if (request == 0) {
29 return false;
30 }
Brian Silverman8fce7482020-01-05 13:18:21 -080031 auto it = std::find_if(m_requests.begin(), m_requests.end(),
32 [=](auto r) { return r == request; });
Austin Schuh812d0d12021-11-04 20:16:48 -070033 if (it == m_requests.end()) {
34 return false; // no waiters
35 }
Brian Silverman8fce7482020-01-05 13:18:21 -080036 m_requests.erase(it);
37 return true;
38}
39
40} // namespace detail
41
42future<void> PromiseFactory<void>::MakeReadyFuture() {
43 std::unique_lock lock(GetResultMutex());
44 uint64_t req = CreateErasedRequest();
45 m_results.emplace_back(req);
46 return future<void>{this, req};
47}
48
49void PromiseFactory<void>::SetValue(uint64_t request) {
50 std::unique_lock lock(GetResultMutex());
Austin Schuh812d0d12021-11-04 20:16:48 -070051 if (!EraseRequest(request)) {
52 return;
53 }
Brian Silverman8fce7482020-01-05 13:18:21 -080054 auto it = std::find_if(m_thens.begin(), m_thens.end(),
55 [=](const auto& x) { return x.request == request; });
56 if (it != m_thens.end()) {
57 uint64_t outRequest = it->outRequest;
58 ThenFunction func = std::move(it->func);
59 m_thens.erase(it);
60 lock.unlock();
61 return func(outRequest);
62 }
63 m_results.emplace_back(request);
64 Notify();
65}
66
67void PromiseFactory<void>::SetThen(uint64_t request, uint64_t outRequest,
68 ThenFunction func) {
69 std::unique_lock lock(GetResultMutex());
70 auto it = std::find_if(m_results.begin(), m_results.end(),
71 [=](const auto& r) { return r == request; });
72 if (it != m_results.end()) {
73 m_results.erase(it);
74 lock.unlock();
75 return func(outRequest);
76 }
77 m_thens.emplace_back(request, outRequest, func);
78}
79
80bool PromiseFactory<void>::IsReady(uint64_t request) noexcept {
81 std::unique_lock lock(GetResultMutex());
82 auto it = std::find_if(m_results.begin(), m_results.end(),
83 [=](const auto& r) { return r == request; });
84 return it != m_results.end();
85}
86
87void PromiseFactory<void>::GetResult(uint64_t request) {
88 // wait for response
89 std::unique_lock lock(GetResultMutex());
90 while (IsActive()) {
91 // Did we get a response to *our* request?
92 auto it = std::find_if(m_results.begin(), m_results.end(),
93 [=](const auto& r) { return r == request; });
94 if (it != m_results.end()) {
95 // Yes, remove it from the vector and we're done.
96 m_results.erase(it);
97 return;
98 }
99 // No, keep waiting for a response
100 Wait(lock);
101 }
102}
103
104void PromiseFactory<void>::WaitResult(uint64_t request) {
105 // wait for response
106 std::unique_lock lock(GetResultMutex());
107 while (IsActive()) {
108 // Did we get a response to *our* request?
109 auto it = std::find_if(m_results.begin(), m_results.end(),
110 [=](const auto& r) { return r == request; });
Austin Schuh812d0d12021-11-04 20:16:48 -0700111 if (it != m_results.end()) {
112 return;
113 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800114 // No, keep waiting for a response
115 Wait(lock);
116 }
117}
118
119PromiseFactory<void>& PromiseFactory<void>::GetInstance() {
120 static PromiseFactory<void> inst;
121 return inst;
122}
123
124} // namespace wpi