Support async::future::then
This commit is contained in:
parent
dd32ab00d3
commit
1bfbaaa840
1 changed files with 112 additions and 9 deletions
|
|
@ -38,6 +38,18 @@ namespace psemek::async
|
||||||
using type = bool;
|
using type = bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct then_function
|
||||||
|
{
|
||||||
|
using type = util::function<void(T &)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct then_function<void>
|
||||||
|
{
|
||||||
|
using type = util::function<void()>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct task_state
|
struct task_state
|
||||||
{
|
{
|
||||||
|
|
@ -50,6 +62,9 @@ namespace psemek::async
|
||||||
|
|
||||||
std::condition_variable value_cv;
|
std::condition_variable value_cv;
|
||||||
|
|
||||||
|
std::mutex then_mutex;
|
||||||
|
typename then_function<T>::type then_func;
|
||||||
|
|
||||||
task_state(bool auto_cancel)
|
task_state(bool auto_cancel)
|
||||||
: auto_cancel{auto_cancel}
|
: auto_cancel{auto_cancel}
|
||||||
{}
|
{}
|
||||||
|
|
@ -159,6 +174,9 @@ namespace psemek::async
|
||||||
return wait_for(std::chrono::seconds{0});
|
return wait_for(std::chrono::seconds{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto then(F && f);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<detail::task_state<T>> state_;
|
std::shared_ptr<detail::task_state<T>> state_;
|
||||||
|
|
||||||
|
|
@ -202,18 +220,26 @@ namespace psemek::async
|
||||||
void set_value(T const & value)
|
void set_value(T const & value)
|
||||||
{
|
{
|
||||||
if (!state_) throw empty_promise_error{};
|
if (!state_) throw empty_promise_error{};
|
||||||
|
{
|
||||||
std::lock_guard lock{state_->value_mutex};
|
std::lock_guard lock{state_->value_mutex};
|
||||||
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
||||||
state_->value = value;
|
state_->value = value;
|
||||||
}
|
}
|
||||||
|
if (state_->then_func)
|
||||||
|
state_->then_func(*state_->value);
|
||||||
|
}
|
||||||
|
|
||||||
void set_value(T && value)
|
void set_value(T && value)
|
||||||
{
|
{
|
||||||
if (!state_) throw empty_promise_error{};
|
if (!state_) throw empty_promise_error{};
|
||||||
|
{
|
||||||
std::lock_guard lock{state_->value_mutex};
|
std::lock_guard lock{state_->value_mutex};
|
||||||
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
||||||
state_->value = std::move(value);
|
state_->value = std::move(value);
|
||||||
}
|
}
|
||||||
|
if (state_->then_func)
|
||||||
|
state_->then_func(*state_->value);
|
||||||
|
}
|
||||||
|
|
||||||
void set_exception(std::exception_ptr e)
|
void set_exception(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
|
|
@ -254,10 +280,14 @@ namespace psemek::async
|
||||||
void set_value()
|
void set_value()
|
||||||
{
|
{
|
||||||
if (!state_) throw empty_promise_error{};
|
if (!state_) throw empty_promise_error{};
|
||||||
|
{
|
||||||
std::lock_guard lock{state_->value_mutex};
|
std::lock_guard lock{state_->value_mutex};
|
||||||
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
if (state_->value || state_->exception) throw satisfied_promise_error{};
|
||||||
state_->value = true;
|
state_->value = true;
|
||||||
}
|
}
|
||||||
|
if (state_->then_func)
|
||||||
|
state_->then_func();
|
||||||
|
}
|
||||||
|
|
||||||
void set_exception(std::exception_ptr e)
|
void set_exception(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
|
|
@ -333,4 +363,77 @@ namespace psemek::async
|
||||||
util::function<R(Args...)> func_;
|
util::function<R(Args...)> func_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename F>
|
||||||
|
auto future<T>::then(F && f)
|
||||||
|
{
|
||||||
|
if (!state_) throw empty_future_error{};
|
||||||
|
|
||||||
|
std::lock_guard lock{state_->value_mutex};
|
||||||
|
if (state_->value || state_->exception)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<T, void>)
|
||||||
|
{
|
||||||
|
using R = decltype(f());
|
||||||
|
promise<R> p;
|
||||||
|
|
||||||
|
if (state_->value)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<R, void>)
|
||||||
|
{
|
||||||
|
std::forward<F>(f)();
|
||||||
|
p.set_value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.set_value(std::forward<F>(f)());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p.set_exception(state_->exception);
|
||||||
|
return p.get_future();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using R = decltype(f(*(state_->value)));
|
||||||
|
promise<R> p;
|
||||||
|
|
||||||
|
if (state_->value)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<R, void>)
|
||||||
|
{
|
||||||
|
std::forward<F>(f)(*(state_->value));
|
||||||
|
p.set_value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.set_value(std::forward<F>(f)(*(state_->value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p.set_exception(state_->exception);
|
||||||
|
return p.get_future();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, void>)
|
||||||
|
{
|
||||||
|
using R = decltype(f());
|
||||||
|
packaged_task<R()> t(std::forward<F>(f));
|
||||||
|
|
||||||
|
std::lock_guard lock{state_->then_mutex};
|
||||||
|
state_->then_func = std::move(t);
|
||||||
|
return t.get_future();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using R = decltype(f(*(state_->value)));
|
||||||
|
packaged_task<R(T &)> t(std::forward<F>(f));
|
||||||
|
|
||||||
|
std::lock_guard lock{state_->then_mutex};
|
||||||
|
state_->then_func = std::move(t);
|
||||||
|
return t.get_future();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue