Skip to content

Commit

Permalink
Add support for multiple channel signatures with c++11.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriskohlhoff committed Nov 1, 2023
1 parent fe4fd7a commit 0fa8c68
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
83 changes: 83 additions & 0 deletions asio/include/asio/experimental/detail/channel_payload.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#if defined(ASIO_HAS_STD_VARIANT)
# include <variant>
#else // defined(ASIO_HAS_STD_VARIANT)
# include <new>
#endif // defined(ASIO_HAS_STD_VARIANT)

#include "asio/detail/push_options.hpp"
Expand Down Expand Up @@ -128,6 +130,87 @@ class channel_payload<R1(), R2(asio::error_code)>
bool empty_;
};

template <typename Sig1, typename Sig2>
class channel_payload<Sig1, Sig2>
{
public:
typedef channel_message<Sig1> message_1_type;
typedef channel_message<Sig2> message_2_type;

channel_payload(message_1_type&& m)
: index_(1)
{
new (&storage_.message_1_) message_1_type(static_cast<message_1_type&&>(m));
}

channel_payload(message_2_type&& m)
: index_(2)
{
new (&storage_.message_2_) message_2_type(static_cast<message_2_type&&>(m));
}

channel_payload(channel_payload&& other)
: index_(other.index_)
{
switch (index_)
{
case 1:
new (&storage_.message_1_) message_1_type(
static_cast<message_1_type&&>(other.storage_.message_1_));
break;
case 2:
new (&storage_.message_2_) message_2_type(
static_cast<message_2_type&&>(other.storage_.message_2_));
break;
default:
break;
}
}

~channel_payload()
{
switch (index_)
{
case 1:
storage_.message_1_.~message_1_type();
break;
case 2:
storage_.message_2_.~message_2_type();
break;
default:
break;
}
}

template <typename Handler>
void receive(Handler& handler)
{
switch (index_)
{
case 1:
storage_.message_1_.receive(handler);
break;
case 2:
storage_.message_2_.receive(handler);
break;
default:
break;
}
}

private:
union storage
{
storage() {}
~storage() {}

char dummy_;
message_1_type message_1_;
message_2_type message_2_;
} storage_;
unsigned char index_;
};

#endif // defined(ASIO_HAS_STD_VARIANT)

} // namespace detail
Expand Down
94 changes: 94 additions & 0 deletions asio/src/tests/unit/experimental/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,99 @@ void try_send_n_via_dispatch()
ASIO_CHECK(s3.empty());
}

struct multi_signature_handler
{
std::string* s_;
asio::error_code* ec_;

void operator()(std::string s)
{
*s_ = s;
}

void operator()(asio::error_code ec)
{
*ec_ = ec;
}
};

void implicit_error_signature_channel_test()
{
io_context ctx;

channel<void(std::string)> ch1(ctx);

ASIO_CHECK(ch1.is_open());
ASIO_CHECK(!ch1.ready());

bool b1 = ch1.try_send("hello");

ASIO_CHECK(!b1);

std::string s1 = "abcdefghijklmnopqrstuvwxyz";
bool b2 = ch1.try_send(std::move(s1));

ASIO_CHECK(!b2);
ASIO_CHECK(!s1.empty());

std::string s2;
asio::error_code ec1 = asio::error::would_block;
multi_signature_handler h1 = {&s2, &ec1};
ch1.async_receive(h1);

bool b3 = ch1.try_send(std::move(s1));

ASIO_CHECK(b3);
ASIO_CHECK(s1.empty());

ctx.run();

ASIO_CHECK(s2 == "abcdefghijklmnopqrstuvwxyz");
ASIO_CHECK(ec1 == asio::error::would_block);

std::string s3;
asio::error_code ec2;
multi_signature_handler h2 = {&s3, &ec2};
bool b4 = ch1.try_receive(h2);

ASIO_CHECK(!b4);

std::string s4 = "zyxwvutsrqponmlkjihgfedcba";
asio::error_code ec3;
ch1.async_send(std::move(s4),
[&](asio::error_code ec)
{
ec3 = ec;
});

std::string s5;
asio::error_code ec4 = asio::error::would_block;
multi_signature_handler h3 = {&s5, &ec4};
bool b5 = ch1.try_receive(h3);

ASIO_CHECK(b5);
ASIO_CHECK(ec4 == asio::error::would_block);
ASIO_CHECK(s5 == "zyxwvutsrqponmlkjihgfedcba");

ctx.restart();
ctx.run();

ASIO_CHECK(!ec3);

std::string s6;
asio::error_code ec5 = asio::error::would_block;
multi_signature_handler h4 = {&s6, &ec5};
ch1.async_receive(h4);

ch1.close();

ctx.restart();
ctx.run();

ASIO_CHECK(s6.empty());
ASIO_CHECK(ec5 == asio::experimental::channel_errc::channel_closed);
}

ASIO_TEST_SUITE
(
"experimental/channel",
Expand All @@ -753,4 +846,5 @@ ASIO_TEST_SUITE
ASIO_TEST_CASE(buffered_executor_send)
ASIO_TEST_CASE(try_send_via_dispatch)
ASIO_TEST_CASE(try_send_n_via_dispatch)
ASIO_TEST_CASE(implicit_error_signature_channel_test)
)

0 comments on commit 0fa8c68

Please sign in to comment.