/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #pragma once #define HAVE_IRCD_CTX_FUTURE_H namespace ircd::ctx { 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; }