mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 15:33:54 +01:00
ircd::ctx: Improve promise / future behaviors; cleanup.
This commit is contained in:
parent
30700b2ad8
commit
07c1356dae
3 changed files with 99 additions and 22 deletions
|
@ -20,9 +20,6 @@ namespace ircd::ctx
|
|||
template<class... T> struct scoped_future;
|
||||
enum class future_status;
|
||||
|
||||
template<class T,
|
||||
class time_point>
|
||||
future_status wait_until(const future<T> &, const time_point &);
|
||||
}
|
||||
|
||||
enum class ircd::ctx::future_status
|
||||
|
@ -35,7 +32,7 @@ enum class ircd::ctx::future_status
|
|||
template<class T>
|
||||
struct ircd::ctx::future
|
||||
{
|
||||
shared_state<T> st;
|
||||
mutable shared_state<T> st;
|
||||
|
||||
public:
|
||||
using value_type = typename shared_state<T>::value_type;
|
||||
|
@ -69,7 +66,7 @@ struct ircd::ctx::future
|
|||
template<>
|
||||
struct ircd::ctx::future<void>
|
||||
{
|
||||
shared_state<void> st;
|
||||
mutable shared_state<void> st;
|
||||
|
||||
public:
|
||||
using value_type = typename shared_state<void>::value_type;
|
||||
|
@ -95,6 +92,13 @@ struct ircd::ctx::future<void>
|
|||
~future() noexcept;
|
||||
};
|
||||
|
||||
namespace ircd::ctx
|
||||
{
|
||||
template<class T,
|
||||
class time_point>
|
||||
future_status wait_until(const future<T> &, const time_point &, std::nothrow_t);
|
||||
}
|
||||
|
||||
template<class... T>
|
||||
struct ircd::ctx::scoped_future
|
||||
:future<T...>
|
||||
|
@ -199,8 +203,11 @@ T
|
|||
ircd::ctx::future<T>::get()
|
||||
{
|
||||
wait();
|
||||
if(unlikely(retrieved(st)))
|
||||
throw future_already_retrieved{};
|
||||
|
||||
if(unlikely(bool(st.eptr)))
|
||||
set_retrieved(st);
|
||||
if(bool(st.eptr))
|
||||
std::rethrow_exception(st.eptr);
|
||||
|
||||
return st.val;
|
||||
|
@ -271,7 +278,15 @@ ircd::ctx::future_status
|
|||
ircd::ctx::future<void>::wait_until(const time_point &tp)
|
||||
const
|
||||
{
|
||||
return ircd::ctx::wait_until(*this, tp);
|
||||
const auto status
|
||||
{
|
||||
this->wait_until(tp, std::nothrow)
|
||||
};
|
||||
|
||||
if(status == future_status::timeout)
|
||||
throw timeout{};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -290,7 +305,19 @@ ircd::ctx::future<void>::wait_until(const time_point &tp,
|
|||
std::nothrow_t)
|
||||
const
|
||||
{
|
||||
return ircd::ctx::wait_until(*this, tp, std::nothrow);
|
||||
const auto status
|
||||
{
|
||||
ircd::ctx::wait_until(*this, tp, std::nothrow)
|
||||
};
|
||||
|
||||
if(status == future_status::ready)
|
||||
{
|
||||
set_retrieved(st);
|
||||
if(bool(st.eptr))
|
||||
std::rethrow_exception(st.eptr);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
template<class T,
|
||||
|
|
|
@ -24,13 +24,6 @@ namespace ircd::ctx
|
|||
IRCD_EXCEPTION(future_error, broken_promise)
|
||||
IRCD_EXCEPTION(future_error, future_already_retrieved)
|
||||
IRCD_EXCEPTION(future_error, promise_already_satisfied)
|
||||
|
||||
template<class T> size_t refcount(const shared_state<T> &);
|
||||
template<class T> void update(shared_state<T> &s);
|
||||
template<class T> void invalidate(shared_state<T> &);
|
||||
template<class T> void remove(shared_state<T> &, promise<T> &);
|
||||
template<class T> void update(promise<T> &new_, promise<T> &old);
|
||||
template<class T> void append(promise<T> &new_, promise<T> &old);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -90,6 +83,16 @@ struct ircd::ctx::promise<void>
|
|||
~promise() noexcept;
|
||||
};
|
||||
|
||||
namespace ircd::ctx
|
||||
{
|
||||
template<class T> size_t refcount(const shared_state<T> &);
|
||||
template<class T> void update(shared_state<T> &s);
|
||||
template<class T> void invalidate(shared_state<T> &);
|
||||
template<class T> void remove(shared_state<T> &, promise<T> &);
|
||||
template<class T> void update(promise<T> &new_, promise<T> &old);
|
||||
template<class T> void append(promise<T> &new_, promise<T> &old);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ircd::ctx::promise<T>::promise(promise<T> &&o)
|
||||
noexcept
|
||||
|
@ -195,12 +198,15 @@ void
|
|||
ircd::ctx::promise<T>::set_value(T&& val)
|
||||
{
|
||||
assert(valid());
|
||||
assert(pending(*st));
|
||||
if(unlikely(ready(*st)))
|
||||
throw promise_already_satisfied{};
|
||||
|
||||
st->val = std::move(val);
|
||||
auto *const st{this->st};
|
||||
invalidate(*st);
|
||||
set_ready(*st);
|
||||
notify(*st);
|
||||
assert(!valid());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -208,23 +214,29 @@ void
|
|||
ircd::ctx::promise<T>::set_value(const T &val)
|
||||
{
|
||||
assert(valid());
|
||||
assert(pending(*st));
|
||||
if(unlikely(!pending(*st)))
|
||||
throw promise_already_satisfied{};
|
||||
|
||||
st->val = val;
|
||||
auto *const st{this->st};
|
||||
invalidate(*st);
|
||||
set_ready(*st);
|
||||
notify(*st);
|
||||
assert(!valid());
|
||||
}
|
||||
|
||||
inline void
|
||||
ircd::ctx::promise<void>::set_value()
|
||||
{
|
||||
assert(valid());
|
||||
assert(pending(*st));
|
||||
if(unlikely(!pending(*st)))
|
||||
throw promise_already_satisfied{};
|
||||
|
||||
auto *const st{this->st};
|
||||
invalidate(*st);
|
||||
set_ready(*st);
|
||||
notify(*st);
|
||||
assert(!valid());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -232,24 +244,30 @@ void
|
|||
ircd::ctx::promise<T>::set_exception(std::exception_ptr eptr)
|
||||
{
|
||||
assert(valid());
|
||||
assert(pending(*st));
|
||||
if(unlikely(!pending(*st)))
|
||||
throw promise_already_satisfied{};
|
||||
|
||||
st->eptr = std::move(eptr);
|
||||
auto *const st{this->st};
|
||||
invalidate(*st);
|
||||
set_ready(*st);
|
||||
notify(*st);
|
||||
assert(!valid());
|
||||
}
|
||||
|
||||
inline void
|
||||
ircd::ctx::promise<void>::set_exception(std::exception_ptr eptr)
|
||||
{
|
||||
assert(valid());
|
||||
assert(pending(*st));
|
||||
if(unlikely(!pending(*st)))
|
||||
throw promise_already_satisfied{};
|
||||
|
||||
st->eptr = std::move(eptr);
|
||||
auto *const st{this->st};
|
||||
invalidate(*st);
|
||||
set_ready(*st);
|
||||
notify(*st);
|
||||
assert(!valid());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
|
@ -22,9 +22,13 @@ namespace ircd::ctx
|
|||
|
||||
template<class T> bool invalid(const shared_state<T> &);
|
||||
template<class T> bool pending(const shared_state<T> &);
|
||||
template<class T> bool retrieved(const shared_state<T> &);
|
||||
template<class T> bool ready(const shared_state<T> &);
|
||||
template<class T> void set_ready(shared_state<T> &);
|
||||
template<class T> void notify(shared_state<T> &);
|
||||
template<class T> void set_retrieved(shared_state<T> &);
|
||||
template<class T> void set_ready(shared_state<T> &);
|
||||
template<class T> void set_observed(shared_state<T> &);
|
||||
template<> void set_observed(shared_state<void> &);
|
||||
}
|
||||
|
||||
struct ircd::ctx::shared_state_base
|
||||
|
@ -73,6 +77,20 @@ ircd::ctx::notify(shared_state<T> &st)
|
|||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ircd::ctx::set_observed(shared_state<T> &st)
|
||||
{
|
||||
set_ready(st);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
ircd::ctx::set_observed(shared_state<void> &st)
|
||||
{
|
||||
set_retrieved(st);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ircd::ctx::set_ready(shared_state<T> &st)
|
||||
|
@ -80,6 +98,13 @@ ircd::ctx::set_ready(shared_state<T> &st)
|
|||
st.p = reinterpret_cast<promise<T> *>(uintptr_t(0x42));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ircd::ctx::set_retrieved(shared_state<T> &st)
|
||||
{
|
||||
st.p = reinterpret_cast<promise<T> *>(uintptr_t(0x84));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
ircd::ctx::ready(const shared_state<T> &st)
|
||||
|
@ -87,11 +112,18 @@ ircd::ctx::ready(const shared_state<T> &st)
|
|||
return st.p == reinterpret_cast<const promise<T> *>(uintptr_t(0x42));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
ircd::ctx::retrieved(const shared_state<T> &st)
|
||||
{
|
||||
return st.p == reinterpret_cast<const promise<T> *>(uintptr_t(0x84));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
ircd::ctx::pending(const shared_state<T> &st)
|
||||
{
|
||||
return st.p > reinterpret_cast<const promise<T> *>(uintptr_t(0x42));
|
||||
return st.p > reinterpret_cast<const promise<T> *>(uintptr_t(0x1000));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
Loading…
Reference in a new issue