mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Enforce worse-case O(log n) dispatch for messages when using message router for c++11 and up (#1312)
* Added compare_message_id * Added new C++11 and up message routing code using a sorted type_list * Renamed compare_message)id to compare_message_id_less * Added documenation for compare_message_id_less Added static asserts for message type template parameters * Added optimisation for contiguous message IDs Added more Doxygen documentation * Added etl::type_list_all_of, etl::type_list_any_of, and etl::type_list_none_of * Added etl::type_list_is_unique * Added common definitions to all router types * Added static_asserts to check message types * Added etl::type_list to etl::nth_type * Added missing 'typename' to type_list nth_type * Added type_list_is_empty * indentation fix * Renamed type_list_prepend & type_list_append to type_list_push_front & type_list_push_back respectively * Added tests for make_index_sequence & make_index_sequence_with_offset * Add more features to etl::type_list (#1307) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Added etl::type_list to etl::observer * Added etl::type_list to etl::nth_type * Added missing 'typename' to type_list nth_type * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Added type_list definitions for nth_type and observer * Added etl::type_list to etl::variant * Updated comments * Addedetl::type~_list to message_router, observer, visitor # Conflicts: # include/etl/observer.h # test/vs2022/etl.vcxproj.filters * Added member type_list type to tuple * Work in progress * Copy changes from other source * Removed unused tests * Fix iter_swap namespace * Add type_list functionality to etl::variant using etl::variant_from_type_list * Add type_list functionality to etl::message_packet using etl::message_packet_from_type_list * Add type_list functionality to etl::message_router using etl::message_router_from_type_list * Add type_list functionality to etl::observer using etl::observer_from_type_list * Add type_list functionality to etl::tuple using etl::tuple_from_type_list * Allow etl::make_index_sequence to be created from an etl::type_list * Add type_list functionality to etl::visitor using etl::visitor_from_type_list * Fix iter_swap namespace * Allow creation of a message_packet with no message types * Allow creation of a message_router with no message types * Updated VS2022 project files * Added missing test files CMakeLists.txt * Fix C++03 compatibility Fixed unused aregument warnings * Synced message_packet generator to updated code * Synced message_router generator to updated code * Synced message_router generator to updated code # Conflicts: # include/etl/generators/message_router_generator.h # include/etl/message_router.h * Fixed missing zero message specialisation for <= C++14 * Fixed missing zero message specialisation for <= C++14 * Fix year_month arithmetic and correct chrono API behavior (#1257) * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Restore default constructor behavior for chrono calender * Suppress warnings from std in optimized builds (#1259) When testing with ./run-tests.sh 23 3 10, some warnings from std surfaced which resulted in build errors. * Add template deduction guide for span from vector (#1264) * Create span from vector deduction * Use ivector for deduction. Add vector_ext to test * Add vector pointer to test * Finish tests * Initialize pdata_ext and others * Document how to implement platform specifics (#1262) Some interfaces need to be implemented in every project or platform using the ETL: * etl_get_high_resolution_clock * etl_get_system_clock * etl_get_steady_clock * etl_putchar Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Fix etl::as_bytes for etl::span<const T> (#1266) A missing 'const' in the etl::as_bytes implementation was causing a compile-time error when etl::as_bytes was called on a span of const values. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Remove some UB in test_vector_non_trivial.cpp (#1268) Some of the tests' UB are detectable by Gcc15 and thus give a compile error due to warnings-as-error flag. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Update C++26 deprecated constructs to ensure future standard compliance (#1267) * Update C++26 deprecated constructs to ensure future standard compliance I replaced std::is_trivial with a combination of std::is_trivially_default_constructible and std::is_trivially_copyable. Additionally, I added the required comma before the ellipsis in variadic functions to match updated language specifications. * Some additional is_trivial related changes not found directly when compiling tests in C++26 --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Fix return value of get_token_list (#1271) Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Fix etl::tuple template signature error in pair assignment operator (#1265) * Fix etl::tuple template signature error in pair assignment operator * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update etl::tuple to explicitly use etl::pair or std::pair in assignment operator * Added tests for etl::tuple assignment from pair --------- Co-authored-by: Bryton Flecker <bflecker@swe.com> Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Remove advance() on static spans (#1281) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Remove advance() on static spans Since the size of a static span is constant, we can't reasonably advance() on it. --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Add missing includes (#1286) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Add missing includes Before this change, the includes needed to be done explicitly by files using basic_string_stream.h, and be included first. This was error prone, especially if includes are reordered (e.g. via the currently defined clang-format rules). --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Move comparison operators of etl::expected to namespace etl (#1287) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Move comparison operators of etl::expected to namespace etl --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Make typed_storage constructor constexpr (#1291) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Make typed_storage constructor constexpr --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Add basic_format_arg constructor for ibasic_string (#1288) * Allow string as format arg * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Added test string escaped * Add temporary string test --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * QR Code for Github * Added etl::visitor_from_type_list * accepts(id) for empty router passes on to a sucessor * Fixed incorrect comment from 'tuple' to 'message_router' * PR review changes * PR review changes * Fixed internal constexptr flag in message_packet * Fixed unused variable in unti test * Added new type_list features Added make_index_sequence_with_offset * Renamed type_list_select_from_sequence to type_list_select_from_index_sequence * Replaced type_list_size<TTypeList>::value with TTypeList::size internally for better clarity. * Added etl::type_list_remove, etl::type_list_remove_if, etl::type_list_unique, etl::type_list_pop_front, etl::type_list_pop_back * Add ref-qualifiers to basic_format_spec (#1292) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * feat: use ref-qualifiers for basic_format_spec Converted the l-value methods to ref-qualified and also added r-value ref-qualified methods. --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Add support for size_t and unsigned long to etl::format (#1290) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Add support for size_t and unsigned long to etl::format * Document list of supported types in etl::supported_format_types * Add further types and tests for etl::format --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> Co-authored-by: Sergei <sergej.shirokov@gmail.com> * Deduce underlying storage size when constructing string_ext from char[]. (#1269) * Deduce underlying storage size when constructing string_ext from char[]. This removes the need for passing sizeof(storage) to the constructor. * Add array constructors for the other string types. - u16string_ext - u32string_ext - u8string_ext - wstring_ext * Add additional constructors to match existing API. * Fix inconsistent test argument order. --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Added etl::type_list_all_of, etl::type_list_any_of, and etl::type_list_none_of * Added etl::type_list_is_unique * Added type_list_is_empty * indentation fix * Fix merge error * Renamed type_list_prepend & type_list_append to type_list_push_front & type_list_push_back respectively * Added tests for make_index_sequence & make_index_sequence_with_offset * Resolve coderabbit review issues * Resolve coderabbit review issues * Resolve coderabbit review issues * Resolve coderabbit review issues * Added etl::type_list_indices_of_type which create an etl::index_sequence of all of the indexes of a specified type in an etl::type_list * Updated comments * Resolve coderabbit review issues Added index_sequence utility to support type_list utilities. Added additional index_sequence utilities for completeness * Added etl::index_sequence_cat, etl::index_sequence_pop_front, etl::index_sequence_pop_back, etl::index_sequence_at * Fix 'unused variable' error in index_sequence tests --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.co.uk> Co-authored-by: Sergei <sergej.shirokov@gmail.com> Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: Bo Rydberg <2945606+bolry@users.noreply.github.com> Co-authored-by: Roland Reichwein <Roland.Reichwein@bmw.de> Co-authored-by: Mike Bloom <91038685+mike919192@users.noreply.github.com> Co-authored-by: taltenbach <92919739+taltenbach@users.noreply.github.com> Co-authored-by: Bryton Flecker <fleckerbr@gmail.com> Co-authored-by: Bryton Flecker <bflecker@swe.com> Co-authored-by: Drew Rife <drew.rife95@gmail.com> Co-authored-by: Marco Nilsson <marco@zyax.se> * Moved O(1)/O(logN) index search test to get_dispatch_index_from_message_id Updated message_router generator * Fixed C++03 compatibilty * Replaced is_base_of with is_message * Missing 'return' in chrono example * Fixed doxygen comments * Check message inherits from etl::message<> * Copilot & coderabbit review changes Check for no duplicated message IDs Added diagnostic disable Make Message_Id_Start an etl::message_id_t type * Synchronised message_router_generator.h * Modified the "All message IDs must be unique" static_assert to directly use the index_sequence of message IDs Added addition index_sequence utilities to support this change. * Changed Router1 definition to use unordered message ids to check message sorting in message_router * Added has_message_id and compare_message_id_less to message.h * Moved member type definitions to a traits class message_packet, message_types, sorted_message_types * Sync message_router_generator to changes * Fixed C++03 compatibility --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.co.uk> Co-authored-by: Sergei <sergej.shirokov@gmail.com> Co-authored-by: Bo Rydberg <2945606+bolry@users.noreply.github.com> Co-authored-by: Roland Reichwein <Roland.Reichwein@bmw.de> Co-authored-by: Mike Bloom <91038685+mike919192@users.noreply.github.com> Co-authored-by: taltenbach <92919739+taltenbach@users.noreply.github.com> Co-authored-by: Bryton Flecker <fleckerbr@gmail.com> Co-authored-by: Bryton Flecker <bflecker@swe.com> Co-authored-by: Drew Rife <drew.rife95@gmail.com> Co-authored-by: Marco Nilsson <marco@zyax.se>
This commit is contained in:
parent
e439963258
commit
7ef01fcaed
@ -228,7 +228,7 @@ extern "C"
|
||||
|
||||
etl::chrono::high_resolution_clock::rep etl_get_high_resolution_clock()
|
||||
{
|
||||
etl::chrono::high_resolution_clock::rep(static_cast<int64_t>(getSystemTimeNs()));
|
||||
return etl::chrono::high_resolution_clock::rep(static_cast<int64_t>(getSystemTimeNs()));
|
||||
}
|
||||
|
||||
etl::chrono::system_clock::rep etl_get_system_clock()
|
||||
|
||||
@ -77,6 +77,8 @@ cog.outl("//********************************************************************
|
||||
#include "successor.h"
|
||||
#include "type_traits.h"
|
||||
#include "type_list.h"
|
||||
#include "array.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace etl
|
||||
@ -107,6 +109,53 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
namespace private_message_router
|
||||
{
|
||||
//***************************************************************************
|
||||
// Traits for a message router.
|
||||
// message packet type
|
||||
// message type_list
|
||||
// sorted message type_list.
|
||||
//***************************************************************************
|
||||
template <typename... TMessageTypes>
|
||||
class traits
|
||||
{
|
||||
#if ETL_USING_CPP11
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
|
||||
|
||||
public:
|
||||
|
||||
using message_packet = etl::message_packet<TMessageTypes...>;
|
||||
using message_types = etl::type_list<TMessageTypes...>;
|
||||
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
|
||||
|
||||
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
|
||||
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
|
||||
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
// Specialisation of traits for no message types.
|
||||
// message packet type
|
||||
// message type_list
|
||||
// sorted message type_list.
|
||||
//***************************************************************************
|
||||
template <>
|
||||
class traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
using message_packet = etl::message_packet<>;
|
||||
using message_types = etl::type_list<>;
|
||||
using sorted_message_types = etl::type_list<>;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Forward declare null message router functionality.
|
||||
//***************************************************************************
|
||||
@ -200,6 +249,7 @@ namespace etl
|
||||
/// This router can be used as a sink for messages or a 'null source' router.
|
||||
//***************************************************************************
|
||||
class null_message_router : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
@ -278,6 +328,7 @@ namespace etl
|
||||
/// This router can be used as a producer-only of messages, such an interrupt routine.
|
||||
//***************************************************************************
|
||||
class message_producer : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
@ -411,31 +462,40 @@ namespace etl
|
||||
}
|
||||
|
||||
//*************************************************************************************************
|
||||
// For C++17 and above.
|
||||
// For C++11 and above.
|
||||
//*************************************************************************************************
|
||||
#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
//***************************************************************************
|
||||
// The definition for all message types.
|
||||
//***************************************************************************
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
class message_router : public imessage_router
|
||||
, public private_message_router::traits<TMessageTypes...>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef etl::message_packet<TMessageTypes...> message_packet;
|
||||
using typename private_message_router::traits<TMessageTypes...>::message_packet;
|
||||
using typename private_message_router::traits<TMessageTypes...>::message_types;
|
||||
using typename private_message_router::traits<TMessageTypes...>::sorted_message_types;
|
||||
|
||||
//**********************************************
|
||||
/// Default constructor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router()
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with successor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router(etl::imessage_router& successor_)
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_)
|
||||
: imessage_router(id_)
|
||||
@ -443,6 +503,8 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id and successor.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
|
||||
: imessage_router(id_, successor_)
|
||||
@ -450,15 +512,36 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class receive() methods.
|
||||
//**********************************************
|
||||
using etl::imessage_router::receive;
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for all messages passed as an etl::imessage.
|
||||
/// It will dispatch the message to the correct handler based on the message id,
|
||||
/// or pass it to a successor if there is no handler for the message id.
|
||||
/// \param msg The message.
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
const bool was_handled = (receive_message_type<TMessageTypes>(msg) || ...);
|
||||
etl::message_id_t id = msg.get_message_id();
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
if (!was_handled)
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
}
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
dispatch(msg, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
@ -472,34 +555,75 @@ namespace etl
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value, int>::type = 0>
|
||||
//**********************************************
|
||||
/// This will be called for messages where TMessage is in the message type list.
|
||||
/// \tparam TMessage The message type.
|
||||
/// \param msg The message.
|
||||
/// Enabled if TMessage is in the message type list.
|
||||
//**********************************************
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
if constexpr (etl::is_one_of<TMessage, TMessageTypes...>::value)
|
||||
{
|
||||
static_cast<TDerived*>(this)->on_receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
}
|
||||
}
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for messages where TMessage is a message type, but not in the message type list.
|
||||
/// \tparam TMessage The message type.
|
||||
/// \param msg The message.
|
||||
/// Enabled if TMessage is a message type, but not in the message type list.
|
||||
//**********************************************
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_message<TMessage>::value &&
|
||||
!etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class accepts() methods.
|
||||
//**********************************************
|
||||
using imessage_router::accepts;
|
||||
|
||||
//**********************************************
|
||||
/// This will return true if the message id is in the message type list, or if a successor accepts the message id.
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
return (accepts_type<TMessageTypes>(id) || ...);
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
}
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************
|
||||
@ -522,68 +646,183 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool receive_message_type(const etl::imessage& msg)
|
||||
{
|
||||
if (TMessage::ID == msg.get_message_id())
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive(static_cast<const TMessage&>(msg));
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
|
||||
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool accepts_type(etl::message_id_t id) const
|
||||
//**********************************************
|
||||
// Checks that the message ids are contiguous.
|
||||
//**********************************************
|
||||
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
|
||||
struct contiguous_impl;
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, true> : etl::true_type
|
||||
{
|
||||
if (TMessage::ID == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, false>
|
||||
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
|
||||
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
|
||||
contiguous_impl<Index + 1U>::value>
|
||||
{
|
||||
};
|
||||
|
||||
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
|
||||
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
|
||||
|
||||
using handler_ptr = void (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
|
||||
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
|
||||
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
|
||||
|
||||
//**********************************************
|
||||
// Call for a single message type
|
||||
//**********************************************
|
||||
template <typename TMessage>
|
||||
static void call_on_receive(TDerived& derived, const imessage& msg)
|
||||
{
|
||||
derived.on_receive(static_cast<const TMessage&>(msg));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the handler for a single message type at the index in the sorted type_list.
|
||||
// This will be called for each message type to generate the dispatch table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr handler_ptr get_message_handler()
|
||||
{
|
||||
return &call_on_receive<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the dispatch table at compile time.
|
||||
// This will create an array of handler pointers, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the message id for a single message type at an index in the sorted type_list.
|
||||
// This will be called for each message type to generate the message id table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr etl::message_id_t get_message_id_from_index()
|
||||
{
|
||||
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the message id table at compile time.
|
||||
// This will create an array of message ids, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the dispatch index for a message id.
|
||||
// This will be used at runtime to find the handler for a message id.
|
||||
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
|
||||
// This will return Number_Of_Messages if the message id is not found, which indicates that the message should be passed to the successor.
|
||||
//**********************************************
|
||||
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
|
||||
{
|
||||
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
|
||||
{
|
||||
// The IDs are contiguous, so we can calculate the index directly.
|
||||
return static_cast<size_t>(id - Message_Id_Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The IDs are not contiguous, so we need to do a binary search.
|
||||
size_t left = 0;
|
||||
size_t right = Number_Of_Messages;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
size_t mid = (left + right) / 2;
|
||||
|
||||
if (message_id_table[mid] == id)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (message_id_table[mid] < id)
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Number_Of_Messages; // Not found
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
|
||||
//**********************************************
|
||||
void dispatch(const etl::imessage& msg, size_t index)
|
||||
{
|
||||
message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
|
||||
etl::message_router<TDerived, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::message_router<TDerived, TMessageTypes...>::Number_Of_Messages>{});
|
||||
|
||||
//**********************************************
|
||||
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
|
||||
etl::message_router<TDerived, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::message_router<TDerived, TMessageTypes...>::Number_Of_Messages>{});
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11 && !ETL_USING_CPP17
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
constexpr const typename etl::message_router<TDerived, TMessageTypes...>::message_dispatch_table_t
|
||||
etl::message_router<TDerived, TMessageTypes...>::message_dispatch_table;
|
||||
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
constexpr const typename etl::message_router<TDerived, TMessageTypes...>::message_id_table_t
|
||||
etl::message_router<TDerived, TMessageTypes...>::message_id_table;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
// The definition for 0 message types.
|
||||
// The definition of a message_router for zero message types.
|
||||
//***************************************************************************
|
||||
template <typename TDerived>
|
||||
class message_router<TDerived> : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
using message_packet = etl::message_packet<>;
|
||||
using message_types = etl::type_list<>;
|
||||
|
||||
//**********************************************
|
||||
/// Default constructor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router()
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with successor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router(etl::imessage_router& successor_)
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_)
|
||||
: imessage_router(id_)
|
||||
@ -591,6 +830,8 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id and successor.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
|
||||
: imessage_router(id_, successor_)
|
||||
@ -599,19 +840,16 @@ namespace etl
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class receive() methods.
|
||||
using etl::imessage_router::receive;
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for all messages passed as an etl::imessage.
|
||||
/// Since there are no message types, this will just pass the message to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
/// \param msg The message.
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
if (has_successor())
|
||||
{
|
||||
@ -620,9 +858,14 @@ namespace etl
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class accepts() methods.
|
||||
//**********************************************
|
||||
using imessage_router::accepts;
|
||||
|
||||
//**********************************************
|
||||
/// This will return true if a successor accepts the message id.
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
if (has_successor())
|
||||
@ -656,6 +899,7 @@ namespace etl
|
||||
|
||||
//***************************************************************************
|
||||
/// Helper to turn etl::type_list<TTypes...> into etl::message_router<TTypes...>
|
||||
//***************************************************************************
|
||||
template <typename TDerived, typename TList>
|
||||
struct message_router_from_type_list;
|
||||
|
||||
@ -670,7 +914,7 @@ namespace etl
|
||||
|
||||
#else
|
||||
//*************************************************************************************************
|
||||
// For C++14 and below.
|
||||
// For C++03/98.
|
||||
//*************************************************************************************************
|
||||
/*[[[cog
|
||||
import cog
|
||||
@ -687,6 +931,8 @@ namespace etl
|
||||
if n % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
else:
|
||||
cog.out(" ")
|
||||
cog.outl("typename T%s = void>" % int(Handlers))
|
||||
cog.out("class message_router")
|
||||
cog.outl(" : public imessage_router")
|
||||
@ -764,7 +1010,7 @@ namespace etl
|
||||
cog.outl(" }")
|
||||
cog.outl("")
|
||||
cog.outl(" template <typename TMessage>")
|
||||
cog.out(" typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, ")
|
||||
cog.out(" typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("T%s, " % n)
|
||||
cog.outl("T%s>::value, void>::type" % int(Handlers))
|
||||
@ -776,7 +1022,7 @@ namespace etl
|
||||
cog.outl(" }")
|
||||
cog.outl("")
|
||||
cog.outl(" template <typename TMessage>")
|
||||
cog.out(" typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, ")
|
||||
cog.out(" typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("T%s, " % n)
|
||||
cog.outl("T%s>::value, void>::type" % int(Handlers))
|
||||
@ -859,6 +1105,8 @@ namespace etl
|
||||
if t % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
else:
|
||||
cog.out(" ")
|
||||
cog.outl("typename T%d>" % n)
|
||||
cog.out("class message_router<TDerived, ")
|
||||
for t in range(1, n + 1):
|
||||
@ -947,7 +1195,7 @@ namespace etl
|
||||
cog.outl(" }")
|
||||
cog.outl("")
|
||||
cog.outl(" template <typename TMessage>")
|
||||
cog.out(" typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, ")
|
||||
cog.out(" typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, ")
|
||||
for t in range(1, n):
|
||||
cog.out("T%s, " % t)
|
||||
cog.outl("T%s>::value, void>::type" % n)
|
||||
@ -959,7 +1207,7 @@ namespace etl
|
||||
cog.outl(" }")
|
||||
cog.outl("")
|
||||
cog.outl(" template <typename TMessage>")
|
||||
cog.out(" typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, ")
|
||||
cog.out(" typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, ")
|
||||
for t in range(1, n):
|
||||
cog.out("T%s, " % t)
|
||||
cog.outl("T%s>::value, void>::type" % n)
|
||||
@ -990,6 +1238,7 @@ namespace etl
|
||||
cog.out(" case T%d::ID:" % t)
|
||||
if t % 8 == 0:
|
||||
cog.outl("")
|
||||
if t != n:
|
||||
cog.out(" ")
|
||||
cog.outl("")
|
||||
cog.outl(" return true;")
|
||||
|
||||
@ -263,6 +263,106 @@ namespace etl
|
||||
template <typename T>
|
||||
inline constexpr bool is_user_message_base_v = is_user_message_base<T>::value;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Detects presence of a static ID member.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
struct has_message_id
|
||||
{
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT(etl::is_message<T>::value, "T is not an ETL message");
|
||||
|
||||
typedef char yes;
|
||||
struct no { char value[2]; };
|
||||
|
||||
template <typename U>
|
||||
static yes test(char (*)[sizeof(&U::ID)]);
|
||||
|
||||
template <typename>
|
||||
static no test(...);
|
||||
|
||||
public:
|
||||
|
||||
static const bool value = sizeof(test<typename etl::remove_cv<T>::type>(0)) == sizeof(yes);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const bool has_message_id<T>::value;
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
template <typename T>
|
||||
inline constexpr bool has_message_id_v = has_message_id<T>::value;
|
||||
#endif
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
namespace private_message
|
||||
{
|
||||
template <typename TMsg1, typename TMsg2, bool HasIDs>
|
||||
struct compare_message_id_less_impl;
|
||||
|
||||
//**********************************************
|
||||
// Compare the message ID of two messages.
|
||||
// \tparam TMsg1 The first message type.
|
||||
// \tparam TMsg2 The second message type.
|
||||
// Only selected if both TMsg1 or TMsg2 don't have an ID.
|
||||
//**********************************************
|
||||
template <typename TMsg1, typename TMsg2>
|
||||
struct compare_message_id_less_impl<TMsg1, TMsg2, false>
|
||||
{
|
||||
ETL_STATIC_ASSERT(etl::has_message_id<TMsg1>::value, "TMsg1 does not have an ID");
|
||||
ETL_STATIC_ASSERT(etl::has_message_id<TMsg2>::value, "TMsg2 does not have an ID");
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg1>::value, "TMsg1 is not derived from etl::message<>");
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg2>::value, "TMsg2 is not derived from etl::message<>");
|
||||
};
|
||||
|
||||
//**********************************************
|
||||
// Compare the message ID of two messages.
|
||||
// \tparam TMsg1 The first message type.
|
||||
// \tparam TMsg2 The second message type.
|
||||
// value is true if TMsg1::ID < TMsg2::ID.
|
||||
// Only selected if both TMsg1 and TMsg2 have an ID.
|
||||
//***********************************************
|
||||
template <typename TMsg1, typename TMsg2>
|
||||
struct compare_message_id_less_impl<TMsg1, TMsg2, true>
|
||||
: etl::bool_constant < TMsg1::ID < TMsg2::ID>
|
||||
{
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg1>::value, "TMsg1 is not derived from etl::message<>");
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg2>::value, "TMsg2 is not derived from etl::message<>");
|
||||
};
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Compare the message ID of two messages.
|
||||
/// \tparam TMsg1 The first message type.
|
||||
/// \tparam TMsg2 The second message type.
|
||||
/// value is true if TMsg1::ID < TMsg2::ID.
|
||||
//**********************************************
|
||||
template <typename TMsg1, typename TMsg2>
|
||||
struct compare_message_id_less : public private_message::compare_message_id_less_impl<TMsg1, TMsg2, has_message_id<TMsg1>::value && has_message_id<TMsg2>::value>
|
||||
{
|
||||
};
|
||||
#else
|
||||
//**********************************************
|
||||
/// Compare the message ID of two messages.
|
||||
/// \tparam TMsg1 The first message type.
|
||||
/// \tparam TMsg2 The second message type.
|
||||
/// value is true if TMsg1::ID < TMsg2::ID.
|
||||
//**********************************************
|
||||
template <typename TMsg1, typename TMsg2>
|
||||
struct compare_message_id_less
|
||||
: etl::bool_constant<TMsg1::ID < TMsg2::ID>
|
||||
{
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg1>::value, "TMsg1 is not derived from etl::message<>");
|
||||
ETL_STATIC_ASSERT(etl::is_message_type<TMsg2>::value, "TMsg2 is not derived from etl::message<>");
|
||||
};
|
||||
#endif
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
template <typename TMsg1, typename TMsg2>
|
||||
inline constexpr bool compare_message_id_less_v = compare_message_id_less<TMsg1, TMsg2>::value;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -65,6 +65,8 @@ SOFTWARE.
|
||||
#include "successor.h"
|
||||
#include "type_traits.h"
|
||||
#include "type_list.h"
|
||||
#include "array.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace etl
|
||||
@ -95,6 +97,53 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
namespace private_message_router
|
||||
{
|
||||
//***************************************************************************
|
||||
// Traits for a message router.
|
||||
// message packet type
|
||||
// message type_list
|
||||
// sorted message type_list.
|
||||
//***************************************************************************
|
||||
template <typename... TMessageTypes>
|
||||
class traits
|
||||
{
|
||||
#if ETL_USING_CPP11
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
|
||||
|
||||
public:
|
||||
|
||||
using message_packet = etl::message_packet<TMessageTypes...>;
|
||||
using message_types = etl::type_list<TMessageTypes...>;
|
||||
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
|
||||
|
||||
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
|
||||
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
|
||||
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
// Specialisation of traits for no message types.
|
||||
// message packet type
|
||||
// message type_list
|
||||
// sorted message type_list.
|
||||
//***************************************************************************
|
||||
template <>
|
||||
class traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
using message_packet = etl::message_packet<>;
|
||||
using message_types = etl::type_list<>;
|
||||
using sorted_message_types = etl::type_list<>;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Forward declare null message router functionality.
|
||||
//***************************************************************************
|
||||
@ -188,6 +237,7 @@ namespace etl
|
||||
/// This router can be used as a sink for messages or a 'null source' router.
|
||||
//***************************************************************************
|
||||
class null_message_router : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
@ -266,6 +316,7 @@ namespace etl
|
||||
/// This router can be used as a producer-only of messages, such an interrupt routine.
|
||||
//***************************************************************************
|
||||
class message_producer : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
@ -399,31 +450,40 @@ namespace etl
|
||||
}
|
||||
|
||||
//*************************************************************************************************
|
||||
// For C++17 and above.
|
||||
// For C++11 and above.
|
||||
//*************************************************************************************************
|
||||
#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
//***************************************************************************
|
||||
// The definition for all message types.
|
||||
//***************************************************************************
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
class message_router : public imessage_router
|
||||
, public private_message_router::traits<TMessageTypes...>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef etl::message_packet<TMessageTypes...> message_packet;
|
||||
using typename private_message_router::traits<TMessageTypes...>::message_packet;
|
||||
using typename private_message_router::traits<TMessageTypes...>::message_types;
|
||||
using typename private_message_router::traits<TMessageTypes...>::sorted_message_types;
|
||||
|
||||
//**********************************************
|
||||
/// Default constructor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router()
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with successor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router(etl::imessage_router& successor_)
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_)
|
||||
: imessage_router(id_)
|
||||
@ -431,6 +491,8 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id and successor.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
|
||||
: imessage_router(id_, successor_)
|
||||
@ -438,15 +500,36 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class receive() methods.
|
||||
//**********************************************
|
||||
using etl::imessage_router::receive;
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for all messages passed as an etl::imessage.
|
||||
/// It will dispatch the message to the correct handler based on the message id,
|
||||
/// or pass it to a successor if there is no handler for the message id.
|
||||
/// \param msg The message.
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
const bool was_handled = (receive_message_type<TMessageTypes>(msg) || ...);
|
||||
etl::message_id_t id = msg.get_message_id();
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
if (!was_handled)
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
}
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
dispatch(msg, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
@ -460,34 +543,75 @@ namespace etl
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value, int>::type = 0>
|
||||
//**********************************************
|
||||
/// This will be called for messages where TMessage is in the message type list.
|
||||
/// \tparam TMessage The message type.
|
||||
/// \param msg The message.
|
||||
/// Enabled if TMessage is in the message type list.
|
||||
//**********************************************
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
if constexpr (etl::is_one_of<TMessage, TMessageTypes...>::value)
|
||||
{
|
||||
static_cast<TDerived*>(this)->on_receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
}
|
||||
}
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for messages where TMessage is a message type, but not in the message type list.
|
||||
/// \tparam TMessage The message type.
|
||||
/// \param msg The message.
|
||||
/// Enabled if TMessage is a message type, but not in the message type list.
|
||||
//**********************************************
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_message<TMessage>::value &&
|
||||
!etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class accepts() methods.
|
||||
//**********************************************
|
||||
using imessage_router::accepts;
|
||||
|
||||
//**********************************************
|
||||
/// This will return true if the message id is in the message type list, or if a successor accepts the message id.
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
return (accepts_type<TMessageTypes>(id) || ...);
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
}
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************
|
||||
@ -510,68 +634,183 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool receive_message_type(const etl::imessage& msg)
|
||||
{
|
||||
if (TMessage::ID == msg.get_message_id())
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive(static_cast<const TMessage&>(msg));
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
|
||||
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool accepts_type(etl::message_id_t id) const
|
||||
//**********************************************
|
||||
// Checks that the message ids are contiguous.
|
||||
//**********************************************
|
||||
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
|
||||
struct contiguous_impl;
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, true> : etl::true_type
|
||||
{
|
||||
if (TMessage::ID == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, false>
|
||||
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
|
||||
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
|
||||
contiguous_impl<Index + 1U>::value>
|
||||
{
|
||||
};
|
||||
|
||||
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
|
||||
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
|
||||
|
||||
using handler_ptr = void (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
|
||||
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
|
||||
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
|
||||
|
||||
//**********************************************
|
||||
// Call for a single message type
|
||||
//**********************************************
|
||||
template <typename TMessage>
|
||||
static void call_on_receive(TDerived& derived, const imessage& msg)
|
||||
{
|
||||
derived.on_receive(static_cast<const TMessage&>(msg));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the handler for a single message type at the index in the sorted type_list.
|
||||
// This will be called for each message type to generate the dispatch table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr handler_ptr get_message_handler()
|
||||
{
|
||||
return &call_on_receive<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the dispatch table at compile time.
|
||||
// This will create an array of handler pointers, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the message id for a single message type at an index in the sorted type_list.
|
||||
// This will be called for each message type to generate the message id table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr etl::message_id_t get_message_id_from_index()
|
||||
{
|
||||
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the message id table at compile time.
|
||||
// This will create an array of message ids, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the dispatch index for a message id.
|
||||
// This will be used at runtime to find the handler for a message id.
|
||||
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
|
||||
// This will return Number_Of_Messages if the message id is not found, which indicates that the message should be passed to the successor.
|
||||
//**********************************************
|
||||
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
|
||||
{
|
||||
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
|
||||
{
|
||||
// The IDs are contiguous, so we can calculate the index directly.
|
||||
return static_cast<size_t>(id - Message_Id_Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The IDs are not contiguous, so we need to do a binary search.
|
||||
size_t left = 0;
|
||||
size_t right = Number_Of_Messages;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
size_t mid = (left + right) / 2;
|
||||
|
||||
if (message_id_table[mid] == id)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (message_id_table[mid] < id)
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Number_Of_Messages; // Not found
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
|
||||
//**********************************************
|
||||
void dispatch(const etl::imessage& msg, size_t index)
|
||||
{
|
||||
message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
|
||||
etl::message_router<TDerived, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::message_router<TDerived, TMessageTypes...>::Number_Of_Messages>{});
|
||||
|
||||
//**********************************************
|
||||
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
|
||||
etl::message_router<TDerived, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::message_router<TDerived, TMessageTypes...>::Number_Of_Messages>{});
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11 && !ETL_USING_CPP17
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
constexpr const typename etl::message_router<TDerived, TMessageTypes...>::message_dispatch_table_t
|
||||
etl::message_router<TDerived, TMessageTypes...>::message_dispatch_table;
|
||||
|
||||
template <typename TDerived, typename... TMessageTypes>
|
||||
constexpr const typename etl::message_router<TDerived, TMessageTypes...>::message_id_table_t
|
||||
etl::message_router<TDerived, TMessageTypes...>::message_id_table;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
// The definition for 0 message types.
|
||||
// The definition of a message_router for zero message types.
|
||||
//***************************************************************************
|
||||
template <typename TDerived>
|
||||
class message_router<TDerived> : public imessage_router
|
||||
, public private_message_router::traits<>
|
||||
{
|
||||
public:
|
||||
|
||||
using message_packet = etl::message_packet<>;
|
||||
using message_types = etl::type_list<>;
|
||||
|
||||
//**********************************************
|
||||
/// Default constructor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router()
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with successor. The message router id will be MESSAGE_ROUTER.
|
||||
//**********************************************
|
||||
message_router(etl::imessage_router& successor_)
|
||||
: imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
|
||||
{
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_)
|
||||
: imessage_router(id_)
|
||||
@ -579,6 +818,8 @@ namespace etl
|
||||
ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Constructor with message router id and successor.
|
||||
//**********************************************
|
||||
message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
|
||||
: imessage_router(id_, successor_)
|
||||
@ -587,19 +828,16 @@ namespace etl
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class receive() methods.
|
||||
using etl::imessage_router::receive;
|
||||
|
||||
//**********************************************
|
||||
/// This will be called for all messages passed as an etl::imessage.
|
||||
/// Since there are no message types, this will just pass the message to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
/// \param msg The message.
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TMessage, typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value, int>::type = 0>
|
||||
void receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
if (has_successor())
|
||||
{
|
||||
@ -608,9 +846,14 @@ namespace etl
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
/// Allow visibility of base class accepts() methods.
|
||||
//**********************************************
|
||||
using imessage_router::accepts;
|
||||
|
||||
//**********************************************
|
||||
/// This will return true if a successor accepts the message id.
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
if (has_successor())
|
||||
@ -644,6 +887,7 @@ namespace etl
|
||||
|
||||
//***************************************************************************
|
||||
/// Helper to turn etl::type_list<TTypes...> into etl::message_router<TTypes...>
|
||||
//***************************************************************************
|
||||
template <typename TDerived, typename TList>
|
||||
struct message_router_from_type_list;
|
||||
|
||||
@ -658,7 +902,7 @@ namespace etl
|
||||
|
||||
#else
|
||||
//*************************************************************************************************
|
||||
// For C++14 and below.
|
||||
// For C++03/98.
|
||||
//*************************************************************************************************
|
||||
//***************************************************************************
|
||||
// The definition for all 16 message types.
|
||||
@ -747,7 +991,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -756,7 +1000,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -901,7 +1145,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -910,7 +1154,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1055,7 +1299,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1064,7 +1308,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1208,7 +1452,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1217,7 +1461,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1359,7 +1603,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1368,7 +1612,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1509,7 +1753,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1518,7 +1762,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1658,7 +1902,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1667,7 +1911,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1806,7 +2050,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1815,7 +2059,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -1952,7 +2196,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -1961,7 +2205,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7, T8>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2097,7 +2341,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2106,7 +2350,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6, T7>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2240,7 +2484,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2249,7 +2493,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5, T6>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2382,7 +2626,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4, T5>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2391,7 +2635,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4, T5>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2522,7 +2766,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3, T4>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2531,7 +2775,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3, T4>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2661,7 +2905,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2, T3>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2670,7 +2914,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2, T3>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2799,7 +3043,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1, T2>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1, T2>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2808,7 +3052,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1, T2>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1, T2>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
@ -2936,7 +3180,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && etl::is_one_of<TMessage, T1>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && etl::is_one_of<TMessage, T1>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
@ -2945,7 +3189,7 @@ namespace etl
|
||||
}
|
||||
|
||||
template <typename TMessage>
|
||||
typename etl::enable_if<etl::is_base_of<imessage, TMessage>::value && !etl::is_one_of<TMessage, T1>::value, void>::type
|
||||
typename etl::enable_if<etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, T1>::value, void>::type
|
||||
receive(const TMessage& msg)
|
||||
{
|
||||
if (has_successor())
|
||||
|
||||
@ -762,6 +762,112 @@ namespace etl
|
||||
template <typename TIndexSequence, size_t Nth>
|
||||
inline constexpr size_t index_sequence_at_v = index_sequence_at<TIndexSequence, Nth>::value;
|
||||
#endif
|
||||
|
||||
//************************************
|
||||
/// Checks if an index_sequence contains a value.
|
||||
//************************************
|
||||
template <typename TIndexSequence, size_t Value>
|
||||
struct index_sequence_contains;
|
||||
|
||||
// An empty sequence does not contain any value.
|
||||
template <size_t Value>
|
||||
struct index_sequence_contains<etl::index_sequence<>, Value> : etl::false_type
|
||||
{
|
||||
};
|
||||
|
||||
// When the front index of the sequence is the value, the sequence contains the value.
|
||||
// When the front index of the sequence is not the value, recurse with the tail of the sequence.
|
||||
template <size_t Index, size_t... Indices, size_t Value>
|
||||
struct index_sequence_contains<etl::index_sequence<Index, Indices...>, Value>
|
||||
: etl::integral_constant<bool, (Index == Value) || index_sequence_contains<etl::index_sequence<Indices...>, Value>::value>
|
||||
{
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
template <typename TIndexSequence, size_t Value>
|
||||
inline constexpr bool index_sequence_contains_v = index_sequence_contains<TIndexSequence, Value>::value;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Defines a new index_sequence by removing duplicate indexes from a given index_sequence, preserving the first occurrence.
|
||||
//***************************************************************************
|
||||
namespace private_index_sequence
|
||||
{
|
||||
template <typename TIndexSequence, typename TUniqueIndices>
|
||||
struct type_index_sequence_impl;
|
||||
|
||||
// When the front index of the sequence is not in the unique sequence, add it to the back of the unique sequence and recurse with the tail of the sequence.
|
||||
template <size_t Index, size_t... Indices, size_t... UniqueIndices>
|
||||
struct type_index_sequence_impl<etl::index_sequence<Index, Indices...>, etl::index_sequence<UniqueIndices...>>
|
||||
{
|
||||
// If the index is already in the unique sequence, do not add it again. Otherwise, add it to the back of the unique sequence.
|
||||
using type = typename etl::conditional_t<etl::index_sequence_contains<etl::index_sequence<UniqueIndices...>, Index>::value,
|
||||
type_index_sequence_impl<etl::index_sequence<Indices...>, etl::index_sequence<UniqueIndices...>>,
|
||||
type_index_sequence_impl<etl::index_sequence<Indices...>, etl::index_sequence_push_back_t<etl::index_sequence<UniqueIndices...>, Index>>>::type;
|
||||
};
|
||||
|
||||
// When the sequence is empty, the unique sequence is the result.
|
||||
template <size_t... UniqueIndices>
|
||||
struct type_index_sequence_impl<etl::index_sequence<>, etl::index_sequence<UniqueIndices...>>
|
||||
{
|
||||
using type = etl::index_sequence<UniqueIndices...>;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct index_sequence_unique;
|
||||
|
||||
template <size_t... Indices>
|
||||
struct index_sequence_unique<etl::index_sequence<Indices...>>
|
||||
{
|
||||
using type = typename private_index_sequence::type_index_sequence_impl<etl::index_sequence<Indices...>, etl::index_sequence<>>::type;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TIndexSequence>
|
||||
using index_sequence_unique_t = typename etl::index_sequence_unique<TIndexSequence>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Checks that all of the indices in an index_sequence are unique.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
struct index_sequence_is_unique;
|
||||
|
||||
template <size_t... Indices>
|
||||
struct index_sequence_is_unique<etl::index_sequence<Indices...>>
|
||||
: etl::bool_constant<etl::is_same<etl::index_sequence<Indices...>,
|
||||
etl::index_sequence_unique_t<etl::index_sequence<Indices...>>>::value>
|
||||
{
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
template <typename TIndexSequence>
|
||||
inline constexpr bool index_sequence_is_unique_v = index_sequence_is_unique<TIndexSequence>::type::value;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Checks if the index_sequence is empty.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
struct index_sequence_is_empty;
|
||||
|
||||
template <>
|
||||
struct index_sequence_is_empty<etl::index_sequence<>>
|
||||
: etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t... Indices>
|
||||
struct index_sequence_is_empty<etl::index_sequence<Indices...>>
|
||||
: etl::false_type
|
||||
{
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
template <typename... TTypes>
|
||||
inline constexpr bool index_sequence_is_empty_v = index_sequence_is_empty<TTypes...>::value;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
|
||||
@ -129,4 +129,40 @@ SUITE(test_message)
|
||||
CHECK_FALSE((std::is_same<MessageBase, Message1::base_type>::value));
|
||||
CHECK_FALSE((std::is_same<etl::imessage, Message2::base_type>::value));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_has_message_id)
|
||||
{
|
||||
struct Message1 : public etl::message<1> {};
|
||||
struct Message2 : public etl::message<2> {};
|
||||
struct MessageNoID : public etl::imessage {};
|
||||
|
||||
CHECK_TRUE(etl::has_message_id<Message1>::value);
|
||||
CHECK_TRUE(etl::has_message_id<Message2>::value);
|
||||
CHECK_FALSE(etl::has_message_id<MessageNoID>::value);
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
CHECK_TRUE(etl::has_message_id_v<Message1>);
|
||||
CHECK_TRUE(etl::has_message_id_v<Message2>);
|
||||
CHECK_FALSE(etl::has_message_id_v<MessageNoID>);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_message_compare_message_id)
|
||||
{
|
||||
struct Message1 : public etl::message<1> {};
|
||||
struct Message2 : public etl::message<2> {};
|
||||
struct MessageNoID : public etl::imessage {};
|
||||
|
||||
CHECK_TRUE((etl::compare_message_id_less<Message1, Message2>::value));
|
||||
CHECK_FALSE((etl::compare_message_id_less<Message2, Message1>::value));
|
||||
|
||||
// CHECK_FALSE((etl::compare_message_id_less<Message1, MessageNoID>::value)); // Uncomment to trigger static assert.
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
CHECK_TRUE((etl::compare_message_id_less_v<Message1, Message2>));
|
||||
CHECK_FALSE((etl::compare_message_id_less_v<Message2, Message1>));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,10 +138,10 @@ namespace
|
||||
// Created from a type list.
|
||||
//***************************************************************************
|
||||
#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
using Router1Messages = etl::type_list<Message1, Message2, Message3, Message4, Message5>;
|
||||
using Router1Messages = etl::type_list<Message5, Message3, Message2, Message4, Message1>;
|
||||
class Router1 : public etl::message_router_from_type_list_t<Router1, Router1Messages>
|
||||
#else
|
||||
class Router1 : public etl::message_router<Router1, Message1, Message2, Message3, Message4, Message5>
|
||||
class Router1 : public etl::message_router<Router1, Message5, Message3, Message2, Message4, Message1>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
@ -397,6 +397,32 @@ namespace
|
||||
CHECK_EQUAL(4, r2.callback_count);
|
||||
}
|
||||
|
||||
#if !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
|
||||
//*************************************************************************
|
||||
TEST(message_router_member_types)
|
||||
{
|
||||
CHECK((std::is_same<etl::message_packet<>, Router0::message_packet>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, Router0::message_types>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, Router0::sorted_message_types>::value));
|
||||
|
||||
CHECK((std::is_same<etl::message_packet<Message5, Message3, Message2, Message4, Message1>, Router1::message_packet>::value));
|
||||
CHECK((std::is_same<etl::type_list<Message5, Message3, Message2, Message4, Message1>, Router1::message_types>::value));
|
||||
CHECK((std::is_same<etl::type_list<Message1, Message2, Message3, Message4, Message5>, Router1::sorted_message_types>::value));
|
||||
|
||||
CHECK((std::is_same<etl::message_packet<Message1, Message2, Message4, Message5>, Router2::message_packet>::value));
|
||||
CHECK((std::is_same<etl::type_list<Message1, Message2, Message4, Message5>, Router2::message_types>::value));
|
||||
CHECK((std::is_same<etl::type_list<Message1, Message2, Message4, Message5>, Router2::sorted_message_types>::value));
|
||||
|
||||
CHECK((std::is_same<etl::message_packet<>, etl::null_message_router::message_packet>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, etl::null_message_router::message_types>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, etl::null_message_router::sorted_message_types>::value));
|
||||
|
||||
CHECK((std::is_same<etl::message_packet<>, etl::message_producer::message_packet>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, etl::message_producer::message_types>::value));
|
||||
CHECK((std::is_same<etl::type_list<>, etl::message_producer::sorted_message_types>::value));
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST(message_router_with_no_message_types)
|
||||
{
|
||||
@ -411,8 +437,6 @@ namespace
|
||||
|
||||
r0.append_successor(r1); // All messages are passed to r1.
|
||||
|
||||
CHECK_TRUE((etl::is_same<Router0::message_types, etl::type_list<>>::value));
|
||||
|
||||
CHECK(!r0.is_null_router());
|
||||
CHECK(r0.is_producer());
|
||||
CHECK(r0.is_consumer());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user