// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_CTX_FUTURE_H namespace ircd::ctx { IRCD_OVERLOAD(use_future) template class future; template<> class future; template struct scoped_future; enum class future_status; template future_status wait_until(const future &, const time_point &); } enum class ircd::ctx::future_status { ready, timeout, deferred, }; template class ircd::ctx::future { std::shared_ptr> st; public: using value_type = typename shared_state::value_type; using pointer_type = typename shared_state::pointer_type; using reference_type = typename shared_state::reference_type; bool valid() const { return bool(st); } bool operator!() const { return !valid(); } operator bool() const { return valid(); } template friend future_status wait_until(const future &, const time_point &); template future_status wait_until(const time_point &) const; template future_status wait(const duration &d) const; void wait() const; T get(); operator T() { return get(); } future(); future(promise &promise); }; template<> class ircd::ctx::future { std::shared_ptr> st; public: using value_type = typename shared_state::value_type; bool valid() const { return bool(st); } bool operator!() const { return !valid(); } operator bool() const { return valid(); } template friend future_status wait_until(const future &, const time_point &); template future_status wait_until(const time_point &) const; template future_status wait(const duration &d) const; void wait() const; future(); future(promise &promise); }; template struct ircd::ctx::scoped_future :future { template scoped_future(Args&&... args); ~scoped_future() noexcept; }; template template ircd::ctx::scoped_future::scoped_future(Args&&... args) :future{std::forward(args)...} { } template ircd::ctx::scoped_future::~scoped_future() noexcept { if(std::uncaught_exception()) return; if(this->valid()) this->wait(); } inline ircd::ctx::future::future() :st{nullptr} { } template ircd::ctx::future::future() :st{nullptr} { } inline ircd::ctx::future::future(promise &promise) :st{promise.get_state().share()} { } template ircd::ctx::future::future(promise &promise) :st{promise.get_state().share()} { } template T ircd::ctx::future::get() { wait(); if(unlikely(bool(st->eptr))) std::rethrow_exception(st->eptr); return st->val; } inline void ircd::ctx::future::wait() const { this->wait_until(steady_clock::time_point::max()); } template void ircd::ctx::future::wait() const { this->wait_until(steady_clock::time_point::max()); } template ircd::ctx::future_status ircd::ctx::future::wait(const duration &d) const { return this->wait_until(steady_clock::now() + d); } template template ircd::ctx::future_status ircd::ctx::future::wait(const duration &d) const { return this->wait_until(steady_clock::now() + d); } template template ircd::ctx::future_status ircd::ctx::future::wait_until(const time_point &tp) const { return ircd::ctx::wait_until(*this, tp); } template ircd::ctx::future_status ircd::ctx::future::wait_until(const time_point &tp) const { return ircd::ctx::wait_until(*this, tp); } template ircd::ctx::future_status ircd::ctx::wait_until(const future &f, const time_point &tp) { const auto wfun([&f]() -> bool { return f.st->finished; }); if(unlikely(!f.valid())) throw no_state(); if(unlikely(!f.st->cond.wait_until(tp, wfun))) return future_status::timeout; return likely(wfun())? future_status::ready: future_status::deferred; }