// 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 { template class future; template<> class future; template struct scoped_future; IRCD_EXCEPTION(future_error, future_already_retrieved) IRCD_OVERLOAD(use_future) template const shared_state &state(const future &); template shared_state &state(future &); template bool _wait_until(const future &, const time_point &, std::nothrow_t); template void _wait_until(const future &, const time_point &); } template struct ircd::ctx::future :private shared_state { using value_type = typename shared_state::value_type; using pointer_type = typename shared_state::pointer_type; using reference_type = typename shared_state::reference_type; const shared_state &state() const { return *this; } shared_state &state() { return *this; } bool valid() const { return !is(state(), future_state::INVALID); } bool operator!() const { return !valid(); } explicit operator T() { return get(); } template friend bool wait_until(const future &, const time_point &, std::nothrow_t); template friend void wait_until(const future &, const time_point &); template bool wait_until(const time_point &, std::nothrow_t) const; template void wait_until(const time_point &) const; template bool wait(const duration &d, std::nothrow_t) const; template void wait(const duration &d) const; void wait() const; T get(); template T get(const duration &d); template T get_until(const time_point &); using shared_state::shared_state; using shared_state::operator=; }; template<> struct ircd::ctx::future :private shared_state { using value_type = typename shared_state::value_type; const shared_state &state() const { return *this; } shared_state &state() { return *this; } bool valid() const { return !is(state(), future_state::INVALID); } bool operator!() const { return !valid(); } template friend bool wait_until(const future &, const time_point &, std::nothrow_t); template friend void wait_until(const future &, const time_point &); template bool wait_until(const time_point &, std::nothrow_t) const; template void wait_until(const time_point &) const; template bool wait(const duration &d, std::nothrow_t) const; template void wait(const duration &d) const; void wait() const; using shared_state::shared_state; using shared_state::operator=; }; template struct ircd::ctx::scoped_future :future { using future::future; ~scoped_future() noexcept; }; template inline ircd::ctx::scoped_future::~scoped_future() noexcept { if(std::uncaught_exceptions() || !this->valid()) return; this->wait(); } template template inline T ircd::ctx::future::get_until(const time_point &tp) { this->wait_until(tp); return this->get(); } template template inline T ircd::ctx::future::get(const duration &d) { this->wait(d); return this->get(); } template inline T ircd::ctx::future::get() { wait(); if(unlikely(is(state(), future_state::RETRIEVED))) throw future_already_retrieved{}; set(state(), future_state::RETRIEVED); if(bool(state().eptr)) std::rethrow_exception(state().eptr); return std::move(state().val); } template inline void ircd::ctx::future::wait() const { this->wait_until(system_point::max()); } inline void ircd::ctx::future::wait() const { this->wait_until(system_point::max()); } template template inline void ircd::ctx::future::wait(const duration &d) const { this->wait_until(now() + d); } template inline void ircd::ctx::future::wait(const duration &d) const { this->wait_until(now() + d); } template template inline bool ircd::ctx::future::wait(const duration &d, std::nothrow_t) const { return this->wait_until(now() + d, std::nothrow); } template inline bool ircd::ctx::future::wait(const duration &d, std::nothrow_t) const { return this->wait_until(now() + d, std::nothrow); } template template inline void ircd::ctx::future::wait_until(const time_point &tp) const { if(!this->wait_until(tp, std::nothrow)) throw timeout{}; } template inline void ircd::ctx::future::wait_until(const time_point &tp) const { if(!this->wait_until(tp, std::nothrow)) throw timeout{}; } template template inline bool ircd::ctx::future::wait_until(const time_point &tp, std::nothrow_t) const { return _wait_until(*this, tp, std::nothrow); } template inline bool ircd::ctx::future::wait_until(const time_point &tp, std::nothrow_t) const { if(_wait_until(*this, tp, std::nothrow)) { auto &state(mutable_cast(this->state())); set(state, future_state::RETRIEVED); if(bool(state.eptr)) std::rethrow_exception(state.eptr); return true; } else return false; } template inline void ircd::ctx::wait_until(const future &f, const time_point &tp) { if(!_wait_until(f, tp, std::nothrow)) throw timeout{}; } template inline bool ircd::ctx::_wait_until(const future &f, const time_point &tp, std::nothrow_t) { auto &state(mutable_cast(f.state())); if(unlikely(is(state, future_state::INVALID))) throw no_state{}; return state.cond.wait_until(tp, [&state]() noexcept { return !is(state, future_state::PENDING); }); } template inline ircd::ctx::shared_state & ircd::ctx::state(future &future) { return future.state(); } template inline const ircd::ctx::shared_state & ircd::ctx::state(const future &future) { return future.state(); }