/*----------------------------------------------------------------------------*/ /* Copyright (c) 2018-2019 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 lock(m_resultMutex); EraseRequest(request); } uint64_t PromiseFactoryBase::CreateRequest() { std::unique_lock 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 PromiseFactory::MakeReadyFuture() { std::unique_lock lock(GetResultMutex()); uint64_t req = CreateErasedRequest(); m_results.emplace_back(req); return future{this, req}; } void PromiseFactory::SetValue(uint64_t request) { std::unique_lock 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::SetThen(uint64_t request, uint64_t outRequest, ThenFunction func) { std::unique_lock 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::IsReady(uint64_t request) noexcept { std::unique_lock 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::GetResult(uint64_t request) { // wait for response std::unique_lock 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::WaitResult(uint64_t request) { // wait for response std::unique_lock 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& PromiseFactory::GetInstance() { static PromiseFactory inst; return inst; } } // namespace wpi