diff --git a/support-lib/cpp/Future.hpp b/support-lib/cpp/Future.hpp index dede703d..9bd6eaf6 100644 --- a/support-lib/cpp/Future.hpp +++ b/support-lib/cpp/Future.hpp @@ -271,16 +271,15 @@ class Future { std::unique_lock lk(sharedState->mutex); return sharedState->isReady(); } + // wait until future becomes `isReady()` or the timeout elapses + // returns true if the future is ready, false if the timeout elapsed + template + bool waitFor(std::chrono::duration duration) const { + return waitImpl(std::make_optional(std::chrono::steady_clock::now() + duration)); + } // wait until future becomes `isReady()` void wait() const { - auto sharedState = std::atomic_load(&_sharedState); - assert(sharedState); // call on invalid future will trigger assertion - std::unique_lock lk(sharedState->mutex); -#if defined(__EMSCRIPTEN__) - assert(sharedState->isReady()); // in wasm we must not block and wait -#else - sharedState->cv.wait(lk, [state = sharedState] {return state->isReady();}); -#endif + waitImpl({}); } // wait until future becomes `isReady()` and return the result. This can // only be called once. @@ -343,6 +342,24 @@ class Future { private: detail::SharedStatePtr _sharedState; + + template + bool waitImpl(std::optional> deadline) const { + auto sharedState = std::atomic_load(&_sharedState); + assert(sharedState); // call on invalid future will trigger assertion + std::unique_lock lk(sharedState->mutex); +#if defined(__EMSCRIPTEN__) + assert(sharedState->isReady()); // in wasm we must not block and wait +#else + auto predicate = [&sharedState] {return sharedState->isReady();}; + if (deadline) { + return sharedState->cv.wait_until(lk, *deadline, std::move(predicate)); + } else { + sharedState->cv.wait(lk, std::move(predicate)); + return true; + } +#endif + } #if defined(DJINNI_FUTURE_HAS_COROUTINE_SUPPORT) public: