diff --git a/include/etl/message_router.h b/include/etl/message_router.h index e08c8344..02942c8d 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -550,9 +550,158 @@ namespace etl } } }; +#elif ETL_USING_CPP14 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************************************* + // Unified C++11/14 variadic implementation (no fold expressions). + //************************************************************************************************* + template + class message_router : public imessage_router + { + public: + typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + + // Constructors (inherit public base ones) + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + using etl::imessage_router::receive; + + // Route by runtime message_id with pack expansion via initializer list. + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + const etl::message_id_t id = msg.get_message_id(); + bool handled = false; + +#include "etl/private/diagnostic_array_bounds_push.h" + // Expand across TMessageTypes... and attempt cast/dispatch on matching IDs. + int dummy[] = {0, (handled = handled || try_receive_one(id, msg), 0)...}; + (void)dummy; +#include "etl/private/diagnostic_pop.h" + + if (!handled) + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + static_cast(this)->on_receive_unknown(msg); + } + } + } + + // Overload for concrete message types; forwards to on_receive or successor. + template + typename etl::enable_if::value, void>::type + receive(const TMessage& msg) + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (is_in_message_set()) + { + static_cast(this)->on_receive(msg); + } + else + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + static_cast(this)->on_receive_unknown(msg); + } + } +#include "etl/private/diagnostic_pop.h" + } + + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + bool accepted = false; + int dummy[] = {0, (accepted = accepted || accepts_one(id), 0)...}; + (void)dummy; + if (!accepted) + { + if (has_successor()) + { + return get_successor().accepts(id); + } + } + return accepted; + } + + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE { return false; } + bool is_producer() const ETL_OVERRIDE { return true; } + bool is_consumer() const ETL_OVERRIDE { return true; } + + private: + // Helper: is T in the message set? + template + static ETL_CONSTEXPR bool is_in_message_set() + { + return etl::is_one_of::value; + } + + // Try to handle one type by ID match and cast. + template + bool try_receive_one(etl::message_id_t id, const etl::imessage& msg) + { + if (TMessage::ID == id) + { + static_cast(this)->on_receive(static_cast(msg)); + return true; + } + return false; + } + + // Accepts one type by ID + template + bool accepts_one(etl::message_id_t id) const + { + return TMessage::ID == id; + } + }; + + // Convenience bridge: allow message_router> + template + class message_router> + : public message_router + { + public: + typedef message_router base_type; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + + using base_type::base_type; // inherit constructors + }; #else //************************************************************************************************* -// For C++14 and below. +// For C++03. //************************************************************************************************* //*************************************************************************** // The definition for all 16 message types. @@ -2955,7 +3104,7 @@ namespace etl }; #endif -#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) template class message_router> : public message_router diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 899ae047..31b7776d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -234,6 +234,7 @@ add_executable(etl_tests test_message_bus.cpp test_message_packet.cpp test_message_router.cpp + test_message_router_with_type_list.cpp test_message_router_registry.cpp test_message_timer.cpp test_message_timer_atomic.cpp @@ -252,6 +253,7 @@ add_executable(etl_tests test_nth_type.cpp test_numeric.cpp test_observer.cpp + test_observer_with_type_list.cpp test_optional.cpp test_overload.cpp test_packet.cpp @@ -370,6 +372,7 @@ add_executable(etl_tests test_vector_pointer.cpp test_vector_pointer_external_buffer.cpp test_visitor.cpp + test_visitor_with_type_list.cpp test_xor_checksum.cpp test_xor_rotate_checksum.cpp ) diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index 01a4ca1f..ec02bdaf 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "data.h" #include "etl/tuple.h" +#include "etl/type_list.h" #include #include @@ -103,6 +104,15 @@ namespace CHECK_TRUE((std::is_same>::value)); } + //************************************************************************* + TEST(test_tuple_type_list) + { + using Tuple = etl::tuple; + using TupleTypes = etl::type_list; + + CHECK_TRUE((std::is_same::value)); + } + //************************************************************************* TEST(test_default_constructor) {