From f801b9a0933ad77e634f9e0a2b10246d286fc442 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 20 Aug 2025 09:25:50 +0100 Subject: [PATCH 01/24] Fix VS2022 filters --- test/vs2022/etl.vcxproj.filters | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 7e7037be..c534b4df 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3701,6 +3701,18 @@ Tests\Misc + + Tests\Syntax Checks\Source + + + Tests\Syntax Checks\Source + + + Tests\Syntax Checks\Source + + + Tests\Syntax Checks\Source + From 5f70befa4aaf68494a24a1d37e6a04f06b8dfd11 Mon Sep 17 00:00:00 2001 From: Mario Luzeiro Date: Thu, 11 Sep 2025 18:38:48 +0100 Subject: [PATCH 02/24] 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 91aa52988b51dc4e410baba5bf922073704040c5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 11 Sep 2025 19:28:03 +0100 Subject: [PATCH 03/24] 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 416544828262f735bac35e43bcb865ea6f39fa90 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:47:18 +0100 Subject: [PATCH 04/24] 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 fd7edc937d6319aa0af5af86f43d8bc77e0a67e2 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:47:51 +0100 Subject: [PATCH 05/24] 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 9a9a96f5c5353f02dad74b2dd11566d14a879946 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 12:48:18 +0100 Subject: [PATCH 06/24] 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 7a2c918b1e8704db869356d9484d9123b877ad8f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 20:19:27 +0100 Subject: [PATCH 07/24] Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() Removed ETL_NOEXCEPT from closureoperator(), call_if(), and call_or() --- include/etl/private/delegate_cpp11.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/etl/private/delegate_cpp11.h b/include/etl/private/delegate_cpp11.h index a922a3e3..7c9382d2 100644 --- a/include/etl/private/delegate_cpp11.h +++ b/include/etl/private/delegate_cpp11.h @@ -372,7 +372,7 @@ namespace etl //************************************************************************* /// Execute the delegate. //************************************************************************* - ETL_CONSTEXPR14 TReturn operator()(TParams... args) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 TReturn operator()(TParams... args) const { ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised)); @@ -386,7 +386,7 @@ namespace etl template ETL_CONSTEXPR14 typename etl::enable_if_t::value, bool> - call_if(TParams... args) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + call_if(TParams... args) const { if (is_valid()) { @@ -406,7 +406,7 @@ namespace etl template ETL_CONSTEXPR14 typename etl::enable_if_t::value, etl::optional> - call_if(TParams... args) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + call_if(TParams... args) const { etl::optional result; @@ -423,7 +423,7 @@ namespace etl /// Run time alternative. //************************************************************************* template - ETL_CONSTEXPR14 TReturn call_or(TAlternative alternative, TParams... args) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 TReturn call_or(TAlternative alternative, TParams... args) const { if (is_valid()) { @@ -440,7 +440,7 @@ namespace etl /// Compile time alternative. //************************************************************************* template - ETL_CONSTEXPR14 TReturn call_or(TParams... args) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 TReturn call_or(TParams... args) const { if (is_valid()) { From 5177f69994255e84bc310362f338eb88c386ef50 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 20:20:19 +0100 Subject: [PATCH 08/24] Updated version and release notes --- arduino/library-arduino.json | 2 +- arduino/library-arduino.properties | 2 +- include/etl/closure.h | 12 ++++++------ include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- version.txt | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arduino/library-arduino.json b/arduino/library-arduino.json index 917ae676..bfe01943 100644 --- a/arduino/library-arduino.json +++ b/arduino/library-arduino.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library ETL", - "version": "20.43.2", + "version": "20.43.3", "authors": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/arduino/library-arduino.properties b/arduino/library-arduino.properties index cee37df3..5204c0fc 100644 --- a/arduino/library-arduino.properties +++ b/arduino/library-arduino.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.43.2 +version=20.43.3 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/include/etl/closure.h b/include/etl/closure.h index bc4c137a..a1e885b0 100644 --- a/include/etl/closure.h +++ b/include/etl/closure.h @@ -71,7 +71,7 @@ namespace etl /// \param f The delegate to be invoked. /// \param args The arguments to bind to the delegate. //********************************************************************* - ETL_CONSTEXPR14 closure(const delegate_type& f, const TArgs... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 closure(const delegate_type& f, const TArgs... args) : m_f(f) , m_args(args...) { @@ -81,7 +81,7 @@ namespace etl /// Invoke the stored delegate with the bound arguments. /// \return The result of the delegate invocation. //********************************************************************* - ETL_CONSTEXPR14 TReturn operator()() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 TReturn operator()() const { return execute(etl::index_sequence_for{}); } @@ -94,7 +94,7 @@ namespace etl /// \param arg The new value to bind. //********************************************************************* template - ETL_CONSTEXPR14 void bind(UArg arg) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 void bind(UArg arg) { static_assert(etl::is_convertible>::value, "Argument is not convertible"); static_assert(!etl::is_reference::value, "Cannot bind reference arguments"); @@ -108,7 +108,7 @@ namespace etl /// \param args The new values to bind. ///********************************************************************* template - ETL_CONSTEXPR14 void bind(UArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 void bind(UArgs&&... args) { static_assert(sizeof...(UArgs) == sizeof...(TArgs), "Argument count mismatch"); bind_impl(etl::make_index_sequence{}, etl::forward(args)...); @@ -121,7 +121,7 @@ namespace etl /// \param args The new values to bind. ///********************************************************************* template - ETL_CONSTEXPR14 void bind_impl(etl::index_sequence, UArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 void bind_impl(etl::index_sequence, UArgs&&... args) { // Expand the pack and call bind(arg) for each argument int dummy[] = {0, (bind(etl::forward(args)), 0)...}; @@ -134,7 +134,7 @@ namespace etl /// \return The result of the delegate invocation. //********************************************************************* template - ETL_CONSTEXPR14 TReturn execute(etl::index_sequence) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 TReturn execute(etl::index_sequence) const { return m_f(etl::get(m_args)...); } diff --git a/include/etl/version.h b/include/etl/version.h index cabd4d69..90c97396 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -40,7 +40,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 43 -#define ETL_VERSION_PATCH 2 +#define ETL_VERSION_PATCH 3 #define ETL_VERSION ETL_STRING(ETL_VERSION_MAJOR) "." ETL_STRING(ETL_VERSION_MINOR) "." ETL_STRING(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_WIDE_STRING(ETL_VERSION_MAJOR) L"." ETL_WIDE_STRING(ETL_VERSION_MINOR) L"." ETL_WIDE_STRING(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 57cf258f..3f83f304 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library", - "version": "20.43.2", + "version": "20.43.3", "authors": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index 4079e46f..1428e78e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=20.43.2 +version=20.43.3 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/version.txt b/version.txt index f9ffdf0b..4ba170c4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -20.43.2 +20.43.3 From df6d3b8f023df257e9b685b82262c957a0c05a4b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 12 Sep 2025 20:38:41 +0100 Subject: [PATCH 09/24] Updated version and release notes --- support/Release notes.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/support/Release notes.txt b/support/Release notes.txt index 77d9728d..0559b6d3 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,4 +1,10 @@ =============================================================================== +20.43.3 + +Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() +Removed ETL_NOEXCEPT from closure + +=============================================================================== 20.43.2 Pull Requests: From c80939759c2499757c7daf70b8b6dedc0cba50fa Mon Sep 17 00:00:00 2001 From: Marco Nilsson Date: Sat, 13 Sep 2025 09:23:15 +0200 Subject: [PATCH 10/24] 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. --- include/etl/private/delegate_cpp11.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/etl/private/delegate_cpp11.h b/include/etl/private/delegate_cpp11.h index 7c9382d2..79182656 100644 --- a/include/etl/private/delegate_cpp11.h +++ b/include/etl/private/delegate_cpp11.h @@ -583,7 +583,7 @@ namespace etl /// Stub call for a member function. Run time instance. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn method_stub(void* object, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn method_stub(void* object, TParams... params) { T* p = static_cast(object); return (p->*Method)(etl::forward(params)...); @@ -593,7 +593,7 @@ namespace etl /// Stub call for a const member function. Run time instance. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn const_method_stub(void* object, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn const_method_stub(void* object, TParams... params) { T* const p = static_cast(object); return (p->*Method)(etl::forward(params)...); @@ -603,7 +603,7 @@ namespace etl /// Stub call for a member function. Compile time instance. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn method_instance_stub(void*, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn method_instance_stub(void*, TParams... params) { return (Instance.*Method)(etl::forward(params)...); } @@ -612,7 +612,7 @@ namespace etl /// Stub call for a const member function. Compile time instance. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn const_method_instance_stub(void*, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn const_method_instance_stub(void*, TParams... params) { return (Instance.*Method)(etl::forward(params)...); } @@ -622,7 +622,7 @@ namespace etl /// Stub call for a function operator. Compile time instance. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn operator_instance_stub(void*, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn operator_instance_stub(void*, TParams... params) { return Instance.operator()(etl::forward(params)...); } @@ -632,7 +632,7 @@ namespace etl /// Stub call for a free function. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn function_stub(void*, TParams... params) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn function_stub(void*, TParams... params) { return (Method)(etl::forward(params)...); } @@ -641,7 +641,7 @@ namespace etl /// Stub call for a lambda or functor function. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn lambda_stub(void* object, TParams... arg) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn lambda_stub(void* object, TParams... arg) { TLambda* p = static_cast(object); return (p->operator())(etl::forward(arg)...); @@ -651,7 +651,7 @@ namespace etl /// Stub call for a const lambda or functor function. //************************************************************************* template - static ETL_CONSTEXPR14 TReturn const_lambda_stub(void* object, TParams... arg) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + static ETL_CONSTEXPR14 TReturn const_lambda_stub(void* object, TParams... arg) { const TLambda* p = static_cast(object); return (p->operator())(etl::forward(arg)...); From e4117e9eb487fbd5d22e011f1d2539547952be9f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 13 Sep 2025 08:28:22 +0100 Subject: [PATCH 11/24] Updated version and release notes --- arduino/library-arduino.json | 2 +- arduino/library-arduino.properties | 2 +- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- support/Release notes.txt | 5 +++++ version.txt | 2 +- 7 files changed, 11 insertions(+), 6 deletions(-) diff --git a/arduino/library-arduino.json b/arduino/library-arduino.json index bfe01943..039673b5 100644 --- a/arduino/library-arduino.json +++ b/arduino/library-arduino.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library ETL", - "version": "20.43.3", + "version": "20.43.4", "authors": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/arduino/library-arduino.properties b/arduino/library-arduino.properties index 5204c0fc..64150f49 100644 --- a/arduino/library-arduino.properties +++ b/arduino/library-arduino.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.43.3 +version=20.43.4 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/include/etl/version.h b/include/etl/version.h index 90c97396..145240ce 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -40,7 +40,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 43 -#define ETL_VERSION_PATCH 3 +#define ETL_VERSION_PATCH 4 #define ETL_VERSION ETL_STRING(ETL_VERSION_MAJOR) "." ETL_STRING(ETL_VERSION_MINOR) "." ETL_STRING(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_WIDE_STRING(ETL_VERSION_MAJOR) L"." ETL_WIDE_STRING(ETL_VERSION_MINOR) L"." ETL_WIDE_STRING(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 3f83f304..3a6d76e7 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library", - "version": "20.43.3", + "version": "20.43.4", "authors": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index 1428e78e..f0e30104 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=20.43.3 +version=20.43.4 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/support/Release notes.txt b/support/Release notes.txt index 0559b6d3..9e3ac3b4 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,4 +1,9 @@ =============================================================================== +20.43.4 + +#1185 Remove noexcept from delegate method stubs. + +=============================================================================== 20.43.3 Removed ETL_NOEXCEPT from delegate operator(), call_if(), and call_or() diff --git a/version.txt b/version.txt index 4ba170c4..cfc1db88 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -20.43.3 +20.43.4 From a21b96396e6a7d423830394083d986cb85e1af5a Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 17 Sep 2025 21:16:57 +0200 Subject: [PATCH 12/24] Guards around usage of std::initializer_list in optional.h (#1186) * Guards around usage of std::initializer_list in optional.h In optional.h, ETL_HAS_INITIALIZER_LIST is being used to guard against cases where std::initializer_list is not available. But not consistently. This changes fixes it by adding it in the remaining places. * Fixed #undef in optional.h Instead of undefining ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14, ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL was undefined twice (one of the misspelled). * Fix comment typos --- include/etl/gcd.h | 2 +- include/etl/lcm.h | 2 +- include/etl/optional.h | 6 +++++- include/etl/private/chrono/duration.h | 2 +- include/etl/ratio.h | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/etl/gcd.h b/include/etl/gcd.h index 8a954e0d..0926b2f0 100644 --- a/include/etl/gcd.h +++ b/include/etl/gcd.h @@ -21,7 +21,7 @@ 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 Value1 PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +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 diff --git a/include/etl/lcm.h b/include/etl/lcm.h index ef3008f6..3ffc9821 100644 --- a/include/etl/lcm.h +++ b/include/etl/lcm.h @@ -21,7 +21,7 @@ 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 Value1 PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +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 diff --git a/include/etl/optional.h b/include/etl/optional.h index e8e40439..12d90239 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -195,6 +195,7 @@ namespace etl storage.construct(etl::forward(args)...); } +#if ETL_HAS_INITIALIZER_LIST //******************************************* /// Construct from initializer_list and arguments. //******************************************* @@ -205,6 +206,7 @@ namespace etl { storage.construct(ilist, etl::forward(args)...); } +#endif #endif //*************************************************************************** @@ -816,6 +818,7 @@ namespace etl storage.construct(etl::forward(args)...); } +#if ETL_HAS_INITIALIZER_LIST //******************************************* /// Construct from initializer_list and arguments. //******************************************* @@ -826,6 +829,7 @@ namespace etl { storage.construct(ilist, etl::forward(args)...); } +#endif #endif //*************************************************************************** @@ -2313,7 +2317,7 @@ ETL_CONSTEXPR20_STL void swap(etl::optional& lhs, etl::optional& rhs) #undef ETL_OPTIONAL_ENABLE_CPP14 #undef ETL_OPTIONAL_ENABLE_CPP20_STL +#undef ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 #undef ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL -#undef ETL_OPTIONAL_ENABLE_COMSTEXPR_BOOL_RETURN_CPP20_STL #endif diff --git a/include/etl/private/chrono/duration.h b/include/etl/private/chrono/duration.h index a629c01c..cd81e9d9 100644 --- a/include/etl/private/chrono/duration.h +++ b/include/etl/private/chrono/duration.h @@ -21,7 +21,7 @@ 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 Value1 PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +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 diff --git a/include/etl/ratio.h b/include/etl/ratio.h index 2f2b5075..7e671589 100644 --- a/include/etl/ratio.h +++ b/include/etl/ratio.h @@ -21,7 +21,7 @@ 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 Value1 PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +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 From 1b5ff74a3d796c4199062dd13bdf9aa4039f23fe Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 18 Sep 2025 09:07:34 +0100 Subject: [PATCH 13/24] Fixed spelling of gdc to gcd --- test/test_math_functions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_math_functions.cpp b/test/test_math_functions.cpp index a6aeaed1..40594351 100644 --- a/test/test_math_functions.cpp +++ b/test/test_math_functions.cpp @@ -461,7 +461,7 @@ namespace } //************************************************************************* - TEST(test_gdc_for_positive_integers) + TEST(test_gcd_for_positive_integers) { CHECK_EQUAL(1, etl::gcd( 3, 5, 7)); CHECK_EQUAL(2, etl::gcd( 4, 6, 8)); @@ -471,7 +471,7 @@ namespace } //************************************************************************* - TEST(test_gdc_for_negative_integers) + TEST(test_gcd_for_negative_integers) { CHECK_EQUAL(1, etl::gcd( -3, -5, -7)); CHECK_EQUAL(2, etl::gcd( -4, -6, -8)); @@ -482,7 +482,7 @@ namespace #if ETL_USING_CPP14 //************************************************************************* - TEST(test_constexpr_gdc) + TEST(test_constexpr_gcd) { constexpr int gcd1 = etl::gcd(3, 5, 7); constexpr int gcd2 = etl::gcd(4, 6, 8); From 5face0d8f2830deb95e7cd5e6abd19bbb92d68d4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 6 Sep 2025 10:19:31 +0100 Subject: [PATCH 14/24] Updated version and release notes # Conflicts: # support/Release notes.txt --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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 From fbb92f85fc62fef9e45caa7fb5eefeaa1177534e 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 15/24] 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 972aedd9448db177f4b7e2dd9e5fc2d17d2f9c60 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Sep 2025 14:34:06 +0100 Subject: [PATCH 16/24] 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 5ac8070a8cd97464d4ea16ecaf42e1800eb8f104 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Sep 2025 14:34:57 +0100 Subject: [PATCH 17/24] 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 69c3f74b0f7668ae8c8fd1afd96e21a9e1b54891 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 22 Sep 2025 10:41:50 +0100 Subject: [PATCH 18/24] 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 4cf522ed46a500d81c24969410bb06353ece9128 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 19/24] 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 813e26e3b48c03cfd6984c10762d4e689eccb9cd 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 20/24] 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 4cbc601a69d8acc980e476eda8607a80845e59cc 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 21/24] 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 018c7ce849453ac50b6a5c6d39d4ce56a16d25fe 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 22/24] 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 07bf063daa502e0b1e6a53df11b88e32047cb871 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 1 Oct 2025 18:58:27 +0100 Subject: [PATCH 23/24] 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 3d361cfb..bc0e7529 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -11376,11 +11376,13 @@ + + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 3b9bf643..088c6ca8 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3886,6 +3886,12 @@ ETL\Arduino + + Resource Files\CI\Github + + + Resource Files\CI\Github + From f7cdf1bc3f847d09cab562297d5a9fff03c2ca68 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 2 Oct 2025 07:45:54 +0100 Subject: [PATCH 24/24] 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.