/* * 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 { namespace ctx { enum class future_status { ready, timeout, deferred, }; template class 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 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 future_status wait_until(const future &, const time_point &); template struct scoped_future : future { template scoped_future(Args&&... args); ~scoped_future() noexcept; }; template template scoped_future::scoped_future(Args&&... args): future{std::forward(args)...} { } template scoped_future::~scoped_future() noexcept { if(std::uncaught_exception()) return; if(this->valid()) this->wait(); } inline future::future(): st(nullptr) { } template future::future(): st(nullptr) { } inline future::future(promise &promise): st(promise.get_state().share()) { } template future::future(promise &promise): st(promise.get_state().share()) { } template T future::get() { wait(); if(unlikely(bool(st->eptr))) std::rethrow_exception(st->eptr); return st->val; } inline void future::wait() const { this->wait_until(steady_clock::time_point::max()); } template void future::wait() const { this->wait_until(steady_clock::time_point::max()); } template future_status future::wait(const duration &d) const { return this->wait_until(steady_clock::now() + d); } template template future_status future::wait(const duration &d) const { return this->wait_until(steady_clock::now() + d); } template template future_status future::wait_until(const time_point &tp) const { return ircd::ctx::wait_until(*this, tp); } template future_status future::wait_until(const time_point &tp) const { return ircd::ctx::wait_until(*this, tp); } template future_status 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; } } // namespace ctx } // namespace ircd