diff --git a/include/etl/message.h b/include/etl/message.h index 22a802e61..efd87210b 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -62,6 +62,8 @@ namespace etl } }; + class message_tag {}; + #if ETL_HAS_VIRTUAL_MESSAGES //*************************************************************************** /// Message interface. @@ -85,10 +87,14 @@ namespace etl /// Virtual. //*************************************************************************** template - class message : public TBase + class message : public TBase, public etl::message_tag { public: + ETL_STATIC_ASSERT((etl::is_base_of::value), "TBase is not derived from etl::imessage"); + + typedef TBase base_type; + //*********************************** ETL_NODISCARD virtual etl::message_id_t get_message_id() const ETL_NOEXCEPT ETL_OVERRIDE { @@ -149,12 +155,14 @@ namespace etl /// Non-virtual. //*************************************************************************** template - class message : public TBase + class message : public TBase, public etl::message_tag { public: ETL_STATIC_ASSERT((etl::is_base_of::value), "TBase is not derived from etl::imessage"); + typedef TBase base_type; + //*********************************** message() ETL_NOEXCEPT : TBase(ID) @@ -183,6 +191,78 @@ namespace etl //*************************************************************************** template ETL_CONSTANT etl::message_id_t etl::message::ID; + + //*************************************************************************** + /// Is T an etl::imessage? + //*************************************************************************** + template + struct is_imessage : public etl::bool_constant::type>::value> + { + }; + + //*************************************************************************** + /// Is T ultimately derived from etl::imessage? + //*************************************************************************** + template + struct is_message : public etl::bool_constant::type>::value> + { + }; + + //*************************************************************************** + /// Is T derived from etl::message<> + //*************************************************************************** + template + struct is_message_type : public etl::bool_constant::type>::value> + { + }; + + //*************************************************************************** + /// Is T a base of etl::message + //*************************************************************************** + template + struct is_message_base : public etl::bool_constant::value && !is_message_type::value> + { + }; + + //*************************************************************************** + /// Is T a user defined base of etl::message + //*************************************************************************** + template + struct is_user_message_base : public etl::bool_constant::value && !is_imessage::value> + { + }; + +#if ETL_USING_CPP17 + //*************************************************************************** + /// Is T an etl::imessage? + //*************************************************************************** + template + inline constexpr bool is_imessage_v = is_imessage::value; + + //*************************************************************************** + /// Is T ultimately derived from etl::imessage? + //*************************************************************************** + template + inline constexpr bool is_message_v = is_message::value; + + //*************************************************************************** + /// Is T derived from etl::message<> + //*************************************************************************** + template + inline constexpr bool is_message_type_v = is_message_type::value; + + //*************************************************************************** + /// Is T a base of etl::message + //*************************************************************************** + template + inline constexpr bool is_message_base_v = is_message_base::value; + + //*************************************************************************** + /// Is T a user defined base of etl::message + //*************************************************************************** + template + inline constexpr bool is_user_message_base_v = is_user_message_base::value; +#endif } #endif diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index 80a56165a..da5141e3d 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -76,18 +76,25 @@ namespace etl private: + using ThisPacketType = etl::message_packet; + + template + static constexpr bool IsMessagePacket = etl::is_same_v, ThisPacketType>; + template - static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + static constexpr bool IsInMessageList = etl::is_one_of_v, TMessageTypes...>; template - static constexpr bool IsInMessageList = etl::is_one_of_v>, TMessageTypes...>; + static constexpr bool IsIMessage = etl::is_same_v, etl::imessage>; template - static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + static constexpr bool IsDerivedFromIMessage = etl::is_base_of_v>; public: //******************************************** + /// Default constructor + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() : valid(false) @@ -95,7 +102,9 @@ namespace etl } #include "private/diagnostic_pop.h" - //********************************************** + //******************************************** + /// Copy constructor + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet(const message_packet& other) : valid(other.is_valid()) @@ -107,7 +116,9 @@ namespace etl } #include "private/diagnostic_pop.h" - //********************************************** + //******************************************** + /// Move constructor + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet(message_packet&& other) : valid(other.is_valid()) @@ -119,36 +130,61 @@ namespace etl } #include "private/diagnostic_pop.h" +#include "private/diagnostic_uninitialized_push.h" //******************************************** /// //******************************************** -#include "private/diagnostic_uninitialized_push.h" - template || IsInMessageList>::type> - explicit message_packet(T&& msg) + explicit message_packet(const etl::imessage& msg) : valid(true) { - if constexpr (IsIMessage) + if (accepts(msg)) { - if (accepts(msg)) - { - add_new_message(etl::forward(msg)); - valid = true; - } - else - { - valid = false; - } - - ETL_ASSERT(valid, ETL_ERROR(unhandled_message_exception)); + add_new_message(msg); + valid = true; + } + else + { + valid = false; } - else if constexpr (IsInMessageList) + + ETL_ASSERT(valid, ETL_ERROR(unhandled_message_exception)); + } +#include "private/diagnostic_pop.h" + +#include "private/diagnostic_uninitialized_push.h" + //******************************************** + /// + //******************************************** + explicit message_packet(etl::imessage&& msg) + : valid(true) + { + if (accepts(msg)) { - add_new_message_type(etl::forward(msg)); + add_new_message(etl::move(msg)); + valid = true; } else { - ETL_STATIC_ASSERT(IsInMessageList, "Message not in packet type list"); + valid = false; } + + ETL_ASSERT(valid, ETL_ERROR(unhandled_message_exception)); + } +#include "private/diagnostic_pop.h" + +#include "private/diagnostic_uninitialized_push.h" + //******************************************** + /// Enabled for types that are not a message packet or etl::imessage + /// Invokes a static assert for types not in the message type list. + //******************************************** + template && + !IsIMessage, int>> + explicit message_packet(T&& msg) + : valid(true) + { + ETL_STATIC_ASSERT(IsInMessageList, "Message type not in packet type list"); + + add_new_message_type(etl::forward(msg)); } #include "private/diagnostic_pop.h" @@ -250,7 +286,7 @@ namespace etl //********************************************** template static ETL_CONSTEXPR - typename etl::enable_if::value, bool>::type + typename etl::enable_if_t, bool> accepts() { return accepts(); @@ -258,7 +294,7 @@ namespace etl enum { - SIZE = etl::largest::size, + SIZE = etl::largest::size, ALIGNMENT = etl::largest::alignment }; @@ -308,11 +344,11 @@ namespace etl /// Only enabled for types that are in the typelist. //******************************************** template - etl::enable_if_t>, TMessageTypes...>, void> + etl::enable_if_t> add_new_message_type(TMessage&& msg) { void* p = data; - new (p) etl::remove_reference_t((etl::forward(msg))); + new (p) etl::remove_cvref_t((etl::forward(msg))); } #include "private/diagnostic_pop.h" diff --git a/test/test_message.cpp b/test/test_message.cpp new file mode 100644 index 000000000..8ce9afa86 --- /dev/null +++ b/test/test_message.cpp @@ -0,0 +1,117 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2024 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/message.h" + +SUITE(test_message) +{ + //************************************************************************* + TEST(test_message_traits) + { + // imessage + // ^ + // MessageBase + // ^ + // etl::message + // ^ + // Message + + // | is_imessage | is_message | is_message_type | is_message_base | is_user_message_base + // imessage | T | T | F | T | F + // MessageBase | F | T | F | T | T + // Message | F | T | T | F | F + // int | F | F | F | F | F + + struct MessageBase : public etl::imessage {}; + struct Message : public etl::message<1, MessageBase> {}; + +#if ETL_USING_CPP17 + // Is an imessage? + CHECK_TRUE(etl::is_imessage_v); + CHECK_FALSE(etl::is_imessage_v); + CHECK_FALSE(etl::is_imessage_v); + CHECK_FALSE(etl::is_imessage_v); + + // Is an imessage, or derived from imessage? + CHECK_TRUE(etl::is_message_v); + CHECK_TRUE(etl::is_message_v); + CHECK_TRUE(etl::is_message_v); + CHECK_FALSE(etl::is_message_v); + + // Is a concrete message? + CHECK_FALSE(etl::is_message_type_v); + CHECK_FALSE(etl::is_message_type_v); + CHECK_TRUE(etl::is_message_type_v); + CHECK_FALSE(etl::is_message_type_v); + + // Is a message base? + CHECK_TRUE(etl::is_message_base_v); + CHECK_TRUE(etl::is_message_base_v); + CHECK_FALSE(etl::is_message_base_v); + CHECK_FALSE(etl::is_message_base_v); + + // Is a user message base? + CHECK_FALSE(etl::is_user_message_base_v); + CHECK_TRUE(etl::is_user_message_base_v); + CHECK_FALSE(etl::is_user_message_base_v); + CHECK_FALSE(etl::is_user_message_base_v); +#else + // Is an imessage? + CHECK_TRUE(etl::is_imessage::value); + CHECK_FALSE(etl::is_imessage::value); + CHECK_FALSE(etl::is_imessage::value); + CHECK_FALSE(etl::is_imessage::value); + + // Is an imessage, or derived from imessage? + CHECK_TRUE(etl::is_message::value); + CHECK_TRUE(etl::is_message::value); + CHECK_TRUE(etl::is_message::value); + CHECK_FALSE(etl::is_message::value); + + // Is a concrete message? + CHECK_FALSE(etl::is_message_type::value); + CHECK_FALSE(etl::is_message_type::value); + CHECK_TRUE(etl::is_message_type::value); + CHECK_FALSE(etl::is_message_type::value); + + // Is a message base? + CHECK_TRUE(etl::is_message_base::value); + CHECK_TRUE(etl::is_message_base::value); + CHECK_FALSE(etl::is_message_base::value); + CHECK_FALSE(etl::is_message_base::value); + + // Is a user message base? + CHECK_TRUE(etl::is_user_message_base::value); + CHECK_TRUE(etl::is_user_message_base::value); + CHECK_FALSE(etl::is_user_message_base::value); + CHECK_FALSE(etl::is_user_message_base::value); +#endif + } +}; diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index 5589c0e2d..426c520c6 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -220,6 +220,7 @@ namespace // Should cause a static assert. //Packet packet4(message4); + //Packet packet4((Message4())); CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); @@ -455,7 +456,7 @@ namespace CHECK(Packet::accepts()); CHECK(Packet::accepts()); CHECK(!Packet::accepts()); - + // From static message id. CHECK(Packet::accepts()); CHECK(Packet::accepts()); diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 6fda4cbaf..0450a78f9 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -7396,6 +7396,7 @@ +