From 0fa8c684c03381fdd76035cb8c79a64e0e99bd00 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 1 Nov 2023 21:37:13 +1100 Subject: [PATCH] Add support for multiple channel signatures with c++11. --- .../experimental/detail/channel_payload.hpp | 83 ++++++++++++++++ asio/src/tests/unit/experimental/channel.cpp | 94 +++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/asio/include/asio/experimental/detail/channel_payload.hpp b/asio/include/asio/experimental/detail/channel_payload.hpp index c9d89be8e8..e628b7eedb 100644 --- a/asio/include/asio/experimental/detail/channel_payload.hpp +++ b/asio/include/asio/experimental/detail/channel_payload.hpp @@ -22,6 +22,8 @@ #if defined(ASIO_HAS_STD_VARIANT) # include +#else // defined(ASIO_HAS_STD_VARIANT) +# include #endif // defined(ASIO_HAS_STD_VARIANT) #include "asio/detail/push_options.hpp" @@ -128,6 +130,87 @@ class channel_payload bool empty_; }; +template +class channel_payload +{ +public: + typedef channel_message message_1_type; + typedef channel_message message_2_type; + + channel_payload(message_1_type&& m) + : index_(1) + { + new (&storage_.message_1_) message_1_type(static_cast(m)); + } + + channel_payload(message_2_type&& m) + : index_(2) + { + new (&storage_.message_2_) message_2_type(static_cast(m)); + } + + channel_payload(channel_payload&& other) + : index_(other.index_) + { + switch (index_) + { + case 1: + new (&storage_.message_1_) message_1_type( + static_cast(other.storage_.message_1_)); + break; + case 2: + new (&storage_.message_2_) message_2_type( + static_cast(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 + 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 diff --git a/asio/src/tests/unit/experimental/channel.cpp b/asio/src/tests/unit/experimental/channel.cpp index 64f7dbb150..369ca4f894 100644 --- a/asio/src/tests/unit/experimental/channel.cpp +++ b/asio/src/tests/unit/experimental/channel.cpp @@ -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 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", @@ -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) )