#if !defined(BOOST_ALL_NO_LIB)
#define BOOST_ALL_NO_LIB 1
#endif
#include "asio/compose.hpp"
#include <functional>
#include "asio/bind_cancellation_slot.hpp"
#include "asio/cancellation_signal.hpp"
#include "asio/io_context.hpp"
#include "asio/post.hpp"
#include "asio/system_timer.hpp"
#include "unit_test.hpp"
class impl_0_completion_args
{
public:
explicit impl_0_completion_args(asio::io_context& ioc)
: ioc_(ioc),
state_(starting)
{
}
template <typename Self>
void operator()(Self& self)
{
switch (state_)
{
case starting:
state_ = posting;
asio::post(ioc_, static_cast<Self&&>(self));
break;
case posting:
self.complete();
break;
default:
break;
}
}
private:
asio::io_context& ioc_;
enum { starting, posting } state_;
};
template <typename CompletionToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken, void())
async_0_completion_args(asio::io_context& ioc,
CompletionToken&& token)
{
return asio::async_compose<CompletionToken, void()>(
impl_0_completion_args(ioc), token);
}
void compose_0_args_handler(int* count)
{
++(*count);
}
struct compose_0_args_lvalue_handler
{
int* count_;
void operator()()
{
++(*count_);
}
};
void compose_0_completion_args_test()
{
namespace bindns = std;
asio::io_context ioc;
int count = 0;
async_0_completion_args(ioc, bindns::bind(&compose_0_args_handler, &count));
ASIO_CHECK(!ioc.stopped());
ASIO_CHECK(count == 0);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ioc.restart();
count = 0;
compose_0_args_lvalue_handler lvalue_handler = { &count };
async_0_completion_args(ioc, lvalue_handler);
ASIO_CHECK(!ioc.stopped());
ASIO_CHECK(count == 0);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
}
class impl_1_completion_arg
{
public:
explicit impl_1_completion_arg(asio::io_context& ioc)
: ioc_(ioc),
state_(starting)
{
}
template <typename Self>
void operator()(Self& self)
{
switch (state_)
{
case starting:
state_ = posting;
asio::post(ioc_, static_cast<Self&&>(self));
break;
case posting:
self.complete(42);
break;
default:
break;
}
}
private:
asio::io_context& ioc_;
enum { starting, posting } state_;
};
template <typename CompletionToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int))
async_1_completion_arg(asio::io_context& ioc,
CompletionToken&& token)
{
return asio::async_compose<CompletionToken, void(int)>(
impl_1_completion_arg(ioc), token);
}
void compose_1_arg_handler(int* count, int* result_out, int result)
{
++(*count);
*result_out = result;
}
struct compose_1_arg_lvalue_handler
{
int* count_;
int* result_out_;
void operator()(int result)
{
++(*count_);
*result_out_ = result;
}
};
void compose_1_completion_arg_test()
{
namespace bindns = std;
using bindns::placeholders::_1;
asio::io_context ioc;
int count = 0;
int result = 0;
async_1_completion_arg(ioc,
bindns::bind(&compose_1_arg_handler, &count, &result, _1));
ASIO_CHECK(!ioc.stopped());
ASIO_CHECK(count == 0);
ASIO_CHECK(result == 0);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == 42);
ioc.restart();
count = 0;
result = 0;
compose_1_arg_lvalue_handler lvalue_handler = { &count, &result };
async_1_completion_arg(ioc, lvalue_handler);
ASIO_CHECK(!ioc.stopped());
ASIO_CHECK(count == 0);
ASIO_CHECK(result == 0);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == 42);
}
typedef asio::enable_terminal_cancellation default_filter;
template <typename CancellationFilter>
class impl_cancellable
{
public:
explicit impl_cancellable(CancellationFilter cancellation_filter,
asio::system_timer& timer)
: cancellation_filter_(cancellation_filter),
timer_(timer),
state_(starting)
{
}
template <typename Self>
void operator()(Self& self,
const asio::error_code& ec = asio::error_code())
{
switch (state_)
{
case starting:
if (!asio::is_same<CancellationFilter, default_filter>::value)
self.reset_cancellation_state(cancellation_filter_);
state_ = waiting;
timer_.expires_after(asio::chrono::milliseconds(100));
timer_.async_wait(static_cast<Self&&>(self));
break;
case waiting:
self.complete(!ec);
break;
default:
break;
}
}
private:
CancellationFilter cancellation_filter_;
asio::system_timer& timer_;
enum { starting, waiting } state_;
};
template <typename CancellationFilter, typename CompletionToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken, void(bool))
async_cancellable(CancellationFilter cancellation_filter,
asio::system_timer& timer,
CompletionToken&& token)
{
return asio::async_compose<CompletionToken, void(bool)>(
impl_cancellable<CancellationFilter>(cancellation_filter, timer), token);
}
void compose_partial_cancellation_handler(
int* count, bool* result_out, bool result)
{
++(*count);
*result_out = result;
}
void compose_default_cancellation_test()
{
namespace bindns = std;
using bindns::placeholders::_1;
asio::io_context ioc;
asio::system_timer timer(ioc);
asio::cancellation_signal signal;
int count = 0;
bool result = false;
async_cancellable(default_filter(), timer,
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1));
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(default_filter(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::total);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(default_filter(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::partial);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(default_filter(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::terminal);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
}
void compose_partial_cancellation_test()
{
namespace bindns = std;
using bindns::placeholders::_1;
asio::io_context ioc;
asio::system_timer timer(ioc);
asio::cancellation_signal signal;
int count = 0;
bool result = false;
async_cancellable(asio::enable_partial_cancellation(), timer,
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1));
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_partial_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::total);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_partial_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::partial);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_partial_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::terminal);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
}
void compose_total_cancellation_test()
{
namespace bindns = std;
using bindns::placeholders::_1;
asio::io_context ioc;
asio::system_timer timer(ioc);
asio::cancellation_signal signal;
int count = 0;
bool result = false;
async_cancellable(asio::enable_total_cancellation(), timer,
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1));
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == true);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_total_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::total);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_total_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::partial);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
ioc.restart();
count = 0;
result = 0;
async_cancellable(asio::enable_total_cancellation(), timer,
asio::bind_cancellation_slot(signal.slot(),
bindns::bind(&compose_partial_cancellation_handler,
&count, &result, _1)));
signal.emit(asio::cancellation_type::terminal);
ioc.run();
ASIO_CHECK(ioc.stopped());
ASIO_CHECK(count == 1);
ASIO_CHECK(result == false);
}
ASIO_TEST_SUITE
(
"compose",
ASIO_TEST_CASE(compose_0_completion_args_test)
ASIO_TEST_CASE(compose_1_completion_arg_test)
ASIO_TEST_CASE(compose_default_cancellation_test)
ASIO_TEST_CASE(compose_partial_cancellation_test)
ASIO_TEST_CASE(compose_total_cancellation_test)
)