From c67c617d8c7a78aba872e3cbffafeae27c1593f5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 24 Dec 2025 20:01:38 +0000 Subject: [PATCH] Addedetl::type~_list to message_router, observer, visitor # Conflicts: # include/etl/observer.h # test/vs2022/etl.vcxproj.filters --- include/etl/message_router.h | 139 +++- include/etl/observer.h | 17 + include/etl/visitor.h | 36 + test/test_message_router_with_type_list.cpp | 741 +++++++++++++++++++ test/test_observer_with_type_list.cpp | 583 +++++++++++++++ test/test_visitor_with_type_list.cpp | 761 ++++++++++++++++++++ test/vs2022/etl.vcxproj | 3 + 7 files changed, 2279 insertions(+), 1 deletion(-) create mode 100644 test/test_message_router_with_type_list.cpp create mode 100644 test/test_observer_with_type_list.cpp create mode 100644 test/test_visitor_with_type_list.cpp diff --git a/include/etl/message_router.h b/include/etl/message_router.h index cc6ea40c..e08c8344 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -64,6 +64,7 @@ SOFTWARE. #include "placement_new.h" #include "successor.h" #include "type_traits.h" +#include "type_list.h" #include @@ -410,7 +411,8 @@ namespace etl { public: - typedef etl::message_packet message_packet; + using message_packet = etl::message_packet; + using type_list = etl::type_list; //********************************************** message_router() @@ -566,6 +568,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -717,6 +723,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -868,6 +878,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1018,6 +1032,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1166,6 +1184,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1313,6 +1335,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1459,6 +1485,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1604,6 +1634,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1747,6 +1781,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1889,6 +1927,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2029,6 +2071,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2168,6 +2214,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2305,6 +2355,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2441,6 +2495,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2576,6 +2634,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2710,6 +2772,10 @@ namespace etl typedef etl::message_packet< T1> message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2830,6 +2896,77 @@ namespace etl return true; } }; + + // Helper: select type at index I from a `type_list`, or `void` if out of range. + template + struct message_router_type_or_void + { + typedef typename etl::conditional<(I < etl::type_list_size::value), + etl::type_list_type_at_index, + etl::type_identity>::type::type type; + }; + + // For C++14 and below, map the `type_list` to up to 16 message type parameters (fill with `void`). + template + class message_router, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> + : public message_router>::type, + typename etl::message_router_type_or_void<1, etl::type_list>::type, + typename etl::message_router_type_or_void<2, etl::type_list>::type, + typename etl::message_router_type_or_void<3, etl::type_list>::type, + typename etl::message_router_type_or_void<4, etl::type_list>::type, + typename etl::message_router_type_or_void<5, etl::type_list>::type, + typename etl::message_router_type_or_void<6, etl::type_list>::type, + typename etl::message_router_type_or_void<7, etl::type_list>::type, + typename etl::message_router_type_or_void<8, etl::type_list>::type, + typename etl::message_router_type_or_void<9, etl::type_list>::type, + typename etl::message_router_type_or_void<10, etl::type_list>::type, + typename etl::message_router_type_or_void<11, etl::type_list>::type, + typename etl::message_router_type_or_void<12, etl::type_list>::type, + typename etl::message_router_type_or_void<13, etl::type_list>::type, + typename etl::message_router_type_or_void<14, etl::type_list>::type, + typename etl::message_router_type_or_void<15, etl::type_list>::type> + { + // Enforce the maximum number of message types supported by the C++14 implementation. + static_assert(sizeof...(TMessageTypes) <= 16, "etl::message_router supports up to 16 message types for C++14"); + + public: + using base = message_router>::type, + typename etl::message_router_type_or_void<1, etl::type_list>::type, + typename etl::message_router_type_or_void<2, etl::type_list>::type, + typename etl::message_router_type_or_void<3, etl::type_list>::type, + typename etl::message_router_type_or_void<4, etl::type_list>::type, + typename etl::message_router_type_or_void<5, etl::type_list>::type, + typename etl::message_router_type_or_void<6, etl::type_list>::type, + typename etl::message_router_type_or_void<7, etl::type_list>::type, + typename etl::message_router_type_or_void<8, etl::type_list>::type, + typename etl::message_router_type_or_void<9, etl::type_list>::type, + typename etl::message_router_type_or_void<10, etl::type_list>::type, + typename etl::message_router_type_or_void<11, etl::type_list>::type, + typename etl::message_router_type_or_void<12, etl::type_list>::type, + typename etl::message_router_type_or_void<13, etl::type_list>::type, + typename etl::message_router_type_or_void<14, etl::type_list>::type, + typename etl::message_router_type_or_void<15, etl::type_list>::type>; + + using base::base; // Inherit constructors + using typename base::message_packet; + using type_list = etl::type_list; + }; +#endif + +#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + template + class message_router> + : public message_router + { + public: + + using this_type = message_router>; + using base_type = message_router; + using type_list = etl::type_list; + using base_type::base_type; + }; #endif } diff --git a/include/etl/observer.h b/include/etl/observer.h index d722262b..d7a75776 100644 --- a/include/etl/observer.h +++ b/include/etl/observer.h @@ -321,6 +321,8 @@ namespace etl { public: + using type_list = etl::type_list; + virtual ~observer() = default; virtual void notification(T1) = 0; @@ -337,6 +339,8 @@ namespace etl { public: + using type_list = etl::type_list<>; + virtual ~observer() = default; virtual void notification() = 0; @@ -358,6 +362,19 @@ namespace etl using type_list = etl::type_list; }; + //***************************************************************** + /// The specialised observer class for etl::type_list. + ///\ingroup observer + //**************************************************************** + template + class observer> : public observer + { + public: + + using observer::observer; + using observer::notification; + }; + #else //********************************************************************* diff --git a/include/etl/visitor.h b/include/etl/visitor.h index 2975c678..941af701 100644 --- a/include/etl/visitor.h +++ b/include/etl/visitor.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" +#include "type_list.h" //***************************************************************************** ///\defgroup visitor visitor @@ -64,6 +65,7 @@ namespace etl using visitable::accept; using visitable::accept; + using type_list = etl::type_list; }; //***************************************************************** @@ -75,11 +77,30 @@ namespace etl { public: + using type_list = etl::type_list; + virtual ~visitable() = default; virtual void accept(T1&) = 0; }; + //***************************************************************** + /// The visitable class for an etl::type_list. + /// Expands the type_list into the existing variadic visitable. + ///\ingroup visitor + //***************************************************************** + template + class visitable> : public visitable + { + ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); + + public: + + using type_list = etl::type_list; + + using visitable::accept; + }; + #else //***************************************************************** @@ -187,6 +208,21 @@ namespace etl virtual void visit(T1) = 0; }; + //***************************************************************** + /// The visitor class for an etl::type_list. + /// Expands the type_list into the existing variadic visitor. + ///\ingroup visitor + //***************************************************************** + template + class visitor> : public visitor + { + ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); + + public: + + using visitor::visit; + }; + #else //***************************************************************** diff --git a/test/test_message_router_with_type_list.cpp b/test/test_message_router_with_type_list.cpp new file mode 100644 index 00000000..b997f59f --- /dev/null +++ b/test/test_message_router_with_type_list.cpp @@ -0,0 +1,741 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/message_router.h" +#include "etl/queue.h" +#include "etl/largest.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE0, + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1, + ROUTER2, + ROUTER3 + }; + + //*********************************** + struct NotInterface + { + virtual ~NotInterface() {} + virtual int VirtualFunction() const = 0; + }; + + ////*********************************** + // Uncomment to demonstrate static assert + //struct Message0 : public etl::message + //{ + //}; + + //*********************************** + struct Message1 : public etl::message + { + Message1(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message2 : public etl::message + { + Message2(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message3 : public etl::message + { + Message3(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + int value[10]; + }; + + //*********************************** + struct Message4 : public etl::message + { + Message4(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message5 : public etl::message + { + }; + + Message5 message5; + + using Router1Messages = etl::type_list; + using Router2Messages = etl::type_list; + using Router3Messages = etl::type_list; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. + //*************************************************************************** + class Router1 : public etl::message_router + { + public: + + Router1() + : message_router(ROUTER1), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(const Message1& msg) + { + ++message1_count; + etl::send_message(msg.callback, message5); + //CHECK_EQUAL(1, msg.VirtualFunction()); + } + + void on_receive(const Message2& msg) + { + ++message2_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message3& msg) + { + ++message3_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message4& msg) + { + ++message4_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message5&) + { + ++callback_count; + } + + void on_receive_unknown(const etl::imessage&) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class Router2 : public etl::message_router + { + public: + + Router2() + : message_router(ROUTER2), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0), + sender_id(0) + { + + } + + Router2(etl::imessage_router& successor_) + : message_router(ROUTER2, successor_), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0), + sender_id(0) + { + + } + + void on_receive(const Message1& msg) + { + ++message1_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + //CHECK_EQUAL(1, msg.VirtualFunction()); + } + + void on_receive(const Message2& msg) + { + ++message2_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message4& msg) + { + ++message4_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message5&) + { + ++callback_count; + } + + void on_receive_unknown(const etl::imessage&) + { + ++message_unknown_count; + sender_id = 0; + } + + int message1_count; + int message2_count; + int message4_count; + int message_unknown_count; + int callback_count; + int sender_id; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 3. + // 'receive' is overridden. + //*************************************************************************** + class Router3 : public etl::message_router + { + public: + + using base = etl::message_router; + + Router3() + : message_router(ROUTER3) + , message1_received(false) + , message2_received(false) + , message3_received(false) + , unknown_message_received(false) + { + } + + void receive(const etl::imessage& msg) override + { + switch (msg.get_message_id()) + { + case MESSAGE1: + { + message1_received = true; + break; + } + + case MESSAGE2: + { + message2_received = true; + break; + } + + case MESSAGE3: + { + message3_received = true; + break; + } + + default: + { + unknown_message_received = true; + break; + } + } + } + + void on_receive(const Message1&) + { + } + + void on_receive(const Message2&) + { + } + + void on_receive(const Message3&) + { + } + + void on_receive_unknown(const etl::imessage&) + { + } + + bool message1_received; + bool message2_received; + bool message3_received; + bool unknown_message_received; + }; + + etl::imessage_router* p_router; + + SUITE(test_message_router_with_type_list) + { + //************************************************************************* + TEST(message_router) + { + Router1 r1; + Router2 r2; + + p_router = &r1; + + Message1 message1(r2); + Message2 message2(r2); + Message3 message3(r2); + Message4 message4(r2); + + // CHECK(!r1.is_null_router()); + CHECK(r1.is_producer()); + CHECK(r1.is_consumer()); + + p_router->receive(message1); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(1, r2.callback_count); + + p_router->receive(message2); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(2, r2.callback_count); + + p_router->receive(message3); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(3, r2.callback_count); + + p_router->receive(message4); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(1, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(4, r2.callback_count); + } + + //************************************************************************* + TEST(message_null_router) + { + Router2 router; + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + // CHECK(null_router.is_null_router()); + CHECK(!null_router.is_producer()); + CHECK(!null_router.is_consumer()); + + // Send from the null router. + etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + // Send to the null router. + etl::send_message(null_router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //************************************************************************* + TEST(message_producer) + { + Router2 router; + etl::message_producer producer(ROUTER3); + + Message1 message1(producer); + Message2 message2(producer); + Message3 message3(producer); + Message4 message4(producer); + + // CHECK(!producer.is_null_router()); + CHECK(producer.is_producer()); + CHECK(!producer.is_consumer()); + + CHECK_EQUAL(0, router.sender_id); + + // Send from the producer. + router.receive(message1); + //etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + CHECK_EQUAL(0, router.sender_id); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + // Send to the producer. + etl::send_message(producer, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //************************************************************************* + TEST(message_router_accepts) + { + Router2 r2; + + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(!r2.accepts(message3)); + CHECK(!r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + + //************************************************************************* + TEST(message_router_accepts_successors) + { + Router1 r1; // M1, M2, M3, M4, M5 + Router2 r2; // M1, M2, M4, M5 + + r2.set_successor(r1); + + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(r2.accepts(message3)); + CHECK(r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + +#if ETL_HAS_VIRTUAL_MESSAGES + //************************************************************************* + TEST(message_router_queue) + { + Router1 r1; + Router2 r2; + + typedef Router2::message_packet Packet; + typedef etl::queue Queue; + + Queue queue; + + etl::imessage* im; + + Message1 message1(r1); + Message2 message2(r1); + Message3 message3(r1); + Message4 message4(r1); + + // Queue some messages in the message packet queue. + im = &message1; + queue.emplace(*im); + + im = &message2; + queue.emplace(*im); + + // The router2 queue doesn't accept Message3 types. + im = &message3; + CHECK_THROW(queue.emplace(*im), etl::unhandled_message_exception); + + im = &message4; + queue.emplace(*im); + + im = &message4; + queue.emplace(*im); + + etl::imessage& imr1 = queue.front().get(); + r2.receive(imr1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + queue.pop(); + + etl::imessage& imr2 = queue.front().get(); + r2.receive(imr2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + queue.pop(); + + const etl::imessage& imr3 = queue.front().get(); + r2.receive(imr3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + queue.pop(); + + const Queue& crqueue = queue; + const etl::imessage& imr4 = crqueue.front().get(); + r2.receive(imr4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(2, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + queue.pop(); + } +#endif + + //************************************************************************* + TEST(message_router_successor) + { + Router1 r1; + Router2 r2(r1); + + etl::null_message_router null_router; + + Message1 message1(r2); + Message2 message2(r2); + Message3 message3(r2); + Message4 message4(r2); + + etl::send_message(r2, message1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + etl::send_message(r2, message2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + r2.receive(message3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + etl::send_message(r2, message4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + } + + //************************************************************************* + TEST(message_router_with_overloaded_receive) + { + Router3 router; + + Message1 message1(router); + Message2 message2(router); + Message3 message3(router); + + router.receive(message1); + CHECK_TRUE(router.message1_received); + + router.receive(message2); + CHECK_TRUE(router.message2_received); + + router.receive(message3); + CHECK_TRUE(router.message3_received); + + CHECK_FALSE(router.unknown_message_received); + } + } +} diff --git a/test/test_observer_with_type_list.cpp b/test/test_observer_with_type_list.cpp new file mode 100644 index 00000000..e0b61f54 --- /dev/null +++ b/test/test_observer_with_type_list.cpp @@ -0,0 +1,583 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/observer.h" +#include "etl/type_list.h" + +#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + +namespace +{ + //***************************************************************************** + // Notification1 + //***************************************************************************** + struct Notification1 + { + }; + + //***************************************************************************** + // Notification2 + //***************************************************************************** + struct Notification2 + { + }; + + //***************************************************************************** + // Notification3 + //***************************************************************************** + struct Notification3 + { + }; + + //***************************************************************************** + // Generic notification. + //***************************************************************************** + template + struct Notification + { + }; + + //***************************************************************************** + // The observer base type. + // Declare what notifications you want to observe and how they are passed to 'notification'. + // The Notification1 is passed by value. + // The Notification2 is passed by reference. + // The Notification3 is passed by const reference. + //***************************************************************************** + using NotificationTypes = etl::type_list; + using ObserverType = etl::observer; + + //***************************************************************************** + // The observer base type that does not take a notification type. + //***************************************************************************** + typedef etl::observer ObserverVoidIntType; +} + +//***************************************************************************** +// The concrete observable 1 class. +//***************************************************************************** +class Observable1 : public etl::observable +{ +public: + + Notification1 data1; + Notification2 data2; + Notification1& data3 = data1; + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(data3); + notify_observers(data2); + } +}; + +//***************************************************************************** +// The concrete observable 2 class. +//***************************************************************************** +class Observable2 : public etl::observable +{ +public: + + Notification3 data3; + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(data3); + } +}; + +//***************************************************************************** +// The concrete observable 3 class. +//***************************************************************************** +class ObservableVoidInt : public etl::observable +{ +public: + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(); + } + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications(int n) + { + notify_observers(n); + } +}; + +//***************************************************************************** +// The first observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class Observer1 : public ObserverType +{ +public: + + Observer1() + : data1_count(0) + , data2_count(0) + , data3_count(0) + { + } + + //******************************************* + // Notification1 is passed by value. + //******************************************* + void notification(Notification1 /*data1*/) + { + ++data1_count; + } + + //******************************************* + // Notification2 is passed by reference. + //******************************************* + void notification(Notification2& /*data2*/) + { + ++data2_count; + } + + //******************************************* + // Notification3 is passed by const reference. + //******************************************* + void notification(const Notification3& /*data3*/) + { + ++data3_count; + } + + int data1_count; + int data2_count; + int data3_count; +}; + +//***************************************************************************** +// The second observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class Observer2 : public ObserverType +{ +public: + + Observer2() + : data1_count(0) + , data2_count(0) + , data3_count(0) + { + } + + //******************************************* + // Notification1 is passed by value. + //******************************************* + void notification(Notification1 /*data1*/) + { + ++data1_count; + } + + //******************************************* + // Notification2 is passed by reference. + //******************************************* + void notification(Notification2& /*data2*/) + { + ++data2_count; + } + + //******************************************* + // Notification3 is passed by const reference. + //******************************************* + void notification(const Notification3& /*data3*/) + { + ++data3_count; + } + + int data1_count; + int data2_count; + int data3_count; +}; + +//***************************************************************************** +// The third observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class ObserverVoidInt : public ObserverVoidIntType +{ +public: + + ObserverVoidInt() + : data1_count(0) + , data2_count(0) + { + } + + //******************************************* + // Notification1 + //******************************************* + void notification() override + { + ++data1_count; + } + + //******************************************* + // Notification2 + //******************************************* + void notification(int) override + { + ++data2_count; + } + + int data1_count; + int data2_count; +}; + +namespace +{ + SUITE(test_observer) + { + //************************************************************************* + TEST(test_2_observables_2_observers_3_notifications) + { + // The observable objects. + Observable1 observable1; + Observable2 observable2; + + // The observer objects. + Observer1 observer1; + Observer2 observer2; + + observable1.add_observer(observer1); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(0, observer2.data1_count); + CHECK_EQUAL(0, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. observeable2 has no observers yet. + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(0, observer2.data1_count); + CHECK_EQUAL(0, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + // Add an observer to both. + observable1.add_observer(observer2); + observable2.add_observer(observer2); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(1, observer2.data1_count); + CHECK_EQUAL(1, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(1, observer2.data1_count); + CHECK_EQUAL(1, observer2.data2_count); + CHECK_EQUAL(1, observer2.data3_count); + + observable1.remove_observer(observer1); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(2, observer2.data1_count); + CHECK_EQUAL(2, observer2.data2_count); + CHECK_EQUAL(1, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(2, observer2.data1_count); + CHECK_EQUAL(2, observer2.data2_count); + CHECK_EQUAL(2, observer2.data3_count); + } + + //************************************************************************* + TEST(test_observable_2_observers_enable_disable) + { + // The observable objects. + Observable1 observable1; + + // The observer objects. + Observer1 observer1; + Observer2 observer2; + + observable1.add_observer(observer1); + observable1.add_observer(observer2); + + // Send the notifications. + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer2.data1_count); + + // Disable observer1. Send the notifications. + observable1.disable_observer(observer1); + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Disable observer2. Send the notifications. + observable1.enable_observer(observer2, false); + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Enable observer1. Send the notifications. + observable1.enable_observer(observer1); + observable1.send_notifications(); + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Enable observer2. Send the notifications. + observable1.enable_observer(observer2, true); + observable1.send_notifications(); + + CHECK_EQUAL(3, observer1.data1_count); + CHECK_EQUAL(3, observer2.data1_count); + } + + //************************************************************************* + TEST(test_8_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7>, Notification<8> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_7_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_6_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_5_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_notifications) + { + typedef etl::observer, Notification<2>, Notification<3> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_notifications) + { + typedef etl::observer, Notification<2> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_1_notification) + { + typedef etl::observer > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_observer_list) + { + class Observer : public etl::observer + { + void notification(Notification1) {} + }; + + class Observable : public etl::observable + { + }; + + Observable observable; + + Observer observer1; + Observer observer2; + Observer observer3; + Observer observer4; + Observer observer5; + + observable.add_observer(observer1); + CHECK_EQUAL(1UL, observable.number_of_observers()); + + observable.add_observer(observer2); + CHECK_EQUAL(2UL, observable.number_of_observers()); + + observable.add_observer(observer3); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.add_observer(observer2); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.add_observer(observer4); + CHECK_EQUAL(4UL, observable.number_of_observers()); + + CHECK_THROW(observable.add_observer(observer5), etl::observer_list_full); + + CHECK(observable.remove_observer(observer3)); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + // Try again. + CHECK(!observable.remove_observer(observer3)); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.clear_observers(); + CHECK_EQUAL(0UL, observable.number_of_observers()); + } + + //************************************************************************* + TEST(test_void_int_observable) + { + // The observable objects. + ObservableVoidInt observable; + + // The observer objects. + ObserverVoidInt observer; + + observable.add_observer(observer); + + // Send the notifications. + observable.send_notifications(); + CHECK_EQUAL(1U, observer.data1_count); + CHECK_EQUAL(0U, observer.data2_count); + + observable.send_notifications(1); + CHECK_EQUAL(1U, observer.data1_count); + CHECK_EQUAL(1U, observer.data2_count); + } + } +} + + +#endif + diff --git a/test/test_visitor_with_type_list.cpp b/test/test_visitor_with_type_list.cpp new file mode 100644 index 00000000..04660ee9 --- /dev/null +++ b/test/test_visitor_with_type_list.cpp @@ -0,0 +1,761 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/visitor.h" + +#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + +//***************************************************************************** +// Pre-declare the data types. +//***************************************************************************** +class Square; +class Circle; +class Triangle; + +//***************************************************************************** +// What classes do you want the visitors to handle? +// Square will be passed by reference. +// Circle will be passed by reference. +// Triangle will be passed by const reference. +//***************************************************************************** +using DrawTypes = etl::type_list; +using DrawVisitorType = etl::visitor; + +//***************************************************************************** +// What classes do you want the visitors to handle? +// Square will be passed by reference. +// Triangle will be passed by const reference. +//***************************************************************************** +using LogTypes = etl::type_list; +using LogVisitorType = etl::visitor; + +//***************************************************************************** +// Base shape. +//***************************************************************************** +using VisitorTypes = etl::type_list; + +class ShapeBase : public etl::visitable +{ +}; + +//***************************************************************************** +// Square accepts draw & log visitors. +//***************************************************************************** +class Square : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType& visitor) + { + visitor.visit(*this); + } +}; + +//***************************************************************************** +// Circle only accepts draw visitors. +//***************************************************************************** +class Circle : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType&) + { + } +}; + +//***************************************************************************** +// Triangle accepts draw & log visitors. +//***************************************************************************** +class Triangle : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType& visitor) + { + visitor.visit(*this); + } +}; + + +//***************************************************************************** +// Generic other shapes. +//***************************************************************************** +template +class Shape : public etl::visitable +{ +public: + + void accept(TVisitor& visitor) + { + visitor.visit(*this); + } +}; + +//***************************************************************************** +class DrawVisitor : public DrawVisitorType +{ +public: + + DrawVisitor() + : square_called(false), + circle_called(false), + triangle_called(false) + { + } + + void visit(Square&) + { + square_called = true; + } + + void visit(Circle&) + { + circle_called = true; + } + + void visit(const Triangle&) + { + triangle_called = true; + } + + bool square_called; + bool circle_called; + bool triangle_called; +}; + +//***************************************************************************** +class LogVisitor : public LogVisitorType +{ +public: + + LogVisitor() + : square_called(false), + circle_called(false), + triangle_called(false) + { + } + + void visit(Square&) + { + square_called = true; + } + + // SHOULD NEVER BE CALLED. + void visit(Circle&) + { + circle_called = true; + } + + void visit(const Triangle&) + { + triangle_called = true; + } + + bool square_called; + bool circle_called; + bool triangle_called; +}; + +namespace +{ + SUITE(test_visitor) + { + //************************************************************************* + TEST(test_two_visitors_three_visitables) + { + DrawVisitor draw_visitor; + LogVisitor log_visitor; + + Square square; + Circle circle; + Triangle triangle; + + ShapeBase* pShapeBase; + + CHECK_EQUAL(false, draw_visitor.square_called); + CHECK_EQUAL(false, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(false, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + square.accept(draw_visitor); + square.accept(log_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(false, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + circle.accept(draw_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(true, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + pShapeBase = ▵ + pShapeBase->accept(draw_visitor); + pShapeBase->accept(log_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(true, draw_visitor.circle_called); + CHECK_EQUAL(true, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(true, log_visitor.triangle_called); + } + + //************************************************************************* + TEST(test_1_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor3 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + void accept(ShapeVisitor3&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor3 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor4 : public etl::visitor + { + void visit(AShape&) {} + }; + + using ShapeVisitorTypes = etl::type_list; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + void accept(ShapeVisitor3&) {} + void accept(ShapeVisitor4&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_1_visitable) + { + class ShapeVisitor : public etl::visitor > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_5_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_6_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_7_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_8_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_9_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_10_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + + //************************************************************************* + TEST(test_11_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_12_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_13_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_14_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_15_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + void visit(Shape<15, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_16_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor>, Shape<16, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + void visit(Shape<15, ShapeVisitor>) {} + void visit(Shape<16, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + struct NotVisitor {}; + + TEST(test_is_visitor) + { +#if ETL_USING_CPP17 + CHECK_TRUE(etl::is_visitor_v); + CHECK_TRUE(etl::is_visitor_v); + CHECK_FALSE(etl::is_visitor_v); +#else + CHECK_TRUE(etl::is_visitor::value); + CHECK_TRUE(etl::is_visitor::value); + CHECK_FALSE(etl::is_visitor::value); +#endif + } + } +} + +#endif + diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 6396b761..09056bad 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -10357,9 +10357,11 @@ + + @@ -11433,6 +11435,7 @@ +