Addedetl::type~_list to message_router, observer, visitor

# Conflicts:
#	include/etl/observer.h
#	test/vs2022/etl.vcxproj.filters
This commit is contained in:
John Wellbelove 2025-12-24 20:01:38 +00:00
parent 1c0d7a87de
commit c67c617d8c
7 changed files with 2279 additions and 1 deletions

View File

@ -64,6 +64,7 @@ SOFTWARE.
#include "placement_new.h"
#include "successor.h"
#include "type_traits.h"
#include "type_list.h"
#include <stdint.h>
@ -410,7 +411,8 @@ namespace etl
{
public:
typedef etl::message_packet<TMessageTypes...> message_packet;
using message_packet = etl::message_packet<TMessageTypes...>;
using type_list = etl::type_list<TMessageTypes...>;
//**********************************************
message_router()
@ -566,6 +568,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -717,6 +723,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -868,6 +878,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1018,6 +1032,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1166,6 +1184,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1313,6 +1335,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1459,6 +1485,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1604,6 +1634,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8, T9> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8, T9>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1747,6 +1781,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7, T8> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7, T8>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -1889,6 +1927,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6, T7> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6, T7>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -2029,6 +2071,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5, T6> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5, T6>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -2168,6 +2214,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4, T5> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4, T5>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -2305,6 +2355,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3, T4> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3, T4>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -2441,6 +2495,10 @@ namespace etl
typedef etl::message_packet<T1, T2, T3> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2, T3>;
#endif
//**********************************************
message_router(etl::message_router_id_t id_)
: imessage_router(id_)
@ -2576,6 +2634,10 @@ namespace etl
typedef etl::message_packet<T1, T2> message_packet;
#if ETL_USING_CPP11
using type_list = etl::type_list<T1, T2>;
#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<T1>;
#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 <size_t I, typename TList>
struct message_router_type_or_void
{
typedef typename etl::conditional<(I < etl::type_list_size<TList>::value),
etl::type_list_type_at_index<TList, I>,
etl::type_identity<void>>::type::type type;
};
// For C++14 and below, map the `type_list` to up to 16 message type parameters (fill with `void`).
template <typename TDerived, typename... TMessageTypes>
class message_router<TDerived, etl::type_list<TMessageTypes...>, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void>
: public message_router<TDerived,
typename etl::message_router_type_or_void<0, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<1, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<2, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<3, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<4, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<5, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<6, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<7, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<8, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<9, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<10, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<11, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<12, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<13, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<14, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<15, etl::type_list<TMessageTypes...>>::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<TDerived,
typename etl::message_router_type_or_void<0, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<1, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<2, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<3, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<4, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<5, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<6, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<7, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<8, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<9, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<10, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<11, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<12, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<13, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<14, etl::type_list<TMessageTypes...>>::type,
typename etl::message_router_type_or_void<15, etl::type_list<TMessageTypes...>>::type>;
using base::base; // Inherit constructors
using typename base::message_packet;
using type_list = etl::type_list<TMessageTypes...>;
};
#endif
#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
template <typename TDerived, typename... TMessageTypes>
class message_router<TDerived, etl::type_list<TMessageTypes...>>
: public message_router<TDerived, TMessageTypes...>
{
public:
using this_type = message_router<TDerived, etl::type_list<TMessageTypes...>>;
using base_type = message_router<TDerived, TMessageTypes...>;
using type_list = etl::type_list<TMessageTypes...>;
using base_type::base_type;
};
#endif
}

View File

@ -321,6 +321,8 @@ namespace etl
{
public:
using type_list = etl::type_list<T1>;
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<TTypes...>;
};
//*****************************************************************
/// The specialised observer class for etl::type_list.
///\ingroup observer
//****************************************************************
template <typename... TTypes>
class observer<etl::type_list<TTypes...>> : public observer<TTypes...>
{
public:
using observer<TTypes...>::observer;
using observer<TTypes...>::notification;
};
#else
//*********************************************************************

View File

