mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
wpiutil: Change uv::AsyncFunction to use promise/future.
This allows the called function to pass along the promise to another asynchronous callback. To avoid memory allocations, add a home-rolled, simplified, non-allocating version of std::promise and std::future as wpi::promise and wpi::future.
This commit is contained in:
119
wpiutil/src/main/native/cpp/future.cpp
Normal file
119
wpiutil/src/main/native/cpp/future.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "wpi/future.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace detail {
|
||||
|
||||
PromiseFactoryBase::~PromiseFactoryBase() {
|
||||
m_active = false;
|
||||
m_resultCv.notify_all(); // wake up any waiters
|
||||
}
|
||||
|
||||
void PromiseFactoryBase::IgnoreResult(uint64_t request) {
|
||||
std::unique_lock<wpi::mutex> lock(m_resultMutex);
|
||||
EraseRequest(request);
|
||||
}
|
||||
|
||||
uint64_t PromiseFactoryBase::CreateRequest() {
|
||||
std::unique_lock<wpi::mutex> lock(m_resultMutex);
|
||||
uint64_t req = ++m_uid;
|
||||
m_requests.push_back(req);
|
||||
return req;
|
||||
}
|
||||
|
||||
bool PromiseFactoryBase::EraseRequest(uint64_t request) {
|
||||
if (request == 0) return false;
|
||||
auto it = std::find_if(m_requests.begin(), m_requests.end(),
|
||||
[=](auto r) { return r == request; });
|
||||
if (it == m_requests.end()) return false; // no waiters
|
||||
m_requests.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
future<void> PromiseFactory<void>::MakeReadyFuture() {
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
uint64_t req = CreateErasedRequest();
|
||||
m_results.emplace_back(req);
|
||||
return future<void>{this, req};
|
||||
}
|
||||
|
||||
void PromiseFactory<void>::SetValue(uint64_t request) {
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
if (!EraseRequest(request)) return;
|
||||
auto it = std::find_if(m_thens.begin(), m_thens.end(),
|
||||
[=](const auto& x) { return x.request == request; });
|
||||
if (it != m_thens.end()) {
|
||||
uint64_t outRequest = it->outRequest;
|
||||
ThenFunction func = std::move(it->func);
|
||||
m_thens.erase(it);
|
||||
lock.unlock();
|
||||
return func(outRequest);
|
||||
}
|
||||
m_results.emplace_back(request);
|
||||
Notify();
|
||||
}
|
||||
|
||||
void PromiseFactory<void>::SetThen(uint64_t request, uint64_t outRequest,
|
||||
ThenFunction func) {
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
auto it = std::find_if(m_results.begin(), m_results.end(),
|
||||
[=](const auto& r) { return r == request; });
|
||||
if (it != m_results.end()) {
|
||||
m_results.erase(it);
|
||||
lock.unlock();
|
||||
return func(outRequest);
|
||||
}
|
||||
m_thens.emplace_back(request, outRequest, func);
|
||||
}
|
||||
|
||||
bool PromiseFactory<void>::IsReady(uint64_t request) noexcept {
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
auto it = std::find_if(m_results.begin(), m_results.end(),
|
||||
[=](const auto& r) { return r == request; });
|
||||
return it != m_results.end();
|
||||
}
|
||||
|
||||
void PromiseFactory<void>::GetResult(uint64_t request) {
|
||||
// wait for response
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
while (IsActive()) {
|
||||
// Did we get a response to *our* request?
|
||||
auto it = std::find_if(m_results.begin(), m_results.end(),
|
||||
[=](const auto& r) { return r == request; });
|
||||
if (it != m_results.end()) {
|
||||
// Yes, remove it from the vector and we're done.
|
||||
m_results.erase(it);
|
||||
return;
|
||||
}
|
||||
// No, keep waiting for a response
|
||||
Wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void PromiseFactory<void>::WaitResult(uint64_t request) {
|
||||
// wait for response
|
||||
std::unique_lock<wpi::mutex> lock(GetResultMutex());
|
||||
while (IsActive()) {
|
||||
// Did we get a response to *our* request?
|
||||
auto it = std::find_if(m_results.begin(), m_results.end(),
|
||||
[=](const auto& r) { return r == request; });
|
||||
if (it != m_results.end()) return;
|
||||
// No, keep waiting for a response
|
||||
Wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
PromiseFactory<void>& PromiseFactory<void>::GetInstance() {
|
||||
static PromiseFactory<void> inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
Reference in New Issue
Block a user