Skip to content

Instantly share code, notes, and snippets.

@madmongo1
Last active January 9, 2019 04:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madmongo1/15b63e8bf7855788fc7eca33d356838a to your computer and use it in GitHub Desktop.
Save madmongo1/15b63e8bf7855788fc7eca33d356838a to your computer and use it in GitHub Desktop.
// for exposition - a custom variant might be better
#include <variant>
#include <tuple>
// some library constructs
namespace compose
{
struct continue_op_t {
};
constexpr auto continue_op = continue_op_t {};
template<class...Args>
struct complete_t
{
template<class...Supplied>
complete_t(Supplied&&...supplied)
: args_(std::forward<Supplied>(supplied)...)
{}
std::tuple<Args...> args_;
};
template<class...Args>
auto complete(Args&&...args) -> complete_t<std::decay_t<Args>...>
{
return complete_t<std::decay_t<Args>...>
{
std::forward<Args>(args)...
};
}
template<class...Args>
using itermediate_result = std::variant<continue_op_t, complete_t<Args...>>;
}
template<class AsyncWriteStream, class T, class WriteHandler>
auto
async_write_messages(AsyncWriteStream& stream,
T const& message,
std::size_t repeat_count,
WriteHandler&& handler) ->
typename net::async_result<typename std::decay<WriteHandler>::type,
void(error_code)>::return_type
{
auto ex = stream.get_executor();
std::ostringstream os;
os << message;
enum
{
starting,
waiting,
writing
};
auto op = [&stream,
state = starting,
repeat_count,
msg = std::move(os).str(),
timer = net::steady_timer{ex.context()}](
auto yield, error_code ec = {}, std::size_t = 0) mutable -> compose::intermediate_result<error_code>
{
if (ec) return compose::complete(ec);
else if (repeat_count == 0) return compose::complete(ec);
else if (state == starting || state == writing)
{
--repeat_count;
state = waiting;
timer.expires_after(std::chrono::seconds(1));
return timer.async_wait(yield), compose::continue_op;
}
else if (state == waiting)
{
state = writing;
return net::async_write(stream, net::buffer(msg), yield), compose::continue_op;
}
else
{
// for exposition
assert(!"logic error");
return compose::complete(ec);
}
};
net::async_completion<WriteHandler, void(error_code)> completion(handler);
compose::stable_transform(ex, completion, std::move(op)).run();
return completion.result.get();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment