From 62b5a4a6aef905e2fd2d7bc51d23ca087f4d144b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 20 Sep 2025 11:25:09 +0100 Subject: [PATCH 01/27] Rebased on development --- .gitignore | 1 + include/etl/file_error_numbers.h | 1 + include/etl/signal.h | 380 ++++++++++++++++++ test/CMakeLists.txt | 1 + test/syntax_check/CMakeLists.txt | 1 + test/syntax_check/signal.h.t.cpp | 29 ++ test/test_signal.cpp | 641 +++++++++++++++++++++++++++++++ test/vs2022/etl.vcxproj | 22 ++ 8 files changed, 1076 insertions(+) create mode 100644 include/etl/signal.h create mode 100644 test/syntax_check/signal.h.t.cpp create mode 100644 test/test_signal.cpp diff --git a/.gitignore b/.gitignore index 679552e6..068e7602 100644 --- a/.gitignore +++ b/.gitignore @@ -410,3 +410,4 @@ examples/UniquePtrWithPool/CMakeCache.txt examples/UniquePtrWithPool/UniquePtrWithPool test/vs2022/Debug Clang C++20 - Optimised -O2 include/etl/header_file_list.txt +temp diff --git a/include/etl/file_error_numbers.h b/include/etl/file_error_numbers.h index 51a009e7..d6733308 100644 --- a/include/etl/file_error_numbers.h +++ b/include/etl/file_error_numbers.h @@ -108,4 +108,5 @@ SOFTWARE. #define ETL_SPAN_FILE_ID "75" #define ETL_ALGORITHM_FILE_ID "76" #define ETL_NOT_NULL_FILE_ID "77" +#define ETL_SIGNAL_FILE_ID "78" #endif diff --git a/include/etl/signal.h b/include/etl/signal.h new file mode 100644 index 00000000..0f1703ef --- /dev/null +++ b/include/etl/signal.h @@ -0,0 +1,380 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove, Mark Kitson + +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_SIGNAL_INCLUDED +#define ETL_SIGNAL_INCLUDED + +#include + +#include "platform.h" + +#if ETL_NOT_USING_CPP11 +#error NOT SUPPORTED FOR C++03 OR BELOW +#endif + +#if ETL_USING_CPP11 + +#include "exception.h" +#include "error_handler.h" +#include "delegate.h" +#include "algorithm.h" +#include "iterator.h" +#include "type_traits.h" +#include "initializer_list.h" +#include "span.h" +#include "file_error_numbers.h" + +//***************************************************************************** +///\defgroup signal signal +/// Container that handles storing and calling callbacks. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup signal + /// The base class for signal exceptions. + //*************************************************************************** + class signal_exception : public exception + { + public: + signal_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception{reason_, file_name_, line_number_} + { + } + }; + + //*************************************************************************** + ///\ingroup signal + /// Signal full exception. + //*************************************************************************** + class signal_full : public signal_exception + { + public: + signal_full(string_type file_name_, numeric_type line_number_) + : signal_exception{ETL_ERROR_TEXT("signal:full", ETL_SIGNAL_FILE_ID"A"), file_name_, line_number_} + { + } + }; + + //*************************************************************************** + ///\ingroup signal + /// + ///\brief A lightweight signal class designed for efficient memory usage and + /// ability to store in ROM. + /// + ///\tparam TFunction: Callback signature. + ///\tparam Size: Maximum number of slots that can be connected to the signal. + ///\tparam TSlot: Function-object type or container type that can be invoked. Default etl::delegate. + //*************************************************************************** + template > + class signal + { + public: + + using slot_type = TSlot; + using size_type = size_t; + using span_type = etl::span; + + //************************************************************************* + ///\brief Construct the signal from a variadic list of slots. + /// + ///\param slots: Variadic list of slots. + //************************************************************************* + template + ETL_CONSTEXPR14 explicit signal(TSlots&&... slots) ETL_NOEXCEPT + : slot_list{etl::forward(slots)...} + , slot_list_end{slot_list + sizeof...(slots)} + { + static_assert((etl::are_all_same...>::value), "All slots must be slot_type"); + static_assert(sizeof...(slots) <= Size, "Number of slots exceeds capacity"); + } + + //************************************************************************* + ///\brief Connects a slot to the signal. + /// Ignores the slot if it has already been connected. + /// + ///\param slot: The slot to connect. + ///\return false if not all slots could be connected. + //************************************************************************* + bool connect(const slot_type& slot) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + { + if (!connected(slot)) + { + ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false); + append_slot(slot); + } + + return true; + } + +#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP17 + //************************************************************************* + ///\brief Connects slots to the signal. + /// Ignores the slots if it has already been connected. + /// + ///\param slots: std::initializer_list of slots to connect. + ///\return false if not all slots could be connected. + //************************************************************************* + bool connect(std::initializer_list slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + { + for (const slot_type& slot : slots) + { + if (!connected(slot)) + { + ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false); + append_slot(slot); + } + } + + return true; + } +#endif + + //************************************************************************* + ///\brief Connects slots to the signal. + /// Ignores the slots if it has already been connected. + /// + ///\param slots: etl::span of slots to connect. + ///\return false if not all slots could be connected. + //************************************************************************* + bool connect(const span_type slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + { + for (const slot_type& slot : slots) + { + if (!connected(slot)) + { + ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false); + append_slot(slot); + } + } + + return true; + } + + //************************************************************************* + ///\brief Disconnects a slot from the signal. + /// + ///\param slot: To disconnect. + //************************************************************************* + void disconnect(const slot_type& slot) ETL_NOEXCEPT + { + const auto end_itr = end(); + const auto itr = etl::find(begin(), end_itr, slot); + + if (itr != end_itr) + { + // Shifts all elements after 'itr' one position to the left. + etl::copy(etl::next(itr), end_itr, itr); + slot_list_end = etl::prev(slot_list_end); + } + } + +#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP17 + //************************************************************************* + ///\brief Disconnects multiple slots from the signal. + /// + ///\param slot: std::intializer_list of slots to disconnect. + //************************************************************************* + void disconnect(std::initializer_list slots) ETL_NOEXCEPT + { + for (const slot_type& slot : slots) + { + disconnect(slot); + } + } +#endif + + //************************************************************************* + ///\brief Disconnects multiple slots from the signal. + /// + ///\param slot: etl::span of slots to disconnect. + //************************************************************************* + void disconnect(const span_type slots) ETL_NOEXCEPT + { + for (const slot_type& slot : slots) + { + disconnect(slot); + } + } + + //************************************************************************* + ///\brief Disconnects all slots from the signal. + //************************************************************************* + void disconnect_all() ETL_NOEXCEPT + { + slot_list_end = begin(); + } + + //************************************************************************* + ///\brief Checks if a slot is connected to the signal. + /// + ///\param slot: To check. + ///\return true if the slot is connected. + //************************************************************************* + ETL_CONSTEXPR14 bool connected(const slot_type& slot) const ETL_NOEXCEPT + { + return etl::any_of(begin(), end(), [&slot](const slot_type& s) { return s == slot; }); + } + + //************************************************************************* + ///\return true if the signal has no slots connected. + //************************************************************************* + ETL_CONSTEXPR14 bool empty() const ETL_NOEXCEPT + { + return begin() == end(); + } + + //************************************************************************* + ///\return true if the signal has the maximum number of slots connected. + //************************************************************************* + ETL_CONSTEXPR14 bool full() const ETL_NOEXCEPT + { + return size() == max_size(); + } + + //************************************************************************* + ///\return Total number of slots that can be connected. + //************************************************************************* + ETL_CONSTEXPR14 size_type max_size() const ETL_NOEXCEPT + { + return Size; + } + + //************************************************************************* + ///\return Total slots currently connected. + //************************************************************************* + ETL_CONSTEXPR14 size_type size() const ETL_NOEXCEPT + { + return etl::distance(begin(), end()); + } + + //************************************************************************* + ///\return Total empty slots available. + //************************************************************************* + ETL_CONSTEXPR14 size_type available() const ETL_NOEXCEPT + { + return max_size() - size(); + } + + //************************************************************************* + ///\brief Invokes all the slots connected to the signal. + /// Checks if the slot is valid to call. + /// + ///\param args: Arguments to pass to the slots. + //************************************************************************* + template + void operator()(TArgs&&... args) const ETL_NOEXCEPT + { + for (const slot_type& slot : *this) + { + if (slot_is_valid(slot)) + { + slot(etl::forward(args)...); + } + } + } + + private: + + using iterator = slot_type*; + using const_iterator = const slot_type*; + + slot_type slot_list[Size]; + iterator slot_list_end; + + //************************************************************************* + /// Appends a slot to the slot list. + //************************************************************************* + void append_slot(const slot_type& slot) ETL_NOEXCEPT + { + (*slot_list_end) = slot; + slot_list_end = etl::next(slot_list_end); + } + + //************************************************************************* + /// For a delegate slot type. + //************************************************************************* + template + static + typename etl::enable_if_t::value, bool> + slot_is_valid(const TSlotType& s) ETL_NOEXCEPT + { + return s.is_valid(); + } + + //************************************************************************* + /// For a non-delegate slot type. + //************************************************************************* + template + static + typename etl::enable_if_t::value, bool> + slot_is_valid(const TSlotType&) ETL_NOEXCEPT + { + return true; + } + + //************************************************************************* + ///\return Iterator to the beginning of the connected slots. + //************************************************************************* + ETL_CONSTEXPR14 iterator begin() ETL_NOEXCEPT + { + return slot_list; + } + + //************************************************************************* + ///\return Const Iterator to the beginning of the connected slots. + //************************************************************************* + ETL_CONSTEXPR14 const_iterator begin() const ETL_NOEXCEPT + { + return slot_list; + } + + //************************************************************************* + ///\return Iterator to the end of the connected slots. + //************************************************************************* + ETL_CONSTEXPR14 iterator end() ETL_NOEXCEPT + { + return slot_list_end; + } + + //************************************************************************* + ///\return Const Iterator to the end of the connected slots. + //************************************************************************* + ETL_CONSTEXPR14 const_iterator end() const ETL_NOEXCEPT + { + return slot_list_end; + } + }; +} + +#endif +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 888fd12c..c45dbc7a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -285,6 +285,7 @@ add_executable(etl_tests test_scaled_rounding.cpp test_set.cpp test_shared_message.cpp + test_signal.cpp test_singleton.cpp test_singleton_base.cpp test_smallest.cpp diff --git a/test/syntax_check/CMakeLists.txt b/test/syntax_check/CMakeLists.txt index e664a3a2..31629a73 100644 --- a/test/syntax_check/CMakeLists.txt +++ b/test/syntax_check/CMakeLists.txt @@ -290,6 +290,7 @@ target_sources(tests PRIVATE scheduler.h.t.cpp set.h.t.cpp shared_message.h.t.cpp + signal.h.t.cpp singleton.h.t.cpp singleton_base.h.t.cpp smallest.h.t.cpp diff --git a/test/syntax_check/signal.h.t.cpp b/test/syntax_check/signal.h.t.cpp new file mode 100644 index 00000000..5207afb1 --- /dev/null +++ b/test/syntax_check/signal.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/test_signal.cpp b/test/test_signal.cpp new file mode 100644 index 00000000..3d1f0690 --- /dev/null +++ b/test/test_signal.cpp @@ -0,0 +1,641 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++/CheckMacros.h" +#include "unit_test_framework.h" + +#include +#include + +#include "etl/signal.h" + +namespace +{ + using callback_type = void(std::ostream&); + using signal_type = etl::signal; + using slot_type = signal_type::slot_type; + using span_type = signal_type::span_type; + + //************************************************************************* + ///\brief Generic output free function + /// + ///\param out: output stream + ///\param str: input string + //************************************************************************* + void output(std::ostream& out, const std::string& str) + { + out << str; + } + + //************************************************************************* + ///\brief Free function that outputs "free" + /// + ///\param out: output + //************************************************************************* + void output_free(std::ostream& out) + { + output(out, "free"); + } + + //************************************************************************* + ///\brief Free function that outputs "free" + /// + ///\param out: output + //************************************************************************* + void output_extra(std::ostream& out) + { + output(out, "extra"); + } + + //************************************************************************* + ///\brief Lambda that outputs "lambda" + /// + ///\param out: output + //************************************************************************* + auto output_lambda = [](std::ostream& out) { output(out, "lambda"); }; + + class example_class + { + public: + //************************************************************************* + ///\brief Method that outputs "static" + /// + ///\param out: output + //************************************************************************* + static void static_method(std::ostream& out) + { + output(out, "static"); + } + + //************************************************************************* + ///\brief Method that outputs "method" + /// + ///\param out: output + //************************************************************************* + void method(std::ostream& out) + { + output(out, "method"); + } + + //************************************************************************* + ///\brief Functor method that outputs "functor" + /// + ///\param out: output + //************************************************************************* + void operator()(std::ostream& out) + { + output(out, "functor"); + } + }; + + example_class example; + + //************************************************************************* + ///\brief Makes an empty slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_empty_slot() + { + return slot_type(); + } + + //************************************************************************* + ///\brief Makes the free function slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_free_slot() + { + return slot_type::create(); + } + + //************************************************************************* + ///\brief Makes the lambda slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_lambda_slot() + { + return slot_type{output_lambda}; + } + + //************************************************************************* + ///\brief Makes the static method slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_static_slot() + { + return slot_type::create<&example_class::static_method>(); + } + + //************************************************************************* + ///\brief Makes the class method slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_instance_slot() + { + return slot_type::create(); + } + + //************************************************************************* + ///\brief Makes the functor slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_functor_slot() + { + return slot_type::create(); + } + + //************************************************************************* + ///\brief Makes the free function slot + /// + ///\return constexpr slot_type + //************************************************************************* + ETL_CONSTEXPR14 slot_type make_extra_slot() + { + return slot_type::create(); + } + + //************************************************************************* + ///\brief Makes the incorrect slot type + /// Uncomment for test_construct_with_incorrect_slot_type + ///\return An incorrect slot + //************************************************************************* + //ETL_CONSTEXPR14 etl::delegate make_incorrect_slot() + //{ + // return etl::delegate(); + //} + + //*************************************************************************** + SUITE(signal_test) + { + //*************************************************************************** + TEST(test_default_construct) + { + const signal_type test_object; + CHECK_EQUAL(0U, test_object.size()); + CHECK_EQUAL(5U, test_object.max_size()); + CHECK_TRUE(test_object.empty()); + CHECK_FALSE(test_object.full()); + } + +#if ETL_USING_CPP14 + //*************************************************************************** + TEST(test_constexpr_construct) + { + static constexpr signal_type signal + { + make_free_slot(), + make_lambda_slot(), + make_static_slot(), + make_instance_slot(), + make_functor_slot() + }; + + CHECK_EQUAL(5U, signal.size()); + CHECK_EQUAL(0, signal.available()); + CHECK_EQUAL(5U, signal.max_size()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.full()); + } +#endif + + //*************************************************************************** + TEST(test_construct_from_slot_list) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + const signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + CHECK_EQUAL(5, signal.size()); + CHECK_EQUAL(0, signal.available()); + CHECK_EQUAL(5, signal.max_size()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.full()); + } + + //*************************************************************************** + TEST(test_construct_from_too_many_slots) + { + // Uncomment to trigger static_assert "Number of slots exceeds capacity" + //const auto free_slot = make_free_slot(); + //const auto lambda_slot = make_lambda_slot(); + //const auto static_slot = make_static_slot(); + //const auto instance_slot = make_instance_slot(); + //const auto functor_slot = make_functor_slot(); + //const auto extra_slot = make_extra_slot(); + + //signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot }; + } + +#if ETL_USING_CPP14 + //*************************************************************************** + TEST(test_constexpr_construct_from_slot_list) + { + static constexpr auto free_slot = make_free_slot(); + static constexpr auto lambda_slot = make_lambda_slot(); + static constexpr auto static_slot = make_static_slot(); + static constexpr auto instance_slot = make_instance_slot(); + static constexpr auto functor_slot = make_functor_slot(); + + static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + CHECK_EQUAL(5, signal.size()); + CHECK_EQUAL(0, signal.available()); + CHECK_EQUAL(5, signal.max_size()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.full()); + } +#endif + + //*************************************************************************** + TEST(test_construct_with_incorrect_slot_type) + { + // Uncomment to trigger static_assert "All slots must be slot_type" + //const auto free_slot = make_free_slot(); + //const auto lambda_slot = make_lambda_slot(); + //const auto incorrect_slot = make_incorrect_slot(); // Incorrect type + //const auto instance_slot = make_instance_slot(); + //const auto functor_slot = make_functor_slot(); + + //signal_type signal{ free_slot, lambda_slot, incorrect_slot, instance_slot, functor_slot }; + } + + //*************************************************************************** + TEST(test_connect) + { + signal_type signal; + + const auto free_slot = make_free_slot(); + CHECK_TRUE(signal.connect(free_slot)); + CHECK_EQUAL(1U, signal.size()); + CHECK_EQUAL(4U, signal.available()); + signal.connect(free_slot); // Try to connect it again - nothing should change. + CHECK_EQUAL(1U, signal.size()); + CHECK_EQUAL(4U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + CHECK_TRUE(signal.connected(free_slot)); + + const auto lambda_slot = make_lambda_slot(); + CHECK_TRUE(signal.connect(lambda_slot)); + CHECK_EQUAL(2U, signal.size()); + CHECK_EQUAL(3U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + CHECK_TRUE(signal.connected(lambda_slot)); + + const auto static_slot = make_static_slot(); + CHECK_TRUE(signal.connect(static_slot)); + CHECK_EQUAL(3U, signal.size()); + CHECK_EQUAL(2U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + CHECK_TRUE(signal.connected(static_slot)); + + const auto instance_slot = make_instance_slot(); + CHECK_TRUE(signal.connect(instance_slot)); + CHECK_EQUAL(4U, signal.size()); + CHECK_EQUAL(1U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + CHECK_TRUE(signal.connected(instance_slot)); + + const auto functor_slot = make_functor_slot(); + CHECK_TRUE(signal.connect(functor_slot)); + CHECK_EQUAL(5U, signal.size()); + CHECK_EQUAL(0U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.full()); + CHECK_TRUE(signal.connected(functor_slot)); + } + +#if ETL_USING_CPP17 + //*************************************************************************** + TEST(test_connect_from_initializer_list) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + signal_type signal; + CHECK_TRUE(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot })); + + CHECK_EQUAL(5U, signal.size()); + CHECK_TRUE(signal.connected(free_slot)); + CHECK_TRUE(signal.connected(lambda_slot)); + CHECK_TRUE(signal.connected(static_slot)); + CHECK_TRUE(signal.connected(instance_slot)); + CHECK_TRUE(signal.connected(functor_slot)); + CHECK_EQUAL(0U, signal.available()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.full()); + } +#endif + +#if ETL_USING_CPP17 + //*************************************************************************** + TEST(test_connect_from_initializer_list_too_many_slots) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + const auto extra_slot = make_extra_slot(); + + signal_type signal; + CHECK_THROW(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot }), etl::signal_full); + } +#endif + + //*************************************************************************** + TEST(test_connect_from_span) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + signal_type signal; + CHECK_TRUE(signal.connect(slot_list)); + } + + //*************************************************************************** + TEST(test_connect_from_span_too_many_slots) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + const auto extra_slot = make_extra_slot(); + + const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot }; + + signal_type signal; + CHECK_THROW(signal.connect(slot_list), etl::signal_full); + } + + //*************************************************************************** + TEST(test_disconnect) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + signal_type signal; + CHECK_TRUE(signal.connect(slot_list)); + + signal.disconnect(free_slot); + CHECK_EQUAL(4U, signal.size()); + CHECK_EQUAL(1U, signal.available()); + CHECK_FALSE(signal.connected(free_slot)); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + + // Try to remove it again - nothing should change. + signal.disconnect(free_slot); + CHECK_EQUAL(4U, signal.size()); + CHECK_EQUAL(1U, signal.available()); + CHECK_FALSE(signal.connected(free_slot)); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + + signal.disconnect(lambda_slot); + CHECK_EQUAL(3U, signal.size()); + CHECK_EQUAL(2U, signal.available()); + CHECK_FALSE(signal.connected(lambda_slot)); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + + signal.disconnect(static_slot); + CHECK_EQUAL(2U, signal.size()); + CHECK_EQUAL(3U, signal.available()); + CHECK_FALSE(signal.connected(static_slot)); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + + signal.disconnect(instance_slot); + CHECK_EQUAL(1U, signal.size()); + CHECK_EQUAL(4U, signal.available()); + CHECK_FALSE(signal.connected(instance_slot)); + CHECK_FALSE(signal.empty()); + CHECK_FALSE(signal.full()); + + signal.disconnect(functor_slot); + CHECK_EQUAL(0U, signal.size()); + CHECK_EQUAL(5U, signal.available()); + CHECK_FALSE(signal.connected(functor_slot)); + CHECK_TRUE(signal.empty()); + CHECK_FALSE(signal.full()); + } + } + +#if ETL_USING_CPP17 + //*************************************************************************** + TEST(test_disconnect_from_initializer_list) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + signal_type signal; + CHECK_TRUE(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot })); + + signal.disconnect({ lambda_slot, instance_slot }); + CHECK_EQUAL(3U, signal.size()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.connected(free_slot)); + CHECK_FALSE(signal.connected(lambda_slot)); + CHECK_TRUE(signal.connected(static_slot)); + CHECK_FALSE(signal.connected(instance_slot)); + CHECK_TRUE(signal.connected(functor_slot)); + } +#endif + + //*************************************************************************** + TEST(test_disconnect_from_span_list) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + signal_type signal; + CHECK_TRUE(signal.connect(free_slot)); + CHECK_TRUE(signal.connect(lambda_slot)); + CHECK_TRUE(signal.connect(static_slot)); + CHECK_TRUE(signal.connect(instance_slot)); + CHECK_TRUE(signal.connect(functor_slot)); + + const slot_type slot_list[] = { lambda_slot, instance_slot }; + + signal.disconnect(span_type(slot_list)); + CHECK_EQUAL(3U, signal.size()); + CHECK_FALSE(signal.empty()); + CHECK_TRUE(signal.connected(free_slot)); + CHECK_FALSE(signal.connected(lambda_slot)); + CHECK_TRUE(signal.connected(static_slot)); + CHECK_FALSE(signal.connected(instance_slot)); + CHECK_TRUE(signal.connected(functor_slot)); + } + + //*************************************************************************** + TEST(test_disconnect_all) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + signal_type signal; + CHECK_TRUE(signal.connect(slot_list)); + + signal.disconnect_all(); + CHECK_EQUAL(0U, signal.size()); + CHECK_TRUE(signal.empty()); + CHECK_FALSE(signal.connected(free_slot)); + CHECK_FALSE(signal.connected(lambda_slot)); + CHECK_FALSE(signal.connected(static_slot)); + CHECK_FALSE(signal.connected(instance_slot)); + CHECK_FALSE(signal.connected(functor_slot)); + } + + //*************************************************************************** + TEST(test_call_empty) + { + std::stringstream ss; + signal_type signal; + signal(ss); + CHECK_EQUAL(std::string{""}, ss.str()); + } + + //*************************************************************************** + TEST(test_call) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_lambda_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_instance_slot(); + const auto functor_slot = make_functor_slot(); + + signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + std::stringstream ss; + signal(ss); + + // Expect all signals got called + const std::string expected_string{"freelambdastaticmethodfunctor"}; + CHECK_EQUAL(expected_string, ss.str()); + } + +#if ETL_USING_CPP14 + //*************************************************************************** + TEST(test_constexpr_call) + { + static constexpr auto free_slot = make_free_slot(); + static constexpr auto lambda_slot = make_lambda_slot(); + static constexpr auto static_slot = make_static_slot(); + static constexpr auto instance_slot = make_instance_slot(); + static constexpr auto functor_slot = make_functor_slot(); + + static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + std::stringstream ss; + signal(ss); + + // Expect all slots got called + const std::string expected_string{"freelambdastaticmethodfunctor"}; + CHECK_EQUAL(expected_string, ss.str()); + } +#endif + + //*************************************************************************** + TEST(test_call_empty_slots) + { + const auto free_slot = make_free_slot(); + const auto lambda_slot = make_empty_slot(); + const auto static_slot = make_static_slot(); + const auto instance_slot = make_empty_slot(); + const auto functor_slot = make_functor_slot(); + + signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + std::stringstream ss; + signal(ss); + + // Expect only valid slots got called + const std::string expected_string{"freestaticfunctor"}; + CHECK_EQUAL(expected_string, ss.str()); + } + +#if ETL_USING_CPP14 + //*************************************************************************** + TEST(test_call_constexpr_empty_slots) + { + static constexpr auto free_slot = make_free_slot(); + static constexpr auto lambda_slot = make_empty_slot(); + static constexpr auto static_slot = make_static_slot(); + static constexpr auto instance_slot = make_empty_slot(); + static constexpr auto functor_slot = make_functor_slot(); + + static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }; + + std::stringstream ss; + signal(ss); + + // Expect only valid slots got called + const std::string expected_string{"freestaticfunctor"}; + CHECK_EQUAL(expected_string, ss.str()); + } +#endif +} diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 3d361cfb..32f66ccf 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -3651,6 +3651,7 @@ + @@ -8927,6 +8928,26 @@ true true + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true true @@ -11264,6 +11285,7 @@ true true + From cc62f212ab1e83e9d399dc88e806db53d0a225f7 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 21 Sep 2025 10:06:12 +0100 Subject: [PATCH 02/27] Rebased on development --- include/etl/signal.h | 2 +- test/vs2022/etl.vcxproj.filters | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/etl/signal.h b/include/etl/signal.h index 0f1703ef..5278cc04 100644 --- a/include/etl/signal.h +++ b/include/etl/signal.h @@ -35,7 +35,7 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 +#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) #error NOT SUPPORTED FOR C++03 OR BELOW #endif diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 3b9bf643..15ccfdbc 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -1422,12 +1422,6 @@ Tests\Error Handler\Assert Function - - UnitTest++\Header Files - - - UnitTest++\Header Files - ETL\Utilities @@ -1506,9 +1500,6 @@ ETL\Maths\CRC - - UnitTest++\Header Files - ETL\Containers @@ -1524,6 +1515,18 @@ ETL\Utilities + + ETL\Patterns + + + ETL\Utilities + + + ETL\Utilities + + + ETL\Maths\CRC + @@ -3713,6 +3716,12 @@ Tests\Syntax Checks\Source + + Tests + + + Tests\Syntax Checks\Source + From 5b76824c6112f44019ca0ed93930c3be6cbf955a Mon Sep 17 00:00:00 2001 From: mike919192 <91038685+mike919192@users.noreply.github.com> Date: Wed, 10 Sep 2025 05:52:22 -0400 Subject: [PATCH 03/27] Debug assert (#1175) * debug assert POC * Swith to ETL_CONSTEXPR14 * Finish TODO checks * First and last can be equal * Add ETL_DEBUG_THROW_EXCEPTIONS * Try allowing c++11 constexpr * Add macro for throwing from c++11 constexpr * Remove braces * Add extra asserts in size_t overload functions * Fill out debug asserts * Line up comments --- include/etl/array.h | 46 ++++++++++++++++++++++++++++-- include/etl/error_handler.h | 56 +++++++++++++++++++++++++++++++++++++ include/etl/expected.h | 24 ++++------------ include/etl/platform.h | 10 +++++++ test/etl_profile.h | 2 ++ test/test_array.cpp | 25 +++++++++++++++++ 6 files changed, 143 insertions(+), 20 deletions(-) diff --git a/include/etl/array.h b/include/etl/array.h index c0cf8f98..e0854854 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -145,6 +145,8 @@ namespace etl ETL_CONSTEXPR14 reference operator[](size_t i) { + ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + return _buffer[i]; } @@ -156,7 +158,14 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR const_reference operator[](size_t i) const { + //throwing from c++11 constexpr requires a special macro +#if ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_DEBUG_USING_EXCEPTIONS + ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(i < SIZE, ETL_ERROR(array_out_of_range), _buffer[i]); +#else + ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + return _buffer[i]; +#endif } //************************************************************************* @@ -166,6 +175,8 @@ namespace etl ETL_CONSTEXPR14 reference front() { + ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); + return _buffer[0]; } @@ -175,6 +186,8 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR const_reference front() const { + ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); + return _buffer[0]; } @@ -185,6 +198,8 @@ namespace etl ETL_CONSTEXPR14 reference back() { + ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); + return _buffer[SIZE - 1]; } @@ -194,6 +209,8 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR const_reference back() const { + ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); + return _buffer[SIZE - 1]; } @@ -429,6 +446,8 @@ namespace etl //************************************************************************* inline iterator insert_at(size_t position, parameter_t value) { + ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + return insert(begin() + position, value); } @@ -439,6 +458,8 @@ namespace etl //************************************************************************* iterator insert(const_iterator position, parameter_t value) { + ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(position); etl::move_backward(p, end() - 1, end()); @@ -456,6 +477,8 @@ namespace etl template inline iterator insert_at(size_t position, TIterator first, const TIterator last) { + ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + return insert(begin() + position, first, last); } @@ -468,6 +491,8 @@ namespace etl template iterator insert(const_iterator position, TIterator first, const TIterator last) { + ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(position); iterator result(p); @@ -494,6 +519,8 @@ namespace etl //************************************************************************* inline iterator erase_at(size_t position) { + ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + return erase(begin() + position); } @@ -504,6 +531,8 @@ namespace etl //************************************************************************* iterator erase(const_iterator position) { + ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(position); etl::move(p + 1, end(), p); @@ -518,6 +547,8 @@ namespace etl //************************************************************************* iterator erase_range(size_t first, size_t last) { + ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); + return erase(begin() + first, begin() + last); } @@ -529,6 +560,8 @@ namespace etl //************************************************************************* iterator erase(const_iterator first, const_iterator last) { + ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(first); etl::move(last, cend(), p); return p; @@ -541,6 +574,8 @@ namespace etl //************************************************************************* inline iterator erase_at(size_t position, parameter_t value) { + ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + return erase(begin() + position, value); } @@ -551,6 +586,8 @@ namespace etl //************************************************************************* iterator erase(const_iterator position, parameter_t value) { + ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(position); etl::move(p + 1, end(), p); @@ -567,16 +604,21 @@ namespace etl //************************************************************************* iterator erase_range(size_t first, size_t last, parameter_t value) { + ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); + return erase(begin() + first, begin() + last, value); } //************************************************************************* /// Erases a range of values from the array. - ///\param position The iterator to the position to erase at. - ///\param value The value to use to overwrite the last elements in the array. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + ///\param value The value to use to overwrite the last elements in the array. //************************************************************************* iterator erase(const_iterator first, const_iterator last, parameter_t value) { + ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); + iterator p = to_iterator(first); p = etl::move(last, cend(), p); diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 07237f89..75e71381 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -364,6 +364,62 @@ namespace etl #endif #endif +#if ETL_IS_DEBUG_BUILD + #if defined(ETL_DEBUG_USE_ASSERT_FUNCTION) + #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value + + #define ETL_DEBUG_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value + #elif ETL_DEBUG_USING_EXCEPTIONS + #if defined(ETL_DEBUG_LOG_ERRORS) + #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. + + #define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e)); throw((e));} // Calls the error handler then throws an exception. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); throw((e)); return;} // Calls the error handler then throws an exception. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. + #else + #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. + + #define ETL_DEBUG_ASSERT_FAIL(e) {throw((e));} // Throws an exception. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception. + #endif + #elif defined(ETL_DEBUG_LOG_ERRORS) + #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} // If the condition fails, calls the error handler + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} // If the condition fails, calls the error handler and return + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} // If the condition fails, calls the error handler and return a value + + #define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e));} // Calls the error handler + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); return;} // Calls the error handler and return + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); return (v);} // Calls the error handler and return a value + #else + #define ETL_DEBUG_ASSERT(b, e) assert((b)) // If the condition fails, asserts. + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {assert(false); return;}} // If the condition fails, asserts and return. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} // If the condition fails, asserts and return a value. + + #define ETL_DEBUG_ASSERT_FAIL(e) assert(false) // Asserts. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {assert(false); return;} // Asserts. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts. + #endif +#else + #define ETL_DEBUG_ASSERT(b, e) // Does nothing. + #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY return;} // Returns. + #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY return(v);} // Returns a value. + + #define ETL_DEBUG_ASSERT_FAIL(e) // Does nothing. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns. + #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value. +#endif + #if defined(ETL_VERBOSE_ERRORS) #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. diff --git a/include/etl/expected.h b/include/etl/expected.h index 49c3d82b..2e761348 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -675,9 +675,7 @@ namespace etl //******************************************* value_type* operator ->() { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::addressof(etl::get(storage)); } @@ -687,9 +685,7 @@ namespace etl //******************************************* const value_type* operator ->() const { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::addressof(etl::get(storage)); } @@ -699,9 +695,7 @@ namespace etl //******************************************* value_type& operator *() ETL_LVALUE_REF_QUALIFIER { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::get(storage); } @@ -711,9 +705,7 @@ namespace etl //******************************************* const value_type& operator *() const ETL_LVALUE_REF_QUALIFIER { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::get(storage); } @@ -724,9 +716,7 @@ namespace etl //******************************************* value_type&& operator *()&& { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::move(etl::get(storage)); } @@ -736,9 +726,7 @@ namespace etl //******************************************* const value_type&& operator *() const&& { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); -#endif + ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::move(etl::get(storage)); } diff --git a/include/etl/platform.h b/include/etl/platform.h index 012a379b..af0b9a6d 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -251,6 +251,16 @@ SOFTWARE. #define ETL_NOT_USING_EXCEPTIONS 1 #endif +//************************************* +// Indicate if C++ exceptions are enabled for debug asserts. +#if ETL_IS_DEBUG_BUILD && defined(ETL_DEBUG_THROW_EXCEPTIONS) + #define ETL_DEBUG_USING_EXCEPTIONS 1 + #define ETL_DEBUG_NOT_USING_EXCEPTIONS 0 +#else + #define ETL_DEBUG_USING_EXCEPTIONS 0 + #define ETL_DEBUG_NOT_USING_EXCEPTIONS 1 +#endif + //************************************* // Indicate if nullptr is used. #if ETL_NO_NULLPTR_SUPPORT diff --git a/test/etl_profile.h b/test/etl_profile.h index d6475c6a..b396bfde 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -31,7 +31,9 @@ SOFTWARE. #ifndef ETL_PROFILE_H_INCLUDED #define ETL_PROFILE_H_INCLUDED +#define ETL_DEBUG #define ETL_THROW_EXCEPTIONS +#define ETL_DEBUG_THROW_EXCEPTIONS #define ETL_VERBOSE_ERRORS #define ETL_CHECK_PUSH_POP #define ETL_ISTRING_REPAIR_ENABLE diff --git a/test/test_array.cpp b/test/test_array.cpp index 4fd6a263..c779ab76 100644 --- a/test/test_array.cpp +++ b/test/test_array.cpp @@ -134,6 +134,9 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range); } //************************************************************************* @@ -145,6 +148,9 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range); } //************************************************************************* @@ -443,6 +449,10 @@ namespace CHECK_EQUAL(data[9], *result); isEqual = std::equal(data.begin(), data.end(), std::begin(check3)); CHECK(isEqual); + + // Insert out of range + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + CHECK_THROW({ result = data.insert_at(data.size(), 99); }, etl::array_out_of_range); } //************************************************************************* @@ -493,6 +503,10 @@ namespace CHECK_EQUAL(data[4], *result); isEqual = std::equal(data.begin(), data.end(), std::begin(check5)); CHECK(isEqual); + + // Insert out of range + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + CHECK_THROW({ result = data.insert_at(data.size(), &source2[0], &source2[13]); }, etl::array_out_of_range); } //************************************************************************* @@ -547,6 +561,10 @@ namespace CHECK_EQUAL(data[9], *result); isEqual = std::equal(data.begin(), data.end(), std::begin(check3b)); CHECK(isEqual); + + // Erase out of range + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + CHECK_THROW({ result = data.erase_at(data.size()); }, etl::array_out_of_range); } //************************************************************************* @@ -601,6 +619,13 @@ namespace CHECK_EQUAL(data[5], *result); isEqual = std::equal(data.begin(), data.end(), std::begin(check3b)); CHECK(isEqual); + + //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined + // first is greater than last + CHECK_THROW({ result = data.erase_range(6, 5, 99); }, etl::array_out_of_range); + + // Erase out of range + CHECK_THROW({ result = data.erase_range(5, data.size() + 1, 99); }, etl::array_out_of_range); } //************************************************************************* From da32625f1047bc9f7a5136ae3dde239301b2b9e8 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Sep 2025 14:34:06 +0100 Subject: [PATCH 04/27] Removed #define ETL_DEBUG as this is a project define --- test/etl_profile.h | 1 - 1 file changed, 1 deletion(-) diff --git a/test/etl_profile.h b/test/etl_profile.h index b396bfde..d98f6141 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -31,7 +31,6 @@ SOFTWARE. #ifndef ETL_PROFILE_H_INCLUDED #define ETL_PROFILE_H_INCLUDED -#define ETL_DEBUG #define ETL_THROW_EXCEPTIONS #define ETL_DEBUG_THROW_EXCEPTIONS #define ETL_VERBOSE_ERRORS From abc2735504c94c9d908b19ac1f3e4be8c2e4ed13 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Sep 2025 14:34:57 +0100 Subject: [PATCH 05/27] Added more ETL_NOEXCEPT to etl::array --- include/etl/array.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/etl/array.h b/include/etl/array.h index e0854854..fbf5063a 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -116,7 +116,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - reference at(size_t i) + reference at(size_t i) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) { ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); @@ -129,7 +129,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - const_reference at(size_t i) const + const_reference at(size_t i) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) { ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); @@ -143,7 +143,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - reference operator[](size_t i) + reference operator[](size_t i) ETL_NOEXCEPT_EXPR(ETL_DEBUG_NOT_USING_EXCEPTIONS) { ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); @@ -156,7 +156,7 @@ namespace etl ///\param i The index of the element to access. //************************************************************************* ETL_NODISCARD - ETL_CONSTEXPR const_reference operator[](size_t i) const + ETL_CONSTEXPR const_reference operator[](size_t i) const ETL_NOEXCEPT_EXPR(ETL_DEBUG_NOT_USING_EXCEPTIONS) { //throwing from c++11 constexpr requires a special macro #if ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_DEBUG_USING_EXCEPTIONS @@ -173,7 +173,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - reference front() + reference front() ETL_NOEXCEPT { ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); @@ -184,7 +184,7 @@ namespace etl /// Returns a const reference to the first element. //************************************************************************* ETL_NODISCARD - ETL_CONSTEXPR const_reference front() const + ETL_CONSTEXPR const_reference front() const ETL_NOEXCEPT { ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); @@ -196,7 +196,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - reference back() + reference back() ETL_NOEXCEPT { ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); @@ -207,7 +207,7 @@ namespace etl /// Returns a const reference to the last element. //************************************************************************* ETL_NODISCARD - ETL_CONSTEXPR const_reference back() const + ETL_CONSTEXPR const_reference back() const ETL_NOEXCEPT { ETL_STATIC_ASSERT(SIZE > 0, "Array is empty."); From df6b0b20c8873da95d0c0de733a48c10c40ce161 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 22 Sep 2025 10:41:50 +0100 Subject: [PATCH 06/27] Modified to use new ETL_ASSERTs --- include/etl/deque.h | 78 ++++++++---------------- include/etl/error_handler.h | 27 ++++++--- include/etl/forward_list.h | 43 +++++-------- include/etl/indirect_vector.h | 10 ++- include/etl/intrusive_forward_list.h | 5 +- include/etl/intrusive_list.h | 10 ++- include/etl/intrusive_queue.h | 4 +- include/etl/intrusive_stack.h | 5 +- include/etl/list.h | 91 +++++++++++----------------- include/etl/private/pvoidvector.h | 15 ++--- include/etl/queue.h | 45 ++++++-------- include/etl/stack.h | 45 ++++++-------- include/etl/vector.h | 46 ++++++-------- 13 files changed, 171 insertions(+), 253 deletions(-) diff --git a/include/etl/deque.h b/include/etl/deque.h index f70ba26e..44043cdc 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -1757,9 +1757,8 @@ namespace etl //************************************************************************* void push_back(const_reference item) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(deque_full)); + create_element_back(item); } @@ -1771,9 +1770,8 @@ namespace etl //************************************************************************* void push_back(rvalue_reference item) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(deque_full)); + create_element_back(etl::move(item)); } #endif @@ -1786,9 +1784,7 @@ namespace etl template reference emplace_back(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(etl::forward(args)...); ++_end; @@ -1805,9 +1801,7 @@ namespace etl //************************************************************************* reference emplace_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(); ++_end; @@ -1823,9 +1817,7 @@ namespace etl template reference emplace_back(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(value1); ++_end; @@ -1841,9 +1833,7 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(value1, value2); ++_end; @@ -1859,9 +1849,7 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(value1, value2, value3); ++_end; @@ -1877,9 +1865,7 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); ::new (&(*_end)) T(value1, value2, value3, value4); ++_end; @@ -1894,9 +1880,8 @@ namespace etl //************************************************************************* void pop_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(deque_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(deque_empty)); + destroy_element_back(); } @@ -1907,9 +1892,8 @@ namespace etl //************************************************************************* void push_front(const_reference item) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(deque_full)); + create_element_front(item); } @@ -1921,9 +1905,8 @@ namespace etl //************************************************************************* void push_front(rvalue_reference item) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(deque_full)); + create_element_front(etl::move(item)); } #endif @@ -1936,9 +1919,7 @@ namespace etl template reference emplace_front(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(etl::forward(args)...); @@ -1955,9 +1936,7 @@ namespace etl //************************************************************************* reference emplace_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(); @@ -1973,9 +1952,7 @@ namespace etl template reference emplace_front(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(value1); @@ -1991,9 +1968,7 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(value1, value2); @@ -2009,9 +1984,7 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(value1, value2, value3); @@ -2027,9 +2000,7 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(deque_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(deque_full)); --_begin; ::new (&(*_begin)) T(value1, value2, value3, value4); @@ -2044,9 +2015,8 @@ namespace etl //************************************************************************* void pop_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(deque_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(deque_empty)); + destroy_element_front(); } diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 75e71381..a6586250 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -420,18 +420,31 @@ namespace etl #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value. #endif +//************************************* +#if defined(ETL_CHECK_PUSH_POP) + #define ETL_ASSERT_CHECK_PUSH_POP(b, e) ETL_ASSERT(b, e) + #define ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(b, e) ETL_ASSERT_OR_RETURN(b, e) +#else + #define ETL_ASSERT_CHECK_PUSH_POP(b, e) + #define ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(b, e) +#endif + +//************************************* +#ifdef ETL_CHECK_INDEX_OPERATOR + #define ETL_ASSERT_CHECK_INDEX_OPERATOR(b, e) ETL_ASSERT(b,e) +#else + #define ETL_ASSERT_CHECK_INDEX_OPERATOR(b, e) +#endif + +//************************************* #if defined(ETL_VERBOSE_ERRORS) #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. -#else - #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. - #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. -#endif - -#if defined(ETL_VERBOSE_ERRORS) #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. #else - #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. + #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. + #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. + #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. #endif #endif diff --git a/include/etl/forward_list.h b/include/etl/forward_list.h index 4af4bd4a..58ef66f3 100644 --- a/include/etl/forward_list.h +++ b/include/etl/forward_list.h @@ -694,9 +694,7 @@ namespace etl //************************************************************************* void push_front(const T& value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(forward_list_full)); data_node_t& data_node = allocate_data_node(value); insert_node_after(start_node, data_node); @@ -708,9 +706,7 @@ namespace etl //************************************************************************* void push_front(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(forward_list_full)); data_node_t& data_node = allocate_data_node(etl::move(value)); insert_node_after(start_node, data_node); @@ -724,9 +720,8 @@ namespace etl template reference emplace_front(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(etl::forward(args)...); ETL_INCREMENT_DEBUG_COUNT; @@ -739,9 +734,8 @@ namespace etl //************************************************************************* reference emplace_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(); ETL_INCREMENT_DEBUG_COUNT; @@ -755,9 +749,8 @@ namespace etl template reference emplace_front(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(value1); ETL_INCREMENT_DEBUG_COUNT; @@ -771,9 +764,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(value1, value2); ETL_INCREMENT_DEBUG_COUNT; @@ -787,9 +779,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(value1, value2, value3); ETL_INCREMENT_DEBUG_COUNT; @@ -803,9 +794,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(forward_list_full)); + data_node_t* p_data_node = allocate_data_node(); ::new (&(p_data_node->value)) T(value1, value2, value3, value4); ETL_INCREMENT_DEBUG_COUNT; @@ -819,9 +809,8 @@ namespace etl //************************************************************************* void pop_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(forward_list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(forward_list_empty)); + remove_node_after(start_node); } diff --git a/include/etl/indirect_vector.h b/include/etl/indirect_vector.h index bac0502f..36d6c695 100644 --- a/include/etl/indirect_vector.h +++ b/include/etl/indirect_vector.h @@ -757,9 +757,8 @@ namespace etl //********************************************************************* void push_back(const_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != capacity(), ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != capacity(), ETL_ERROR(vector_full)); + T* p = storage.create(value); lookup.push_back(p); } @@ -772,9 +771,8 @@ namespace etl //********************************************************************* void push_back(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != capacity(), ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != capacity(), ETL_ERROR(vector_full)); + T* p = storage.create(etl::move(value)); lookup.push_back(p); } diff --git a/include/etl/intrusive_forward_list.h b/include/etl/intrusive_forward_list.h index d68dd6ad..262c8052 100644 --- a/include/etl/intrusive_forward_list.h +++ b/include/etl/intrusive_forward_list.h @@ -206,9 +206,8 @@ namespace etl //************************************************************************* void pop_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(!empty(), ETL_ERROR(intrusive_forward_list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_forward_list_empty)); + disconnect_link_after(start); } diff --git a/include/etl/intrusive_list.h b/include/etl/intrusive_list.h index 970d0589..36f3966d 100644 --- a/include/etl/intrusive_list.h +++ b/include/etl/intrusive_list.h @@ -172,9 +172,8 @@ namespace etl //************************************************************************* void pop_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_list_empty)); + disconnect_link(get_head()); } @@ -193,9 +192,8 @@ namespace etl //************************************************************************* void pop_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_list_empty)); + disconnect_link(get_tail()); } diff --git a/include/etl/intrusive_queue.h b/include/etl/intrusive_queue.h index 6e7c1382..6b51598e 100644 --- a/include/etl/intrusive_queue.h +++ b/include/etl/intrusive_queue.h @@ -124,9 +124,7 @@ namespace etl //************************************************************************* void pop() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(!empty(), ETL_ERROR(intrusive_queue_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_queue_empty)); link_type* p_front = terminator.etl_next; diff --git a/include/etl/intrusive_stack.h b/include/etl/intrusive_stack.h index fe0a123f..c93c27cb 100644 --- a/include/etl/intrusive_stack.h +++ b/include/etl/intrusive_stack.h @@ -115,9 +115,8 @@ namespace etl //************************************************************************* void pop() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(!empty(), ETL_ERROR(intrusive_stack_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(intrusive_stack_empty)); + link_type* p_next = p_top->etl_next; p_top->clear(); p_top = p_next; diff --git a/include/etl/list.h b/include/etl/list.h index 4a773bcc..ea070c0e 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -837,9 +837,8 @@ namespace etl //************************************************************************* void push_front(const T& value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(list_full)); + insert_node(get_head(), allocate_data_node(value)); } @@ -849,9 +848,8 @@ namespace etl //************************************************************************* void push_front(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(list_full)); + insert_node(get_head(), allocate_data_node(etl::move(value))); } #endif @@ -863,9 +861,9 @@ namespace etl template reference emplace_front(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -880,9 +878,8 @@ namespace etl //************************************************************************* reference emplace_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -898,9 +895,8 @@ namespace etl template reference emplace_front(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -916,9 +912,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -934,9 +929,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -952,9 +946,8 @@ namespace etl template reference emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -970,9 +963,8 @@ namespace etl //************************************************************************* void pop_front() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(list_empty)); + node_t& node = get_head(); remove_node(node); } @@ -982,9 +974,8 @@ namespace etl //************************************************************************* void push_back(const T& value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(list_full)); + insert_node(terminal_node, allocate_data_node(value)); } @@ -994,9 +985,8 @@ namespace etl //************************************************************************* void push_back(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(list_full)); + insert_node(terminal_node, allocate_data_node(etl::move(value))); } #endif @@ -1008,9 +998,8 @@ namespace etl template reference emplace_back(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1022,9 +1011,8 @@ namespace etl #else reference emplace_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1037,9 +1025,8 @@ namespace etl template reference emplace_back(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1052,9 +1039,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1067,9 +1053,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1082,9 +1067,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(list_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != ETL_NULLPTR, ETL_ERROR(list_no_pool)); data_node_t* p_data_node = allocate_data_node(); @@ -1100,9 +1084,8 @@ namespace etl //************************************************************************* void pop_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!empty(), ETL_ERROR(list_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(list_empty)); + node_t& node = get_tail(); remove_node(node); } diff --git a/include/etl/private/pvoidvector.h b/include/etl/private/pvoidvector.h index 728fceb0..9786d740 100644 --- a/include/etl/private/pvoidvector.h +++ b/include/etl/private/pvoidvector.h @@ -400,9 +400,8 @@ namespace etl //********************************************************************* void push_back(value_type value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); + *p_end++ = value; } @@ -413,9 +412,8 @@ namespace etl //********************************************************************* void emplace_back(value_type value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); + * p_end++ = value; } @@ -425,9 +423,8 @@ namespace etl //************************************************************************* void pop_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() > 0, ETL_ERROR(vector_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() > 0, ETL_ERROR(vector_empty)); + --p_end; } diff --git a/include/etl/queue.h b/include/etl/queue.h index 47e9d470..4c4fcd9f 100644 --- a/include/etl/queue.h +++ b/include/etl/queue.h @@ -308,9 +308,8 @@ namespace etl //************************************************************************* void push(const_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(queue_full)); + ::new (&p_buffer[in]) T(value); add_in(); } @@ -323,9 +322,8 @@ namespace etl //************************************************************************* void push(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(queue_full)); + ::new (&p_buffer[in]) T(etl::move(value)); add_in(); } @@ -340,9 +338,8 @@ namespace etl template reference emplace(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(etl::forward(args)...); add_in(); @@ -355,9 +352,8 @@ namespace etl //************************************************************************* reference emplace() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(); add_in(); @@ -372,9 +368,8 @@ namespace etl template reference emplace(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(value1); add_in(); @@ -390,9 +385,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(value1, value2); add_in(); @@ -409,9 +403,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(value1, value2, value3); add_in(); @@ -429,9 +422,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(queue_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(queue_full)); + reference value = p_buffer[in]; ::new (&value) T(value1, value2, value3, value4); add_in(); @@ -468,9 +460,8 @@ namespace etl //************************************************************************* void pop() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(!empty(), ETL_ERROR(queue_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(queue_empty)); + p_buffer[out].~T(); del_out(); } diff --git a/include/etl/stack.h b/include/etl/stack.h index 1c375906..2bcee404 100644 --- a/include/etl/stack.h +++ b/include/etl/stack.h @@ -253,9 +253,8 @@ namespace etl //************************************************************************* void push(const_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(value); } @@ -268,9 +267,8 @@ namespace etl //************************************************************************* void push(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(etl::move(value)); } @@ -285,9 +283,8 @@ namespace etl template reference emplace(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(etl::forward(args)...); @@ -301,9 +298,8 @@ namespace etl //************************************************************************* reference emplace() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(); @@ -318,9 +314,8 @@ namespace etl template reference emplace(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1); @@ -335,9 +330,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2); @@ -352,9 +346,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2, value3); @@ -369,9 +362,8 @@ namespace etl template reference emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(!full(), ETL_ERROR(stack_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(stack_full)); + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2, value3, value4); @@ -412,9 +404,8 @@ namespace etl //************************************************************************* void pop() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(!empty(), ETL_ERROR(stack_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(stack_empty)); + p_buffer[top_index].~T(); base_t::del_out(); } diff --git a/include/etl/vector.h b/include/etl/vector.h index 575c008a..e85d58f2 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -433,9 +433,8 @@ namespace etl //********************************************************************* void push_back(const_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); + create_back(value); } @@ -447,9 +446,8 @@ namespace etl //********************************************************************* void push_back(rvalue_reference value) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != CAPACITY, ETL_ERROR(vector_full)); + create_back(etl::move(value)); } #endif @@ -463,9 +461,8 @@ namespace etl template reference emplace_back(Args && ... args) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(etl::forward(args)...); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -479,9 +476,8 @@ namespace etl //********************************************************************* reference emplace_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -496,9 +492,8 @@ namespace etl template reference emplace_back(const T1& value1) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(value1); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -513,9 +508,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(value1, value2); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -530,9 +524,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(value1, value2, value3); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -547,9 +540,8 @@ namespace etl template reference emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); -#endif + ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + ::new (p_end) T(value1, value2, value3, value4); ++p_end; ETL_INCREMENT_DEBUG_COUNT; @@ -560,12 +552,12 @@ namespace etl //************************************************************************* /// Removes an element from the end of the vector. /// Does nothing if the vector is empty. + /// If asserts or exceptions are enabled, emits vector_empty if the vector is empty. //************************************************************************* void pop_back() { -#if defined(ETL_CHECK_PUSH_POP) - ETL_ASSERT_OR_RETURN(size() > 0, ETL_ERROR(vector_empty)); -#endif + ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() > 0, ETL_ERROR(vector_empty)); + destroy_back(); } From c13d01319e2302efa99161aa3a82ee45c62a4bfa Mon Sep 17 00:00:00 2001 From: mike919192 <91038685+mike919192@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:26:19 -0400 Subject: [PATCH 07/27] etl array checks (#1188) * Regression fix: Support zero arguments emplace() in etl::optional (#1183) * Added coderabbitai configuration * Added builtin mem function tests * Modified etl::typed_storage * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Added ETL_NOEXCEPT and ETL_NOEXCEPT_IF_NO_THROW * Added etl::typed_storage_ext and swap for same * Added etl::typed_storage_ext and swap for same # Conflicts: # include/etl/alignment.h * Added release notes * Fixes to GCC -O2 errors * Changed char* parameters to value_type* parameters * Fixed compilation issues for const containers unit tests * Added automatic selection of __builtin_memxxx functions for GCC and clang * Added enhanced coderabbit configuration * Updated version and release notes * Disabled constexpr const container tests for C++11 * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Updated version and release notes * feat: removed unreachable break statements (#1169) * Updated version and release notes * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Support zero arguments emplace() in etl::optional For non-fundamental types, a recent change in etl::optional was introduced that doesn't support zero arguments emplace() anymore. This change fixes it and adds the respective test. --------- Co-authored-by: John Wellbelove Co-authored-by: Drew Rife * Fix etl::typed_storage by supporting omitted destructors (#1182) * Added coderabbitai configuration * Added builtin mem function tests * Modified etl::typed_storage * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Added ETL_NOEXCEPT and ETL_NOEXCEPT_IF_NO_THROW * Added etl::typed_storage_ext and swap for same * Added etl::typed_storage_ext and swap for same # Conflicts: # include/etl/alignment.h * Added release notes * Fixes to GCC -O2 errors * Changed char* parameters to value_type* parameters * Fixed compilation issues for const containers unit tests * Added automatic selection of __builtin_memxxx functions for GCC and clang * Added enhanced coderabbit configuration * Updated version and release notes * Disabled constexpr const container tests for C++11 * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Updated version and release notes * feat: removed unreachable break statements (#1169) * Updated version and release notes * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Fix etl::typed_storage by supporting omitted destructors In a recent change to alignment.h, the etl::typed_storage was changed in a way that in case of an already constructed object, the object is created via assignment. However, this contradicts the original use case that led to etl::typed_storage in the first place: https://github.com/ETLCPP/etl/pull/1023 The goal is to omit destructors (and at the same time support classes with deleted assignment operators), so they can be optimized out at link time. This change reverts commit ac7b268 to restore the original functionality and changes the test to reflect the original use case. * Fix missing create() in non-C++11 typed_storage_ext constructor * Typo fix --------- Co-authored-by: John Wellbelove Co-authored-by: Drew Rife Co-authored-by: John Wellbelove * removed navis file from project * Updated version and release notes * Removed forced unsigned int cast in type_def bit-shift operators (#1178) * Removed UB in type_def bit-shift operators * Changed shift operators to allow both signed and unsigned operands for shifts This allows the library user to explicitly use unsigned values to avoid UB * Fixed constexpr errors for CPP11 * Changed is_arithmetic checks to use is_integral since valid shifts require integral operands * Removed need for CPP11 since changes are CPP03 compatible * Delete project navis files * Add force CI check on piull requests * Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() Removed ETL_NOEXCEPT from closureoperator(), call_if(), and call_or() * Updated version and release notes * Updated version and release notes * Remove noexcept from delegate method stubs. (#1185) In addition to removing noexcept from call_if, this is also needed to prevent an abort when cancelling a pthread that is executing a delegate. * Updated version and release notes * Re architect the extra checks * Add CHECK_EXTRA * Fix newline at end of file * The check index macro also needs to be defined to throw * Remove ETL_VERBOSE_ERRORS macros --------- Co-authored-by: Roland Reichwein Co-authored-by: John Wellbelove Co-authored-by: Drew Rife Co-authored-by: John Wellbelove Co-authored-by: David Ockey <2897027+ockeydockey@users.noreply.github.com> Co-authored-by: Marco Nilsson --- include/etl/array.h | 36 ++++++++++++++++++------------------ include/etl/error_handler.h | 7 +++++++ test/etl_profile.h | 2 ++ test/test_array.cpp | 6 ------ 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/include/etl/array.h b/include/etl/array.h index fbf5063a..a238269e 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -145,7 +145,7 @@ namespace etl ETL_CONSTEXPR14 reference operator[](size_t i) ETL_NOEXCEPT_EXPR(ETL_DEBUG_NOT_USING_EXCEPTIONS) { - ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < SIZE, ETL_ERROR(array_out_of_range)); return _buffer[i]; } @@ -158,11 +158,11 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR const_reference operator[](size_t i) const ETL_NOEXCEPT_EXPR(ETL_DEBUG_NOT_USING_EXCEPTIONS) { - //throwing from c++11 constexpr requires a special macro -#if ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_DEBUG_USING_EXCEPTIONS - ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(i < SIZE, ETL_ERROR(array_out_of_range), _buffer[i]); + // Throwing from c++11 constexpr requires special syntax +#if ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_USING_EXCEPTIONS && defined(ETL_CHECK_INDEX_OPERATOR) + return i < SIZE ? _buffer[i] : throw(ETL_ERROR(array_out_of_range)); #else - ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < SIZE, ETL_ERROR(array_out_of_range)); return _buffer[i]; #endif @@ -446,7 +446,7 @@ namespace etl //************************************************************************* inline iterator insert_at(size_t position, parameter_t value) { - ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(position < SIZE, ETL_ERROR(array_out_of_range)); return insert(begin() + position, value); } @@ -458,7 +458,7 @@ namespace etl //************************************************************************* iterator insert(const_iterator position, parameter_t value) { - ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(position); @@ -477,7 +477,7 @@ namespace etl template inline iterator insert_at(size_t position, TIterator first, const TIterator last) { - ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(position < SIZE, ETL_ERROR(array_out_of_range)); return insert(begin() + position, first, last); } @@ -491,7 +491,7 @@ namespace etl template iterator insert(const_iterator position, TIterator first, const TIterator last) { - ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(position); iterator result(p); @@ -519,7 +519,7 @@ namespace etl //************************************************************************* inline iterator erase_at(size_t position) { - ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(position < SIZE, ETL_ERROR(array_out_of_range)); return erase(begin() + position); } @@ -531,7 +531,7 @@ namespace etl //************************************************************************* iterator erase(const_iterator position) { - ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(position); etl::move(p + 1, end(), p); @@ -547,7 +547,7 @@ namespace etl //************************************************************************* iterator erase_range(size_t first, size_t last) { - ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); return erase(begin() + first, begin() + last); } @@ -560,7 +560,7 @@ namespace etl //************************************************************************* iterator erase(const_iterator first, const_iterator last) { - ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(first); etl::move(last, cend(), p); @@ -574,7 +574,7 @@ namespace etl //************************************************************************* inline iterator erase_at(size_t position, parameter_t value) { - ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(position < SIZE, ETL_ERROR(array_out_of_range)); return erase(begin() + position, value); } @@ -586,7 +586,7 @@ namespace etl //************************************************************************* iterator erase(const_iterator position, parameter_t value) { - ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(position); @@ -604,8 +604,8 @@ namespace etl //************************************************************************* iterator erase_range(size_t first, size_t last, parameter_t value) { - ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); - + ETL_ASSERT_CHECK_EXTRA(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range)); + return erase(begin() + first, begin() + last, value); } @@ -617,7 +617,7 @@ namespace etl //************************************************************************* iterator erase(const_iterator first, const_iterator last, parameter_t value) { - ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range)); iterator p = to_iterator(first); diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index a6586250..2a2c2d89 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -436,6 +436,13 @@ namespace etl #define ETL_ASSERT_CHECK_INDEX_OPERATOR(b, e) #endif +//************************************* +#ifdef ETL_CHECK_EXTRA + #define ETL_ASSERT_CHECK_EXTRA(b, e) ETL_ASSERT(b,e) +#else + #define ETL_ASSERT_CHECK_EXTRA(b, e) +#endif + //************************************* #if defined(ETL_VERBOSE_ERRORS) #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. diff --git a/test/etl_profile.h b/test/etl_profile.h index d98f6141..a7c680ff 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -35,6 +35,8 @@ SOFTWARE. #define ETL_DEBUG_THROW_EXCEPTIONS #define ETL_VERBOSE_ERRORS #define ETL_CHECK_PUSH_POP +#define ETL_CHECK_INDEX_OPERATOR +#define ETL_CHECK_EXTRA #define ETL_ISTRING_REPAIR_ENABLE #define ETL_IVECTOR_REPAIR_ENABLE #define ETL_IDEQUE_REPAIR_ENABLE diff --git a/test/test_array.cpp b/test/test_array.cpp index c779ab76..857719f2 100644 --- a/test/test_array.cpp +++ b/test/test_array.cpp @@ -135,7 +135,6 @@ namespace CHECK_EQUAL(data[i], compare_data[i]); } - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range); } @@ -149,7 +148,6 @@ namespace CHECK_EQUAL(data[i], compare_data[i]); } - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range); } @@ -451,7 +449,6 @@ namespace CHECK(isEqual); // Insert out of range - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined CHECK_THROW({ result = data.insert_at(data.size(), 99); }, etl::array_out_of_range); } @@ -505,7 +502,6 @@ namespace CHECK(isEqual); // Insert out of range - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined CHECK_THROW({ result = data.insert_at(data.size(), &source2[0], &source2[13]); }, etl::array_out_of_range); } @@ -563,7 +559,6 @@ namespace CHECK(isEqual); // Erase out of range - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined CHECK_THROW({ result = data.erase_at(data.size()); }, etl::array_out_of_range); } @@ -620,7 +615,6 @@ namespace isEqual = std::equal(data.begin(), data.end(), std::begin(check3b)); CHECK(isEqual); - //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined // first is greater than last CHECK_THROW({ result = data.erase_range(6, 5, 99); }, etl::array_out_of_range); From 793bafa1b40119273bdfd748bba51734bcbfb877 Mon Sep 17 00:00:00 2001 From: Mario Luzeiro Date: Thu, 11 Sep 2025 18:38:48 +0100 Subject: [PATCH 08/27] Added callbacks when a timer is inserted or removed (#1155) --- include/etl/callback_timer.h | 39 ++++++++++++++ include/etl/callback_timer_atomic.h | 39 ++++++++++++++ include/etl/callback_timer_deferred_locked.h | 2 + include/etl/callback_timer_interrupt.h | 39 ++++++++++++++ include/etl/callback_timer_locked.h | 39 ++++++++++++++ include/etl/message_timer.h | 40 +++++++++++++++ include/etl/message_timer_atomic.h | 40 +++++++++++++++ include/etl/message_timer_interrupt.h | 39 ++++++++++++++ include/etl/message_timer_locked.h | 38 ++++++++++++++ test/test_callback_timer.cpp | 51 ++++++++++++++++++ test/test_callback_timer_atomic.cpp | 51 ++++++++++++++++++ test/test_callback_timer_deferred_locked.cpp | 53 ++++++++++++++++++- test/test_callback_timer_interrupt.cpp | 51 ++++++++++++++++++ test/test_callback_timer_locked.cpp | 51 ++++++++++++++++++ test/test_message_timer.cpp | 54 ++++++++++++++++++++ test/test_message_timer_atomic.cpp | 54 ++++++++++++++++++++ 16 files changed, 679 insertions(+), 1 deletion(-) diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index c725922d..cbd1924d 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -385,6 +385,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -500,6 +502,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -571,12 +574,14 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.repeating) { // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } if (timer.p_callback != ETL_NULLPTR) @@ -637,10 +642,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; result = true; @@ -670,6 +677,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -756,6 +764,34 @@ namespace etl return false; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //******************************************* @@ -806,6 +842,9 @@ namespace etl #endif uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t MAX_TIMERS; diff --git a/include/etl/callback_timer_atomic.h b/include/etl/callback_timer_atomic.h index d2c63a47..b18703aa 100644 --- a/include/etl/callback_timer_atomic.h +++ b/include/etl/callback_timer_atomic.h @@ -53,6 +53,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -102,6 +104,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -173,6 +176,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -185,6 +189,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -226,10 +231,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); --process_semaphore; result = true; @@ -259,6 +266,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -355,6 +363,34 @@ namespace etl return result; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -638,6 +674,9 @@ namespace etl mutable TSemaphore process_semaphore; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/callback_timer_deferred_locked.h b/include/etl/callback_timer_deferred_locked.h index 2cd97d10..b8546ef7 100644 --- a/include/etl/callback_timer_deferred_locked.h +++ b/include/etl/callback_timer_deferred_locked.h @@ -111,6 +111,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -125,6 +126,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); diff --git a/include/etl/callback_timer_interrupt.h b/include/etl/callback_timer_interrupt.h index 22058cdc..247b69de 100644 --- a/include/etl/callback_timer_interrupt.h +++ b/include/etl/callback_timer_interrupt.h @@ -52,6 +52,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -106,6 +108,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } // Reset in-place. @@ -176,6 +179,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -187,6 +191,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -229,10 +234,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); result = true; } @@ -263,6 +270,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } result = true; @@ -356,6 +364,34 @@ namespace etl return false; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -637,6 +673,9 @@ namespace etl bool enabled; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/callback_timer_locked.h b/include/etl/callback_timer_locked.h index 861f2101..ff2837c5 100644 --- a/include/etl/callback_timer_locked.h +++ b/include/etl/callback_timer_locked.h @@ -54,6 +54,8 @@ namespace etl typedef etl::delegate lock_type; typedef etl::delegate unlock_type; + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -103,6 +105,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -180,10 +183,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); unlock(); result = true; @@ -213,6 +218,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -319,6 +325,34 @@ namespace etl return result; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -604,6 +638,9 @@ namespace etl lock_type lock; ///< The callback that locks. unlock_type unlock; ///< The callback that unlocks. + event_callback_type insert_callback; + event_callback_type remove_callback; + public: template friend class callback_timer_locked; @@ -666,6 +703,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.callback.is_valid()) { @@ -677,6 +715,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); diff --git a/include/etl/message_timer.h b/include/etl/message_timer.h index 7ddc55fc..094d8b03 100644 --- a/include/etl/message_timer.h +++ b/include/etl/message_timer.h @@ -39,6 +39,7 @@ SOFTWARE. #include "timer.h" #include "atomic.h" #include "algorithm.h" +#include "delegate.h" #include @@ -341,6 +342,8 @@ namespace etl { public: + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -396,6 +399,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -467,11 +471,13 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.repeating) { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } if (timer.p_router != ETL_NULLPTR) @@ -518,10 +524,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; result = true; @@ -551,6 +559,7 @@ namespace etl { ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); ETL_ENABLE_TIMER_UPDATES; } @@ -619,6 +628,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //******************************************* @@ -669,6 +706,9 @@ namespace etl #endif uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/message_timer_atomic.h b/include/etl/message_timer_atomic.h index a8826da2..cf349c57 100644 --- a/include/etl/message_timer_atomic.h +++ b/include/etl/message_timer_atomic.h @@ -39,6 +39,7 @@ SOFTWARE. #include "timer.h" #include "atomic.h" #include "algorithm.h" +#include "delegate.h" #include @@ -54,6 +55,8 @@ namespace etl { public: + typedef etl::delegate event_callback_type; + //******************************************* /// Register a timer. //******************************************* @@ -109,6 +112,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -180,6 +184,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -190,6 +195,7 @@ namespace etl { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -231,10 +237,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0U : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); --process_semaphore; result = true; @@ -264,6 +272,7 @@ namespace etl { ++process_semaphore; active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); --process_semaphore; } @@ -332,6 +341,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -620,6 +657,9 @@ namespace etl mutable TSemaphore process_semaphore; uint_least8_t registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t MAX_TIMERS; diff --git a/include/etl/message_timer_interrupt.h b/include/etl/message_timer_interrupt.h index 5fc0281d..6945d968 100644 --- a/include/etl/message_timer_interrupt.h +++ b/include/etl/message_timer_interrupt.h @@ -54,6 +54,8 @@ namespace etl typedef etl::delegate callback_type; + typedef etl::delegate event_callback_type; + public: //******************************************* @@ -116,6 +118,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); } // Reset in-place. @@ -187,6 +190,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -198,6 +202,7 @@ namespace etl // Reinsert the timer. timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -240,10 +245,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); result = true; } @@ -274,6 +281,7 @@ namespace etl (void)guard; // Silence 'unused variable warnings. active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } result = true; @@ -340,6 +348,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -626,6 +662,9 @@ namespace etl bool enabled; uint_least8_t number_of_registered_timers; + event_callback_type insert_callback; + event_callback_type remove_callback; + public: const uint_least8_t Max_Timers; diff --git a/include/etl/message_timer_locked.h b/include/etl/message_timer_locked.h index 9f0e2a2c..1d4e4b61 100644 --- a/include/etl/message_timer_locked.h +++ b/include/etl/message_timer_locked.h @@ -56,6 +56,8 @@ namespace etl typedef etl::delegate lock_type; typedef etl::delegate unlock_type; + typedef etl::delegate event_callback_type; + public: //******************************************* @@ -113,6 +115,7 @@ namespace etl { lock(); active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); unlock(); } @@ -184,6 +187,7 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); + remove_callback.call_if(timer.id); if (timer.p_router != ETL_NULLPTR) { @@ -194,6 +198,7 @@ namespace etl { timer.delta = timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); } has_active = !active_list.empty(); @@ -237,10 +242,12 @@ namespace etl if (timer.is_active()) { active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); } timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + insert_callback.call_if(timer.id); unlock(); result = true; @@ -270,6 +277,7 @@ namespace etl { lock(); active_list.remove(timer.id, false); + remove_callback.call_if(timer.id); unlock(); } @@ -348,6 +356,34 @@ namespace etl return delta; } + //******************************************* + /// Set a callback when a timer is inserted on list + //******************************************* + void set_insert_callback(event_callback_type insert_) + { + insert_callback = insert_; + } + + //******************************************* + /// Set a callback when a timer is removed from list + //******************************************* + void set_remove_callback(event_callback_type remove_) + { + remove_callback = remove_; + } + + //******************************************* + void clear_insert_callback() + { + insert_callback.clear(); + } + + //******************************************* + void clear_remove_callback() + { + remove_callback.clear(); + } + protected: //************************************************************************* @@ -638,6 +674,8 @@ namespace etl lock_type lock; ///< The callback that locks. unlock_type unlock; ///< The callback that unlocks. + event_callback_type insert_callback; + event_callback_type remove_callback; public: const uint_least8_t Max_Timers; diff --git a/test/test_callback_timer.cpp b/test/test_callback_timer.cpp index e800990d..62b2a059 100644 --- a/test/test_callback_timer.cpp +++ b/test/test_callback_timer.cpp @@ -81,10 +81,42 @@ namespace etl::callback_timer<3>* p_controller; }; + using event_callback_type = etl::icallback_timer::event_callback_type; + Object object; etl::function_imv member_callback; etl::function_imv member_callback2; + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -762,36 +794,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer<4> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_atomic.cpp b/test/test_callback_timer_atomic.cpp index 97d1b366..01b09e89 100644 --- a/test/test_callback_timer_atomic.cpp +++ b/test/test_callback_timer_atomic.cpp @@ -86,10 +86,42 @@ namespace using callback_type = etl::icallback_timer_atomic::callback_type; + using event_callback_type = etl::icallback_timer_atomic::event_callback_type; + Object object; callback_type member_callback1 = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -767,36 +799,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer_atomic<3, std::atomic_uint32_t> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_deferred_locked.cpp b/test/test_callback_timer_deferred_locked.cpp index 591cf732..33610c02 100644 --- a/test/test_callback_timer_deferred_locked.cpp +++ b/test/test_callback_timer_deferred_locked.cpp @@ -147,6 +147,8 @@ namespace using lock_type = etl::icallback_timer_locked::lock_type; using unlock_type = etl::icallback_timer_locked::unlock_type; + using event_callback_type = etl::icallback_timer_locked::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); @@ -154,6 +156,36 @@ namespace callback_type member_callback_inc2 = callback_type::create(); callback_type member_callback_inc3 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -1024,6 +1056,7 @@ namespace TEST(message_timer_time_to_next_with_has_active_timer) { locks.clear(); + timerInsertRemoveTest.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); unlock_type unlock = unlock_type::create(); @@ -1034,31 +1067,49 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); timer_controller.tick(11); timer_controller.handle_deferred(); - CHECK_EQUAL(12, timer_controller.time_to_next()); + CHECK_EQUAL(23 - 11, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); timer_controller.handle_deferred(); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); timer_controller.handle_deferred(); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); timer_controller.handle_deferred(); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_interrupt.cpp b/test/test_callback_timer_interrupt.cpp index e13683d1..ae373c6e 100644 --- a/test/test_callback_timer_interrupt.cpp +++ b/test/test_callback_timer_interrupt.cpp @@ -99,10 +99,42 @@ namespace using callback_type = etl::icallback_timer_interrupt::callback_type; + using event_callback_type = etl::icallback_timer_interrupt::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -775,36 +807,55 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); etl::callback_timer_interrupt<3, ScopedGuard> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(member_callback, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_callback_timer_locked.cpp b/test/test_callback_timer_locked.cpp index c0e21bd1..ddeda3a4 100644 --- a/test/test_callback_timer_locked.cpp +++ b/test/test_callback_timer_locked.cpp @@ -121,10 +121,42 @@ namespace using lock_type = etl::icallback_timer_locked::lock_type; using unlock_type = etl::icallback_timer_locked::unlock_type; + using event_callback_type = etl::icallback_timer_locked::event_callback_type; + Object object; callback_type member_callback = callback_type::create(); callback_type member_callback2 = callback_type::create(); + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + //*************************************************************************** // Free function callback via etl::function //*************************************************************************** @@ -874,6 +906,7 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -885,30 +918,48 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer.cpp b/test/test_message_timer.cpp index 0d5231f6..1e4eca2e 100644 --- a/test/test_message_timer.cpp +++ b/test/test_message_timer.cpp @@ -134,6 +134,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer) { //************************************************************************* @@ -646,35 +678,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer<3> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer_atomic.cpp b/test/test_message_timer_atomic.cpp index 98a899ee..b612cd46 100644 --- a/test/test_message_timer_atomic.cpp +++ b/test/test_message_timer_atomic.cpp @@ -134,6 +134,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_atomic::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer) { //************************************************************************* @@ -646,35 +678,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer_atomic<3, std::atomic_uint32_t> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* From 21d7ebe879983c78f382dfb32e14eeb4d8a3dce5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 11 Sep 2025 19:28:03 +0100 Subject: [PATCH 09/27] Added insert and remove timer callback tests to test_message_timer_interrupt and test_message_timer_locked --- test/test_message_timer_interrupt.cpp | 54 +++++++++++++++++++++++++++ test/test_message_timer_locked.cpp | 54 +++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/test/test_message_timer_interrupt.cpp b/test/test_message_timer_interrupt.cpp index e746644b..7c66edb9 100644 --- a/test/test_message_timer_interrupt.cpp +++ b/test/test_message_timer_interrupt.cpp @@ -157,6 +157,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_interrupt::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + SUITE(test_message_timer_interrupt) { //************************************************************************* @@ -693,35 +725,57 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); etl::message_timer_interrupt<3, ScopedGuard> timer_controller; etl::timer::id::type id1 = timer_controller.register_timer(message1, router1, 37, etl::timer::mode::Single_Shot); etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* diff --git a/test/test_message_timer_locked.cpp b/test/test_message_timer_locked.cpp index c3078c2d..6d7c1215 100644 --- a/test/test_message_timer_locked.cpp +++ b/test/test_message_timer_locked.cpp @@ -168,6 +168,38 @@ namespace Router1 router1; Bus1 bus1; + using event_callback_type = etl::imessage_timer_locked::event_callback_type; + + class TimerInsertRemoveTest + { + public: + uint32_t inserted; + uint32_t removed; + TimerInsertRemoveTest() : inserted(0), removed(0) + { + } + + void insert_handler(etl::timer::id::type id_) + { + (void)id_; + inserted++; + } + + void remove_handler(etl::timer::id::type id_) + { + (void)id_; + removed++; + } + + void clear(void) + { + inserted = 0; + removed = 0; + } + }; + + TimerInsertRemoveTest timerInsertRemoveTest; + using try_lock_type = etl::imessage_timer_locked::try_lock_type; using lock_type = etl::imessage_timer_locked::lock_type; using unlock_type = etl::imessage_timer_locked::unlock_type; @@ -773,6 +805,7 @@ namespace //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -784,29 +817,50 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(message2, router1, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(message3, router1, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + router1.clear(); timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); CHECK_EQUAL(12, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(2); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(1); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* From 947f9e523bfece54d077f66c9a1e40d13d3c0b8e Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:47:18 +0100 Subject: [PATCH 10/27] Changed timer to match the internal layout of other timers --- include/etl/callback_timer.h | 633 +++++++++++++++++------------------ 1 file changed, 314 insertions(+), 319 deletions(-) diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index cbd1924d..e44320e9 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -77,305 +77,6 @@ SOFTWARE. namespace etl { - //************************************************************************* - /// The configuration of a timer. - struct callback_timer_data - { - typedef etl::delegate callback_type; - - enum callback_type_id - { - C_CALLBACK, - IFUNCTION, - DELEGATE - }; - - //******************************************* - callback_timer_data() - : p_callback(ETL_NULLPTR), - period(0), - delta(etl::timer::state::Inactive), - id(etl::timer::id::NO_TIMER), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(true), - cbk_type(IFUNCTION) - { - } - - //******************************************* - /// C function callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - void (*p_callback_)(), - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(p_callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(C_CALLBACK) - { - } - - //******************************************* - /// ETL function callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - etl::ifunction& callback_, - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(&callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(IFUNCTION) - { - } - - //******************************************* - /// ETL delegate callback - //******************************************* - callback_timer_data(etl::timer::id::type id_, - callback_type& callback_, - uint32_t period_, - bool repeating_) - : p_callback(reinterpret_cast(&callback_)), - period(period_), - delta(etl::timer::state::Inactive), - id(id_), - previous(etl::timer::id::NO_TIMER), - next(etl::timer::id::NO_TIMER), - repeating(repeating_), - cbk_type(DELEGATE) - { - } - - //******************************************* - /// Returns true if the timer is active. - //******************************************* - bool is_active() const - { - return delta != etl::timer::state::Inactive; - } - - //******************************************* - /// Sets the timer to the inactive state. - //******************************************* - void set_inactive() - { - delta = etl::timer::state::Inactive; - } - - void* p_callback; - uint32_t period; - uint32_t delta; - etl::timer::id::type id; - uint_least8_t previous; - uint_least8_t next; - bool repeating; - callback_type_id cbk_type; - - private: - - // Disabled. - callback_timer_data(const callback_timer_data& other); - callback_timer_data& operator =(const callback_timer_data& other); - }; - - namespace private_callback_timer - { - //************************************************************************* - /// A specialised intrusive linked list for timer data. - //************************************************************************* - class list - { - public: - - //******************************* - list(etl::callback_timer_data* ptimers_) - : head(etl::timer::id::NO_TIMER), - tail(etl::timer::id::NO_TIMER), - current(etl::timer::id::NO_TIMER), - ptimers(ptimers_) - { - } - - //******************************* - bool empty() const - { - return head == etl::timer::id::NO_TIMER; - } - - //******************************* - // Inserts the timer at the correct delta position - //******************************* - void insert(etl::timer::id::type id_) - { - etl::callback_timer_data& timer = ptimers[id_]; - - if (head == etl::timer::id::NO_TIMER) - { - // No entries yet. - head = id_; - tail = id_; - timer.previous = etl::timer::id::NO_TIMER; - timer.next = etl::timer::id::NO_TIMER; - } - else - { - // We already have entries. - etl::timer::id::type test_id = begin(); - - while (test_id != etl::timer::id::NO_TIMER) - { - etl::callback_timer_data& test = ptimers[test_id]; - - // Find the correct place to insert. - if (timer.delta <= test.delta) - { - if (test.id == head) - { - head = timer.id; - } - - // Insert before test. - timer.previous = test.previous; - test.previous = timer.id; - timer.next = test.id; - - // Adjust the next delta to compensate. - test.delta -= timer.delta; - - if (timer.previous != etl::timer::id::NO_TIMER) - { - ptimers[timer.previous].next = timer.id; - } - break; - } - else - { - timer.delta -= test.delta; - } - - test_id = next(test_id); - } - - // Reached the end? - if (test_id == etl::timer::id::NO_TIMER) - { - // Tag on to the tail. - ptimers[tail].next = timer.id; - timer.previous = tail; - timer.next = etl::timer::id::NO_TIMER; - tail = timer.id; - } - } - } - - //******************************* - void remove(etl::timer::id::type id_, bool has_expired) - { - etl::callback_timer_data& timer = ptimers[id_]; - - if (head == id_) - { - head = timer.next; - } - else - { - ptimers[timer.previous].next = timer.next; - } - - if (tail == id_) - { - tail = timer.previous; - } - else - { - ptimers[timer.next].previous = timer.previous; - } - - if (!has_expired) - { - // Adjust the next delta. - if (timer.next != etl::timer::id::NO_TIMER) - { - ptimers[timer.next].delta += timer.delta; - } - } - - timer.previous = etl::timer::id::NO_TIMER; - timer.next = etl::timer::id::NO_TIMER; - timer.delta = etl::timer::state::Inactive; - } - - //******************************* - etl::callback_timer_data& front() - { - return ptimers[head]; - } - - //******************************* - const etl::callback_timer_data& front() const - { - return ptimers[head]; - } - - //******************************* - etl::timer::id::type begin() - { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; - } - - //******************************* - etl::timer::id::type next(etl::timer::id::type last) - { - current = ptimers[last].next; - return current; - } - - //******************************* - void clear() - { - etl::timer::id::type id = begin(); - - while (id != etl::timer::id::NO_TIMER) - { - etl::callback_timer_data& timer = ptimers[id]; - id = next(id); - timer.next = etl::timer::id::NO_TIMER; - } - - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; - } - - private: - - etl::timer::id::type head; - etl::timer::id::type tail; - etl::timer::id::type current; - - etl::callback_timer_data* const ptimers; - }; - } - //*************************************************************************** /// Interface for callback timer //*************************************************************************** @@ -403,12 +104,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, p_callback_, period_, repeating_); + new (&timer) timer_data(i, p_callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -435,12 +136,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, callback_, period_, repeating_); + new (&timer) timer_data(i, callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -468,12 +169,12 @@ namespace etl // Search for the free space. for (uint_least8_t i = 0U; i < MAX_TIMERS; ++i) { - etl::callback_timer_data& timer = timer_array[i]; + timer_data& timer = timer_array[i]; if (timer.id == etl::timer::id::NO_TIMER) { // Create in-place. - new (&timer) callback_timer_data(i, callback_, period_, repeating_); + new (&timer) timer_data(i, callback_, period_, repeating_); ++registered_timers; id = i; break; @@ -494,7 +195,7 @@ namespace etl if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; if (timer.id != etl::timer::id::NO_TIMER) { @@ -507,7 +208,7 @@ namespace etl } // Reset in-place. - new (&timer) callback_timer_data(); + new (&timer) timer_data(); --registered_timers; result = true; @@ -544,7 +245,7 @@ namespace etl for (int i = 0; i < MAX_TIMERS; ++i) { - ::new (&timer_array[i]) callback_timer_data(); + ::new (&timer_array[i]) timer_data(); } registered_timers = 0; @@ -569,7 +270,7 @@ namespace etl { while (has_active && (count >= active_list.front().delta)) { - etl::callback_timer_data& timer = active_list.front(); + timer_data& timer = active_list.front(); count -= timer.delta; @@ -586,17 +287,17 @@ namespace etl if (timer.p_callback != ETL_NULLPTR) { - if (timer.cbk_type == callback_timer_data::C_CALLBACK) + if (timer.cbk_type == timer_data::C_CALLBACK) { // Call the C callback. reinterpret_cast(timer.p_callback)(); } - else if(timer.cbk_type == callback_timer_data::IFUNCTION) + else if(timer.cbk_type == timer_data::IFUNCTION) { // Call the function wrapper callback. (*reinterpret_cast*>(timer.p_callback))(); } - else if(timer.cbk_type == callback_timer_data::DELEGATE) + else if(timer.cbk_type == timer_data::DELEGATE) { // Call the delegate callback. (*reinterpret_cast(timer.p_callback))(); @@ -630,7 +331,7 @@ namespace etl // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -668,7 +369,7 @@ namespace etl // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { - etl::callback_timer_data& timer = timer_array[id_]; + timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -751,7 +452,7 @@ namespace etl { if (has_active_timer()) { - const etl::callback_timer_data& timer = timer_array[id_]; + const timer_data& timer = timer_array[id_]; // Registered timer? if (timer.id != etl::timer::id::NO_TIMER) @@ -794,10 +495,122 @@ namespace etl protected: + //************************************************************************* + /// The configuration of a timer. + struct timer_data + { + typedef etl::delegate callback_type; + + enum callback_type_id + { + C_CALLBACK, + IFUNCTION, + DELEGATE + }; + + //******************************************* + timer_data() + : p_callback(ETL_NULLPTR) + , period(0) + , delta(etl::timer::state::Inactive) + , id(etl::timer::id::NO_TIMER) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(true) + , cbk_type(IFUNCTION) + { + } + + //******************************************* + /// C function callback + //******************************************* + timer_data(etl::timer::id::type id_, + void (*p_callback_)(), + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(p_callback_)) + , period(period_) + , delta(etl::timer::state::Inactive) + , id(id_) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(repeating_) + , cbk_type(C_CALLBACK) + { + } + + //******************************************* + /// ETL function callback + //******************************************* + timer_data(etl::timer::id::type id_, + etl::ifunction& callback_, + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(&callback_)) + , period(period_) + , delta(etl::timer::state::Inactive) + , id(id_) + , previous(etl::timer::id::NO_TIMER) + , next(etl::timer::id::NO_TIMER) + , repeating(repeating_) + , cbk_type(IFUNCTION) + { + } + + //******************************************* + /// ETL delegate callback + //******************************************* + timer_data(etl::timer::id::type id_, + callback_type& callback_, + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast(&callback_)), + period(period_), + delta(etl::timer::state::Inactive), + id(id_), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(repeating_), + cbk_type(DELEGATE) + { + } + + //******************************************* + /// Returns true if the timer is active. + //******************************************* + bool is_active() const + { + return delta != etl::timer::state::Inactive; + } + + //******************************************* + /// Sets the timer to the inactive state. + //******************************************* + void set_inactive() + { + delta = etl::timer::state::Inactive; + } + + void* p_callback; + uint32_t period; + uint32_t delta; + etl::timer::id::type id; + uint_least8_t previous; + uint_least8_t next; + bool repeating; + callback_type_id cbk_type; + + private: + + // Disabled. + timer_data(const timer_data& other); + timer_data& operator =(const timer_data& other); + }; + //******************************************* /// Constructor. //******************************************* - icallback_timer(callback_timer_data* const timer_array_, const uint_least8_t Max_Timers_) + icallback_timer(timer_data* const timer_array_, const uint_least8_t Max_Timers_) : timer_array(timer_array_), active_list(timer_array_), enabled(false), @@ -819,11 +632,193 @@ namespace etl return (id_ < MAX_TIMERS); } + //************************************************************************* + class timer_list + { + public: + + //******************************* + timer_list(timer_data* ptimers_) + : head(etl::timer::id::NO_TIMER) + , tail(etl::timer::id::NO_TIMER) + , current(etl::timer::id::NO_TIMER) + , ptimers(ptimers_) + { + } + + //******************************* + bool empty() const + { + return head == etl::timer::id::NO_TIMER; + } + + //******************************* + // Inserts the timer at the correct delta position + //******************************* + void insert(etl::timer::id::type id_) + { + timer_data& timer = ptimers[id_]; + + if (head == etl::timer::id::NO_TIMER) + { + // No entries yet. + head = id_; + tail = id_; + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + } + else + { + // We already have entries. + etl::timer::id::type test_id = begin(); + + while (test_id != etl::timer::id::NO_TIMER) + { + timer_data& test = ptimers[test_id]; + + // Find the correct place to insert. + if (timer.delta <= test.delta) + { + if (test.id == head) + { + head = timer.id; + } + + // Insert before test. + timer.previous = test.previous; + test.previous = timer.id; + timer.next = test.id; + + // Adjust the next delta to compensate. + test.delta -= timer.delta; + + if (timer.previous != etl::timer::id::NO_TIMER) + { + ptimers[timer.previous].next = timer.id; + } + break; + } + else + { + timer.delta -= test.delta; + } + + test_id = next(test_id); + } + + // Reached the end? + if (test_id == etl::timer::id::NO_TIMER) + { + // Tag on to the tail. + ptimers[tail].next = timer.id; + timer.previous = tail; + timer.next = etl::timer::id::NO_TIMER; + tail = timer.id; + } + } + } + + //******************************* + void remove(etl::timer::id::type id_, bool has_expired) + { + timer_data& timer = ptimers[id_]; + + if (head == id_) + { + head = timer.next; + } + else + { + ptimers[timer.previous].next = timer.next; + } + + if (tail == id_) + { + tail = timer.previous; + } + else + { + ptimers[timer.next].previous = timer.previous; + } + + if (!has_expired) + { + // Adjust the next delta. + if (timer.next != etl::timer::id::NO_TIMER) + { + ptimers[timer.next].delta += timer.delta; + } + } + + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + timer.delta = etl::timer::state::Inactive; + } + + //******************************* + timer_data& front() + { + return ptimers[head]; + } + + //******************************* + const timer_data& front() const + { + return ptimers[head]; + } + + //******************************* + etl::timer::id::type begin() + { + current = head; + return current; + } + + //******************************* + etl::timer::id::type previous(etl::timer::id::type last) + { + current = ptimers[last].previous; + return current; + } + + //******************************* + etl::timer::id::type next(etl::timer::id::type last) + { + current = ptimers[last].next; + return current; + } + + //******************************* + void clear() + { + etl::timer::id::type id = begin(); + + while (id != etl::timer::id::NO_TIMER) + { + timer_data& timer = ptimers[id]; + id = next(id); + timer.next = etl::timer::id::NO_TIMER; + } + + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; + current = etl::timer::id::NO_TIMER; + } + + private: + + etl::timer::id::type head; + etl::timer::id::type tail; + etl::timer::id::type current; + + timer_data* const ptimers; + }; + // The array of timer data structures. - callback_timer_data* const timer_array; + timer_data* const timer_array; // The list of active timers. - private_callback_timer::list active_list; + timer_list active_list; volatile bool enabled; #if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) @@ -870,7 +865,7 @@ namespace etl private: - callback_timer_data timer_array[Max_Timers_]; + timer_data timer_array[Max_Timers_]; }; } From 8dff499500d2e2a373b30df503801f42a1679dfa Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:47:51 +0100 Subject: [PATCH 11/27] Added insert/remove tests --- test/test_callback_timer_deferred_locked.cpp | 35 +++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/test/test_callback_timer_deferred_locked.cpp b/test/test_callback_timer_deferred_locked.cpp index 33610c02..46aaafe5 100644 --- a/test/test_callback_timer_deferred_locked.cpp +++ b/test/test_callback_timer_deferred_locked.cpp @@ -1012,6 +1012,7 @@ namespace //************************************************************************* TEST(callback_timer_is_active) { + timerInsertRemoveTest.clear(); locks.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); @@ -1023,40 +1024,57 @@ namespace etl::timer::id::type id2 = timer_controller.register_timer(free_function_callback, 23, etl::timer::mode::Single_Shot); etl::timer::id::type id3 = timer_controller.register_timer(free_function_callback2, 11, etl::timer::mode::Single_Shot); + timer_controller.set_insert_callback(event_callback_type::create()); + timer_controller.set_remove_callback(event_callback_type::create()); + timer_controller.start(id1); timer_controller.start(id3); timer_controller.start(id2); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.enable(true); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_TRUE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(0, timerInsertRemoveTest.removed); + timer_controller.tick(11); timer_controller.handle_deferred(); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_TRUE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(1, timerInsertRemoveTest.removed); + timer_controller.tick(23 - 11); timer_controller.handle_deferred(); CHECK_TRUE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(2, timerInsertRemoveTest.removed); + timer_controller.tick(37 - 23); timer_controller.handle_deferred(); CHECK_FALSE(timer_controller.is_active(id1)); CHECK_FALSE(timer_controller.is_active(id2)); CHECK_FALSE(timer_controller.is_active(id3)); + + CHECK_EQUAL(3, timerInsertRemoveTest.inserted); + CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* TEST(message_timer_time_to_next_with_has_active_timer) { locks.clear(); - timerInsertRemoveTest.clear(); try_lock_type try_lock = try_lock_type::create(); lock_type lock = lock_type::create(); unlock_type unlock = unlock_type::create(); @@ -1074,9 +1092,6 @@ namespace timer_controller.start(id3); timer_controller.start(id2); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(0, timerInsertRemoveTest.removed); - timer_controller.enable(true); timer_controller.tick(11); @@ -1084,32 +1099,20 @@ namespace CHECK_EQUAL(23 - 11, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(1, timerInsertRemoveTest.removed); - timer_controller.tick(23); timer_controller.handle_deferred(); CHECK_EQUAL(3, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(2, timerInsertRemoveTest.removed); - timer_controller.tick(2); timer_controller.handle_deferred(); CHECK_EQUAL(1, timer_controller.time_to_next()); CHECK_TRUE(timer_controller.has_active_timer()); - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(2, timerInsertRemoveTest.removed); - timer_controller.tick(1); timer_controller.handle_deferred(); CHECK_EQUAL(static_cast(etl::timer::interval::No_Active_Interval), timer_controller.time_to_next()); CHECK_FALSE(timer_controller.has_active_timer()); - - CHECK_EQUAL(3, timerInsertRemoveTest.inserted); - CHECK_EQUAL(3, timerInsertRemoveTest.removed); } //************************************************************************* From da5e42a4bc0eb64be3e2adfcc996302cd24c3ab6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:48:18 +0100 Subject: [PATCH 12/27] Moved and renamed common class to base --- include/etl/callback_timer_deferred_locked.h | 23 +++------------- include/etl/callback_timer_locked.h | 29 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/include/etl/callback_timer_deferred_locked.h b/include/etl/callback_timer_deferred_locked.h index b8546ef7..ce760648 100644 --- a/include/etl/callback_timer_deferred_locked.h +++ b/include/etl/callback_timer_deferred_locked.h @@ -54,22 +54,7 @@ namespace etl private: - class CallbackNode - { - public: - - CallbackNode(callback_type &callback_,uint_least8_t priority_) : callback(callback_), priority(priority_) - { - } - - bool operator < (const CallbackNode& p) const - { - return this->priority > p.priority; // comparison was inverted here to easy the code design - } - - callback_type callback; - uint_least8_t priority; - }; + typedef icallback_timer_locked::callback_node callback_node; public: @@ -117,7 +102,7 @@ namespace etl { if (!handler_queue.full()) { - handler_queue.push(CallbackNode(timer.callback, timer_priorities[timer.id])); + handler_queue.push(callback_node(timer.callback, timer_priorities[timer.id])); } } @@ -167,7 +152,7 @@ namespace etl } else { - CallbackNode &work_todo_callback_node = handler_queue.top(); + callback_node &work_todo_callback_node = handler_queue.top(); work_todo_callback = work_todo_callback_node.callback; handler_queue.pop(); } @@ -213,7 +198,7 @@ namespace etl private: - priority_queue handler_queue; + priority_queue handler_queue; uint_least8_t timer_priorities[Max_Timers_]; timer_data timer_array[Max_Timers_]; }; diff --git a/include/etl/callback_timer_locked.h b/include/etl/callback_timer_locked.h index ff2837c5..75689634 100644 --- a/include/etl/callback_timer_locked.h +++ b/include/etl/callback_timer_locked.h @@ -355,6 +355,23 @@ namespace etl protected: + class callback_node + { + public: + + callback_node(callback_type &callback_,uint_least8_t priority_) : callback(callback_), priority(priority_) + { + } + + bool operator < (const callback_node& p) const + { + return this->priority > p.priority; // comparison was inverted here to easy the code design + } + + callback_type callback; + uint_least8_t priority; + }; + //************************************************************************* /// The configuration of a timer. struct timer_data @@ -642,6 +659,7 @@ namespace etl event_callback_type remove_callback; public: + template friend class callback_timer_locked; @@ -666,6 +684,12 @@ namespace etl typedef icallback_timer_locked::lock_type lock_type; typedef icallback_timer_locked::unlock_type unlock_type; + private: + + typedef icallback_timer_locked::callback_node callback_node; + + public: + //******************************************* /// Constructor. //******************************************* @@ -683,8 +707,9 @@ namespace etl this->set_locks(try_lock_, lock_, unlock_); } - // Implement virtual functions - + //******************************************* + /// Handle the tick call + //******************************************* bool tick(uint32_t count) final { if (enabled) From f2c33a446646267176be1bacec039cbfaf9e2b13 Mon Sep 17 00:00:00 2001 From: mike919192 <91038685+mike919192@users.noreply.github.com> Date: Wed, 10 Sep 2025 05:52:22 -0400 Subject: [PATCH 13/27] Debug assert (#1175) * debug assert POC * Swith to ETL_CONSTEXPR14 * Finish TODO checks * First and last can be equal * Add ETL_DEBUG_THROW_EXCEPTIONS * Try allowing c++11 constexpr * Add macro for throwing from c++11 constexpr * Remove braces * Add extra asserts in size_t overload functions * Fill out debug asserts * Line up comments --- test/etl_profile.h | 1 + 1 file changed, 1 insertion(+) diff --git a/test/etl_profile.h b/test/etl_profile.h index a7c680ff..42b6f500 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -31,6 +31,7 @@ SOFTWARE. #ifndef ETL_PROFILE_H_INCLUDED #define ETL_PROFILE_H_INCLUDED +#define ETL_DEBUG #define ETL_THROW_EXCEPTIONS #define ETL_DEBUG_THROW_EXCEPTIONS #define ETL_VERBOSE_ERRORS From a2415cc30fb9ae1165790b56a78a77e7c6026854 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Sep 2025 14:34:06 +0100 Subject: [PATCH 14/27] Removed #define ETL_DEBUG as this is a project define --- test/etl_profile.h | 1 - 1 file changed, 1 deletion(-) diff --git a/test/etl_profile.h b/test/etl_profile.h index 42b6f500..a7c680ff 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -31,7 +31,6 @@ SOFTWARE. #ifndef ETL_PROFILE_H_INCLUDED #define ETL_PROFILE_H_INCLUDED -#define ETL_DEBUG #define ETL_THROW_EXCEPTIONS #define ETL_DEBUG_THROW_EXCEPTIONS #define ETL_VERBOSE_ERRORS From 32a2e78d79660d3f1028b7a20a3a6c04c1dde834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BCthing?= Date: Sat, 27 Sep 2025 11:28:57 +0200 Subject: [PATCH 15/27] Enforce Semicolon after ETL_ASSERT (#1190) * Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() Removed ETL_NOEXCEPT from closureoperator(), call_if(), and call_or() * Updated version and release notes * Updated version and release notes * Remove noexcept from delegate method stubs. (#1185) In addition to removing noexcept from call_if, this is also needed to prevent an abort when cancelling a pthread that is executing a delegate. * Updated version and release notes * Enforce Semicolon after ETL_ASSERT --------- Co-authored-by: John Wellbelove Co-authored-by: Marco Nilsson Co-authored-by: John Wellbelove --- include/etl/error_handler.h | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 2a2c2d89..da3959cb 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -309,57 +309,57 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN(e) ETL_DO_NOTHING // Does nothing. #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) ETL_DO_NOTHING // Does nothing. #elif defined(ETL_USE_ASSERT_FUNCTION) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} while(false) // If the condition fails, calls the assert function + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} while(false) // If the condition fails, calls the assert function and return + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} while(false) // If the condition fails, calls the assert function and return a value - #define ETL_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value + #define ETL_ASSERT_FAIL(e) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} while(false) // Calls the assert function + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} while(false) // Calls the assert function and return + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} while(false) // Calls the assert function and return a value #elif ETL_USING_EXCEPTIONS - #if defined(ETL_LOG_ERRORS) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. +#if defined(ETL_LOG_ERRORS) + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} while(false) // If the condition fails, calls the error handler then throws an exception. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} while(false) // If the condition fails, calls the error handler then throws an exception. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} while(false) // If the condition fails, calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL(e) {etl::error_handler::error((e)); throw((e));} // Calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); throw((e)); return;} // Calls the error handler then throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL(e) do {etl::error_handler::error((e)); throw((e));} while(false) // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::error_handler::error((e)); throw((e)); return;} while(false) // Calls the error handler then throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::error_handler::error((e)); throw((e)); return(v);} while(false) // Calls the error handler then throws an exception. #else - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {throw((e));}} while(false) // If the condition fails, throws an exception. - #define ETL_ASSERT_FAIL(e) {throw((e));} // Throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception. + #define ETL_ASSERT_FAIL(e) do {throw((e));} while(false) // Throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {throw((e));} while(false) // Throws an exception. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {throw((e));} while(false) // Throws an exception. #endif #else - #if defined(ETL_LOG_ERRORS) - #define ETL_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} // If the condition fails, calls the error handler - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} // If the condition fails, calls the error handler and return - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} // If the condition fails, calls the error handler and return a value +#if defined(ETL_LOG_ERRORS) + #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} while(false) // If the condition fails, calls the error handler + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} while(false) // If the condition fails, calls the error handler and return + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} while(false) // If the condition fails, calls the error handler and return a value - #define ETL_ASSERT_FAIL(e) {etl::error_handler::error((e));} // Calls the error handler - #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); return;} // Calls the error handler and return - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); return (v);} // Calls the error handler and return a value + #define ETL_ASSERT_FAIL(e) do {etl::error_handler::error((e));} while(false) // Calls the error handler + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::error_handler::error((e)); return;} while(false) // Calls the error handler and return + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::error_handler::error((e)); return (v);} while(false) // Calls the error handler and return a value #else #if ETL_IS_DEBUG_BUILD - #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {assert(false); return;}} // If the condition fails, asserts and return. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} // If the condition fails, asserts and return a value. + #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {assert(false); return;}} while(false) // If the condition fails, asserts and return. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} while(false) // If the condition fails, asserts and return a value. - #define ETL_ASSERT_FAIL(e) assert(false) // Asserts. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {assert(false); return;} // Asserts. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts. + #define ETL_ASSERT_FAIL(e) assert(false) // Asserts. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {assert(false); return;} while(false) // Asserts. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {assert(false); return(v);} while(false) // Asserts. #else - #define ETL_ASSERT(b, e) // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY return;} // Returns. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY return(v);} // Returns a value. + #define ETL_ASSERT(b, e) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY return;} while(false) // Returns. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY return(v);} while(false) // Returns a value. - #define ETL_ASSERT_FAIL(e) // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value. + #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN(e) do {return;} while(false) // Returns. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {return(v);} while(false) // Returns a value. #endif #endif #endif From 9e0121125fd7190e5f2ab47722e94d44b7eaf237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BCthing?= Date: Sun, 28 Sep 2025 12:10:50 +0200 Subject: [PATCH 16/27] Allow easy Creation of Generic Exceptions with just a Text (#1192) * Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() Removed ETL_NOEXCEPT from closureoperator(), call_if(), and call_or() * Updated version and release notes * Updated version and release notes * Remove noexcept from delegate method stubs. (#1185) In addition to removing noexcept from call_if, this is also needed to prevent an abort when cancelling a pthread that is executing a delegate. * Updated version and release notes * Allow easy Creation of Generic Exceptions with just a Text Today when using ETL_ASSERT you need to pass a concrete exception type. However, it can be quite unhandy to define a custom exception type for each assert, therefore we want to also allow to simply use the generic etl::exception type and directly provide the message. --------- Co-authored-by: John Wellbelove Co-authored-by: Marco Nilsson Co-authored-by: John Wellbelove --- include/etl/error_handler.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index da3959cb..38c655b4 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -448,10 +448,12 @@ namespace etl #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. + #define ETL_ERROR_UNTYPED(text) (etl::exception((text),__FILE__,__LINE__)) // Make a generic exception with a message, file name and line number. #else #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. + #define ETL_ERROR_UNTYPED(text) (etl::exception((text),"",__LINE__)) // Make a generic exception with a message and line number. #endif #endif From ad1679ff93b96c7725676458dbf8517f29b3f1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BCthing?= Date: Wed, 1 Oct 2025 19:43:52 +0200 Subject: [PATCH 17/27] Introduce Cast to void for Condition of Assert (#1191) * Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() Removed ETL_NOEXCEPT from closureoperator(), call_if(), and call_or() * Updated version and release notes * Updated version and release notes * Remove noexcept from delegate method stubs. (#1185) In addition to removing noexcept from call_if, this is also needed to prevent an abort when cancelling a pthread that is executing a delegate. * Updated version and release notes * Introduce Cast to void for Condition of Assert Currently, in case we use a parameter of a function _only_ inside of an ETL_ASSERT and the ETL configuration disables the ETL_ASSERT, we get a compiler warning about an unused parameter. Therefore, this change casts the condition of ETL_ASSERT to void. * Use sizeof to avoid evaluation of Expression In case we disable ASSERTs in e.g. non debug builds, we want to expand it to "nothing", similar to how the std assert works. Introducing a cast to void on the conidition would still evaluate it and potentially cause side-effects. Therefore, we use the sizeof operator to ensure the expression is not evaluated in case ASSERTs are disabled. --------- Co-authored-by: John Wellbelove Co-authored-by: Marco Nilsson Co-authored-by: John Wellbelove --- include/etl/error_handler.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 38c655b4..113bb870 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -301,13 +301,13 @@ namespace etl ///\ingroup error_handler //*************************************************************************** #if defined(ETL_NO_CHECKS) - #define ETL_ASSERT(b, e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT(b, e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_OR_RETURN(b, e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) static_cast(sizeof(b)) // Does nothing. - #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN(e) ETL_DO_NOTHING // Does nothing. - #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT_FAIL(e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN(e) static_cast(sizeof(b)) // Does nothing. + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) static_cast(sizeof(b)) // Does nothing. #elif defined(ETL_USE_ASSERT_FUNCTION) #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} while(false) // If the condition fails, calls the assert function #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} while(false) // If the condition fails, calls the assert function and return @@ -353,7 +353,7 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN(e) do {assert(false); return;} while(false) // Asserts. #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {assert(false); return(v);} while(false) // Asserts. #else - #define ETL_ASSERT(b, e) ETL_DO_NOTHING // Does nothing. + #define ETL_ASSERT(b, e) static_cast(sizeof(b)) // Does nothing. #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY return;} while(false) // Returns. #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY return(v);} while(false) // Returns a value. From 9c3e786509b1b29940003aa850778740e711626d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 1 Oct 2025 18:58:27 +0100 Subject: [PATCH 18/27] Added missing CI scripts to the project --- test/vs2022/etl.vcxproj | 2 ++ test/vs2022/etl.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 32f66ccf..7a11cfb7 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -11398,11 +11398,13 @@ + + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 15ccfdbc..93a6791e 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3895,6 +3895,12 @@ ETL\Arduino + + Resource Files\CI\Github + + + Resource Files\CI\Github + From d456c785897ce573dcb30c3fa64ec9f04c12d351 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 2 Oct 2025 07:45:54 +0100 Subject: [PATCH 19/27] Fixed indentation Removed unused ETL_ASSERT --- include/etl/error_handler.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index 113bb870..d5898fb2 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -317,7 +317,7 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN(e) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} while(false) // Calls the assert function and return #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} while(false) // Calls the assert function and return a value #elif ETL_USING_EXCEPTIONS -#if defined(ETL_LOG_ERRORS) + #if defined(ETL_LOG_ERRORS) #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} while(false) // If the condition fails, calls the error handler then throws an exception. #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} while(false) // If the condition fails, calls the error handler then throws an exception. #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} while(false) // If the condition fails, calls the error handler then throws an exception. @@ -335,7 +335,7 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {throw((e));} while(false) // Throws an exception. #endif #else -#if defined(ETL_LOG_ERRORS) + #if defined(ETL_LOG_ERRORS) #define ETL_ASSERT(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} while(false) // If the condition fails, calls the error handler #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} while(false) // If the condition fails, calls the error handler and return #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} while(false) // If the condition fails, calls the error handler and return a value @@ -354,8 +354,8 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) do {assert(false); return(v);} while(false) // Asserts. #else #define ETL_ASSERT(b, e) static_cast(sizeof(b)) // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY return;} while(false) // Returns. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY return(v);} while(false) // Returns a value. + #define ETL_ASSERT_OR_RETURN(b, e) do {if (!(b)) ETL_UNLIKELY return;} while(false) // Returns. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) do {if (!(b)) ETL_UNLIKELY return(v);} while(false) // Returns a value. #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. #define ETL_ASSERT_FAIL_AND_RETURN(e) do {return;} while(false) // Returns. @@ -376,7 +376,6 @@ namespace etl #elif ETL_DEBUG_USING_EXCEPTIONS #if defined(ETL_DEBUG_LOG_ERRORS) #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. @@ -385,7 +384,6 @@ namespace etl #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. #else #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. From a25f195637d519095e9e7b6b5e6fb809b98b560b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 2 Oct 2025 08:28:50 +0100 Subject: [PATCH 20/27] Renamed ETL_ASSERT_UNTYPED to ETL_ASSERT_GENERIC --- include/etl/error_handler.h | 70 ++++---------------------------- include/etl/expected.h | 12 +++--- test/test_etl_assert.cpp | 71 +++++++++++++++++++++++++++++++++ test/vs2022/etl.vcxproj | 1 + test/vs2022/etl.vcxproj.filters | 3 ++ 5 files changed, 89 insertions(+), 68 deletions(-) create mode 100644 test/test_etl_assert.cpp diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index d5898fb2..8fd07c88 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -364,60 +364,6 @@ namespace etl #endif #endif -#if ETL_IS_DEBUG_BUILD - #if defined(ETL_DEBUG_USE_ASSERT_FUNCTION) - #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value - - #define ETL_DEBUG_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value - #elif ETL_DEBUG_USING_EXCEPTIONS - #if defined(ETL_DEBUG_LOG_ERRORS) - #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception. - - #define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e)); throw((e));} // Calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); throw((e)); return;} // Calls the error handler then throws an exception. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception. - #else - #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception. - - #define ETL_DEBUG_ASSERT_FAIL(e) {throw((e));} // Throws an exception. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception. - #endif - #elif defined(ETL_DEBUG_LOG_ERRORS) - #define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} // If the condition fails, calls the error handler - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} // If the condition fails, calls the error handler and return - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} // If the condition fails, calls the error handler and return a value - - #define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e));} // Calls the error handler - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); return;} // Calls the error handler and return - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); return (v);} // Calls the error handler and return a value - #else - #define ETL_DEBUG_ASSERT(b, e) assert((b)) // If the condition fails, asserts. - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {assert(false); return;}} // If the condition fails, asserts and return. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} // If the condition fails, asserts and return a value. - - #define ETL_DEBUG_ASSERT_FAIL(e) assert(false) // Asserts. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {assert(false); return;} // Asserts. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts. - #endif -#else - #define ETL_DEBUG_ASSERT(b, e) // Does nothing. - #define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY return;} // Returns. - #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY return(v);} // Returns a value. - - #define ETL_DEBUG_ASSERT_FAIL(e) // Does nothing. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns. - #define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value. -#endif - //************************************* #if defined(ETL_CHECK_PUSH_POP) #define ETL_ASSERT_CHECK_PUSH_POP(b, e) ETL_ASSERT(b, e) @@ -443,15 +389,15 @@ namespace etl //************************************* #if defined(ETL_VERBOSE_ERRORS) - #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. - #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. - #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. - #define ETL_ERROR_UNTYPED(text) (etl::exception((text),__FILE__,__LINE__)) // Make a generic exception with a message, file name and line number. + #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. + #define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value. + #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. + #define ETL_ERROR_GENERIC(text) (etl::exception((text),__FILE__, __LINE__)) // Make a generic exception with a message, file name and line number. #else - #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. - #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. - #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. - #define ETL_ERROR_UNTYPED(text) (etl::exception((text),"",__LINE__)) // Make a generic exception with a message and line number. + #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. + #define ETL_ERROR_WITH_VALUE(e, v) (e("", __LINE__, (v))) // Make an exception with the file name, line number and value. + #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. + #define ETL_ERROR_GENERIC(text) (etl::exception((text),"", __LINE__)) // Make a generic exception with a message and line number. #endif #endif diff --git a/include/etl/expected.h b/include/etl/expected.h index 2e761348..71c9d303 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -675,7 +675,7 @@ namespace etl //******************************************* value_type* operator ->() { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); return etl::addressof(etl::get(storage)); } @@ -685,7 +685,7 @@ namespace etl //******************************************* const value_type* operator ->() const { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); return etl::addressof(etl::get(storage)); } @@ -695,7 +695,7 @@ namespace etl //******************************************* value_type& operator *() ETL_LVALUE_REF_QUALIFIER { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::get(storage); } @@ -705,7 +705,7 @@ namespace etl //******************************************* const value_type& operator *() const ETL_LVALUE_REF_QUALIFIER { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); return etl::get(storage); } @@ -716,7 +716,7 @@ namespace etl //******************************************* value_type&& operator *()&& { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); return etl::move(etl::get(storage)); } @@ -726,7 +726,7 @@ namespace etl //******************************************* const value_type&& operator *() const&& { - ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid)); + ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::move(etl::get(storage)); } diff --git a/test/test_etl_assert.cpp b/test/test_etl_assert.cpp new file mode 100644 index 00000000..2df84d31 --- /dev/null +++ b/test/test_etl_assert.cpp @@ -0,0 +1,71 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Documentation: + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/platform.h" +#include "etl/error_handler.h" +#include "etl/exception.h" + +namespace +{ + class TestException1 : public etl::exception + { + public: + + TestException1(string_type file_name_, numeric_type line_number_) + : exception(ETL_ERROR_TEXT("Test:error1", "1A"), file_name_, line_number_) + { + } + }; + + SUITE(test_etl_asserts) + { + TEST(test_etl_assert) + { + auto te = ETL_ERROR(TestException1); + + CHECK_EQUAL(0, strcmp(te.what(), "Test:error1")); + + CHECK_THROW(ETL_ASSERT(false, ETL_ERROR(TestException1)), TestException1); + CHECK_NO_THROW(ETL_ASSERT(true, ETL_ERROR(TestException1))); + } + + TEST(test_etl_assert_generic) + { + auto te = ETL_ERROR_GENERIC("Generic Assert Exception"); + + CHECK_EQUAL(0, strcmp(te.what(), "Generic Assert Exception")); + + CHECK_THROW(ETL_ASSERT(false, ETL_ERROR_GENERIC("Generic Assert Exception")), etl::exception); + CHECK_NO_THROW(ETL_ASSERT(true, ETL_ERROR_GENERIC("Generic Assert Exception"))); + } + }; +} diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 7a11cfb7..76754ebc 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -10278,6 +10278,7 @@ + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 93a6791e..cf30ac02 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3716,6 +3716,9 @@ Tests\Syntax Checks\Source + + Tests\Misc + Tests From d2e0b07791b1a6b6288bae71df182ff5108852c5 Mon Sep 17 00:00:00 2001 From: Igor Pugachev Date: Fri, 3 Oct 2025 09:54:12 +0200 Subject: [PATCH 21/27] fix variant_variadic documentation (#1194) * fix variant_variadic default constructor documentation * fix valueless doc --- include/etl/private/variant_variadic.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 618e2366..8ec3f195 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -459,7 +459,7 @@ namespace etl //*************************************************************************** /// Default constructor. - /// Sets the state of the instance to containing no valid data. + /// Constructs a variant holding the value-initialized value of the first alternative (index() is zero). //*************************************************************************** #include "diagnostic_uninitialized_push.h" ETL_CONSTEXPR14 variant() @@ -779,8 +779,8 @@ namespace etl } //*************************************************************************** - /// Checks whether a valid value is currently stored. - ///\return true if the value is valid, otherwise false. + /// Checks whether the variant doesn't contain a valid value. + ///\return true if the value is invalid, otherwise false. //*************************************************************************** constexpr bool valueless_by_exception() const ETL_NOEXCEPT { From 99a33535d371ba400c0f42d912d9811d6c23ee14 Mon Sep 17 00:00:00 2001 From: mike919192 <91038685+mike919192@users.noreply.github.com> Date: Fri, 3 Oct 2025 05:10:15 -0400 Subject: [PATCH 22/27] Vector checks (#1193) * Add checks to vector and fix test failures * Add tests to vector * Add tests to external buffer and non trivial * All tests should be implemented * Add checks to vector_pointer and vector_pointer_ext * Get bad iterators from a second vector --- include/etl/private/pvoidvector.h | 18 ++ include/etl/vector.h | 25 ++- test/test_vector.cpp | 99 ++++++++++- test/test_vector_external_buffer.cpp | 68 +++++++- test/test_vector_non_trivial.cpp | 90 +++++++++- test/test_vector_pointer.cpp | 164 ++++++++++++++++++- test/test_vector_pointer_external_buffer.cpp | 148 ++++++++++++++++- 7 files changed, 594 insertions(+), 18 deletions(-) diff --git a/include/etl/private/pvoidvector.h b/include/etl/private/pvoidvector.h index 9786d740..eda3b020 100644 --- a/include/etl/private/pvoidvector.h +++ b/include/etl/private/pvoidvector.h @@ -230,6 +230,7 @@ namespace etl //********************************************************************* reference operator [](size_t i) { + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < size(), ETL_ERROR(vector_out_of_bounds)); return p_buffer[i]; } @@ -240,6 +241,7 @@ namespace etl //********************************************************************* const_reference operator [](size_t i) const { + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < size(), ETL_ERROR(vector_out_of_bounds)); return p_buffer[i]; } @@ -273,6 +275,7 @@ namespace etl //********************************************************************* reference front() { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return p_buffer[0]; } @@ -282,6 +285,7 @@ namespace etl //********************************************************************* const_reference front() const { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return p_buffer[0]; } @@ -291,6 +295,7 @@ namespace etl //********************************************************************* reference back() { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *(p_end - 1); } @@ -300,6 +305,7 @@ namespace etl //********************************************************************* const_reference back() const { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *(p_end - 1); } @@ -440,6 +446,7 @@ namespace etl iterator insert(const_iterator position, value_type value) { ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -473,6 +480,7 @@ namespace etl iterator emplace(const_iterator position) { ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -503,6 +511,7 @@ namespace etl iterator emplace(const_iterator position, value_type value) { ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -536,6 +545,7 @@ namespace etl void insert(const_iterator position, size_t n, value_type value) { ETL_ASSERT_OR_RETURN((size() + n) <= CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -565,6 +575,7 @@ namespace etl iterator position_ = to_iterator(position); ETL_ASSERT_OR_RETURN((size() + count) <= CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); etl::mem_move(position_, p_end, position_ + count); etl::copy(first, last, position_); @@ -588,6 +599,7 @@ namespace etl iterator position_ = to_iterator(position); ETL_ASSERT_OR_RETURN((size() + count) <= CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); etl::mem_move(position_, p_end, position_ + count); etl::mem_move((void**)first, (void**)last, position_); @@ -601,6 +613,8 @@ namespace etl //********************************************************************* iterator erase(iterator i_element) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds)); + etl::mem_move(i_element + 1, end(), i_element); --p_end; @@ -614,6 +628,8 @@ namespace etl //********************************************************************* iterator erase(const_iterator i_element) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds)); + iterator i_element_ = to_iterator(i_element); etl::mem_move(i_element_ + 1, end(), i_element_); @@ -632,6 +648,8 @@ namespace etl //********************************************************************* iterator erase(const_iterator first, const_iterator last) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(vector_out_of_bounds)); + iterator first_ = to_iterator(first); iterator last_ = to_iterator(last); diff --git a/include/etl/vector.h b/include/etl/vector.h index e85d58f2..c36f9b55 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -279,6 +279,7 @@ namespace etl //********************************************************************* reference operator [](size_t i) { + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < size(), ETL_ERROR(vector_out_of_bounds)); return p_buffer[i]; } @@ -289,6 +290,7 @@ namespace etl //********************************************************************* const_reference operator [](size_t i) const { + ETL_ASSERT_CHECK_INDEX_OPERATOR(i < size(), ETL_ERROR(vector_out_of_bounds)); return p_buffer[i]; } @@ -322,6 +324,7 @@ namespace etl //********************************************************************* reference front() { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *p_buffer; } @@ -331,6 +334,7 @@ namespace etl //********************************************************************* const_reference front() const { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *p_buffer; } @@ -340,6 +344,7 @@ namespace etl //********************************************************************* reference back() { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *(p_end - 1); } @@ -349,6 +354,7 @@ namespace etl //********************************************************************* const_reference back() const { + ETL_ASSERT_CHECK_EXTRA(size() > 0, ETL_ERROR(vector_out_of_bounds)); return *(p_end - 1); } @@ -570,6 +576,7 @@ namespace etl iterator insert(const_iterator position, const_reference value) { ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -597,6 +604,7 @@ namespace etl iterator insert(const_iterator position, rvalue_reference value) { ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -623,6 +631,7 @@ namespace etl iterator emplace(const_iterator position, Args && ... args) { ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -650,6 +659,7 @@ namespace etl iterator emplace(const_iterator position, const T1& value1) { ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -677,6 +687,7 @@ namespace etl iterator emplace(const_iterator position, const T1& value1, const T2& value2) { ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -704,6 +715,7 @@ namespace etl iterator emplace(const_iterator position, const T1& value1, const T2& value2, const T3& value3) { ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -731,6 +743,7 @@ namespace etl iterator emplace(const_iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) { ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -765,6 +778,7 @@ namespace etl void insert(const_iterator position, size_t n, parameter_t value) { ETL_ASSERT_OR_RETURN((size() + n) <= CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); iterator position_ = to_iterator(position); @@ -804,8 +818,8 @@ namespace etl etl::uninitialized_fill_n(p_end, construct_new_n, value); ETL_ADD_DEBUG_COUNT(construct_new_n); - // Copy new. - etl::fill_n(p_buffer + insert_begin, copy_new_n, value); + // Copy new. + etl::fill_n(p_buffer + insert_begin, copy_new_n, value); p_end += n; } @@ -824,6 +838,7 @@ namespace etl size_t count = etl::distance(first, last); ETL_ASSERT_OR_RETURN((size() + count) <= CAPACITY, ETL_ERROR(vector_full)); + ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds)); size_t insert_n = count; size_t insert_begin = etl::distance(cbegin(), position); @@ -874,6 +889,8 @@ namespace etl //********************************************************************* iterator erase(iterator i_element) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds)); + etl::move(i_element + 1, end(), i_element); destroy_back(); @@ -887,6 +904,8 @@ namespace etl //********************************************************************* iterator erase(const_iterator i_element) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds)); + iterator i_element_ = to_iterator(i_element); etl::move(i_element_ + 1, end(), i_element_); @@ -905,6 +924,8 @@ namespace etl //********************************************************************* iterator erase(const_iterator first, const_iterator last) { + ETL_ASSERT_CHECK_EXTRA(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(vector_out_of_bounds)); + iterator first_ = to_iterator(first); iterator last_ = to_iterator(last); diff --git a/test/test_vector.cpp b/test/test_vector.cpp index 38c70791..f7df1aaf 100644 --- a/test/test_vector.cpp +++ b/test/test_vector.cpp @@ -276,8 +276,8 @@ namespace Data data(10); const Data constData(10); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -459,6 +459,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -472,6 +474,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -509,6 +513,9 @@ namespace Data data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + Data emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -518,6 +525,9 @@ namespace const Data data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + const Data emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -527,6 +537,9 @@ namespace Data data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + Data emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -536,8 +549,10 @@ namespace const Data data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); - } + const Data emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); + } //************************************************************************* TEST_FIXTURE(SetupFixture, test_data) @@ -778,6 +793,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + const int INITIAL_VALUE = 1; + + Data data; + Data data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_emplace_position_value) { @@ -805,6 +832,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + const int INITIAL_VALUE = 1; + + Data data; + Data data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.emplace(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST(test_emplace_default) { @@ -849,6 +888,15 @@ namespace CHECK_TRUE(std::equal(compare_data.begin(), compare_data.end(), data.begin())); } + //************************************************************************* + TEST(test_emplace_out_of_range) + { + etl::vector data; + etl::vector data2; + + CHECK_THROW(data.emplace(data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST(test_emplace_back_default) { @@ -943,6 +991,17 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) + { + const int INITIAL_VALUE = 0; + + Data data; + Data data2; + + CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess) { @@ -996,6 +1055,15 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds) + { + Data data; + Data data2; + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_range_excess) { @@ -1046,6 +1114,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_iterator_outofbounds) + { + Data data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single_const_iterator) { @@ -1071,6 +1147,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_const_iterator_outofbounds) + { + Data data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { @@ -1096,6 +1180,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds) + { + Data data(initial_data.begin(), initial_data.end()); + Data data2(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_vector_external_buffer.cpp b/test/test_vector_external_buffer.cpp index 773e68ea..a8b0c07b 100644 --- a/test/test_vector_external_buffer.cpp +++ b/test/test_vector_external_buffer.cpp @@ -268,8 +268,8 @@ namespace Data data(10, buffer1, SIZE); const Data constData(10, buffer1, SIZE); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -462,6 +462,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -475,6 +477,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -512,6 +516,9 @@ namespace Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK_EQUAL(compare_data.front(), data.front()); + + Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -521,6 +528,9 @@ namespace const Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK_EQUAL(compare_data.front(), data.front()); + + const Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -530,6 +540,9 @@ namespace Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK_EQUAL(compare_data.back(), data.back()); + + Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -539,8 +552,10 @@ namespace const Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK_EQUAL(compare_data.back(), data.back()); - } + const Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); + } //************************************************************************* TEST_FIXTURE(SetupFixture, test_data) @@ -781,6 +796,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + const int INITIAL_VALUE = 1; + + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* #include "etl/private/diagnostic_array_bounds_push.h" TEST_FIXTURE(SetupFixture, test_insert_position_value_excess) @@ -831,6 +858,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) + { + const int INITIAL_VALUE = 11; + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess) { @@ -909,6 +946,14 @@ namespace CHECK_THROW(data.insert(data.begin() + offset, initial_data.begin(), initial_data.end()), etl::vector_full); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds) + { + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single) @@ -929,6 +974,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_iterator_outofbounds) + { + Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { @@ -948,6 +1001,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds) + { + Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + Data data2(initial_data.begin(), initial_data.end(), buffer2, SIZE); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_vector_non_trivial.cpp b/test/test_vector_non_trivial.cpp index 0acb1a22..413ca3cd 100644 --- a/test/test_vector_non_trivial.cpp +++ b/test/test_vector_non_trivial.cpp @@ -364,8 +364,8 @@ namespace DataDC data(10); const DataDC constData(10); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -465,6 +465,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -478,6 +480,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -515,6 +519,9 @@ namespace DataNDC data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + DataNDC emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -524,6 +531,9 @@ namespace const DataNDC data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + const DataNDC emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -533,6 +543,9 @@ namespace DataNDC data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + DataNDC emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -542,6 +555,9 @@ namespace const DataNDC data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + const DataNDC emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -934,6 +950,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + const NDC INITIAL_VALUE("1"); + + DataNDC data; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + DataNDC data2; + CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_emplace_position_value) { @@ -961,6 +989,28 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + const std::string INITIAL_VALUE("1"); + + DataNDC data; + DataNDC data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.emplace(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + } + + //************************************************************************* + TEST(test_emplace_out_of_range) + { + DataNDC data; + DataNDC data2; + const std::string INITIAL_VALUE("1"); + + CHECK_THROW(data.emplace(data2.end(), INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* #include "etl/private/diagnostic_array_bounds_push.h" TEST_FIXTURE(SetupFixture, test_insert_position_value_excess) @@ -1012,6 +1062,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) + { + DataNDC data; + DataNDC data2; + const NDC INITIAL_VALUE("1"); + + CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess) { @@ -1091,6 +1151,15 @@ namespace CHECK_THROW(data.insert(data.begin() + offset, initial_data.begin(), initial_data.end()), etl::vector_full); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds) + { + DataNDC data; + DataNDC data2; + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_single) { @@ -1110,6 +1179,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_iterator_outofbounds) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { @@ -1129,6 +1206,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds) + { + DataNDC data(initial_data.begin(), initial_data.end()); + DataNDC data2(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_vector_pointer.cpp b/test/test_vector_pointer.cpp index f59c8d29..aa41eac0 100644 --- a/test/test_vector_pointer.cpp +++ b/test/test_vector_pointer.cpp @@ -459,8 +459,8 @@ namespace Data data(10); const Data constData(10); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -469,8 +469,8 @@ namespace CData data(10); const CData constData(10); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -654,6 +654,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -667,6 +669,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -680,6 +684,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -693,6 +699,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -758,6 +766,9 @@ namespace Data data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + Data emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -767,6 +778,9 @@ namespace CData data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + CData emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -776,6 +790,9 @@ namespace const Data data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + const Data emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -785,6 +802,9 @@ namespace const CData data(initial_data.begin(), initial_data.end()); CHECK(data.front() == compare_data.front()); + + const CData emptyData; + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -794,6 +814,9 @@ namespace Data data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + Data emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -803,6 +826,9 @@ namespace CData data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + CData emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -812,6 +838,9 @@ namespace const Data data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + const Data emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -821,6 +850,9 @@ namespace const CData data(initial_data.begin(), initial_data.end()); CHECK(data.back() == compare_data.back()); + + const CData emptyData; + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -1200,6 +1232,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + int INITIAL_VALUE = 1; + + Data data; + Data data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_value) { @@ -1225,6 +1269,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + int INITIAL_VALUE = 1; + + CData data; + CData data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* #include "etl/private/diagnostic_array_bounds_push.h" TEST_FIXTURE(SetupFixture, test_insert_position_value_excess) @@ -1273,6 +1329,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5; + int INITIAL_VALUE = 1; + + Data data; + Data data2; + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.emplace(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value) { @@ -1296,6 +1364,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) + { + int INITIAL_VALUE = 0; + Data data; + Data data2; + + CHECK_THROW(data.insert(data2.end(), 1, &INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_n_value) { @@ -1319,6 +1397,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_n_value_outofbounds) + { + int INITIAL_VALUE = 0; + CData data; + CData data2; + + CHECK_THROW(data.insert(data2.end(), 1, &INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess) { @@ -1394,6 +1482,15 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds) + { + Data data; + Data data2; + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_pointer_range) { @@ -1417,6 +1514,14 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_pointer_range_out_of_bounds) + { + Data data; + + CHECK_THROW(data.insert(data.data() + data.size() + 1, insert_data.data(), insert_data.data() + insert_data.size());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_range) { @@ -1440,6 +1545,15 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_range_out_of_bounds) + { + CData data; + CData data2; + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_range_excess) { @@ -1506,6 +1620,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_outofbounds) + { + Data data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_erase_single_iterator) { @@ -1522,6 +1644,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_single_iterator_outofbounds) + { + CData data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_erase_single_const_iterator) { @@ -1538,6 +1668,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_single_const_iterator_outofbounds) + { + CData data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { @@ -1554,6 +1692,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds) + { + Data data(initial_data.begin(), initial_data.end()); + Data data2(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_erase_range) { @@ -1569,6 +1716,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_range_outofbounds) + { + CData data(initial_data.begin(), initial_data.end()); + CData data2(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_vector_pointer_external_buffer.cpp b/test/test_vector_pointer_external_buffer.cpp index 975a8d7c..330801d8 100644 --- a/test/test_vector_pointer_external_buffer.cpp +++ b/test/test_vector_pointer_external_buffer.cpp @@ -448,8 +448,8 @@ namespace Data data(10, buffer1, SIZE); const Data constData(10, buffer2, SIZE); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -458,8 +458,8 @@ namespace CData data(10, buffer1, SIZE); const CData constData(10, buffer2, SIZE); - CHECK_EQUAL(&data[10], data.end()); - CHECK_EQUAL(&constData[10], constData.end()); + CHECK_EQUAL(data.begin() + data.size(), data.end()); + CHECK_EQUAL(constData.begin() + constData.size(), constData.end()); } //************************************************************************* @@ -645,6 +645,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -658,6 +660,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -671,6 +675,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -684,6 +690,8 @@ namespace { CHECK_EQUAL(data[i], compare_data[i]); } + + CHECK_THROW(data[data.size()], etl::vector_out_of_bounds); } //************************************************************************* @@ -749,6 +757,9 @@ namespace Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.front() == compare_data.front()); + + Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -758,6 +769,9 @@ namespace CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.front() == compare_data.front()); + + CData emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -767,6 +781,9 @@ namespace const Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.front() == compare_data.front()); + + const Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -776,6 +793,9 @@ namespace const CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.front() == compare_data.front()); + + const CData emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds); } //************************************************************************* @@ -785,6 +805,9 @@ namespace Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.back() == compare_data.back()); + + Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -794,6 +817,9 @@ namespace CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.back() == compare_data.back()); + + CData emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -803,6 +829,9 @@ namespace const Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.back() == compare_data.back()); + + const Data emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -812,6 +841,9 @@ namespace const CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); CHECK(data.back() == compare_data.back()); + + const CData emptyData(buffer1, SIZE); + CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds); } //************************************************************************* @@ -1149,6 +1181,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5UL; + int INITIAL_VALUE = 1; + + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_value) { @@ -1174,6 +1218,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5UL; + int INITIAL_VALUE = 1; + + CData data(buffer1, SIZE); + CData data2(buffer2, SIZE); + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.insert(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* #include "etl/private/diagnostic_array_bounds_push.h" TEST_FIXTURE(SetupFixture, test_insert_position_value_excess) @@ -1222,6 +1278,18 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds) + { + const size_t INITIAL_SIZE = 5UL; + int INITIAL_VALUE = 1; + + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + CHECK_THROW(data.emplace(data2.cbegin(), &INITIAL_VALUE), etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value) { @@ -1245,6 +1313,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) + { + int INITIAL_VALUE = 0; + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), 1, &INITIAL_VALUE);, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_n_value) { @@ -1268,6 +1346,16 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_n_value_outofbounds) + { + int INITIAL_VALUE = 0; + CData data(buffer1, SIZE); + CData data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), 1, &INITIAL_VALUE);, etl::vector_out_of_bounds); + } + #include "etl/private/diagnostic_array_bounds_push.h" //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess) @@ -1345,6 +1433,15 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds) + { + Data data(buffer1, SIZE); + Data data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_insert_position_range) { @@ -1368,6 +1465,15 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_insert_position_range_out_of_bounds) + { + CData data(buffer1, SIZE); + CData data2(buffer2, SIZE); + + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + } + #include "etl/private/diagnostic_array_bounds_push.h" //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_range_excess) @@ -1435,6 +1541,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_outofbounds) + { + Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_erase_single) { @@ -1450,6 +1564,14 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_single_outofbounds) + { + CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + + CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { @@ -1465,6 +1587,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds) + { + Data data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + Data data2(initial_data.begin(), initial_data.end(), buffer2, SIZE); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_const_erase_range) { @@ -1480,6 +1611,15 @@ namespace CHECK(is_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_range_outofbounds) + { + CData data(initial_data.begin(), initial_data.end(), buffer1, SIZE); + CData data2(initial_data.begin(), initial_data.end(), buffer2, SIZE); + + CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { From 1ea45ff28efc97ffdb52f2cb57b5dc1ebc9b3f54 Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Fri, 3 Oct 2025 02:44:16 -0500 Subject: [PATCH 23/27] Added conditional support of `noexcept` to fix IAR support (#1195) --- include/etl/platform.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/etl/platform.h b/include/etl/platform.h index af0b9a6d..ee0032c4 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -341,8 +341,13 @@ SOFTWARE. #define ETL_ENUM_CLASS(name) enum class name #define ETL_ENUM_CLASS_TYPE(name, type) enum class name : type #define ETL_LVALUE_REF_QUALIFIER & - #define ETL_NOEXCEPT noexcept - #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) + #if ETL_USING_EXCEPTIONS + #define ETL_NOEXCEPT noexcept + #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) + #else + #define ETL_NOEXCEPT + #define ETL_NOEXCEPT_EXPR(...) + #endif #else #define ETL_CONSTEXPR #define ETL_CONSTEXPR11 From 07734033d31a178a0a44ef74b6baade4b8a82f80 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 3 Oct 2025 10:18:21 +0100 Subject: [PATCH 24/27] Minor layout changes --- include/etl/platform.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/etl/platform.h b/include/etl/platform.h index ee0032c4..f6658d49 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -242,22 +242,22 @@ SOFTWARE. #endif //************************************* -// Indicate if C++ exceptions are enabled. +// Indicate if C++ exceptions within the ETL are enabled. #if defined(ETL_THROW_EXCEPTIONS) - #define ETL_USING_EXCEPTIONS 1 + #define ETL_USING_EXCEPTIONS 1 #define ETL_NOT_USING_EXCEPTIONS 0 #else - #define ETL_USING_EXCEPTIONS 0 + #define ETL_USING_EXCEPTIONS 0 #define ETL_NOT_USING_EXCEPTIONS 1 #endif //************************************* // Indicate if C++ exceptions are enabled for debug asserts. #if ETL_IS_DEBUG_BUILD && defined(ETL_DEBUG_THROW_EXCEPTIONS) - #define ETL_DEBUG_USING_EXCEPTIONS 1 + #define ETL_DEBUG_USING_EXCEPTIONS 1 #define ETL_DEBUG_NOT_USING_EXCEPTIONS 0 #else - #define ETL_DEBUG_USING_EXCEPTIONS 0 + #define ETL_DEBUG_USING_EXCEPTIONS 0 #define ETL_DEBUG_NOT_USING_EXCEPTIONS 1 #endif @@ -342,8 +342,8 @@ SOFTWARE. #define ETL_ENUM_CLASS_TYPE(name, type) enum class name : type #define ETL_LVALUE_REF_QUALIFIER & #if ETL_USING_EXCEPTIONS - #define ETL_NOEXCEPT noexcept - #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) + #define ETL_NOEXCEPT noexcept + #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) #else #define ETL_NOEXCEPT #define ETL_NOEXCEPT_EXPR(...) From d14f7a66a9ce41561a0c9f0f38b85c88ed104448 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 17 Sep 2025 20:44:52 +0100 Subject: [PATCH 25/27] Added and fixed noexcept attributes Added ETL_NOEXCEPT_FROM to set noexcept attributes based on an object or function. # Conflicts: # include/etl/platform.h --- include/etl/array.h | 2 +- include/etl/array_view.h | 58 +++++++-------- include/etl/array_wrapper.h | 36 +++++----- include/etl/char_traits.h | 42 +++++------ include/etl/memory.h | 4 +- include/etl/platform.h | 1 + include/etl/span.h | 4 +- include/etl/string_view.h | 138 ++++++++++++++++++------------------ 8 files changed, 143 insertions(+), 142 deletions(-) diff --git a/include/etl/array.h b/include/etl/array.h index a238269e..953b5bea 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -397,7 +397,7 @@ namespace etl /// Swaps the contents of this array and another. ///\param other A reference to the other array. //************************************************************************* - ETL_CONSTEXPR14 void swap(array& other) ETL_NOEXCEPT + ETL_CONSTEXPR14 void swap(array& other) ETL_NOEXCEPT_FROM(ETL_OR_STD::swap(etl::declval(), etl::declval())) { using ETL_OR_STD::swap; // Allow ADL diff --git a/include/etl/array_view.h b/include/etl/array_view.h index 653a8954..5015d55e 100644 --- a/include/etl/array_view.h +++ b/include/etl/array_view.h @@ -123,7 +123,7 @@ namespace etl //************************************************************************* /// Default constructor. //************************************************************************* - ETL_CONSTEXPR array_view() + ETL_CONSTEXPR array_view() ETL_NOEXCEPT : mbegin(ETL_NULLPTR), mend(ETL_NULLPTR) { @@ -238,7 +238,7 @@ namespace etl /// Construct from iterators //************************************************************************* template - ETL_CONSTEXPR array_view(const TIterator begin_, const TIterator end_) + ETL_CONSTEXPR array_view(const TIterator begin_, const TIterator end_) ETL_NOEXCEPT : mbegin(etl::to_address(begin_)), mend(etl::to_address(begin_) + etl::distance(begin_, end_)) { @@ -249,7 +249,7 @@ namespace etl //************************************************************************* template - ETL_CONSTEXPR array_view(const TIterator begin_, const TSize size_) + ETL_CONSTEXPR array_view(const TIterator begin_, const TSize size_) ETL_NOEXCEPT : mbegin(etl::to_address(begin_)), mend(etl::to_address(begin_) + size_) { @@ -259,7 +259,7 @@ namespace etl /// Construct from C array //************************************************************************* template - ETL_CONSTEXPR array_view(T(&begin_)[Array_Size]) + ETL_CONSTEXPR array_view(T(&begin_)[Array_Size]) ETL_NOEXCEPT : mbegin(begin_), mend(begin_ + Array_Size) { @@ -268,7 +268,7 @@ namespace etl //************************************************************************* /// Copy constructor //************************************************************************* - ETL_CONSTEXPR array_view(const array_view& other) + ETL_CONSTEXPR array_view(const array_view& other) ETL_NOEXCEPT : mbegin(other.mbegin), mend(other.mend) { @@ -309,7 +309,7 @@ namespace etl //************************************************************************* /// Returns a pointer to the first element of the internal storage. //************************************************************************* - pointer data() + pointer data() ETL_NOEXCEPT { return mbegin; } @@ -317,7 +317,7 @@ namespace etl //************************************************************************* /// Returns a const pointer to the first element of the internal storage. //************************************************************************* - const_pointer data() const + const_pointer data() const ETL_NOEXCEPT { return mbegin; } @@ -325,7 +325,7 @@ namespace etl //************************************************************************* /// Returns an iterator to the beginning of the array. //************************************************************************* - iterator begin() + iterator begin() ETL_NOEXCEPT { return mbegin; } @@ -333,7 +333,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - const_iterator begin() const + const_iterator begin() const ETL_NOEXCEPT { return mbegin; } @@ -341,7 +341,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - const_iterator cbegin() const + const_iterator cbegin() const ETL_NOEXCEPT { return mbegin; } @@ -349,7 +349,7 @@ namespace etl //************************************************************************* /// Returns an iterator to the end of the array. //************************************************************************* - iterator end() + iterator end() ETL_NOEXCEPT { return mend; } @@ -357,7 +357,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the end of the array. //************************************************************************* - const_iterator end() const + const_iterator end() const ETL_NOEXCEPT { return mend; } @@ -365,7 +365,7 @@ namespace etl //************************************************************************* // Returns a const iterator to the end of the array. //************************************************************************* - const_iterator cend() const + const_iterator cend() const ETL_NOEXCEPT { return mend; } @@ -373,7 +373,7 @@ namespace etl //************************************************************************* // Returns an reverse iterator to the reverse beginning of the array. //************************************************************************* - reverse_iterator rbegin() + reverse_iterator rbegin() ETL_NOEXCEPT { return reverse_iterator(mend); } @@ -381,7 +381,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - const_reverse_iterator rbegin() const + const_reverse_iterator rbegin() const ETL_NOEXCEPT { return const_reverse_iterator(mend); } @@ -389,7 +389,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - const_reverse_iterator crbegin() const + const_reverse_iterator crbegin() const ETL_NOEXCEPT { return const_reverse_iterator(mend); } @@ -397,7 +397,7 @@ namespace etl //************************************************************************* /// Returns a reverse iterator to the end of the array. //************************************************************************* - reverse_iterator rend() + reverse_iterator rend() ETL_NOEXCEPT { return reverse_iterator(mbegin); } @@ -405,7 +405,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - const_reverse_iterator rend() const + const_reverse_iterator rend() const ETL_NOEXCEPT { return const_reverse_iterator(mbegin); } @@ -413,7 +413,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - const_reverse_iterator crend() const + const_reverse_iterator crend() const ETL_NOEXCEPT { return const_reverse_iterator(mbegin); } @@ -421,7 +421,7 @@ namespace etl //************************************************************************* /// Returns true if the array size is zero. //************************************************************************* - ETL_CONSTEXPR bool empty() const + ETL_CONSTEXPR bool empty() const ETL_NOEXCEPT { return (mbegin == mend); } @@ -429,7 +429,7 @@ namespace etl //************************************************************************* /// Returns the size of the array. //************************************************************************* - ETL_CONSTEXPR size_t size() const + ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT { return static_cast(mend - mbegin); } @@ -437,7 +437,7 @@ namespace etl //************************************************************************* /// Returns the maximum possible size of the array. //************************************************************************* - ETL_CONSTEXPR size_t max_size() const + ETL_CONSTEXPR size_t max_size() const ETL_NOEXCEPT { return size(); } @@ -445,7 +445,7 @@ namespace etl //************************************************************************* /// Assign from a view. //************************************************************************* - array_view& operator=(const array_view& other) + array_view& operator=(const array_view& other) ETL_NOEXCEPT { mbegin = other.mbegin; mend = other.mend; @@ -477,7 +477,7 @@ namespace etl //************************************************************************* /// Returns a reference to the indexed value. //************************************************************************* - reference operator[](const size_t i) + reference operator[](const size_t i) ETL_NOEXCEPT { return mbegin[i]; } @@ -486,7 +486,7 @@ namespace etl //************************************************************************* /// Returns a const reference to the indexed value. //************************************************************************* - const_reference operator[](const size_t i) const + const_reference operator[](const size_t i) const ETL_NOEXCEPT { return mbegin[i]; } @@ -516,7 +516,7 @@ namespace etl //************************************************************************* /// Swaps with another array_view. //************************************************************************* - void swap(array_view& other) + void swap(array_view& other) ETL_NOEXCEPT { using ETL_OR_STD::swap; // Allow ADL @@ -527,7 +527,7 @@ namespace etl //************************************************************************* /// Shrinks the view by moving its start forward. //************************************************************************* - void remove_prefix(const size_type n) + void remove_prefix(const size_type n) ETL_NOEXCEPT { if (n < size()) mbegin += n; @@ -538,7 +538,7 @@ namespace etl //************************************************************************* /// Shrinks the view by moving its end backward. //************************************************************************* - void remove_suffix(const size_type n) + void remove_suffix(const size_type n) ETL_NOEXCEPT { if (n < size()) mend -= n; @@ -647,7 +647,7 @@ namespace etl /// Swaps the values. //************************************************************************* template -void swap(etl::array_view& lhs, etl::array_view& rhs) +void swap(etl::array_view& lhs, etl::array_view& rhs) ETL_NOEXCEPT { lhs.swap(rhs); } diff --git a/include/etl/array_wrapper.h b/include/etl/array_wrapper.h index 72655f98..b422634d 100644 --- a/include/etl/array_wrapper.h +++ b/include/etl/array_wrapper.h @@ -141,7 +141,7 @@ namespace etl //************************************************************************* /// Returns a pointer to the first element of the internal storage. //************************************************************************* - pointer data() + pointer data() ETL_NOEXCEPT { return &ARRAY_[BEGIN]; } @@ -149,7 +149,7 @@ namespace etl //************************************************************************* /// Returns a const pointer to the first element of the internal storage. //************************************************************************* - ETL_CONSTEXPR const_pointer data() const + ETL_CONSTEXPR const_pointer data() const ETL_NOEXCEPT { return &ARRAY_[BEGIN]; } @@ -157,7 +157,7 @@ namespace etl //************************************************************************* /// Returns an iterator to the beginning of the array. //************************************************************************* - iterator begin() + iterator begin() ETL_NOEXCEPT { return &ARRAY_[BEGIN]; } @@ -165,7 +165,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator begin() const + ETL_CONSTEXPR const_iterator begin() const ETL_NOEXCEPT { return &ARRAY_[BEGIN]; } @@ -173,7 +173,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator cbegin() const + ETL_CONSTEXPR const_iterator cbegin() const ETL_NOEXCEPT { return &ARRAY_[BEGIN]; } @@ -181,7 +181,7 @@ namespace etl //************************************************************************* /// Returns an iterator to the end of the array. //************************************************************************* - iterator end() + iterator end() ETL_NOEXCEPT { return &ARRAY_[END]; } @@ -189,7 +189,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator end() const + ETL_CONSTEXPR const_iterator end() const ETL_NOEXCEPT { return &ARRAY_[END]; } @@ -197,7 +197,7 @@ namespace etl //************************************************************************* // Returns a const iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator cend() const + ETL_CONSTEXPR const_iterator cend() const ETL_NOEXCEPT { return &ARRAY_[END]; } @@ -205,7 +205,7 @@ namespace etl //************************************************************************* // Returns an reverse iterator to the reverse beginning of the array. //************************************************************************* - reverse_iterator rbegin() + reverse_iterator rbegin() ETL_NOEXCEPT { return reverse_iterator(&ARRAY_[END]); } @@ -213,7 +213,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator rbegin() const + ETL_CONSTEXPR const_reverse_iterator rbegin() const ETL_NOEXCEPT { return const_reverse_iterator(&ARRAY_[END]); } @@ -221,7 +221,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator crbegin() const + ETL_CONSTEXPR const_reverse_iterator crbegin() const ETL_NOEXCEPT { return const_reverse_iterator(&ARRAY_[END]); } @@ -229,7 +229,7 @@ namespace etl //************************************************************************* /// Returns a reverse iterator to the end of the array. //************************************************************************* - reverse_iterator rend() + reverse_iterator rend() ETL_NOEXCEPT { return reverse_iterator(&ARRAY_[BEGIN]); } @@ -237,7 +237,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator rend() const + ETL_CONSTEXPR const_reverse_iterator rend() const ETL_NOEXCEPT { return const_reverse_iterator(&ARRAY_[BEGIN]); } @@ -245,7 +245,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator crend() const + ETL_CONSTEXPR const_reverse_iterator crend() const ETL_NOEXCEPT { return const_reverse_iterator(&ARRAY_[BEGIN]); } @@ -253,7 +253,7 @@ namespace etl //************************************************************************* /// Returns the size of the array. //************************************************************************* - ETL_CONSTEXPR size_t size() const + ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT { return SIZE; } @@ -261,7 +261,7 @@ namespace etl //************************************************************************* /// Returns the maximum possible size of the array. //************************************************************************* - ETL_CONSTEXPR size_t max_size() const + ETL_CONSTEXPR size_t max_size() const ETL_NOEXCEPT { return MAX_SIZE; } @@ -269,7 +269,7 @@ namespace etl //************************************************************************* /// Returns a reference to the indexed value. //************************************************************************* - reference operator[](size_t i) + reference operator[](size_t i) ETL_NOEXCEPT { return ARRAY_[i]; } @@ -277,7 +277,7 @@ namespace etl //************************************************************************* /// Returns a const reference to the indexed value. //************************************************************************* - ETL_CONSTEXPR const_reference operator[](size_t i) const + ETL_CONSTEXPR const_reference operator[](size_t i) const ETL_NOEXCEPT { return ARRAY_[i]; } diff --git a/include/etl/char_traits.h b/include/etl/char_traits.h index 25ed1638..d298914f 100644 --- a/include/etl/char_traits.h +++ b/include/etl/char_traits.h @@ -125,19 +125,19 @@ namespace etl typedef typename char_traits_types::state_type state_type; //************************************************************************* - static ETL_CONSTEXPR bool eq(char_type a, char_type b) + static ETL_CONSTEXPR bool eq(char_type a, char_type b) ETL_NOEXCEPT { return a == b; } //************************************************************************* - static ETL_CONSTEXPR bool lt(char_type a, char_type b) + static ETL_CONSTEXPR bool lt(char_type a, char_type b) ETL_NOEXCEPT { return a < b; } //************************************************************************* - static ETL_CONSTEXPR14 size_t length(const char_type* begin) + static ETL_CONSTEXPR14 size_t length(const char_type* begin) ETL_NOEXCEPT { if (begin == ETL_NULLPTR) { @@ -155,7 +155,7 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 size_t length(const char_type* str, size_t max_length) + static ETL_CONSTEXPR14 size_t length(const char_type* str, size_t max_length) ETL_NOEXCEPT { size_t count = 0UL; @@ -171,13 +171,13 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 void assign(char_type& r, const char_type& c) + static ETL_CONSTEXPR14 void assign(char_type& r, const char_type& c) ETL_NOEXCEPT { r = c; } //************************************************************************* - static ETL_CONSTEXPR14 char_type* assign(char_type* p, size_t n, char_type c) + static ETL_CONSTEXPR14 char_type* assign(char_type* p, size_t n, char_type c) ETL_NOEXCEPT { if (p != ETL_NULLPTR) { @@ -188,7 +188,7 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 char_type* move(char_type* dst, const char_type* src, size_t count) + static ETL_CONSTEXPR14 char_type* move(char_type* dst, const char_type* src, size_t count) ETL_NOEXCEPT { if ((dst < src) || (dst > (src + count))) { @@ -205,7 +205,7 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 char_type* copy(char_type* dst, const char_type* src, size_t count) + static ETL_CONSTEXPR14 char_type* copy(char_type* dst, const char_type* src, size_t count) ETL_NOEXCEPT { etl::copy_n(src, count, dst); @@ -213,7 +213,7 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 int compare(const char_type* s1, const char_type* s2, size_t count) + static ETL_CONSTEXPR14 int compare(const char_type* s1, const char_type* s2, size_t count) ETL_NOEXCEPT { for (size_t i = 0UL; i < count; ++i) { @@ -234,7 +234,7 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR14 const char_type* find(const char_type* p, size_t count, const char_type& ch) + static ETL_CONSTEXPR14 const char_type* find(const char_type* p, size_t count, const char_type& ch) ETL_NOEXCEPT { for (size_t i = 0UL; i < count; ++i) { @@ -250,31 +250,31 @@ namespace etl } //************************************************************************* - static ETL_CONSTEXPR char_type to_char_type(int_type c) + static ETL_CONSTEXPR char_type to_char_type(int_type c) ETL_NOEXCEPT { return static_cast(c); } //************************************************************************* - static ETL_CONSTEXPR int_type to_int_type(char_type c) + static ETL_CONSTEXPR int_type to_int_type(char_type c) ETL_NOEXCEPT { return static_cast(c); } //************************************************************************* - static ETL_CONSTEXPR bool eq_int_type(int_type c1, int_type c2) + static ETL_CONSTEXPR bool eq_int_type(int_type c1, int_type c2) ETL_NOEXCEPT { return (c1 == c2); } //************************************************************************* - static ETL_CONSTEXPR int_type eof() + static ETL_CONSTEXPR int_type eof() ETL_NOEXCEPT { return -1; } //************************************************************************* - static ETL_CONSTEXPR int_type not_eof(int_type e) + static ETL_CONSTEXPR int_type not_eof(int_type e) ETL_NOEXCEPT { return (e == eof()) ? eof() - 1 : e; } @@ -284,7 +284,7 @@ namespace etl /// Alternative strlen for all character types. //*************************************************************************** template - ETL_CONSTEXPR14 size_t strlen(const T* t) + ETL_CONSTEXPR14 size_t strlen(const T* t) ETL_NOEXCEPT { return etl::char_traits::length(t); } @@ -293,7 +293,7 @@ namespace etl /// Alternative strlen for all character types, with maximum length. //*************************************************************************** template - ETL_CONSTEXPR14 size_t strlen(const T* t, size_t max_length) + ETL_CONSTEXPR14 size_t strlen(const T* t, size_t max_length) ETL_NOEXCEPT { return etl::char_traits::length(t, max_length); } @@ -302,7 +302,7 @@ namespace etl /// Alternative strcmp for all character types. //*************************************************************************** template - ETL_CONSTEXPR14 int strcmp(const T* t1, const T* t2) + ETL_CONSTEXPR14 int strcmp(const T* t1, const T* t2) ETL_NOEXCEPT { while ((*t1 != 0) || (*t2 != 0)) { @@ -327,7 +327,7 @@ namespace etl /// Alternative strncmp for all character types. //*************************************************************************** template - ETL_CONSTEXPR14 int strncmp(const T* t1, const T* t2, size_t n) + ETL_CONSTEXPR14 int strncmp(const T* t1, const T* t2, size_t n) ETL_NOEXCEPT { while (((*t1 != 0) || (*t2 != 0)) && (n != 0)) { @@ -352,7 +352,7 @@ namespace etl /// Alternative strcpy for all character types. //*************************************************************************** template - ETL_CONSTEXPR14 T* strcpy(T* dst, const T* src) + ETL_CONSTEXPR14 T* strcpy(T* dst, const T* src) ETL_NOEXCEPT { T* result = dst; @@ -370,7 +370,7 @@ namespace etl /// Alternative strncpy for all character types. //*************************************************************************** template - ETL_CONSTEXPR14 T* strncpy(T* dst, const T* src, size_t n) + ETL_CONSTEXPR14 T* strncpy(T* dst, const T* src, size_t n) ETL_NOEXCEPT { T* result = dst; diff --git a/include/etl/memory.h b/include/etl/memory.h index 119c1fce..c2e162bd 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -59,7 +59,7 @@ namespace etl /// Defined when not using the STL or C++20 //***************************************************************************** template - ETL_CONSTEXPR T* to_address(T* p) + ETL_CONSTEXPR T* to_address(T* p) ETL_NOEXCEPT { return p; } @@ -70,7 +70,7 @@ namespace etl /// Defined when not using the STL or C++20 //***************************************************************************** template - ETL_CONSTEXPR typename Iterator::pointer to_address(const Iterator& itr) + ETL_CONSTEXPR typename Iterator::pointer to_address(const Iterator& itr) ETL_NOEXCEPT { return etl::to_address(itr.operator->()); } diff --git a/include/etl/platform.h b/include/etl/platform.h index f6658d49..5e239aa4 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -359,6 +359,7 @@ SOFTWARE. #define ETL_NORETURN #define ETL_NOEXCEPT #define ETL_NOEXCEPT_EXPR(...) + #define ETL_NOEXCEPT_FROM(x) #define ETL_MOVE(x) x #define ETL_ENUM_CLASS(name) enum name #define ETL_ENUM_CLASS_TYPE(name, type) enum name diff --git a/include/etl/span.h b/include/etl/span.h index 935e82da..b2d6f76b 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -141,7 +141,7 @@ namespace etl /// Construct from iterators //************************************************************************* template - ETL_CONSTEXPR explicit span(const TIterator begin_, const TIterator /*end_*/) + ETL_CONSTEXPR explicit span(const TIterator begin_, const TIterator /*end_*/) ETL_NOEXCEPT : pbegin(etl::to_address(begin_)) { } @@ -585,7 +585,7 @@ namespace etl /// Construct from iterators //************************************************************************* template - ETL_CONSTEXPR span(const TIterator begin_, const TIterator end_) + ETL_CONSTEXPR span(const TIterator begin_, const TIterator end_) ETL_NOEXCEPT : pbegin(etl::to_address(begin_)) , pend(etl::to_address(begin_) + etl::distance(begin_, end_)) { diff --git a/include/etl/string_view.h b/include/etl/string_view.h index 0ed1ad85..4e596594 100644 --- a/include/etl/string_view.h +++ b/include/etl/string_view.h @@ -132,7 +132,7 @@ namespace etl //************************************************************************* /// Construct from string. //************************************************************************* - ETL_CONSTEXPR basic_string_view(const etl::ibasic_string& str) + ETL_CONSTEXPR basic_string_view(const etl::ibasic_string& str) ETL_NOEXCEPT : mbegin(str.begin()) , mend(str.end()) { @@ -141,7 +141,7 @@ namespace etl //************************************************************************* /// Construct from T*. //************************************************************************* - ETL_CONSTEXPR14 ETL_EXPLICIT_STRING_FROM_CHAR basic_string_view(const T* begin_) + ETL_CONSTEXPR14 ETL_EXPLICIT_STRING_FROM_CHAR basic_string_view(const T* begin_) ETL_NOEXCEPT : mbegin(begin_) , mend(begin_ + TTraits::length(begin_)) { @@ -150,7 +150,7 @@ namespace etl //************************************************************************* /// Construct from pointer range. //************************************************************************* - ETL_CONSTEXPR basic_string_view(const T* begin_, const T* end_) + ETL_CONSTEXPR basic_string_view(const T* begin_, const T* end_) ETL_NOEXCEPT : mbegin(begin_) , mend(end_) { @@ -159,7 +159,7 @@ namespace etl //************************************************************************* /// Construct from pointer/size. //************************************************************************* - ETL_CONSTEXPR basic_string_view(const T* begin_, size_t size_) + ETL_CONSTEXPR basic_string_view(const T* begin_, size_t size_) ETL_NOEXCEPT : mbegin(begin_) , mend(begin_ + size_) { @@ -193,7 +193,7 @@ namespace etl //************************************************************************* /// Returns a const pointer to the first element of the internal storage. //************************************************************************* - ETL_CONSTEXPR const_pointer data() const + ETL_CONSTEXPR const_pointer data() const ETL_NOEXCEPT { return mbegin; } @@ -201,7 +201,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator begin() const + ETL_CONSTEXPR const_iterator begin() const ETL_NOEXCEPT { return mbegin; } @@ -209,7 +209,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator cbegin() const + ETL_CONSTEXPR const_iterator cbegin() const ETL_NOEXCEPT { return mbegin; } @@ -217,7 +217,7 @@ namespace etl //************************************************************************* /// Returns a const iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator end() const + ETL_CONSTEXPR const_iterator end() const ETL_NOEXCEPT { return mend; } @@ -225,7 +225,7 @@ namespace etl //************************************************************************* // Returns a const iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_iterator cend() const + ETL_CONSTEXPR const_iterator cend() const ETL_NOEXCEPT { return mend; } @@ -233,7 +233,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator rbegin() const + ETL_CONSTEXPR const_reverse_iterator rbegin() const ETL_NOEXCEPT { return const_reverse_iterator(mend); } @@ -241,7 +241,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the reverse beginning of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator crbegin() const + ETL_CONSTEXPR const_reverse_iterator crbegin() const ETL_NOEXCEPT { return const_reverse_iterator(mend); } @@ -249,7 +249,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator rend() const + ETL_CONSTEXPR const_reverse_iterator rend() const ETL_NOEXCEPT { return const_reverse_iterator(mbegin); } @@ -257,7 +257,7 @@ namespace etl //************************************************************************* /// Returns a const reverse iterator to the end of the array. //************************************************************************* - ETL_CONSTEXPR const_reverse_iterator crend() const + ETL_CONSTEXPR const_reverse_iterator crend() const ETL_NOEXCEPT { return const_reverse_iterator(mbegin); } @@ -269,7 +269,7 @@ namespace etl //************************************************************************* /// Returns true if the array size is zero. //************************************************************************* - ETL_CONSTEXPR bool empty() const + ETL_CONSTEXPR bool empty() const ETL_NOEXCEPT { return (mbegin == mend); } @@ -277,7 +277,7 @@ namespace etl //************************************************************************* /// Returns the size of the array. //************************************************************************* - ETL_CONSTEXPR size_t size() const + ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT { return static_cast(mend - mbegin); } @@ -285,7 +285,7 @@ namespace etl //************************************************************************* /// Returns the size of the array. //************************************************************************* - ETL_CONSTEXPR size_t length() const + ETL_CONSTEXPR size_t length() const ETL_NOEXCEPT { return size(); } @@ -293,7 +293,7 @@ namespace etl //************************************************************************* /// Returns the maximum possible size of the array. //************************************************************************* - ETL_CONSTEXPR size_t max_size() const + ETL_CONSTEXPR size_t max_size() const ETL_NOEXCEPT { return size(); } @@ -301,7 +301,7 @@ namespace etl //************************************************************************* /// Assign from a view. //************************************************************************* - ETL_CONSTEXPR14 etl::basic_string_view& operator=(const etl::basic_string_view& other) + ETL_CONSTEXPR14 etl::basic_string_view& operator=(const etl::basic_string_view& other) ETL_NOEXCEPT { mbegin = other.mbegin; mend = other.mend; @@ -311,7 +311,7 @@ namespace etl //************************************************************************* /// Assign from iterators //************************************************************************* - ETL_CONSTEXPR14 void assign(const_pointer begin_, const_pointer end_) + ETL_CONSTEXPR14 void assign(const_pointer begin_, const_pointer end_) ETL_NOEXCEPT { mbegin = begin_; mend = end_; @@ -320,7 +320,7 @@ namespace etl //************************************************************************* /// Assign from iterator and size. //************************************************************************* - ETL_CONSTEXPR14 void assign(const_pointer begin_, size_t size_) + ETL_CONSTEXPR14 void assign(const_pointer begin_, size_t size_) ETL_NOEXCEPT { mbegin = begin_; mend = begin_ + size_; @@ -329,7 +329,7 @@ namespace etl //************************************************************************* /// Returns a const reference to the indexed value. //************************************************************************* - ETL_CONSTEXPR const_reference operator[](size_t i) const + ETL_CONSTEXPR const_reference operator[](size_t i) const ETL_NOEXCEPT { return mbegin[i]; } @@ -358,7 +358,7 @@ namespace etl //************************************************************************* /// Copies characters //************************************************************************* - ETL_CONSTEXPR14 size_type copy(T* destination, size_type count, size_type position = 0) const + ETL_CONSTEXPR14 size_type copy(T* destination, size_type count, size_type position = 0) const ETL_NOEXCEPT { size_t n = 0UL; @@ -375,7 +375,7 @@ namespace etl //************************************************************************* /// Returns a substring //************************************************************************* - ETL_CONSTEXPR14 basic_string_view substr(size_type position = 0, size_type count = npos) const + ETL_CONSTEXPR14 basic_string_view substr(size_type position = 0, size_type count = npos) const ETL_NOEXCEPT { basic_string_view view = basic_string_view(); @@ -392,7 +392,7 @@ namespace etl //************************************************************************* /// Shrinks the view by moving its start forward. //************************************************************************* - ETL_CONSTEXPR14 void remove_prefix(size_type n) + ETL_CONSTEXPR14 void remove_prefix(size_type n) ETL_NOEXCEPT { mbegin += n; } @@ -400,7 +400,7 @@ namespace etl //************************************************************************* /// Shrinks the view by moving its end backward. //************************************************************************* - ETL_CONSTEXPR14 void remove_suffix(size_type n) + ETL_CONSTEXPR14 void remove_suffix(size_type n) ETL_NOEXCEPT { mend -= n; } @@ -408,24 +408,24 @@ namespace etl //************************************************************************* /// Compares two views //************************************************************************* - ETL_CONSTEXPR14 int compare(basic_string_view view) const + ETL_CONSTEXPR14 int compare(basic_string_view view) const ETL_NOEXCEPT { return (*this == view) ? 0 : ((*this > view) ? 1 : -1); } - ETL_CONSTEXPR14 int compare(size_type position, size_type count, basic_string_view view) const + ETL_CONSTEXPR14 int compare(size_type position, size_type count, basic_string_view view) const ETL_NOEXCEPT { return substr(position, count).compare(view); } ETL_CONSTEXPR14 int compare(size_type position1, size_type count1, basic_string_view view, - size_type position2, size_type count2) const + size_type position2, size_type count2) const ETL_NOEXCEPT { return substr(position1, count1).compare(view.substr(position2, count2)); } - ETL_CONSTEXPR14 int compare(const T* text) const + ETL_CONSTEXPR14 int compare(const T* text) const ETL_NOEXCEPT { const T* view_itr = mbegin; const T* text_itr = text; @@ -458,12 +458,12 @@ namespace etl } } - ETL_CONSTEXPR14 int compare(size_type position, size_type count, const T* text) const + ETL_CONSTEXPR14 int compare(size_type position, size_type count, const T* text) const ETL_NOEXCEPT { return substr(position, count).compare(text); } - ETL_CONSTEXPR14 int compare(size_type position, size_type count1, const T* text, size_type count2) const + ETL_CONSTEXPR14 int compare(size_type position, size_type count1, const T* text, size_type count2) const ETL_NOEXCEPT { return substr(position, count1).compare(etl::basic_string_view(text, count2)); } @@ -471,18 +471,18 @@ namespace etl //************************************************************************* /// Checks if the string view starts with the given prefix //************************************************************************* - ETL_CONSTEXPR14 bool starts_with(etl::basic_string_view view) const + ETL_CONSTEXPR14 bool starts_with(etl::basic_string_view view) const ETL_NOEXCEPT { return (size() >= view.size()) && (compare(0, view.size(), view) == 0); } - ETL_CONSTEXPR14 bool starts_with(T c) const + ETL_CONSTEXPR14 bool starts_with(T c) const ETL_NOEXCEPT { return !empty() && (front() == c); } - ETL_CONSTEXPR14 bool starts_with(const T* text) const + ETL_CONSTEXPR14 bool starts_with(const T* text) const ETL_NOEXCEPT { size_t lengthtext = TTraits::length(text); @@ -493,7 +493,7 @@ namespace etl //************************************************************************* /// Checks if the string view ends with the given suffix //************************************************************************* - ETL_CONSTEXPR14 bool ends_with(etl::basic_string_view view) const + ETL_CONSTEXPR14 bool ends_with(etl::basic_string_view view) const ETL_NOEXCEPT { return (size() >= view.size()) && (compare(size() - view.size(), npos, view) == 0); @@ -516,7 +516,7 @@ namespace etl //************************************************************************* /// Find characters in the view //************************************************************************* - ETL_CONSTEXPR14 size_type find(etl::basic_string_view view, size_type position = 0) const + ETL_CONSTEXPR14 size_type find(etl::basic_string_view view, size_type position = 0) const ETL_NOEXCEPT { if ((size() < view.size())) { @@ -535,17 +535,17 @@ namespace etl } } - ETL_CONSTEXPR14 size_type find(T c, size_type position = 0) const + ETL_CONSTEXPR14 size_type find(T c, size_type position = 0) const ETL_NOEXCEPT { return find(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type find(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type find(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return find(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type find(const T* text, size_type position = 0) const + ETL_CONSTEXPR14 size_type find(const T* text, size_type position = 0) const ETL_NOEXCEPT { return find(etl::basic_string_view(text), position); } @@ -553,7 +553,7 @@ namespace etl //************************************************************************* /// Find the last occurrence of a substring //************************************************************************* - ETL_CONSTEXPR14 size_type rfind(etl::basic_string_view view, size_type position = npos) const + ETL_CONSTEXPR14 size_type rfind(etl::basic_string_view view, size_type position = npos) const ETL_NOEXCEPT { if ((size() < view.size())) { @@ -577,17 +577,17 @@ namespace etl } } - ETL_CONSTEXPR14 size_type rfind(T c, size_type position = npos) const + ETL_CONSTEXPR14 size_type rfind(T c, size_type position = npos) const ETL_NOEXCEPT { return rfind(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return rfind(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position = npos) const + ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position = npos) const ETL_NOEXCEPT { return rfind(etl::basic_string_view(text), position); } @@ -595,7 +595,7 @@ namespace etl //************************************************************************* /// Find first occurrence of characters //************************************************************************* - ETL_CONSTEXPR14 size_type find_first_of(etl::basic_string_view view, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_of(etl::basic_string_view view, size_type position = 0) const ETL_NOEXCEPT { const size_t lengthtext = size(); @@ -618,17 +618,17 @@ namespace etl return npos; } - ETL_CONSTEXPR14 size_type find_first_of(T c, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_of(T c, size_type position = 0) const ETL_NOEXCEPT { return find_first_of(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return find_first_of(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position = 0) const ETL_NOEXCEPT { return find_first_of(etl::basic_string_view(text), position); } @@ -636,7 +636,7 @@ namespace etl //************************************************************************* /// Find last occurrence of characters //************************************************************************* - ETL_CONSTEXPR14 size_type find_last_of(etl::basic_string_view view, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_of(etl::basic_string_view view, size_type position = npos) const ETL_NOEXCEPT { if (empty()) { @@ -666,17 +666,17 @@ namespace etl return npos; } - ETL_CONSTEXPR14 size_type find_last_of(T c, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_of(T c, size_type position = npos) const ETL_NOEXCEPT { return find_last_of(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return find_last_of(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position = npos) const ETL_NOEXCEPT { return find_last_of(etl::basic_string_view(text), position); } @@ -684,7 +684,7 @@ namespace etl //************************************************************************* /// Find first absence of characters //************************************************************************* - ETL_CONSTEXPR14 size_type find_first_not_of(etl::basic_string_view view, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_not_of(etl::basic_string_view view, size_type position = 0) const ETL_NOEXCEPT { const size_t lengthtext = size(); @@ -715,17 +715,17 @@ namespace etl return npos; } - ETL_CONSTEXPR14 size_type find_first_not_of(T c, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_not_of(T c, size_type position = 0) const ETL_NOEXCEPT { return find_first_not_of(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return find_first_not_of(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position = 0) const + ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position = 0) const ETL_NOEXCEPT { return find_first_not_of(etl::basic_string_view(text), position); } @@ -733,7 +733,7 @@ namespace etl //************************************************************************* /// Find last absence of characters //************************************************************************* - ETL_CONSTEXPR14 size_type find_last_not_of(etl::basic_string_view view, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_not_of(etl::basic_string_view view, size_type position = npos) const ETL_NOEXCEPT { if (empty()) { @@ -771,17 +771,17 @@ namespace etl return npos; } - ETL_CONSTEXPR14 size_type find_last_not_of(T c, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_not_of(T c, size_type position = npos) const ETL_NOEXCEPT { return find_last_not_of(etl::basic_string_view(&c, 1), position); } - ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position, size_type count) const + ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT { return find_last_not_of(etl::basic_string_view(text, count), position); } - ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position = npos) const + ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position = npos) const ETL_NOEXCEPT { return find_last_not_of(etl::basic_string_view(text), position); } @@ -789,7 +789,7 @@ namespace etl //********************************************************************* /// Checks that the view is within this string //********************************************************************* - bool contains(const etl::basic_string_view& view) const + bool contains(const etl::basic_string_view& view) const ETL_NOEXCEPT { return find(view) != npos; } @@ -797,7 +797,7 @@ namespace etl //********************************************************************* /// Checks that text is within this string //********************************************************************* - bool contains(const_pointer s) const + bool contains(const_pointer s) const ETL_NOEXCEPT { return find(s) != npos; } @@ -805,7 +805,7 @@ namespace etl //********************************************************************* /// Checks that character is within this string //********************************************************************* - bool contains(value_type c) const + bool contains(value_type c) const ETL_NOEXCEPT { return find(c) != npos; } @@ -875,7 +875,7 @@ namespace etl /// make_string_view. //************************************************************************* template - ETL_CONSTEXPR14 string_view make_string_view(const char(&text)[Array_Size]) + ETL_CONSTEXPR14 string_view make_string_view(const char(&text)[Array_Size]) ETL_NOEXCEPT { size_t length = etl::char_traits::length(text, Array_Size - 1U); @@ -884,7 +884,7 @@ namespace etl //*********************************** template - ETL_CONSTEXPR14 wstring_view make_string_view(const wchar_t(&text)[Array_Size]) + ETL_CONSTEXPR14 wstring_view make_string_view(const wchar_t(&text)[Array_Size]) ETL_NOEXCEPT { size_t length = etl::char_traits::length(text, Array_Size - 1U); @@ -893,7 +893,7 @@ namespace etl //*********************************** template - ETL_CONSTEXPR14 u8string_view make_string_view(const char8_t(&text)[Array_Size]) + ETL_CONSTEXPR14 u8string_view make_string_view(const char8_t(&text)[Array_Size]) ETL_NOEXCEPT { size_t length = etl::char_traits::length(text, Array_Size - 1U); @@ -902,7 +902,7 @@ namespace etl //*********************************** template - ETL_CONSTEXPR14 u16string_view make_string_view(const char16_t(&text)[Array_Size]) + ETL_CONSTEXPR14 u16string_view make_string_view(const char16_t(&text)[Array_Size]) ETL_NOEXCEPT { size_t length = etl::char_traits::length(text, Array_Size - 1U); @@ -911,7 +911,7 @@ namespace etl //*********************************** template - ETL_CONSTEXPR14 u32string_view make_string_view(const char32_t(&text)[Array_Size]) + ETL_CONSTEXPR14 u32string_view make_string_view(const char32_t(&text)[Array_Size]) ETL_NOEXCEPT { size_t length = etl::char_traits::length(text, Array_Size - 1U); @@ -968,13 +968,13 @@ namespace etl /// Swaps the values. //************************************************************************* template -void swap(etl::basic_string_view& lhs, etl::basic_string_view& rhs) +void swap(etl::basic_string_view& lhs, etl::basic_string_view& rhs) ETL_NOEXCEPT { lhs.swap(rhs); } template -void swap(etl::basic_string_view >& lhs, etl::basic_string_view >& rhs) +void swap(etl::basic_string_view >& lhs, etl::basic_string_view >& rhs) ETL_NOEXCEPT { lhs.swap(rhs); } From fa10567482dd3168d0fc631a4351446a3472c958 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 4 Oct 2025 08:02:17 +0100 Subject: [PATCH 26/27] Restore ETL_NOEXCEPT_FROM missing from merges --- include/etl/platform.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/etl/platform.h b/include/etl/platform.h index 5e239aa4..a4710d09 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -344,9 +344,11 @@ SOFTWARE. #if ETL_USING_EXCEPTIONS #define ETL_NOEXCEPT noexcept #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) + #define ETL_NOEXCEPT_FROM(x) noexcept(noexcept(x)) #else #define ETL_NOEXCEPT #define ETL_NOEXCEPT_EXPR(...) + #define ETL_NOEXCEPT_FROM(x) #endif #else #define ETL_CONSTEXPR From 6ab05a5d7eb71bd7967d2cdf059efed5bcff82ef Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 21 Sep 2025 10:06:12 +0100 Subject: [PATCH 27/27] Rebased on development --- test/vs2022/etl.vcxproj.filters | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index cf30ac02..1a12ad7c 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3716,6 +3716,12 @@ Tests\Syntax Checks\Source + + Tests + + + Tests\Syntax Checks\Source + Tests\Misc