@ -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<T1>::accept;
using visitable<Types...>::accept;
using type_list = etl::type_list<T1, Types...>;
};
//*****************************************************************
@ -75,11 +77,30 @@ namespace etl
{
public:
using type_list = etl::type_list<T1>;
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 <typename... TTypes>
class visitable<etl::type_list<TTypes...>> : public visitable<TTypes...>
{
ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty");
public:
using type_list = etl::type_list<TTypes...>;
using visitable<TTypes...>::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 <typename... TTypes>
class visitor<etl::type_list<TTypes...>> : public visitor<TTypes...>
{
ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty");
public:
using visitor<TTypes...>::visit;
};
#else
//*****************************************************************

View File

@ -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<MESSAGE0, NotInterface>
//{
//};
//***********************************
struct Message1 : public etl::message<MESSAGE1>
{
Message1(etl::imessage_router& callback_)
: callback(callback_)
{
}
etl::imessage_router& callback;
};
//***********************************
struct Message2 : public etl::message<MESSAGE2>
{
Message2(etl::imessage_router& callback_)
: callback(callback_)
{
}
etl::imessage_router& callback;
};
//***********************************
struct Message3 : public etl::message<MESSAGE3>
{
Message3(etl::imessage_router& callback_)
: callback(callback_)
{
}
etl::imessage_router& callback;
int value[10];
};
//***********************************
struct Message4 : public etl::message<MESSAGE4>
{
Message4(etl::imessage_router& callback_)
: callback(callback_)
{
}
etl::imessage_router& callback;
};
//***********************************
struct Message5 : public etl::message<MESSAGE5>
{
};
Message5 message5;
using Router1Messages = etl::type_list<Message1, Message2, Message3, Message4, Message5>;
using Router2Messages = etl::type_list<Message1, Message2, Message4, Message5>;
using Router3Messages = etl::type_list<Message1, Message2, Message3>;
//***************************************************************************
// Router that handles messages 1, 2, 3, 4 and 5 and returns nothing.
//***************************************************************************
class Router1 : public etl::message_router<Router1, Router1Messages>
{
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<Router2, Router2Messages>
{
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<Router3, Router3Messages>
{
public:
using base = etl::message_router<Router3, Router3Messages>;
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<Packet, 4> 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);
}
}
}

View File

@ -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 <const int ID>
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<Notification1, Notification2&, const Notification3&>;
using ObserverType = etl::observer<NotificationTypes>;
//*****************************************************************************
// The observer base type that does not take a notification type.
//*****************************************************************************
typedef etl::observer<void, int> ObserverVoidIntType;
}
//*****************************************************************************
// The concrete observable 1 class.
//*****************************************************************************
class Observable1 : public etl::observable<ObserverType, 2>
{
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<ObserverType, 2>
{
public:
Notification3 data3;
//*********************************
// Notify all of the observers.
//*********************************
void send_notifications()
{
notify_observers(data3);
}
};
//*****************************************************************************
// The concrete observable 3 class.
//*****************************************************************************
class ObservableVoidInt : public etl::observable<ObserverVoidIntType, 2>
{
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<1>, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7>, Notification<8> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_7_notifications)
{
typedef etl::observer<Notification<1>, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_6_notifications)
{
typedef etl::observer<Notification<1>, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_5_notifications)
{
typedef etl::observer<Notification<1>, Notification<2>, Notification<3>, Notification<4>, Notification<5> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_4_notifications)
{
typedef etl::observer<Notification<1>, Notification<2>, Notification<3>, Notification<4> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_3_notifications)
{
typedef etl::observer<Notification<1>, Notification<2>, Notification<3> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_2_notifications)
{
typedef etl::observer<Notification<1>, Notification<2> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_1_notification)
{
typedef etl::observer<Notification<1> > Observer;
class Observable : public etl::observable<Observer, 1>
{
};
// This test just needs to compile without errors.
CHECK(true);
}
//*************************************************************************
TEST(test_observer_list)
{
class Observer : public etl::observer<Notification1>
{
void notification(Notification1) {}
};
class Observable : public etl::observable<Observer, 4>
{
};
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

View File

@ -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<Square&, Circle&, const Triangle&>;
using DrawVisitorType = etl::visitor<DrawTypes>;
//*****************************************************************************
// 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<Square&, const Triangle&>;
using LogVisitorType = etl::visitor<LogTypes>;
//*****************************************************************************
// Base shape.
//*****************************************************************************
using VisitorTypes = etl::type_list<DrawVisitorType, LogVisitorType>;
class ShapeBase : public etl::visitable<VisitorTypes>
{
};
//*****************************************************************************
// 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 <const int ID, typename TVisitor>
class Shape : public etl::visitable<TVisitor>
{
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 = &triangle;
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<AShape&>
{
void visit(AShape&) {}
};
class AShape : public etl::visitable<ShapeVisitor1>
{
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<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor2 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
class AShape : public etl::visitable<ShapeVisitor1, ShapeVisitor2>
{
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<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor2 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor3 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
class AShape : public etl::visitable<ShapeVisitor1, ShapeVisitor2, ShapeVisitor3>
{
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<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor2 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor3 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
class ShapeVisitor4 : public etl::visitor<AShape&>
{
void visit(AShape&) {}
};
using ShapeVisitorTypes = etl::type_list<ShapeVisitor1, ShapeVisitor2, ShapeVisitor3, ShapeVisitor4>;
class AShape : public etl::visitable<ShapeVisitorTypes>
{
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 <Shape<1, ShapeVisitor> >
{
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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<1, ShapeVisitor>, 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<DrawVisitor>);
CHECK_TRUE(etl::is_visitor_v<LogVisitor>);
CHECK_FALSE(etl::is_visitor_v<NotVisitor>);
#else
CHECK_TRUE(etl::is_visitor<DrawVisitor>::value);
CHECK_TRUE(etl::is_visitor<LogVisitor>::value);
CHECK_FALSE(etl::is_visitor<NotVisitor>::value);
#endif
}
}
}
#endif

View File

@ -10357,9 +10357,11 @@
<ClCompile Include="..\test_math_functions.cpp" />
<ClCompile Include="..\test_message.cpp" />
<ClCompile Include="..\test_message_broker.cpp" />
<ClCompile Include="..\test_message_router_with_type_list.cpp" />
<ClCompile Include="..\test_not_null_pointer.cpp" />
<ClCompile Include="..\test_not_null_pointer_constexpr.cpp" />
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
<ClCompile Include="..\test_observer_with_type_list.cpp" />
<ClCompile Include="..\test_poly_span_dynamic_extent.cpp" />
<ClCompile Include="..\test_poly_span_fixed_extent.cpp" />
<ClCompile Include="..\test_pseudo_moving_average.cpp" />
@ -11433,6 +11435,7 @@
<ClCompile Include="..\test_vector_pointer_external_buffer.cpp" />
<ClCompile Include="..\test_visitor.cpp" />
<ClCompile Include="..\test_string_stream_wchar_t.cpp" />
<ClCompile Include="..\test_visitor_with_type_list.cpp" />
<ClCompile Include="..\test_xor_checksum.cpp" />
<ClCompile Include="..\test_xor_rotate_checksum.cpp" />
<ClCompile Include="..\unittest++\AssertException.cpp" />