diff --git a/src/algorithm.h b/src/algorithm.h index 2a7f236b..3f2b0575 100644 --- a/src/algorithm.h +++ b/src/algorithm.h @@ -418,6 +418,52 @@ namespace etl return o_begin; } + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value) + { + TIterator it = std::lower_bound(begin, end, value); + + if ((it == end) || (*it != value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value, + TBinaryPredicate predicate, + TBinaryEquality equality) + { + TIterator it = std::lower_bound(begin, end, value, predicate); + + if ((it == end) || !equality(*it, value)) + { + it = end; + } + + return it; + } + //*************************************************************************** /// find_if_not ///\ingroup algorithm diff --git a/src/alignment.h b/src/alignment.h index 18f20aea..578ae40c 100644 --- a/src/alignment.h +++ b/src/alignment.h @@ -113,7 +113,7 @@ namespace etl template operator T& () { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -121,7 +121,7 @@ namespace etl template operator const T& () const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -129,7 +129,7 @@ namespace etl template operator T* () { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -137,7 +137,7 @@ namespace etl template operator const T* () const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -145,7 +145,7 @@ namespace etl template T& get_reference() { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -153,7 +153,7 @@ namespace etl template const T& get_reference() const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -161,7 +161,7 @@ namespace etl template T* get_address() { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -169,7 +169,7 @@ namespace etl template const T* get_address() const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } diff --git a/src/file_error_numbers.txt b/src/file_error_numbers.txt index 5cea1e44..24ffa829 100644 --- a/src/file_error_numbers.txt +++ b/src/file_error_numbers.txt @@ -34,4 +34,6 @@ 34 fsm 35 message_router 36 scheduler -37 task \ No newline at end of file +37 task +38 message +39 message_bus diff --git a/src/fsm.h b/src/fsm.h new file mode 100644 index 00000000..7c31acfc --- /dev/null +++ b/src/fsm.h @@ -0,0 +1,1204 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers= fsm_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include + +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class fsm_helper; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// Helper class for FSM. + /// Allows ifsm_state functions to be private. + //*************************************************************************** + class fsm_helper + { + public: + + //******************************************* + inline void set_fsm_context(etl::ifsm_state& state, + etl::fsm& context) + { + state.set_fsm_context(context); + } + + //******************************************* + inline fsm_state_id_t process_event(etl::ifsm_state& state, + etl::imessage_router& source, + const etl::imessage& message) + { + return state.process_event(source, message); + } + + //******************************************* + inline fsm_state_id_t on_enter_state(etl::ifsm_state& state) + { + return state.on_enter_state(); + } + + //******************************************* + inline void on_exit_state(etl::ifsm_state& state) + { + state.on_exit_state(); + } + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router, protected etl::fsm_helper + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + fsm_helper::set_fsm_context(*state_list[i], *this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + fsm_helper::on_enter_state(*p_state); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = fsm_helper::process_event(*p_state, source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state = p_next_state; + fsm_helper::on_exit_state(*p_state); + + next_state_id = fsm_helper::on_enter_state(*p_state); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T15::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T16::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T15::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + return static_cast(this)->on_event_unknown(source, message); + } + }; +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif diff --git a/src/fsm_generator.h b/src/fsm_generator.h new file mode 100644 index 00000000..0072dbd0 --- /dev/null +++ b/src/fsm_generator.h @@ -0,0 +1,569 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers= fsm_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include + +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class fsm_helper; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// Helper class for FSM. + /// Allows ifsm_state functions to be private. + //*************************************************************************** + class fsm_helper + { + public: + + //******************************************* + inline void set_fsm_context(etl::ifsm_state& state, + etl::fsm& context) + { + state.set_fsm_context(context); + } + + //******************************************* + inline fsm_state_id_t process_event(etl::ifsm_state& state, + etl::imessage_router& source, + const etl::imessage& message) + { + return state.process_event(source, message); + } + + //******************************************* + inline fsm_state_id_t on_enter_state(etl::ifsm_state& state) + { + return state.on_enter_state(); + } + + //******************************************* + inline void on_exit_state(etl::ifsm_state& state) + { + state.on_exit_state(); + } + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router, protected etl::fsm_helper + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + fsm_helper::set_fsm_context(*state_list[i], *this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + fsm_helper::on_enter_state(*p_state); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = fsm_helper::process_event(*p_state, source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state = p_next_state; + fsm_helper::on_exit_state(*p_state); + + next_state_id = fsm_helper::on_enter_state(*p_state); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + /*[[[cog + import cog + cog.outl("") + ################################################ + # The first definition for all of the events. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template " % Handlers) + cog.outl("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast(this)->on_event(source, static_cast(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template " % n) + cog.out("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, n + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast(this)->on_event(source, static_cast(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + #################################### + # Specialisation for zero messages. + #################################### + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for 0 message types.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" return static_cast(this)->on_event_unknown(source, message);") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif diff --git a/src/generate.bat b/src/generate.bat new file mode 100644 index 00000000..8902cbde --- /dev/null +++ b/src/generate.bat @@ -0,0 +1,5 @@ +python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h \ No newline at end of file diff --git a/src/generate_fsm.bat b/src/generate_fsm.bat new file mode 100644 index 00000000..07c25ece --- /dev/null +++ b/src/generate_fsm.bat @@ -0,0 +1 @@ +python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h diff --git a/src/generate_message_router.bat b/src/generate_message_router.bat new file mode 100644 index 00000000..b30597fb --- /dev/null +++ b/src/generate_message_router.bat @@ -0,0 +1 @@ +python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h diff --git a/src/largest.h b/src/largest.h index 311adc0b..a3334c99 100644 --- a/src/largest.h +++ b/src/largest.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes= largest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_LARGEST__ #define __ETL_LARGEST__ @@ -47,9 +69,9 @@ namespace etl /// Defines 'size' which is the size of the largest parameter. ///\ingroup largest //*************************************************************************** - template struct largest_type { @@ -78,14 +100,14 @@ namespace etl public: // Define 'largest_other' as 'largest_type' with all but the first parameter. - typedef typename largest_type::type largest_other; + typedef typename largest_type::type largest_other; // Set 'type' to be the largest of the first parameter and any of the others. // This is recursive. typedef typename choose_type<(sizeof(T1) > sizeof(largest_other)), // Boolean - T1, // TrueType - largest_other> // FalseType - ::type type; // The largest type of the two. + T1, // TrueType + largest_other> // FalseType + ::type type; // The largest type of the two. // The size of the largest type. enum @@ -98,10 +120,8 @@ namespace etl // Specialisation for one template parameter. //*************************************************************************** template - struct largest_type + struct largest_type { typedef T1 type; @@ -117,12 +137,14 @@ namespace etl /// Defines value which is the largest alignment of all the parameters. ///\ingroup largest //*************************************************************************** - template + template struct largest_alignment { + private: + // Determine the largest size. template struct max_size @@ -136,22 +158,22 @@ namespace etl // All of the alignments. enum { - t1 = alignment_of::value, - t2 = alignment_of::value, - t3 = alignment_of::value, - t4 = alignment_of::value, - t5 = alignment_of::value, - t6 = alignment_of::value, - t7 = alignment_of::value, - t8 = alignment_of::value, - t9 = alignment_of::value, - t10 = alignment_of::value, - t11 = alignment_of::value, - t12 = alignment_of::value, - t13 = alignment_of::value, - t14 = alignment_of::value, - t15 = alignment_of::value, - t16 = alignment_of::value + t1 = etl::alignment_of::value, + t2 = etl::alignment_of::value, + t3 = etl::alignment_of::value, + t4 = etl::alignment_of::value, + t5 = etl::alignment_of::value, + t6 = etl::alignment_of::value, + t7 = etl::alignment_of::value, + t8 = etl::alignment_of::value, + t9 = etl::alignment_of::value, + t10 = etl::alignment_of::value, + t11 = etl::alignment_of::value, + t12 = etl::alignment_of::value, + t13 = etl::alignment_of::value, + t14 = etl::alignment_of::value, + t15 = etl::alignment_of::value, + t16 = etl::alignment_of::value }; public: @@ -216,6 +238,27 @@ namespace etl typedef typename etl::smallest_int_for_bits::bits + 1>::type type; }; + + //*************************************************************************** + /// Template to determine the largest type, size and alignment. + /// Supports up to 16 types. + /// Defines value which is the largest type, size and alignment of all the parameters. + ///\ingroup largest + //*************************************************************************** + template + struct largest + { + typedef typename etl::largest_type::type type; + + enum + { + size = etl::largest_type::size, + alignment = etl::largest_alignment::value + }; + }; } #endif diff --git a/src/largest_generator.h b/src/largest_generator.h new file mode 100644 index 00000000..27464662 --- /dev/null +++ b/src/largest_generator.h @@ -0,0 +1,323 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes= largest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_LARGEST__ +#define __ETL_LARGEST__ + +///\defgroup largest largest +///\ingroup utilities + +#include "type_traits.h" +#include "smallest.h" +#include "static_assert.h" + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the largest parameter.") + cog.outl("/// Defines 'size' which is the size of the largest parameter.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % int(NTypes)) + cog.outl("struct largest_type") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Declaration.") + cog.outl(" template ") + cog.outl(" struct choose_type;") + cog.outl("") + cog.outl(" // Specialisation for 'true'.") + cog.outl(" // Defines 'type' as 'TrueType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef TrueType type;") + cog.outl(" };") + cog.outl("") + cog.outl(" // Specialisation for 'false'. ") + cog.outl(" // Defines 'type' as 'FalseType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef FalseType type;") + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // Define 'largest_other' as 'largest_type' with all but the first parameter. ") + cog.out(" typedef typename largest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type largest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the largest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename choose_type<(sizeof(T1) > sizeof(largest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" largest_other> // FalseType") + cog.outl(" ::type type; // The largest type of the two.") + cog.outl("") + cog.outl(" // The size of the largest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("struct largest_type") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest alignment.") + cog.outl("/// Supports up to %s types." % int(NTypes)) + cog.outl("/// Defines value which is the largest alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % NTypes) + cog.outl("struct largest_alignment") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Determine the largest size.") + cog.outl(" template ") + cog.outl(" struct max_size") + cog.outl(" {") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" value = (size1 > size2) ? size1 : size2") + cog.outl(" };") + cog.outl(" };") + cog.outl("") + cog.outl(" // All of the alignments.") + cog.outl(" enum") + cog.outl(" {") + for n in range(1, int(NTypes)): + cog.outl(" t%s = etl::alignment_of::value," %(n, n)) + cog.outl(" t%s = etl::alignment_of::value" % (NTypes, NTypes)) + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // The largest of all of them.") + cog.outl(" enum") + cog.outl(" {") + cog.out(" value = ") + for n in range(1, int(NTypes)): + cog.out("max_size" % int(NTypes)) + cog.out(" ") + for n in range(1, int(NTypes) - 1): + cog.out("::value>") + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("::value") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template + struct larger_int_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template + struct larger_uint_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + /// The returned type will be of the same sign. + ///\ingroup largest + //*************************************************************************** + template ::value> + struct larger_type; + + template + struct larger_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits::bits + 1>::type type; + }; + + template + struct larger_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits::bits + 1>::type type; + }; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type, size and alignment.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines value which is the largest type, size and alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % NTypes) + cog.outl("struct largest") + cog.outl("{") + cog.out(" typedef typename etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type type;" % NTypes) + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" size = etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::size," % NTypes) + cog.out(" alignment = etl::largest_alignment<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::value" % NTypes) + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#endif diff --git a/src/memory.h b/src/memory.h index 947c1124..1920f0b2 100644 --- a/src/memory.h +++ b/src/memory.h @@ -662,6 +662,27 @@ namespace etl return i_begin; } + + //***************************************************************************** + /// Copy constructs a derived class to an address. + ///\tparam T The derived type. + ///\ingroup memory + //***************************************************************************** + template + struct create_copy + { + void create_copy_at(void* p) + { + new (p) T(static_cast(*this)); + } + + template + void create_copy_at(void* p, TCounter& count) + { + new (p) T(static_cast(*this)); + ++count; + } + }; } #endif diff --git a/src/message.h b/src/message.h new file mode 100644 index 00000000..d422e7b5 --- /dev/null +++ b/src/message.h @@ -0,0 +1,96 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_MESSAGE__ +#define __ETL_MESSAGE__ + +#include + +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +namespace etl +{ + //*************************************************************************** + class message_exception : public etl::exception + { + public: + + message_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + class unhandled_message_exception : public etl::message_exception + { + public: + + unhandled_message_exception(string_type file_name, numeric_type line_number) + : message_exception(ETL_ERROR_TEXT("message:unknown", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage + { + public: + + //******************************************** + virtual ~imessage() {} + virtual etl::message_id_t get_message_id() const = 0; + }; + + //*************************************************************************** + template + class message : public imessage + { + public: + + enum + { + ID = ID_ + }; + + //******************************************** + etl::message_id_t get_message_id() const + { + return ID; + } + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/message_bus.h b/src/message_bus.h new file mode 100644 index 00000000..ef8c811b --- /dev/null +++ b/src/message_bus.h @@ -0,0 +1,389 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_BUS_ +#define __ETL_MESSAGE_BUS_ + +#include +#include + +#include "algorithm.h" +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" +#include "message.h" +#include "message_router.h" + +#undef ETL_FILE +#define ETL_FILE "39" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message bus + //*************************************************************************** + class message_bus_exception : public etl::exception + { + public: + + message_bus_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Too many subscribers. + //*************************************************************************** + class message_bus_too_many_subscribers : public etl::message_bus_exception + { + public: + + message_bus_too_many_subscribers(string_type file_name, numeric_type line_number) + : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface for message bus + //*************************************************************************** + class imessage_bus : public etl::imessage_router + { + private: + + typedef etl::ivector router_list_t; + + public: + + using etl::imessage_router::receive; + + //******************************************* + /// Subscribe to the bus. + //******************************************* + bool subscribe(etl::imessage_router& router) + { + bool ok = true; + + // There's no point actually adding null routers. + if (router.get_message_router_id() != etl::imessage_router::NULL_MESSAGE_ROUTER) + { + ok = !router_list.full(); + + ETL_ASSERT(ok, ETL_ERROR(etl::message_bus_too_many_subscribers)); + + if (ok) + { + if (router.get_message_router_id() == etl::imessage_router::MESSAGE_BUS) + { + // Message busses get added to the end. + router_list.push_back(&router); + } + else + { + // Routers get added in id order. + router_list_t::iterator irouter = std::upper_bound(router_list.begin(), + router_list.end(), + router.get_message_router_id(), + compare_router_id()); + + router_list.insert(irouter, &router); + } + } + } + + return ok; + } + + //******************************************* + /// Unsubscribe from the bus. + //******************************************* + void unsubscribe(etl::message_router_id_t id) + { + if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS) + { + clear(); + } + else + { + std::pair range = std::equal_range(router_list.begin(), + router_list.end(), + id, + compare_router_id()); + + router_list.erase(range.first, range.second); + } + } + + //******************************************* + void unsubscribe(etl::imessage_router& router) + { + router_list_t::iterator irouter = std::find(router_list.begin(), + router_list.end(), + &router); + + if (irouter != router_list.end()) + { + router_list.erase(irouter); + } + } + + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, destination_router_id, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + const etl::imessage& message) + { + receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + switch (destination_router_id) + { + //***************************** + // Null message router. These routers can never be subscribed. + case etl::imessage_router::NULL_MESSAGE_ROUTER: + { + break; + } + + //***************************** + // Broadcast to all routers. + case etl::imessage_router::ALL_MESSAGE_ROUTERS: + { + router_list_t::iterator irouter = router_list.begin(); + + // Broadcast to everyone. + while (irouter != router_list.end()) + { + etl::imessage_router& router = **irouter; + + if (router.get_message_router_id() == etl::imessage_router::MESSAGE_BUS) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast(router); + + // So pass it on. + bus.receive(source, destination_router_id, message); + } + else if (router.accepts(message.get_message_id())) + { + router.receive(source, message); + } + + ++irouter; + } + + break; + } + + //***************************** + // Must be an addressed message. + default: + { + router_list_t::iterator irouter = router_list.begin(); + + // Find routers with the id. + std::pair range = std::equal_range(router_list.begin(), + router_list.end(), + destination_router_id, + compare_router_id()); + + // Call all of them. + while (range.first != range.second) + { + if ((*(range.first))->accepts(message.get_message_id())) + { + (*(range.first))->receive(source, message); + } + + ++range.first; + } + + // Do any message buses. + // These are always at the end of the list. + irouter = std::lower_bound(router_list.begin(), + router_list.end(), + etl::imessage_bus::MESSAGE_BUS, + compare_router_id()); + + while (irouter != router_list.end()) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast(**irouter); + + // So pass it on. + bus.receive(source, destination_router_id, message); + + ++irouter; + } + + break; + } + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this message bus accept the message id? + /// Yes!, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + size_t size() const + { + return router_list.size(); + } + + //******************************************* + void clear() + { + return router_list.clear(); + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + imessage_bus(router_list_t& list) + : imessage_router(etl::imessage_router::MESSAGE_BUS), + router_list(list) + { + } + + private: + + //******************************************* + // How to compare routers to router ids. + //******************************************* + struct compare_router_id + { + bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const + { + return prouter->get_message_router_id() < id; + } + + bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const + { + return id < prouter->get_message_router_id(); + } + }; + + router_list_t& router_list; + }; + + //*************************************************************************** + /// The message bus + //*************************************************************************** + template + class message_bus : public etl::imessage_bus + { + public: + + //******************************************* + /// Constructor. + //******************************************* + message_bus() + : imessage_bus(router_list) + { + } + + private: + + etl::vector router_list; + }; + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(id, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(source, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(source, id, message); + } +} + +#undef ETL_FILE + +#endif diff --git a/src/message_router.h b/src/message_router.h new file mode 100644 index 00000000..c024391b --- /dev/null +++ b/src/message_router.h @@ -0,0 +1,2200 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name, numeric_type line_number) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id) + : message_router_id(id) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage& message) + { + } + + //******************************************** + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************** + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + case T15::ID: ::new (p) T15(static_cast(msg)); break; + case T16::ID: ::new (p) T16(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T16::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + case T15::ID: ::new (p) T15(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: + return true; break; + default: + return false; break; + } + } + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/message_router_generator.h b/src/message_router_generator.h new file mode 100644 index 00000000..cf1c3685 --- /dev/null +++ b/src/message_router_generator.h @@ -0,0 +1,514 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name, numeric_type line_number) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id) + : message_router_id(id) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage& message) + { + } + + //******************************************** + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************** + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + /*[[[cog + import cog + ################################################ + # The first definition for all of the messages. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template " % int(Handlers)) + cog.out("class message_router") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast(msg)); break;" % (n, n, n)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template ") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet");""" % int(Handlers)) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::size," % int(Handlers)) + cog.out(" ALIGNMENT = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::alignment" % int(Handlers)) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id)") + cog.outl(" : imessage_router(id)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const etl::message_id_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" static_cast(this)->on_receive(source, static_cast(msg));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" static_cast(this)->on_receive_unknown(source, msg);") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for n in range(1, int(Handlers) + 1): + cog.out("case T%d::ID: " % n) + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template " % n) + cog.out("class message_router") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast(msg)); break;" % (t, t, t)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template ") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet");""" % n) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::size," % n) + cog.out(" ALIGNMENT = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::alignment" % n) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id)") + cog.outl(" : imessage_router(id)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.out(" case T%d::ID:" % t) + cog.out(" static_cast(this)->on_receive(source, static_cast(msg));" % t) + cog.outl(" break;") + cog.out(" default:") + cog.out(" static_cast(this)->on_receive_unknown(source, msg);") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for t in range(1, n + 1): + cog.out("case T%d::ID: " % t) + if t % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#endif diff --git a/src/message_types.h b/src/message_types.h new file mode 100644 index 00000000..a049dae9 --- /dev/null +++ b/src/message_types.h @@ -0,0 +1,46 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_DEFS__ +#define __ETL_MESSAGE_DEFS__ + +#include + +namespace etl +{ + /// Allow alternative type for message id. +#if !defined(ETL_MESSAGE_ID_TYPE) + typedef uint_least8_t message_id_t; +#else + typedef ETL_MESSAGE_ID_TYPE message_id_t; +#endif + + typedef uint_least8_t message_router_id_t; +} + +#endif diff --git a/src/packet.h b/src/packet.h new file mode 100644 index 00000000..ef0e2d79 --- /dev/null +++ b/src/packet.h @@ -0,0 +1,128 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_PACKET__ +#define __ETL_PACKET__ + +#include "platform.h" +#include "static_assert.h" +#include "alignment.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +//***************************************************************************** +///\defgroup packet packet +/// A class that can contain one a several related types. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// A template class that can store any types derived from TBase that conform + /// to the size and alignment requirements. + ///\ingroup packet + //*************************************************************************** + template + class packet + { + public: + + //*************************************************************************** + /// Constructor that static asserts any types that do not conform to the max size and alignment. + //*************************************************************************** + template + explicit packet(const T& value) + { + STATIC_ASSERT((etl::is_base_of::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Unsupported alignment"); + + ::new (static_cast(data)) T(value); + } + + //*************************************************************************** + /// Destructor + //*************************************************************************** + ~packet() + { + static_cast(data)->~TBase(); + } + + //*************************************************************************** + /// Assignment operator for type. + ///\param value The value to assign. + //*************************************************************************** + template + packet& operator =(const T& value) + { + STATIC_ASSERT((etl::is_base_of::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Unsupported alignment"); + + static_cast(data)->~TBase(); + ::new (static_cast(data)) T(value); + + return *this; + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + TBase& get() + { + return *static_cast(data); + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + const TBase& get() const + { + return *static_cast(data); + } + + private: + + packet(const packet& other); + packet& operator =(const packet& other); + + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + typename etl::aligned_storage::type data; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/scheduler.h b/src/scheduler.h new file mode 100644 index 00000000..388b0a8c --- /dev/null +++ b/src/scheduler.h @@ -0,0 +1,410 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_SCHEDULER__ +#define __ETL_SCHEDULER__ + +#include + +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "task.h" +#include "type_traits.h" +#include "function.h" + +#undef ETL_FILE +#define ETL_FILE "36" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for scheduler. + //*************************************************************************** + class scheduler_exception : public etl::exception + { + public: + + scheduler_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'No tasks' exception. + //*************************************************************************** + class scheduler_no_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_no_tasks_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:no tasks", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'Null tasks' exception. + //*************************************************************************** + class scheduler_null_task_exception : public etl::scheduler_exception + { + public: + + scheduler_null_task_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:null task", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'Too many tasks' exception. + //*************************************************************************** + class scheduler_too_many_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_too_many_tasks_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:too many tasks", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Sequencial Single. + /// A policy the scheduler can use to decide what to do next. + /// Only calls the task to process work once, if it has work to do. + //*************************************************************************** + struct scheduler_policy_sequencial_single + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Sequencial Multiple. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task to process work until it reports that it has no more. + //*************************************************************************** + struct scheduler_policy_sequencial_multiple + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + while (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Highest Priority. + /// A policy the scheduler can use to decide what to do next. + /// Calls the highest priority task that has work. + //*************************************************************************** + struct scheduler_policy_highest_priority + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + size_t index = 0; + while (index < task_list.size()) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + break; + } + else + { + ++index; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Most Work. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task that has the most work. + /// Starts looking from the task with the highest priority. + //*************************************************************************** + struct scheduler_policy_most_work + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + size_t most_index = 0; + uint_least8_t most_work = 0; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + uint_least8_t n_work = task.task_request_work(); + + if (n_work > most_work) + { + most_index = index; + most_work = n_work; + idle = false; + } + } + + if (!idle) + { + task_list[most_index]->task_process_work(); + } + + return idle; + } + }; + + //*************************************************************************** + /// Scheduler base. + //*************************************************************************** + class ischeduler + { + public: + + //******************************************* + // Virtuals. + //******************************************* + virtual void start() = 0; + + virtual ~ischeduler() + { + } + + //******************************************* + /// Set the idle callback. + //******************************************* + void set_idle_callback(etl::ifunction& callback) + { + p_idle_callback = &callback; + } + + //******************************************* + /// Set the watchdog callback. + //******************************************* + void set_watchdog_callback(etl::ifunction& callback) + { + p_watchdog_callback = &callback; + } + + //******************************************* + /// Set the running state for the scheduler. + //******************************************* + void set_scheduler_running(bool scheduler_running_) + { + scheduler_running = scheduler_running_; + } + + //******************************************* + /// Get the running state for the scheduler. + //******************************************* + bool scheduler_is_running() const + { + return scheduler_running; + } + + //******************************************* + /// Force the scheduler to exit. + //******************************************* + void exit_scheduler() + { + scheduler_exit = true; + } + + //******************************************* + /// Add a task. + /// Add to the task list in priority order. + //******************************************* + void add_task(etl::task& task) + { + ETL_ASSERT(!task_list.full(), ETL_ERROR(etl::scheduler_too_many_tasks_exception)) + + if (!task_list.full()) + { + typename task_list_t::iterator itask = std::upper_bound(task_list.begin(), + task_list.end(), + task.get_task_priority(), + compare_priority()); + + task_list.insert(itask, &task); + } + } + + //******************************************* + /// Add a task list. + /// Adds to the tasks to the internal task list in priority order. + /// Input order is ignored. + //******************************************* + template + void add_task_list(etl::task** p_tasks, TSize size) + { + for (TSize i = 0; i < size; ++i) + { + ETL_ASSERT((p_tasks[i] != nullptr), ETL_ERROR(etl::scheduler_null_task_exception)); + add_task(*(p_tasks[i])); + } + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ischeduler(etl::ivector& task_list_) + : scheduler_running(false), + scheduler_exit(false), + p_idle_callback(nullptr), + p_watchdog_callback(nullptr), + task_list(task_list_) + { + } + + bool scheduler_running; + bool scheduler_exit; + etl::ifunction* p_idle_callback; + etl::ifunction* p_watchdog_callback; + + private: + + //******************************************* + // Used to order tasks in descending priority. + //******************************************* + struct compare_priority + { + bool operator()(etl::task* ptask, etl::task_priority_t priority) const + { + return ptask->get_task_priority() > priority; + } + + bool operator()(etl::task_priority_t priority, etl::task* ptask) const + { + return priority > ptask->get_task_priority(); + } + }; + + typedef etl::ivector task_list_t; + task_list_t& task_list; + }; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + template + class scheduler : public etl::ischeduler, protected TSchedulerPolicy + { + public: + + enum + { + MAX_TASKS = MAX_TASKS_, + }; + + scheduler() + : ischeduler(task_list) + { + } + + //******************************************* + /// Start the scheduler. SEQUENCIAL_SINGLE + /// Only calls the task to process work once, if it has work to do. + //******************************************* + void start() + { + ETL_ASSERT(task_list.size() > 0, ETL_ERROR(etl::scheduler_no_tasks_exception)); + + const size_t task_list_size = task_list.size(); + + scheduler_running = true; + + while (!scheduler_exit) + { + if (scheduler_running) + { + bool idle = TSchedulerPolicy::schedule_tasks(task_list); + + if (p_watchdog_callback) + { + (*p_watchdog_callback)(); + } + + if (idle && p_idle_callback) + { + (*p_idle_callback)(); + } + } + } + } + + private: + + typedef etl::vector task_list_t; + task_list_t task_list; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/smallest.h b/src/smallest.h index b9ac9e22..16a2ed7c 100644 --- a/src/smallest.h +++ b/src/smallest.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes= smallest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_SMALLEST__ #define __ETL_SMALLEST__ @@ -47,9 +69,9 @@ namespace etl /// Defines 'size' which is the size of the smallest parameter. ///\ingroup smallest //*************************************************************************** - template struct smallest_type { @@ -82,10 +104,10 @@ namespace etl // Set 'type' to be the smallest of the first parameter and any of the others. // This is recursive. - typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)),// Boolean - T1, // TrueType - smallest_other> // FalseType - ::type type; // The smallest type of the two. + typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean + T1, // TrueType + smallest_other> // FalseType + ::type type; // The smallest type of the two. // The size of the smallest type. enum @@ -98,10 +120,8 @@ namespace etl // Specialisation for one template parameter. //*************************************************************************** template - struct smallest_type + struct smallest_type { typedef T1 type; diff --git a/src/smallest_generator.h b/src/smallest_generator.h new file mode 100644 index 00000000..1c99c09c --- /dev/null +++ b/src/smallest_generator.h @@ -0,0 +1,336 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes= smallest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_SMALLEST__ +#define __ETL_SMALLEST__ + +#include + +#include "integral_limits.h" + +///\defgroup smallest smallest +///\ingroup utilities + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the smallest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the smallest parameter.") + cog.outl("/// Defines 'size' which is the size of the smallest parameter.") + cog.outl("///\ingroup smallest") + cog.outl("//***************************************************************************") + cog.out("template " % int(NTypes)) + cog.outl("struct smallest_type") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Declaration.") + cog.outl(" template ") + cog.outl(" struct choose_type;") + cog.outl("") + cog.outl(" // Specialisation for 'true'.") + cog.outl(" // Defines 'type' as 'TrueType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef TrueType type;") + cog.outl(" };") + cog.outl("") + cog.outl(" // Specialisation for 'false'. ") + cog.outl(" // Defines 'type' as 'FalseType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef FalseType type;") + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // Define 'smallest_other' as 'smallest_type' with all but the first parameter. ") + cog.out(" typedef typename smallest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type smallest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the smallest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" smallest_other> // FalseType") + cog.outl(" ::type type; // The smallest type of the two.") + cog.outl("") + cog.outl(" // The size of the smallest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("struct smallest_type") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + namespace __private_smallest__ + { + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template + struct best_fit_uint_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<0> + { + typedef uint_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<1> + { + typedef uint_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<2> + { + typedef uint_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<3> + { + typedef uint_least64_t type; + }; + + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template + struct best_fit_int_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_int_type<0> + { + typedef int_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_int_type<1> + { + typedef int_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_int_type<2> + { + typedef int_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_int_type<3> + { + typedef int_least64_t type; + }; + } + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_uint_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest signed int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_int_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain the + /// specified unsigned value. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_uint_for_value + { + private: + + // Determines the index of the best unsigned type for the required value. + static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX) ? 1 : 0) + + ((VALUE > UINT16_MAX) ? 1 : 0) + + ((VALUE > UINT32_MAX) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest int type that can contain the + /// specified signed value. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_int_for_value + { + private: + + // Determines the index of the best signed type for the required value. + static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX) || (VALUE < INT_LEAST8_MIN)) ? 1 : 0) + + (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) + + (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type::type type; + }; +} + +#endif diff --git a/src/task.h b/src/task.h new file mode 100644 index 00000000..dbe410f1 --- /dev/null +++ b/src/task.h @@ -0,0 +1,125 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_TASK__ +#define __ETL_TASK__ + +#include + +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "37" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for task. + //*************************************************************************** + class task_exception : public etl::exception + { + public: + + task_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + typedef uint_least8_t task_priority_t; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + class task + { + public: + + //******************************************* + /// Constructor. + //******************************************* + task(task_priority_t priority) + : task_running(true), + task_priority(priority) + { + } + + //******************************************* + /// Destructor. + //******************************************* + virtual ~task() + { + } + + //******************************************* + /// Called to check if the task has work. + /// Returns a score as to the amount of work it has to do. + //******************************************* + virtual uint32_t task_request_work() const = 0; + + //******************************************* + /// Called to get the task to do work. + //******************************************* + virtual void task_process_work() = 0; + + //******************************************* + /// Set the running state for the task. + //******************************************* + void set_task_running(bool task_running_) + { + task_running = task_running_; + } + + //******************************************* + /// Get the running state for the task. + //******************************************* + bool task_is_running() const + { + return task_running; + } + + //******************************************* + /// Get the priority of the task. + /// Higher value = higher priority. + //******************************************* + etl::task_priority_t get_task_priority() const + { + return task_priority; + } + + private: + + bool task_running; + etl::task_priority_t task_priority; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/type_traits.h b/src/type_traits.h index 5c9876a5..afd8be8d 100644 --- a/src/type_traits.h +++ b/src/type_traits.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers= types_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_TYPE_TRAITS__ #define __ETL_TYPE_TRAITS__ @@ -152,7 +174,6 @@ namespace etl template struct is_integral : is_integral {}; template struct is_integral : is_integral {}; - /// is_signed ///\ingroup type_traits template struct is_signed : false_type {}; @@ -237,15 +258,15 @@ namespace etl template struct is_reference : true_type {}; /// is_pod + /// For C++03, only fundamental and pointers types are recognised. ///\ingroup type_traits - #if defined(ETL_C11_TYPE_TRAITS_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) // For compilers that support C++11 template struct is_pod : std::is_pod {}; #else /// For C++03, only fundamental and pointers types are recognised. template struct is_pod : etl::integral_constant::value || - etl::is_pointer::value> {}; + etl::is_pointer::value> {}; #endif #if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) && defined(ETL_C11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) @@ -290,6 +311,7 @@ namespace etl template struct is_trivially_copy_assignable : etl::is_pod {}; #endif + /// conditional ///\ingroup type_traits template struct conditional { typedef T type; }; @@ -392,29 +414,80 @@ namespace etl typename etl::remove_cv::type>::type type; }; + /// is_base_of + ///\ingroup type_traits + template + struct is_base_of + { + private: + + template struct dummy {}; + struct internal: TDerived, dummy{}; + + static TBase* check(TBase*); + template static char check(dummy*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + /// Alignment templates. /// These require compiler specific intrinsics. ///\ingroup type_traits -#if defined(ETL_C11_ALIGNOF_SUPPORTED) - template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_MICROSOFT) +#ifdef ETL_COMPILER_MICROSOFT template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_GCC) +#endif + +#ifdef ETL_COMPILER_GCC template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_KEIL) +#endif + +#ifdef ETL_COMPILER_KEIL template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_IAR) +#endif + +#ifdef ETL_COMPILER_IAR template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_TI) +#endif + +#ifdef ETL_COMPILER_TI template struct alignment_of : integral_constant {}; -#else - // Best guess! - template struct alignment_of : integral_constant {}; #endif /// Specialisation of 'alignment_of' for 'void'. ///\ingroup type_traits template <> struct alignment_of : integral_constant {}; + + //*************************************************************************** + /// Template to determine if a type is one of a specified list. + ///\ingroup types + //*************************************************************************** + template + struct is_one_of + { + static const bool value = + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value; + }; } #endif diff --git a/src/type_traits_generator.h b/src/type_traits_generator.h new file mode 100644 index 00000000..68a2202d --- /dev/null +++ b/src/type_traits_generator.h @@ -0,0 +1,500 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers= types_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_TYPE_TRAITS__ +#define __ETL_TYPE_TRAITS__ + +#include + +#include "platform.h" +#include "nullptr.h" + +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) + #include +#endif + +///\defgroup type_traits type_traits +/// A set of type traits definitions for compilers that do not support the standard header. +/// \ingroup utilities + +namespace etl +{ + /// integral_constant + ///\ingroup type_traits + template + struct integral_constant + { + static const T value = VALUE; + + typedef T value_type; + typedef integral_constant type; + + operator value_type() const + { + return value; + } + }; + + /// integral_constant specialisations + ///\ingroup type_traits + typedef integral_constant false_type; + typedef integral_constant true_type; + + /// remove_reference + ///\ingroup type_traits + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; + + /// add_reference + ///\ingroup type_traits + template struct add_reference { typedef T& type; }; + template struct add_reference { typedef T& type; }; + + /// remove_pointer + ///\ingroup type_traits + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + + /// add_pointer + ///\ingroup type_traits + template struct add_pointer { typedef typename remove_reference::type* type; }; + + /// is_const + ///\ingroup type_traits + template struct is_const : false_type {}; + template struct is_const : true_type {}; + template struct is_const : true_type {}; + + /// remove_const + ///\ingroup type_traits + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + + /// add_const + ///\ingroup type_traits + template struct add_const { typedef const T type; }; + template struct add_const { typedef const T type; }; + + /// is_volatile + ///\ingroup type_traits + template struct is_volatile : false_type {}; + template struct is_volatile : true_type {}; + template struct is_volatile : true_type {}; + + /// remove_volatile + ///\ingroup type_traits + template struct remove_volatile { typedef T type; }; + template struct remove_volatile { typedef T type; }; + + /// add_volatile + ///\ingroup type_traits + template struct add_volatile { typedef volatile T type; }; + template struct add_volatile { typedef volatile T type; }; + + /// remove_cv + ///\ingroup type_traits + template struct remove_cv + { + typedef typename remove_volatile::type>::type type; + }; + + /// add_cv + ///\ingroup type_traits + template struct add_cv + { + typedef typename add_volatile::type>::type type; + }; + + /// is_integral + ///\ingroup type_traits + template struct is_integral : false_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template struct is_integral : is_integral {}; + template struct is_integral : is_integral {}; + template struct is_integral : is_integral {}; + + /// is_signed + ///\ingroup type_traits + template struct is_signed : false_type {}; + template <> struct is_signed : integral_constant {}; + template <> struct is_signed : public etl::integral_constant(wchar_t(-1) < wchar_t(0))> {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type{}; + template <> struct is_signed : true_type{}; + template <> struct is_signed : true_type{}; + template struct is_signed : is_signed {}; + template struct is_signed : is_signed {}; + template struct is_signed : is_signed {}; + + /// is_unsigned + ///\ingroup type_traits + template struct is_unsigned : false_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : integral_constant 0)> {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : public etl::integral_constant wchar_t(0))> {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template struct is_unsigned : is_unsigned {}; + template struct is_unsigned : is_unsigned {}; + template struct is_unsigned : is_unsigned {}; + + /// is_floating_point + ///\ingroup type_traits + template struct is_floating_point : false_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template struct is_floating_point : is_floating_point {}; + template struct is_floating_point : is_floating_point {}; + template struct is_floating_point : is_floating_point {}; + + /// is_same + ///\ingroup type_traits + template struct is_same : public false_type {}; + template struct is_same : public true_type {}; + + /// is_void + ///\ingroup type_traits + template struct is_void : false_type {}; + template<> struct is_void : true_type {}; + + /// is_arithmetic + ///\ingroup type_traits + template struct is_arithmetic : integral_constant::value || is_floating_point::value> {}; + + /// is_fundamental + ///\ingroup type_traits + template struct is_fundamental : integral_constant::value || + is_void::value || + is_same::type>::value> {}; + + /// is_compound + ///\ingroup type_traits + template struct is_compound : integral_constant::value> {}; + + /// is_array + ///\ingroup type_traits + template struct is_array : false_type {}; + template struct is_array : true_type {}; + template struct is_array : true_type {}; + + /// is_pointer + ///\ingroup type_traits + template struct is_pointer : false_type {}; + template struct is_pointer : true_type {}; + + /// is_reference + ///\ingroup type_traits + template struct is_reference : false_type {}; + template struct is_reference : true_type {}; + + /// is_pod + /// For C++03, only fundamental and pointers types are recognised. + ///\ingroup type_traits +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) + // For compilers that support C++11 + template struct is_pod : std::is_pod {}; +#else + /// For C++03, only fundamental and pointers types are recognised. + template struct is_pod : etl::integral_constant::value || + etl::is_pointer::value> {}; +#endif + +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) && defined(ETL_C11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_constructible : std::is_trivially_constructible {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_constructible : std::is_trivially_copy_constructible {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_destructible : std::is_trivially_destructible {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_assignable : std::is_trivially_copy_assignable {}; +#else + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_constructible : etl::is_pod {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_constructible : etl::is_pod {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_destructible : etl::is_pod {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_assignable : etl::is_pod {}; +#endif + + + /// conditional + ///\ingroup type_traits + template struct conditional { typedef T type; }; + template struct conditional { typedef F type; }; + + /// make_signed + ///\ingroup type_traits + template struct make_signed { typedef T type; }; + template <> struct make_signed { typedef signed char type; }; + template <> struct make_signed { typedef signed char type; }; + + template <> struct make_signed + { + typedef etl::conditional::type>::type type; + }; + + template <> struct make_signed { typedef short type; }; + template <> struct make_signed { typedef int type; }; + template <> struct make_signed { typedef long type; }; + template <> struct make_signed { typedef long long type; }; + template struct make_signed : add_const::type> {}; + template struct make_signed : add_volatile::type> {}; + template struct make_signed : add_const::type>::type> {}; + + /// make_unsigned + ///\ingroup type_traits + template struct make_unsigned { typedef T type; }; + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef unsigned short type; }; + + template <> struct make_unsigned + { + typedef etl::conditional::type>::type type; + }; + + template <> struct make_unsigned { typedef unsigned int type; }; + template <> struct make_unsigned { typedef unsigned long type; }; + template <> struct make_unsigned { typedef unsigned long long type; }; + template struct make_unsigned : add_const::type> {}; + template struct make_unsigned : add_volatile::type> {}; + template struct make_unsigned : add_const::type>::type> {}; + + /// enable_if + ///\ingroup type_traits + template struct enable_if {}; + template struct enable_if { typedef T type; }; + + /// extent + ///\ingroup type_traits + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant::value> {}; + + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant::value> {}; + + /// remove_extent + ///\ingroup type_traits + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type;}; + + /// remove_all_extents + ///\ingroup type_traits + template struct remove_all_extents { typedef T type;}; + template struct remove_all_extents { typedef typename remove_all_extents::type type; }; + template struct remove_all_extents { typedef typename remove_all_extents::type type; }; + + /// rank + ///\ingroup type_traits + template struct rank : integral_constant {}; + template struct rank : public integral_constant::value + 1> {}; + template struct rank : public integral_constant::value + 1> {}; + + /// decay + ///\ingroup type_traits + template + struct decay + { + typedef typename etl::remove_reference::type U; + typedef typename etl::conditional::value, + typename etl::remove_extent::type*, + typename etl::remove_cv::type>::type type; + }; + + /// is_base_of + ///\ingroup type_traits + template + struct is_base_of + { + private: + + template struct dummy {}; + struct internal: TDerived, dummy{}; + + static TBase* check(TBase*); + template static char check(dummy*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + + /// Alignment templates. + /// These require compiler specific intrinsics. + ///\ingroup type_traits +#ifdef ETL_COMPILER_MICROSOFT + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_GCC + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_KEIL + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_IAR + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_TI + template struct alignment_of : integral_constant {}; +#endif + + /// Specialisation of 'alignment_of' for 'void'. + ///\ingroup type_traits + template <> struct alignment_of : integral_constant {}; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine if a type is one of a specified list.") + cog.outl("///\ingroup types") + cog.outl("//***************************************************************************") + cog.outl("template " % IsOneOf) + cog.outl("struct is_one_of") + cog.outl("{") + cog.outl(" static const bool value = ") + for n in range(1, int(IsOneOf)): + cog.outl(" etl::is_same::value ||" % n) + cog.outl(" etl::is_same::value;" % IsOneOf) + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#endif diff --git a/src/user_type.h b/src/user_type.h index 98837a92..4ecb193c 100644 --- a/src/user_type.h +++ b/src/user_type.h @@ -89,43 +89,16 @@ SOFTWARE. TypeName operator ++(int) { TypeName temp(*this); TypeName::operator ++(); return temp; } \ TypeName& operator --() { --value; return *this; } \ TypeName operator --(int) { TypeName temp(*this); TypeName::operator --(); return temp; } \ - TypeName& operator +=(const TypeName& rhs) { value += rhs.value; return *this; } \ - TypeName& operator -=(const TypeName& rhs) { value -= rhs.value; return *this; } \ - TypeName& operator *=(const TypeName& rhs) { value *= rhs.value; return *this; } \ - TypeName& operator /=(const TypeName& rhs) { value /= rhs.value; return *this; } \ - TypeName& operator %=(const TypeName& rhs) { value %= rhs.value; return *this; } \ - TypeName& operator &=(const TypeName& rhs) { value &= rhs.value; return *this; } \ - TypeName& operator &=(ValueType mask) { value &= mask; return *this; } \ - TypeName& operator |=(const TypeName& rhs) { value |= rhs.value; return *this; } \ - TypeName& operator |=(ValueType mask) { value &= mask; return *this; } \ - TypeName& operator ^=(const TypeName& rhs) { value ^= rhs.value; return *this; } \ - TypeName& operator ^=(ValueType mask) { value ^= mask; return *this; } \ + TypeName& operator +=(const ValueType& rhs) { value += rhs; return *this; } \ + TypeName& operator -=(const ValueType& rhs) { value -= rhs; return *this; } \ + TypeName& operator *=(const ValueType& rhs) { value *= rhs; return *this; } \ + TypeName& operator /=(const ValueType& rhs) { value /= rhs; return *this; } \ + TypeName& operator %=(const ValueType& rhs) { value %= rhs; return *this; } \ + TypeName& operator &=(const ValueType& rhs) { value &= rhs; return *this; } \ + TypeName& operator |=(const ValueType& rhs) { value |= rhs; return *this; } \ + TypeName& operator ^=(const ValueType& rhs) { value ^= rhs; return *this; } \ TypeName& operator <<=(ValueType distance) { value <<= distance; return *this; } \ TypeName& operator >>=(ValueType distance) { value >>= distance; return *this; } \ - \ - /* Volatile definitions.*/ \ - TypeName(const volatile TypeName &other) : value(other.value) {} \ - void operator=(const volatile TypeName &other) volatile { value = other.value; } \ - operator ValueType() volatile const { return value; } \ - volatile ValueType& get() volatile { return value; } \ - const volatile ValueType& get() volatile const { return value; } \ - void operator ++() volatile { ++value; } \ - volatile TypeName operator ++(int) volatile { volatile TypeName temp(*this); TypeName::operator ++(); return temp; } \ - void operator --() volatile { --value; } \ - volatile TypeName operator --(int) volatile { volatile TypeName temp(*this); TypeName::operator --(); return temp; } \ - void operator +=(const volatile TypeName& rhs) volatile { value += rhs.value; } \ - void operator -=(const volatile TypeName& rhs) volatile { value -= rhs.value; } \ - void operator *=(const volatile TypeName& rhs) volatile { value *= rhs.value; } \ - void operator /=(const volatile TypeName& rhs) volatile { value /= rhs.value; } \ - void operator %=(const volatile TypeName& rhs) volatile { value %= rhs.value; } \ - void operator &=(const volatile TypeName& rhs) volatile { value &= rhs.value; } \ - void operator &=(ValueType mask) volatile { value &= mask; } \ - void operator |=(const volatile TypeName& rhs) volatile { value |= rhs.value; } \ - void operator |=(ValueType mask) volatile { value &= mask; } \ - void operator ^=(const volatile TypeName& rhs) volatile { value ^= rhs.value; } \ - void operator ^=(ValueType mask) volatile { value ^= mask; } \ - void operator <<=(ValueType distance) volatile { value <<= distance; } \ - void operator >>=(ValueType distance) volatile { value >>= distance; } \ private: \ ValueType value; \ public: \ diff --git a/src/variant.h b/src/variant.h index 6b2931eb..0d57a4a4 100644 --- a/src/variant.h +++ b/src/variant.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -42,7 +42,6 @@ SOFTWARE. #include "static_assert.h" #include "alignment.h" #include "error_handler.h" -#include "largest.h" #if defined(ETL_COMPILER_KEIL) #pragma diag_suppress 940 @@ -124,6 +123,11 @@ namespace etl //*************************************************************************** typedef typename largest_type::type largest_t; + //*************************************************************************** + /// The largest size. + //*************************************************************************** + static const size_t SIZE = sizeof(largest_t); + //*************************************************************************** /// The largest alignment. //*************************************************************************** @@ -139,46 +143,6 @@ namespace etl //*************************************************************************** static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits::max; - //*************************************************************************** - /// Do we pass this type by value? - //*************************************************************************** - template - struct pass_by_value : integral_constant::value || etl::is_pointer::value> - { - }; - - //*************************************************************************** - /// Define the type for a parameter. - //*************************************************************************** - template - struct type_definition; - - //*************************************************************************** - /// Pass by value. - //*************************************************************************** - template - struct type_definition - { - typedef T type; - }; - - //*************************************************************************** - /// Pass by const reference. - //*************************************************************************** - template - struct type_definition - { - typedef const T& type; - }; - - //*************************************************************************** - /// Determines the type for parameters. - //*************************************************************************** - template - struct parameter_type : public type_definition::value> - { - }; - //*************************************************************************** /// Short form of no_type placeholders. //*************************************************************************** @@ -249,14 +213,14 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; }; //************************************************************************* @@ -269,13 +233,13 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -292,12 +256,12 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -315,11 +279,11 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -338,10 +302,10 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -361,9 +325,9 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -384,8 +348,8 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -407,7 +371,7 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -862,7 +826,7 @@ namespace etl //*************************************************************************** void clear() { - type_id = UNSUPPORTED_TYPE_ID; + destruct_current(); } //*************************************************************************** @@ -962,7 +926,7 @@ namespace etl /// The internal storage. /// Aligned on a suitable boundary, which should be good for all types. //*************************************************************************** - typename etl::aligned_storage::value>::type data; + typename etl::aligned_storage::type data; //*************************************************************************** /// The id of the current stored type. diff --git a/temp/message_router.h b/temp/message_router.h new file mode 100644 index 00000000..85d95fe0 --- /dev/null +++ b/temp/message_router.h @@ -0,0 +1,984 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +namespace etl +{ + /// Allow alternative type for message id. +#if !defined(ETL_MESSAGE_ID_TYPE) + typedef uint_least8_t message_id_t; +#else + typedef ETL_MESSAGE_ID_TYPE message_id_t; +#endif + + //*************************************************************************** + class imessage + { + public: + + virtual ~imessage() {} + virtual etl::message_id_t get_message_id() const = 0; + }; + + //*************************************************************************** + template + class message : public imessage + { + public: + + enum + { + ID = ID_ + }; + + //******************************************* + etl::message_id_t get_message_id() const + { + return etl::message_id_t(ID); + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************* + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************* + void send_message(imessage_router& destination, + const etl::imessage& message) + { + destination.receive(*this, message); + } + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + //******************************************* + void receive(const etl::imessage& message) + { + } + + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************* + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************* + static null_message_router& get() + { + static null_message_router instance; + return instance; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + //*************************************************************************** + // To generate to header file, run this at the command line. + // Note: You will need Python and COG installed. + // + // python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h + // Where is the number of messages to support. + // + // e.g. + // To generate handlers for up to 16 messages... + // python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h + // + // See CreateMessageProcessor.bat + //*************************************************************************** + + //*************************************************************************** + // The code below has been auto generated. Do not manually edit. + //*************************************************************************** + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T16::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: + return true; break; + default: + return false; break; + } + } + + class message_packet + { + public: + + explicit message_packet(const imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: new (&storage) T1(static_cast(msg)); break; + case T2::ID: new (&storage) T2(static_cast(msg)); break; + case T3::ID: new (&storage) T3(static_cast(msg)); break; + default: break; + } + } + + ~message_packet() + { + static_cast(storage).~imessage(); + } + + message_packet(const message_packet& other) + { + const etl::message_id_t id = other.get_imessage().get_message_id(); + + switch (id) + { + case T1::ID: new (&storage) T1(static_cast(msg)); break; + case T2::ID: new (&storage) T2(static_cast(msg)); break; + case T3::ID: new (&storage) T3(static_cast(msg)); break; + default: break; + } + } + + message_packet& operator = (const message_packet& other) + { + if (this != &other) + { + static_cast(storage).~imessage(); + new (this) message_packet(other); + } + } + + const etl::imessage& get_imessage() const + { + return *reiniterpret_cast(storage); + } + + operator const imessage&() const + { + return get_imessage(); + } + + private: + + etl::aligned_storage::size, etl::largest_alignment::value>::type storage; + }; + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: + return true; break; + default: + return false; break; + } + } + }; +} + +#endif diff --git a/test/codeblocks/ETL.cbp b/test/codeblocks/ETL.cbp index 963db74b..60485a23 100644 --- a/test/codeblocks/ETL.cbp +++ b/test/codeblocks/ETL.cbp @@ -172,6 +172,8 @@ + + @@ -193,12 +195,17 @@ + + + + + @@ -206,6 +213,7 @@ + @@ -226,12 +234,16 @@ + + + + @@ -273,6 +285,7 @@ + @@ -291,12 +304,15 @@ + + + @@ -314,12 +330,14 @@ + + diff --git a/test/codeblocks/ETL.depend b/test/codeblocks/ETL.depend index c4e17a7b..1b6a961c 100644 --- a/test/codeblocks/ETL.depend +++ b/test/codeblocks/ETL.depend @@ -3289,7 +3289,7 @@ "CurrentTest.h" "ReportAssertImpl.h" -1501066687 source:d:\users\john\documents\programming\github\etl\test\test_algorithm.cpp +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_algorithm.cpp "UnitTest++.h" "algorithm.h" "container.h" @@ -3538,7 +3538,7 @@ "static_assert.h" "exception.h" -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_deque.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_deque.cpp "UnitTest++.h" "ExtraCheckMacros.h" "deque.h" @@ -3727,7 +3727,7 @@ 1482623723 v_1.h" -1497713618 source:d:\users\john\documents\programming\github\etl\test\test_forward_list.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_forward_list.cpp "UnitTest++.h" "ExtraCheckMacros.h" "data.h" @@ -4151,12 +4151,12 @@ "../exception.h" "../error_handler.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_type_traits.cpp +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_type_traits.cpp "UnitTest++.h" "type_traits.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_variant.cpp +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_variant.cpp "UnitTest++.h" "ExtraCheckMacros.h" "variant.h" @@ -5302,7 +5302,7 @@ "platform.h" "static_assert.h" -1501066686 d:\users\john\documents\programming\github\etl\src\algorithm.h +1502118978 d:\users\john\documents\programming\github\etl\src\algorithm.h @@ -5312,7 +5312,7 @@ "iterator.h" "type_traits.h" -1501066686 d:\users\john\documents\programming\github\etl\src\type_traits.h +1502118978 d:\users\john\documents\programming\github\etl\src\type_traits.h "platform.h" "nullptr.h" @@ -5322,7 +5322,7 @@ -1500986416 d:\users\john\documents\programming\github\etl\src\alignment.h +1502118978 d:\users\john\documents\programming\github\etl\src\alignment.h "type_traits.h" "static_assert.h" @@ -5370,7 +5370,7 @@ "log.h" -1501066686 d:\users\john\documents\programming\github\etl\src\smallest.h +1502118978 d:\users\john\documents\programming\github\etl\src\smallest.h "integral_limits.h" @@ -5484,7 +5484,7 @@ "static_assert.h" "exception.h" -1501067284 d:\users\john\documents\programming\github\etl\src\deque.h +1501803126 d:\users\john\documents\programming\github\etl\src\deque.h @@ -5561,7 +5561,7 @@ "../error_handler.h" "../debug_count.h" -1501067284 d:\users\john\documents\programming\github\etl\src\vector.h +1501803126 d:\users\john\documents\programming\github\etl\src\vector.h @@ -5606,7 +5606,7 @@ "../ivector.h" "../error_handler.h" -1497713617 d:\users\john\documents\programming\github\etl\src\forward_list.h +1501803126 d:\users\john\documents\programming\github\etl\src\forward_list.h @@ -5703,12 +5703,12 @@ "nullptr.h" "parameter_type.h" -1501067284 d:\users\john\documents\programming\github\etl\src\largest.h +1502118978 d:\users\john\documents\programming\github\etl\src\largest.h "type_traits.h" "smallest.h" "static_assert.h" -1501067284 d:\users\john\documents\programming\github\etl\src\list.h +1502118941 d:\users\john\documents\programming\github\etl\src\list.h @@ -5930,7 +5930,7 @@ "exception.h" "error_handler.h" -1500986416 d:\users\john\documents\programming\github\etl\src\variant.h +1501803139 d:\users\john\documents\programming\github\etl\src\variant.h "platform.h" "array.h" @@ -5941,7 +5941,6 @@ "static_assert.h" "alignment.h" "error_handler.h" - "largest.h" 1479515291 d:\users\john\documents\programming\github\etl\src\visitor.h @@ -7825,7 +7824,7 @@ "type_traits.h" -1501066686 d:\users\john\documents\programming\github\etl\src\memory.h +1502118978 d:\users\john\documents\programming\github\etl\src\memory.h "type_traits.h" @@ -7835,10 +7834,10 @@ "platform.h" -1501067284 source:d:\users\john\documents\programming\github\etl\src\random.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\src\random.cpp "random.h" -1501067284 d:\users\john\documents\programming\github\etl\src\random.h +1501803126 d:\users\john\documents\programming\github\etl\src\random.h 1494277861 source:d:\users\john\documents\programming\github\etl\test\test_intrusive_flat_map.cpp @@ -7933,7 +7932,7 @@ "UnitTest++.h" "iterator.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_memory.cpp +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_memory.cpp "UnitTest++.h" "memory.h" "debug_count.h" @@ -7944,7 +7943,7 @@ -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_random.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_random.cpp "UnitTest++.h" "random.h" @@ -7952,7 +7951,7 @@ -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_vector_non_trivial.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_vector_non_trivial.cpp "UnitTest++.h" @@ -8229,3 +8228,133 @@ "exception.h" "vector.h" +1479515291 source:d:\users\john\documents\programming\github\etl\test\test_compile.cpp + "algorithm.h" + "alignment.h" + "array.h" + "bitset.h" + "container.h" + "crc8_ccitt.h" + "crc16.h" + "crc16_ccitt.h" + "crc16_kermit.h" + "crc32.h" + "crc64_ecma.h" + "cyclic_value.h" + "deque.h" + "io_port.h" + "vector.h" + "variant.h" + "list.h" + "map.h" + + +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_fsm.cpp + "UnitTest++.h" + "fsm.h" + "enum_type.h" + "container.h" + + +1501803139 d:\users\john\documents\programming\github\etl\src\fsm.h + + "array.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "user_type.h" + "message_router.h" + "integral_limits.h" + "largest.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\user_type.h + +1501803139 d:\users\john\documents\programming\github\etl\src\message_router.h + + "message.h" + "message_types.h" + "alignment.h" + "error_handler.h" + "exception.h" + "largest.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_message_router.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "message_router.h" + "queue.h" + "largest.h" + "packet.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\packet.h + "platform.h" + "static_assert.h" + "alignment.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_packet.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "packet.h" + "largest.h" + "queue.h" + "pool.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_task_scheduler.cpp + "UnitTest++.h" + + + + "task.h" + "scheduler.h" + "container.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\task.h + + "error_handler.h" + "exception.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\scheduler.h + + "vector.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "task.h" + "type_traits.h" + "function.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message.h + + "error_handler.h" + "exception.h" + "message_types.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message_types.h + + +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_message_bus.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "message_router.h" + "message_bus.h" + "queue.h" + "largest.h" + "packet.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message_bus.h + + + "algorithm.h" + "vector.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "message_types.h" + "message.h" + "message_router.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_user_type.cpp + "UnitTest++.h" + + "user_type.h" + diff --git a/test/codeblocks/ETL.layout b/test/codeblocks/ETL.layout index 613556e7..7fc9cd9e 100644 --- a/test/codeblocks/ETL.layout +++ b/test/codeblocks/ETL.layout @@ -2,269 +2,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - + @@ -272,4 +27,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 6403aa23..eb631739 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -42,6 +42,39 @@ namespace typedef std::vector Data; Data data = { 2, 1, 4, 3, 6, 5, 8, 7, 10, 9 }; + struct StructData + { + int a; + int b; + }; + + bool operator ==(const StructData& lhs, const StructData& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b); + } + + struct StructDataPredicate + { + bool operator ()(const StructData& lhs, const StructData& rhs) const + { + return lhs.a < rhs.a; + } + }; + + struct StructDataEquality + { + bool operator ()(const StructData& lhs, const StructData& rhs) const + { + return lhs.a == rhs.a; + } + }; + + std::ostream& operator << (std::ostream& os, const StructData& data) + { + os << data.a << "," << data.b; + return os; + } + SUITE(test_algorithm) { //========================================================================= @@ -543,10 +576,40 @@ namespace int data1[] = { 1, 2, 3, 5, 6, 7, 8 }; // Find the element not less than 4. - int* p = std::find_if_not(std::begin(data1), std::end(data1), std::bind2nd(std::less(), 4)); + int* p = etl::find_if_not(std::begin(data1), std::end(data1), std::bind2nd(std::less(), 4)); CHECK_EQUAL(5, *p); } + //========================================================================= + TEST(binary_find) + { + int data1[] = { 1, 2, 3, 5, 6, 7, 8 }; + + // Find the element of value 5. + int* p = etl::binary_find(std::begin(data1), std::end(data1), 5); + CHECK_EQUAL(5, *p); + + // Find the element of value 4. + p = etl::binary_find(std::begin(data1), std::end(data1), 4); + CHECK_EQUAL(std::end(data1), p); + } + + //========================================================================= + TEST(binary_find_StructDataPredicate_StructDataEquality) + { + StructData data1[] = { { 1, 8 }, { 2, 7 }, { 3, 6 },{ 4, 5 },{ 5, 4 },{ 6, 3 },{ 7, 2 },{ 8, 1 } }; + StructData test1 = { 4, 5 }; + StructData test2 = { 9, 0 }; + + // Find the element of value 5. + StructData* p = etl::binary_find(std::begin(data1), std::end(data1), test1, StructDataPredicate(), StructDataEquality()); + CHECK_EQUAL(test1, *p); + + // Find the element of value 4. + p = etl::binary_find(std::begin(data1), std::end(data1), test2, StructDataPredicate(), StructDataEquality()); + CHECK_EQUAL(std::end(data1), p); + } + //========================================================================= TEST(for_each_if) { diff --git a/test/test_fsm.cpp b/test/test_fsm.cpp new file mode 100644 index 00000000..71a78263 --- /dev/null +++ b/test/test_fsm.cpp @@ -0,0 +1,503 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" + +#include "fsm.h" +#include "enum_type.h" +#include "container.h" + +#include + +namespace +{ + const etl::message_router_id_t MOTOR_CONTROL = 0; + + + //*************************************************************************** + // Events + struct EventId + { + enum enum_type + { + START, + STOP, + STOPPED, + SET_SPEED, + UNSUPPORTED + }; + + ETL_DECLARE_ENUM_TYPE(EventId, etl::message_id_t) + ETL_ENUM_TYPE(START, "Start") + ETL_ENUM_TYPE(STOP, "Stop") + ETL_ENUM_TYPE(STOPPED, "Stopped") + ETL_ENUM_TYPE(SET_SPEED, "Set Speed") + ETL_ENUM_TYPE(UNSUPPORTED, "Unsupported") + ETL_END_ENUM_TYPE + }; + + //*********************************** + class Start : public etl::message + { + }; + + //*********************************** + class Stop : public etl::message + { + public: + + Stop() : isEmergencyStop(false) {} + Stop(bool emergency) : isEmergencyStop(emergency) {} + + const bool isEmergencyStop; + }; + + //*********************************** + class SetSpeed : public etl::message + { + public: + + SetSpeed(int speed) : speed(speed) {} + + const int speed; + }; + + //*********************************** + class Stopped : public etl::message + { + }; + + //*********************************** + class Unsupported : public etl::message + { + }; + + //*************************************************************************** + // States + struct StateId + { + enum enum_type + { + IDLE, + RUNNING, + WINDING_DOWN, + LOCKED, + NUMBER_OF_STATES + }; + + ETL_DECLARE_ENUM_TYPE(StateId, etl::fsm_state_id_t) + ETL_ENUM_TYPE(IDLE, "Idle") + ETL_ENUM_TYPE(RUNNING, "Running") + ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") + ETL_ENUM_TYPE(LOCKED, "Locked") + ETL_END_ENUM_TYPE + }; + + //*********************************** + // The motor control FSM. + //*********************************** + class MotorControl : public etl::fsm + { + public: + + MotorControl(etl::ifsm_state** p_states, size_t size) + : fsm(MOTOR_CONTROL) + { + set_states(p_states, size); + ClearStatistics(); + } + + //*********************************** + void ClearStatistics() + { + startCount = 0; + stopCount = 0; + setSpeedCount = 0; + unknownCount = 0; + stoppedCount = 0; + isLampOn = false; + speed = 0; + } + + //*********************************** + void SetSpeed(int speed_) + { + speed = speed_; + } + + //*********************************** + void TurnRunningLampOn() + { + isLampOn = true; + } + + //*********************************** + void TurnRunningLampOff() + { + isLampOn = false; + } + + int startCount; + int stopCount; + int setSpeedCount; + int unknownCount; + int stoppedCount; + bool isLampOn; + int speed; + }; + + //*********************************** + // The idle state. + //*********************************** + class Idle : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const Start& event) + { + ++get_fsm_context().startCount; + return StateId::RUNNING; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& sender, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_enter_state() + { + get_fsm_context().TurnRunningLampOff(); + return StateId::LOCKED; + } + }; + + //*********************************** + // The running state. + //*********************************** + class Running : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const Stop& event) + { + ++get_fsm_context().stopCount; + + if (event.isEmergencyStop) + { + return StateId::IDLE; + } + else + { + return StateId::WINDING_DOWN; + } + } + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const SetSpeed& event) + { + ++get_fsm_context().setSpeedCount; + get_fsm_context().SetSpeed(event.speed); + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& sender, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_enter_state() + { + get_fsm_context().TurnRunningLampOn(); + + return STATE_ID; + } + }; + + //*********************************** + // The winding down state. + //*********************************** + class WindingDown : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& source, const Stopped& event) + { + ++get_fsm_context().stoppedCount; + return StateId::IDLE; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& source, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + }; + + //*********************************** + // The locked state. + //*********************************** + class Locked : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& source, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + }; + + // The states. + Idle idle; + Running running; + WindingDown windingDown; + Locked locked; + + etl::ifsm_state* stateList[StateId::NUMBER_OF_STATES] = + { + &idle, &running, &windingDown, &locked + }; + + MotorControl motorControl(stateList, etl::size(stateList)); + + SUITE(test_map) + { + //************************************************************************* + TEST(test_fsm) + { + etl::null_message_router nmr; + + motorControl.reset(); + motorControl.ClearStatistics(); + + CHECK(!motorControl.is_started()); + + // Start the FSM. + motorControl.start(); + CHECK(motorControl.is_started()); + + // Now in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Stop()); + motorControl.receive(nmr, Stopped()); + motorControl.receive(nmr, SetSpeed(10)); + + CHECK_EQUAL(StateId::IDLE, motorControl.get_state_id()); + CHECK_EQUAL(StateId::IDLE, motorControl.get_state().get_state_id()); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(3, motorControl.unknownCount); + + // Send Start event. + motorControl.receive(nmr, Start()); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(3, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Start()); + motorControl.receive(nmr, Stopped()); + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send SetSpeed event. + motorControl.receive(nmr, SetSpeed(100)); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send Stop event. + motorControl.receive(nmr, Stop()); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Start()); + motorControl.receive(nmr, Stop()); + motorControl.receive(nmr, SetSpeed(100)); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(8, motorControl.unknownCount); + + // Send Stopped event. + motorControl.receive(nmr, Stopped()); + + // Now in Locked state via Idle state. + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(8, motorControl.unknownCount); + } + + //************************************************************************* + TEST(test_fsm_emergency_stop) + { + etl::null_message_router nmr; + + motorControl.reset(); + motorControl.ClearStatistics(); + + CHECK(!motorControl.is_started()); + + // Start the FSM. + motorControl.start(); + CHECK(motorControl.is_started()); + + // Now in Idle state. + + // Send Start event. + motorControl.receive(nmr, Start()); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + + // Send emergency Stop event. + motorControl.receive(nmr, Stop(true)); + + // Now in Locked state via Idle state. + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + } + + //************************************************************************* + TEST(test_fsm_supported) + { + CHECK(motorControl.accepts(EventId::SET_SPEED)); + CHECK(motorControl.accepts(EventId::START)); + CHECK(motorControl.accepts(EventId::STOP)); + CHECK(motorControl.accepts(EventId::STOPPED)); + CHECK(motorControl.accepts(EventId::UNSUPPORTED)); + + CHECK(motorControl.accepts(SetSpeed(0))); + CHECK(motorControl.accepts(Start())); + CHECK(motorControl.accepts(Stop())); + CHECK(motorControl.accepts(Stopped())); + CHECK(motorControl.accepts(Unsupported())); + } + }; +} diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 44b5f0d6..1e237565 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -445,5 +445,31 @@ namespace etl::destroy(p, p + SIZE, count); CHECK_EQUAL(0U, count); } + + //************************************************************************* + TEST(test_create_copy) + { + struct Test : etl::create_copy + { + std::string text; + }; + + char buffer[sizeof(Test)]; + + Test test1; + test1.text = "12345678"; + test1.create_copy_at(buffer); + test1.text = "87654321"; + + Test& test2 = *reinterpret_cast(buffer); + + CHECK_EQUAL(std::string("87654321"), test1.text); + CHECK_EQUAL(std::string("12345678"), test2.text); + + int count = 0; + test1.create_copy_at(buffer, count); + + CHECK_EQUAL(1, count); + } }; } diff --git a/test/test_message_bus.cpp b/test/test_message_bus.cpp new file mode 100644 index 00000000..66e079f5 --- /dev/null +++ b/test/test_message_bus.cpp @@ -0,0 +1,729 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "message_router.h" +#include "message_bus.h" +#include "queue.h" +#include "largest.h" +#include "packet.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1 = 1, + ROUTER2 = 2, + ROUTER3 = 3, + ROUTER4 = 4, + ROUTER5 = 5 + }; + + struct Message1 : public etl::message + { + }; + + struct Message2 : public etl::message + { + }; + + struct Message3 : public etl::message + { + int value[10]; + }; + + struct Message4 : public etl::message + { + }; + + struct Message5 : public etl::message + { + }; + + Message1 message1; + Message2 message2; + Message3 message3; + Message4 message4; + Message5 message5; + + int call_order; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4, 5. + //*************************************************************************** + class RouterA : public etl::message_router + { + public: + + RouterA(etl::message_router_id_t id) + : message_router(id), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message5_count(0), + message_unknown_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + + order = call_order++; + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message3& msg) + { + ++message3_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++message5_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message5_count; + int message_unknown_count; + int order; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class RouterB : public etl::message_router + { + public: + + RouterB(etl::message_router_id_t id) + : message_router(id), + message1_count(0), + message2_count(0), + message4_count(0), + message5_count(0), + message_unknown_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++message5_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + etl::send_message(sender, message5); + } + + int message1_count; + int message2_count; + int message4_count; + int message5_count; + int message_unknown_count; + }; + + etl::imessage_router* p_router; + etl::imessage_bus* p_bus; + + SUITE(test_message_router) + { + //========================================================================= + TEST(message_bus_subscribe_unsubscribe) + { + etl::message_bus<2> bus1; + + RouterA router1(0); + RouterB router2(1); + RouterA router3(2); + + CHECK_EQUAL(0U, bus1.size()); + + CHECK_NO_THROW(bus1.subscribe(router1)); + CHECK_EQUAL(1U, bus1.size()); + + CHECK_NO_THROW(bus1.subscribe(router2)); + CHECK_EQUAL(2U, bus1.size()); + + CHECK_THROW(bus1.subscribe(router3), etl::message_bus_too_many_subscribers); + CHECK_EQUAL(2U, bus1.size()); + + bus1.unsubscribe(router1); + CHECK_EQUAL(1U, bus1.size()); + + // Erase router not in list. + bus1.unsubscribe(router3); + CHECK_EQUAL(1U, bus1.size()); + + // Erase using id. + bus1.unsubscribe(router2.get_message_router_id()); + CHECK_EQUAL(0U, bus1.size()); + + // Erase router from empty list. + bus1.unsubscribe(router2); + CHECK_EQUAL(0U, bus1.size()); + } + + //========================================================================= + TEST(message_bus_subscribe_unsubscribe_sub_bus) + { + etl::message_bus<4> bus1; + etl::message_bus<2> bus2; + etl::message_bus<3> bus3; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4(ROUTER4); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(bus2); + bus1.subscribe(bus3); + + bus2.subscribe(router3); + bus3.subscribe(router4); + + CHECK_EQUAL(4U, bus1.size()); + + bus1.unsubscribe(etl::imessage_bus::MESSAGE_BUS); + CHECK_EQUAL(2U, bus1.size()); + + bus1.unsubscribe(etl::imessage_bus::ALL_MESSAGE_ROUTERS); + CHECK_EQUAL(0U, bus1.size()); + } + + //========================================================================= + TEST(message_bus_broadcast) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + bus1.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + bus1.receive(sender, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + bus1.receive(sender, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Use global function. + etl::send_message(sender, bus1, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(1, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(7, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_as_router) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + // Reference to router sub-type + etl::imessage_router& irouter = bus1; + + irouter.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + irouter.receive(sender, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + irouter.receive(sender, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Use global function. + etl::send_message(sender, irouter, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(1, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(7, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_addressed) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + bus1.receive(sender, ROUTER1, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, sender.message5_count); + + bus1.receive(sender, ROUTER2, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + bus1.receive(sender, ROUTER1, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(3, sender.message5_count); + + // Use global function. + etl::send_message(sender, bus1, ROUTER2, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + // Send to a router not subscribed to the bus. + bus1.receive(sender, ROUTER5, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_addressed_duplicate_router_id) + { + etl::message_bus<3> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER1); + RouterB router3(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(router3); + + bus1.receive(sender, ROUTER1, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(0, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_addressed_sub_bus) + { + etl::message_bus<3> bus1; + etl::message_bus<2> bus2; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4(ROUTER4); + + RouterA sender(ROUTER5); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(bus2); + + bus2.subscribe(router3); + bus2.subscribe(router4); + + // Broadcast to bus1 + bus1.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + // Addressed to ROUTER2 + bus1.receive(sender, ROUTER2, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(2, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Addressed to ROUTER3 via bus2 + bus1.receive(sender, ROUTER3, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(2, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(6, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_order) + { + etl::message_bus<4> bus1; + etl::message_bus<2> bus2; + etl::message_bus<2> bus3; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4a(ROUTER4); + RouterA router4b(ROUTER4); + + RouterA sender(ROUTER5); + + bus1.subscribe(router1); + bus1.subscribe(bus3); + bus1.subscribe(bus2); + bus1.subscribe(router2); + + bus2.subscribe(router3); + bus3.subscribe(router4b); + bus3.subscribe(router4a); + + call_order = 0; + + bus1.receive(sender, message1); + + CHECK_EQUAL(0, router1.order); + CHECK_EQUAL(1, router2.order); + CHECK_EQUAL(2, router4b.order); + CHECK_EQUAL(3, router4a.order); + CHECK_EQUAL(4, router3.order); + } + }; +} diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp new file mode 100644 index 00000000..c2890fb0 --- /dev/null +++ b/test/test_message_router.cpp @@ -0,0 +1,421 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "message_router.h" +#include "queue.h" +#include "largest.h" +#include "packet.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1, + ROUTER2 + }; + + struct Message1 : public etl::message + { + }; + + struct Message2 : public etl::message + { + }; + + struct Message3 : public etl::message + { + int value[10]; + }; + + struct Message4 : public etl::message + { + }; + + struct Message5 : public etl::message + { + }; + + Message1 message1; + Message2 message2; + Message3 message3; + Message4 message4; + Message5 message5; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. + //*************************************************************************** + class Router1 : public etl::message_router + { + public: + + Router1() + : message_router(ROUTER1), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message3& msg) + { + ++message3_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++callback_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class Router2 : public etl::message_router + { + public: + + Router2() + : message_router(ROUTER2), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++callback_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + etl::send_message(sender, message5); + } + + int message1_count; + int message2_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + + etl::imessage_router* p_router; + + SUITE(test_message_router) + { + //========================================================================= + TEST(message_router) + { + Router1 r1; + Router2 r2; + + p_router = &r1; + + p_router->receive(r2, message1); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(1, r2.callback_count); + + p_router->receive(r2, message2); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(2, r2.callback_count); + + p_router->receive(r2, message3); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(3, r2.callback_count); + + p_router->receive(r2, message4); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(1, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(4, r2.callback_count); + + p_router = &r2; + + p_router->receive(r1, message1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + + p_router->receive(r1, message2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + + p_router->receive(r1, message3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(1, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + + p_router->receive(r1, message4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(1, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + } + + //========================================================================= + TEST(message_null_router) + { + Router2 router; + etl::null_message_router null_router; + + // Send from the null router. + etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + // Send to the null router. + etl::send_message(null_router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //========================================================================= + TEST(message_router_accepts) + { + Router2 r2; + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(!r2.accepts(message3)); + CHECK(!r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + + //========================================================================= + TEST(message_router_queue) + { + Router1 r1; + Router2 r2; + + typedef Router2::message_packet Packet; + typedef etl::queue Queue; + + Queue queue; + + etl::imessage* im; + + // Queue some messages in the message packet queue. + im = &message1; + queue.emplace(*im); + + im = &message2; + queue.emplace(*im); + + // The router2 queue doesn't accept Message3 types. + im = &message3; + CHECK_THROW(queue.emplace(*im), etl::unhandled_message_exception); + + im = &message4; + queue.emplace(*im); + + im = &message4; + queue.emplace(*im); + + etl::imessage& imr1 = queue.front().get(); + r2.receive(r1, imr1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + queue.pop(); + + etl::imessage& imr2 = queue.front().get(); + r2.receive(r1, imr2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + queue.pop(); + + const etl::imessage& imr3 = queue.front().get(); + r2.receive(r1, imr3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + queue.pop(); + + const Queue& crqueue = queue; + const etl::imessage& imr4 = crqueue.front().get(); + r2.receive(r1, imr4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(2, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + queue.pop(); + } + }; +} diff --git a/test/test_packet.cpp b/test/test_packet.cpp new file mode 100644 index 00000000..90f70c67 --- /dev/null +++ b/test/test_packet.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "packet.h" +#include "largest.h" +#include "queue.h" +#include "pool.h" + +namespace +{ + // Test classes for polymorphic tests. + struct base + { + base(int v_) + : v(v_) + { + } + + virtual ~base() + { + } + + virtual int value() const = 0; + + protected: + + const int v; + }; + + struct not_base + { + not_base() + { + } + }; + + struct derived_1 : public base + { + derived_1(int value) + : base(value) + { + } + + int value() const + { + return v; + } + + static int count; + }; + + struct derived_2 : public base + { + derived_2(int value) + : base(value) + { + } + + int value() const + { + return v; + } + }; + + typedef etl::largest types; + // + //// Test packet types. + typedef etl::packet packet1_t; + typedef etl::packet packet2_t; + + SUITE(test_packet) + { + //************************************************************************* + TEST(test_constructor_value) + { + derived_1 d1(1); + derived_2 d2(2); + + packet1_t p11(d1); + packet1_t p12(d2); + + base* b; + b = &p11.get(); + CHECK_EQUAL(d1.value(), b->value()); + + b = &p12.get(); + CHECK_EQUAL(d2.value(), b->value()); + + // These lines should fail to compile. + //p11 = p12; + //packet2_t p21(d1); + //packet2_t p22(d1); + } + + //************************************************************************* + TEST(test_assignment) + { + derived_1 d1(1); + derived_2 d2(2); + + packet1_t p(d1); + + base* b; + b = &p.get(); + CHECK_EQUAL(d1.value(), b->value()); + + p = d2; + CHECK_EQUAL(d2.value(), b->value()); + } + + //************************************************************************* + TEST(test_packet_queueing) + { + derived_1 da(1); + derived_2 db(2); + derived_1 dc(3); + derived_2 dd(4); + + etl::queue queue; + + queue.emplace(da); + queue.emplace(db); + queue.emplace(dc); + queue.emplace(dd); + + CHECK_EQUAL(da.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(db.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(dc.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(dd.value(), queue.front().get().value()); + queue.pop(); + } + + //************************************************************************* + TEST(test_packet_get) + { + derived_1 da(1); + + // Non-const. + packet1_t p1(da); + base& rb = p1.get(); + CHECK_EQUAL(da.value(), rb.value()); + + // Const. + const packet1_t p2(da); + const base& crb = p2.get(); + CHECK_EQUAL(da.value(), crb.value()); + } + } +} diff --git a/test/test_task_scheduler.cpp b/test/test_task_scheduler.cpp new file mode 100644 index 00000000..7680e37f --- /dev/null +++ b/test/test_task_scheduler.cpp @@ -0,0 +1,263 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" + +#include +#include +#include + +#include "task.h" +#include "scheduler.h" +#include "container.h" + +typedef std::vector WorkList_t; + +//***************************************************************************** +struct Common +{ + //********************************************* + Common() + : idle_callback(*this, &Common::IdleCallback), + watchdog_callback(*this, &Common::WatchdogCallback), + watchdog_called(false) + { + } + + //********************************************* + void Clear() + { + workList.clear(); + } + + //********************************************* + void IdleCallback() + { + pScheduler->exit_scheduler(); + } + + //********************************************* + void WatchdogCallback() + { + watchdog_called = true; + } + + WorkList_t workList; + etl::function idle_callback; + etl::function watchdog_callback; + etl::ischeduler* pScheduler; + bool watchdog_called; +}; + +//***************************************************************************** +class Task : public etl::task +{ +public: + + //********************************************* + Task(etl::task_priority_t priority, WorkList_t& work, Common& common) + : task(priority), + work(work), + common(common), + workIndex(0), + addAtIndex(0), + workToAdd(""), + pTaskToAddTo(nullptr) + { + workCopy = work; + } + + //********************************************* + void Reset() + { + workIndex = 0; + addAtIndex = 0; + workToAdd = ""; + pTaskToAddTo = nullptr; + work = workCopy; + } + + //********************************************* + void WorkToAdd(int addAtIndex_, const std::string& workToAdd_, Task& taskToAddTo_) + { + addAtIndex = addAtIndex_; + workToAdd = workToAdd_; + pTaskToAddTo = &taskToAddTo_; + } + + //********************************************* + uint32_t task_request_work() const + { + return uint_least8_t(work.size() - workIndex); + } + + //********************************************* + void task_process_work() + { + common.workList.push_back(work[workIndex]); + ++workIndex; + + if (workIndex == addAtIndex) + { + pTaskToAddTo->work.push_back(workToAdd); + } + } + +private: + + WorkList_t work; + WorkList_t workCopy; + Common &common; + uint_least8_t workIndex; + int addAtIndex; + std::string workToAdd; + Task* pTaskToAddTo; +}; + +Common common; + +WorkList_t work1 = { "T1W1", "T1W2", "T1W3" }; +WorkList_t work2 = { "T2W1", "T2W2", "T2W3", "T2W4" }; +WorkList_t work3 = { "T3W1", "T3W2" }; + +Task task1(1, work1, common); +Task task2(2, work2, common); +Task task3(3, work3, common); + +etl::task* taskList[] = { &task1, &task2, &task3 }; + +typedef etl::scheduler SchedulerSequencialSingle; +typedef etl::scheduler SchedulerSequencialMultiple; +typedef etl::scheduler SchedulerHighestPriority; +typedef etl::scheduler SchedulerMostWork; + +namespace +{ + SUITE(test_task_scheduler) + { + //========================================================================= + TEST(test_scheduler_sequencial_single) + { + SchedulerSequencialSingle s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T2W1", "T1W1", "T3W2", "T2W2", "T1W2", "T3W3", "T2W3", "T1W3", "T2W4" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_sequencial_multiple) + { + SchedulerSequencialMultiple s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T3W2", "T2W1", "T2W2", "T2W3", "T2W4", "T1W1", "T1W2", "T1W3", "T3W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_highest_priority) + { + SchedulerHighestPriority s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T3W2", "T2W1", "T2W2", "T3W3", "T2W3", "T2W4", "T1W1", "T1W2", "T1W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_most_work) + { + SchedulerMostWork s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(3, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T2W1", "T2W2", "T1W1", "T3W1", "T2W3", "T3W2", "T1W2", "T3W3", "T2W4", "T1W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + }; +} diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index b9e624d7..5f80210e 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -41,14 +41,20 @@ namespace std #include "type_traits.h" #include -// A class to test non-fundamental types. -struct Test -{ - int a; -}; - namespace { + // A class to test non-fundamental types. + struct Test + { + int a; + }; + + // A class to test etl::is_one_of + template + struct Type + { + }; + SUITE(test_type_traits) { //************************************************************************* @@ -525,5 +531,55 @@ namespace CHECK(std::alignment_of::value == etl::alignment_of::value); CHECK(std::alignment_of::value == etl::alignment_of::value); } + + //************************************************************************* + TEST(test_is_one_of) + { + typedef Type<0> T0; + typedef Type<1> T1; + typedef Type<2> T2; + typedef Type<3> T3; + typedef Type<4> T4; + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + } + + //************************************************************************* + TEST(test_is_base_of) + { + struct A { }; + struct B : public A { }; + struct C { }; + + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + } }; } diff --git a/test/test_user_type.cpp b/test/test_user_type.cpp new file mode 100644 index 00000000..0e3e5da7 --- /dev/null +++ b/test/test_user_type.cpp @@ -0,0 +1,224 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 "UnitTest++.h" +#include + +#include "user_type.h" + +ETL_DECLARE_USER_TYPE(CompassDirection, int) +ETL_USER_TYPE(North, 0) +ETL_USER_TYPE(South, 180) +ETL_USER_TYPE(East, 90) +ETL_USER_TYPE(West, 270) +ETL_END_USER_TYPE(CompassDirection) + +namespace +{ + SUITE(test_user_type) + { + //************************************************************************* + TEST(Values) + { + CHECK_EQUAL(0, CompassDirection::North); + CHECK_EQUAL(180, CompassDirection::South); + CHECK_EQUAL(90, CompassDirection::East); + CHECK_EQUAL(270, CompassDirection::West); + } + + //************************************************************************* + TEST(test_assignment) + { + CompassDirection value1 = CompassDirection::North; + CompassDirection value2 = CompassDirection(135); + + value1 = value2; + + CHECK_EQUAL(135, value1); + } + + //************************************************************************* + TEST(test_equality) + { + CompassDirection value1 = CompassDirection::North; + CompassDirection value2 = CompassDirection::South; + CompassDirection value3 = CompassDirection::South; + + CHECK(value1 != value2); + CHECK(value2 == value3); + } + + //************************************************************************* + TEST(test_get_value) + { + CompassDirection actual = CompassDirection::North; + CompassDirection expected = CompassDirection::North; + + CHECK_EQUAL(expected, actual.get()); + } + + //************************************************************************* + TEST(test_pre_increment) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North + 1); + + CHECK_EQUAL(expected, ++value); + } + + //************************************************************************* + TEST(test_post_increment) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North + 1); + + CHECK_EQUAL(CompassDirection::North, value++); + CHECK_EQUAL(expected, value); + } + + + //************************************************************************* + TEST(test_pre_decrement) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North - 1); + + CHECK_EQUAL(expected, --value); + } + + //************************************************************************* + TEST(test_post_decrement) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North - 1); + + CHECK_EQUAL(CompassDirection::North, value--); + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_add_equal) + { + CompassDirection value = CompassDirection::North; + value += 3; + CompassDirection expected = CompassDirection(CompassDirection::North + 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_subtract_equal) + { + CompassDirection value = CompassDirection::North; + value -= 3; + CompassDirection expected = CompassDirection(CompassDirection::North - 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_muliply_equal) + { + CompassDirection value = CompassDirection::North; + value *= 3; + CompassDirection expected = CompassDirection(CompassDirection::North * 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_divide_equal) + { + CompassDirection value = CompassDirection::North; + value /= 3; + CompassDirection expected = CompassDirection(CompassDirection::North / 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_mod_equal) + { + CompassDirection value = CompassDirection::North; + value %= 3; + CompassDirection expected = CompassDirection(CompassDirection::North % 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_and_equal) + { + CompassDirection value = CompassDirection::North; + value &= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North & 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_or_equal) + { + CompassDirection value = CompassDirection::North; + value |= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North | 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_xor_equal) + { + CompassDirection value = CompassDirection::North; + value ^= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North ^ 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_shift_left) + { + CompassDirection value = CompassDirection::North; + value <<= 2; + CompassDirection expected = CompassDirection(CompassDirection::North << 2); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_shift_right) + { + CompassDirection value = CompassDirection::North; + value >>= 2; + CompassDirection expected = CompassDirection(CompassDirection::North >> 2); + + CHECK_EQUAL(expected, value); + } + }; +} \ No newline at end of file diff --git a/test/test_variant.cpp b/test/test_variant.cpp index 0430c7f6..5b3324e9 100644 --- a/test/test_variant.cpp +++ b/test/test_variant.cpp @@ -35,70 +35,70 @@ SOFTWARE. #include #include -// Test classes for polymorphic tests. -struct base -{ - virtual ~base() - { - } - - base() - : value(0) - { - } - - virtual void set() = 0; - int value; -}; - -struct not_base -{ - not_base() - : value(0) - { - } - - virtual void set() = 0; - int value; -}; - -struct derived_1 : public base -{ - void set() - { - value = 1; - } -}; - -struct derived_2 : public base -{ - void set() - { - value = 2; - } -}; - -// Test variant types. -typedef etl::variant test_variant_3a; -typedef etl::variant test_variant_3b; - -typedef etl::variant test_variant_1; -typedef etl::variant test_variant_2; -typedef etl::variant test_variant_3; -typedef etl::variant test_variant_4; -typedef etl::variant test_variant_5; -typedef etl::variant test_variant_6; -typedef etl::variant test_variant_7; -typedef etl::variant test_variant_8; - -typedef etl::variant test_variant_polymorphic; -typedef etl::variant test_variant_max_types; - -// This line should compile with no errors. -test_variant_max_types variant_max; - namespace { + // Test classes for polymorphic tests. + struct base + { + virtual ~base() + { + } + + base() + : value(0) + { + } + + virtual void set() = 0; + int value; + }; + + struct not_base + { + not_base() + : value(0) + { + } + + virtual void set() = 0; + int value; + }; + + struct derived_1 : public base + { + void set() + { + value = 1; + } + }; + + struct derived_2 : public base + { + void set() + { + value = 2; + } + }; + + // Test variant types. + typedef etl::variant test_variant_3a; + typedef etl::variant test_variant_3b; + + typedef etl::variant test_variant_1; + typedef etl::variant test_variant_2; + typedef etl::variant test_variant_3; + typedef etl::variant test_variant_4; + typedef etl::variant test_variant_5; + typedef etl::variant test_variant_6; + typedef etl::variant test_variant_7; + typedef etl::variant test_variant_8; + + typedef etl::variant test_variant_polymorphic; + typedef etl::variant test_variant_max_types; + + // This line should compile with no errors. + test_variant_max_types variant_max; + SUITE(test_variant) { TEST(test_alignment) diff --git a/test/vs2017/etl.vcxproj b/test/vs2017/etl.vcxproj index e2eddc14..a1356245 100644 --- a/test/vs2017/etl.vcxproj +++ b/test/vs2017/etl.vcxproj @@ -128,6 +128,19 @@ + + + + + + + + + + + + + @@ -212,7 +225,6 @@ - @@ -236,7 +248,6 @@ - @@ -329,6 +340,7 @@ + @@ -364,6 +376,8 @@ + + @@ -373,6 +387,7 @@ false + @@ -393,12 +408,14 @@ + + @@ -410,6 +427,9 @@ + + + diff --git a/test/vs2017/etl.vcxproj.filters b/test/vs2017/etl.vcxproj.filters index 6c40bcc4..df04c8df 100644 --- a/test/vs2017/etl.vcxproj.filters +++ b/test/vs2017/etl.vcxproj.filters @@ -38,7 +38,13 @@ {7028012c-30c4-4993-b2d9-3b1521a610ae} - {5de50c3d-4679-4eb3-9b76-e43e1aad6a66} + {6be3bc76-e17c-4be0-8b0b-d1053e1a1761} + + + {c1264f38-22fa-4fcb-8cab-f254b1290eab} + + + {39015d44-a7cb-47f0-a7dd-27714f852363} @@ -261,12 +267,6 @@ ETL\Containers - - ETL\Containers - - - ETL\Containers - ETL\Containers @@ -438,6 +438,45 @@ Header Files + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Containers + + + ETL\Frameworks\Generators + + + ETL\Frameworks\Generators + + + ETL\Utilities\Generators + + + ETL\Utilities\Generators + + + ETL\Utilities\Generators + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + @@ -761,6 +800,24 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -769,8 +826,14 @@ Resource Files - - Source Files + + Resource Files + + + Resource Files + + + Resource Files diff --git a/uml/FSM example.png b/uml/FSM example.png new file mode 100644 index 00000000..4bc0bfbc Binary files /dev/null and b/uml/FSM example.png differ diff --git a/uml/Framework.png b/uml/Framework.png new file mode 100644 index 00000000..3ff74411 Binary files /dev/null and b/uml/Framework.png differ diff --git a/uml/MessageFramework.png b/uml/MessageFramework.png new file mode 100644 index 00000000..a4b8a424 Binary files /dev/null and b/uml/MessageFramework.png differ diff --git a/uml/source/FSM example.zargo b/uml/source/FSM example.zargo new file mode 100644 index 00000000..89bfb9b5 Binary files /dev/null and b/uml/source/FSM example.zargo differ diff --git a/uml/source/Message Framework.zargo b/uml/source/Message Framework.zargo new file mode 100644 index 00000000..f874146e Binary files /dev/null and b/uml/source/Message Framework.zargo differ