From 0644f9827b253bb7e3eb305e629141cad30d412f Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:02:46 +0100 Subject: [PATCH 001/167] Fix year_month arithmetic and correct chrono API behavior (#1257) * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Restore default constructor behavior for chrono calender --- include/etl/private/chrono/day.h | 61 ++------------- include/etl/private/chrono/month.h | 54 ++----------- include/etl/private/chrono/weekday.h | 20 ----- include/etl/private/chrono/year.h | 66 +++++----------- include/etl/private/chrono/year_month.h | 16 ++-- include/etl/private/chrono/year_month_day.h | 20 +++-- .../etl/private/chrono/year_month_weekday.h | 12 ++- test/test_chrono_day.cpp | 9 --- test/test_chrono_month.cpp | 9 --- test/test_chrono_weekday_last.cpp | 1 - test/test_chrono_year.cpp | 23 +++--- test/test_chrono_year_month.cpp | 75 ++++++++++++++++++- test/test_chrono_year_month_day.cpp | 2 +- 13 files changed, 148 insertions(+), 220 deletions(-) diff --git a/include/etl/private/chrono/day.h b/include/etl/private/chrono/day.h index fa5bb712..6797c81f 100644 --- a/include/etl/private/chrono/day.h +++ b/include/etl/private/chrono/day.h @@ -57,39 +57,10 @@ namespace etl /// Construct from unsigned //*********************************************************************** ETL_CONSTEXPR explicit day(unsigned value_) ETL_NOEXCEPT - : value(static_cast(value_)) + : value(static_cast(value_)) { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 day(const etl::chrono::day& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::day& operator =(const etl::chrono::day& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - template - ETL_CONSTEXPR14 etl::chrono::day& operator =(const etl::chrono::duration& rhs) - { - value = etl::chrono::duration_cast(rhs); - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -105,7 +76,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day operator ++(int) ETL_NOEXCEPT { - const etl::chrono::day temp = *this; + etl::chrono::day temp = *this; ++value; return temp; @@ -126,7 +97,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day operator --(int) ETL_NOEXCEPT { - const etl::chrono::day temp = *this; + etl::chrono::day temp = *this; --value; return temp; @@ -137,7 +108,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day& operator +=(const etl::chrono::days& ds) ETL_NOEXCEPT { - value += static_cast(ds.count()); + value += static_cast(ds.count()); return *this; } @@ -147,7 +118,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day& operator -=(const etl::chrono::days& ds) ETL_NOEXCEPT { - value -= static_cast(ds.count()); + value -= static_cast(ds.count()); return *this; } @@ -164,9 +135,9 @@ namespace etl //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator unsigned() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator unsigned() const ETL_NOEXCEPT { - return static_cast(value); + return value; } //*********************************************************************** @@ -184,24 +155,6 @@ namespace etl return 0; } - //*********************************************************************** - /// The minimum day value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::day min() ETL_NOEXCEPT - { - return etl::chrono::day(1); - } - - //*********************************************************************** - /// The maximum day value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::day max() ETL_NOEXCEPT - { - return etl::chrono::day(31); - } - private: rep value; diff --git a/include/etl/private/chrono/month.h b/include/etl/private/chrono/month.h index 1ab694d4..4f257da3 100644 --- a/include/etl/private/chrono/month.h +++ b/include/etl/private/chrono/month.h @@ -72,24 +72,6 @@ namespace etl { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 month(const etl::chrono::month& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::month& operator =(const etl::chrono::month& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -105,9 +87,9 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::month operator ++(int) ETL_NOEXCEPT { - const etl::chrono::month temp = *this; + etl::chrono::month temp = *this; - *this += etl::chrono::months(1); + ++*this; return temp; } @@ -129,7 +111,7 @@ namespace etl { etl::chrono::month temp = *this; - *this -= etl::chrono::months(1); + --*this; return temp; } @@ -155,7 +137,7 @@ namespace etl } //*********************************************************************** - /// Returns true if the month is within the valid 1 to 31 range + /// Returns true if the month is within the valid 1 to 12 range //*********************************************************************** ETL_NODISCARD ETL_CONSTEXPR14 bool ok() const ETL_NOEXCEPT @@ -178,30 +160,12 @@ namespace etl return 0; } - //*********************************************************************** - /// The minimum month value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::month min() ETL_NOEXCEPT - { - return etl::chrono::month(1); - } - - //*********************************************************************** - /// The maximum month value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::month max() ETL_NOEXCEPT - { - return etl::chrono::month(12); - } - //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator unsigned() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator unsigned() const ETL_NOEXCEPT { - return static_cast(value); + return value; } private: @@ -331,10 +295,8 @@ namespace etl etl::chrono::months ms(difference); // Check for validity. - if (m1 == (m2 + ms)) - { - return ms; - } + assert(m1 == (m2 + ms)); + return ms; } return etl::chrono::months(); diff --git a/include/etl/private/chrono/weekday.h b/include/etl/private/chrono/weekday.h index de511a83..19246368 100644 --- a/include/etl/private/chrono/weekday.h +++ b/include/etl/private/chrono/weekday.h @@ -362,26 +362,6 @@ namespace etl { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 weekday_indexed(const etl::chrono::weekday_indexed& other) ETL_NOEXCEPT - : wd(other.wd) - , i(other.i) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::weekday_indexed& operator =(const etl::chrono::weekday_indexed& rhs) ETL_NOEXCEPT - { - wd = rhs.wd; - i = rhs.i; - - return *this; - } - //*********************************************************************** /// Get weekday //*********************************************************************** diff --git a/include/etl/private/chrono/year.h b/include/etl/private/chrono/year.h index fd3d8096..b21c572e 100644 --- a/include/etl/private/chrono/year.h +++ b/include/etl/private/chrono/year.h @@ -54,31 +54,13 @@ namespace etl } //*********************************************************************** - /// Construct from unsigned + /// Construct from int //*********************************************************************** - ETL_CONSTEXPR explicit year(unsigned value_) ETL_NOEXCEPT + ETL_CONSTEXPR explicit year(int value_) ETL_NOEXCEPT : value(value_) { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 year(const etl::chrono::year& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::year& operator =(const etl::chrono::year& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -94,7 +76,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year operator ++(int) ETL_NOEXCEPT { - const etl::chrono::year temp = *this; + etl::chrono::year temp = *this; ++value; return temp; @@ -115,7 +97,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year operator --(int) ETL_NOEXCEPT { - const etl::chrono::year temp = *this; + etl::chrono::year temp = *this; --value; return temp; @@ -126,7 +108,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year& operator +=(const etl::chrono::years& ys) ETL_NOEXCEPT { - value += static_cast(ys.count()); + value += ys.count(); return *this; } @@ -136,7 +118,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year& operator -=(const etl::chrono::years& ys) ETL_NOEXCEPT { - value -= static_cast(ys.count()); + value -= ys.count(); return *this; } @@ -182,9 +164,9 @@ namespace etl //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator int() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator int() const ETL_NOEXCEPT { - return static_cast(value); + return value; } //*********************************************************************** @@ -212,7 +194,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator ==(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) == static_cast(y2)); + return (static_cast(y1) == static_cast(y2)); } //*********************************************************************** @@ -228,7 +210,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator <(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) < static_cast(y2)); + return (static_cast(y1) < static_cast(y2)); } //*********************************************************************** @@ -236,7 +218,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator <=(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) <= static_cast(y2)); + return (static_cast(y1) <= static_cast(y2)); } //*********************************************************************** @@ -244,7 +226,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator >(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) > static_cast(y2)); + return (static_cast(y1) > static_cast(y2)); } //*********************************************************************** @@ -252,7 +234,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator >=(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) >= static_cast(y2)); + return (static_cast(y1) >= static_cast(y2)); } //*********************************************************************** @@ -261,7 +243,7 @@ namespace etl #if ETL_USING_CPP20 [[nodiscard]] inline constexpr auto operator <=>(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) <=> static_cast(y2)); + return (static_cast(y1) <=> static_cast(y2)); } #endif @@ -304,27 +286,13 @@ namespace etl return result; } - //*********************************************************************** - /// Subtract etl::chrono::year from etl::chrono::years - ///\return etl::chrono::years - //*********************************************************************** - inline ETL_CONSTEXPR14 etl::chrono::year operator -(const etl::chrono::years& ys, const etl::chrono::year& y) ETL_NOEXCEPT - { - etl::chrono::year result(y); - - result -= ys; - - return result; - } - //*********************************************************************** /// Subtract etl::chrono::year from etl::chrono::year ///\return etl::chrono::years //*********************************************************************** inline ETL_CONSTEXPR14 etl::chrono::years operator -(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return etl::chrono::years(static_cast(static_cast(y1)) - - static_cast(static_cast(y2))); + return etl::chrono::years(static_cast(y1) - static_cast(y2)); } } @@ -337,7 +305,7 @@ namespace etl { size_t operator()(const etl::chrono::year& y) const { - etl::chrono::year::rep value = static_cast(static_cast(y)); + etl::chrono::year::rep value = static_cast(static_cast(y)); const uint8_t* p = reinterpret_cast(&value); return etl::private_hash::generic_hash(p, p + sizeof(value)); @@ -362,7 +330,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year operator ""_y(unsigned long long y) ETL_NOEXCEPT #endif { - return etl::chrono::year(static_cast(y)); + return etl::chrono::year(static_cast(y)); } } } diff --git a/include/etl/private/chrono/year_month.h b/include/etl/private/chrono/year_month.h index 672aadd6..36ca0526 100644 --- a/include/etl/private/chrono/year_month.h +++ b/include/etl/private/chrono/year_month.h @@ -135,7 +135,12 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator +(const etl::chrono::year_month& ym, const etl::chrono::months& dm) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() + dm); + int dmonths = static_cast(static_cast(ym.month())) - 1 + dm.count(); + int dyears = (dmonths - 11 * (dmonths < 0)) / 12; + dmonths -= dyears * 12; + ++dmonths; + return etl::chrono::year_month((ym.year() + etl::chrono::years(dyears)), + etl::chrono::month(static_cast(dmonths))); } //************************************************************************* @@ -144,7 +149,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator +(const etl::chrono::months& dm, const etl::chrono::year_month& ym) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() + dm); + return ym + dm; } //************************************************************************* @@ -162,7 +167,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator -(const etl::chrono::year_month& ym, const etl::chrono::months& dm) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() - dm); + return ym + -dm; } //************************************************************************* @@ -171,7 +176,8 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::months operator -(const etl::chrono::year_month& ym1, const etl::chrono::year_month& ym2) ETL_NOEXCEPT { - return etl::chrono::months(static_cast(((int(ym1.year()) - int(ym2.year())) * 12) + (unsigned(ym1.month()) - unsigned(ym2.month())))); + return etl::chrono::months((ym1.year() - ym2.year()) + etl::chrono::months( + static_cast(static_cast(ym1.month())) - static_cast(static_cast(ym2.month())))); } //************************************************************************* @@ -273,7 +279,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month& ym) const { - etl::chrono::year::rep y = static_cast(static_cast(ym.year())); + etl::chrono::year::rep y = static_cast(static_cast(ym.year())); etl::chrono::month::rep m = static_cast(static_cast(ym.month())); uint8_t buffer[sizeof(y) + sizeof(m)]; diff --git a/include/etl/private/chrono/year_month_day.h b/include/etl/private/chrono/year_month_day.h index 6dcfa9d3..0a911a54 100644 --- a/include/etl/private/chrono/year_month_day.h +++ b/include/etl/private/chrono/year_month_day.h @@ -76,6 +76,9 @@ namespace etl /// Construct from sys_days. //************************************************************************* ETL_CONSTEXPR14 year_month_day(const etl::chrono::sys_days& sd) ETL_NOEXCEPT + : y(0) + , m(0U) + , d(0U) { // Days since 1970-01-01 int days_since_epoch = static_cast(sd.time_since_epoch().count()); @@ -101,7 +104,7 @@ namespace etl // Find the month while (true) { - unsigned char days_in_month = etl::chrono::private_chrono::days_in_month[current_month]; + unsigned char days_in_month = etl::chrono::private_chrono::days_in_month[static_cast(current_month)]; if (current_month == etl::chrono::February && current_year.is_leap()) { ++days_in_month; @@ -126,6 +129,9 @@ namespace etl /// Construct from local_days. //************************************************************************* ETL_CONSTEXPR14 year_month_day(const etl::chrono::local_days& ld) ETL_NOEXCEPT + : y(0) + , m(0) + , d(0) { etl::chrono::year_month_day ymd = sys_days(ld.time_since_epoch()); @@ -254,7 +260,7 @@ namespace etl // Add days for months in the current year for (etl::chrono::month mth(1); mth < this->month(); ++mth) { - day_count += private_chrono::days_in_month[mth]; + day_count += private_chrono::days_in_month[static_cast(mth)]; if (mth == etl::chrono::February && this->year().is_leap()) { @@ -289,7 +295,7 @@ namespace etl if (y.ok() && m.ok()) { - count = private_chrono::days_in_month[m]; + count = private_chrono::days_in_month[static_cast(m)]; if (y.is_leap() && (m == February)) { @@ -507,9 +513,9 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 etl::chrono::day day() const ETL_NOEXCEPT { - etl::chrono::day d = etl::chrono::day(etl::chrono::private_chrono::days_in_month[m]); + etl::chrono::day d = etl::chrono::day(etl::chrono::private_chrono::days_in_month[static_cast(m)]); - return (d == 28) && y.is_leap() ? etl::chrono::day(29) : d; + return (d == etl::chrono::day(28)) && y.is_leap() ? etl::chrono::day(29) : d; } //************************************************************************* @@ -788,7 +794,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_day& ymd) const { - etl::chrono::year::rep y = static_cast(static_cast(ymd.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymd.year())); etl::chrono::month::rep m = static_cast(static_cast(ymd.month())); etl::chrono::day::rep d = static_cast(static_cast(ymd.day())); @@ -812,7 +818,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_day_last& ymdl) const { - etl::chrono::year::rep y = static_cast(static_cast(ymdl.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymdl.year())); etl::chrono::month::rep m = static_cast(static_cast(ymdl.month())); etl::chrono::day::rep d = static_cast(static_cast(ymdl.day())); diff --git a/include/etl/private/chrono/year_month_weekday.h b/include/etl/private/chrono/year_month_weekday.h index ef8d9b31..909ff007 100644 --- a/include/etl/private/chrono/year_month_weekday.h +++ b/include/etl/private/chrono/year_month_weekday.h @@ -69,6 +69,9 @@ namespace etl /// Construct from sys_days. //************************************************************************* ETL_CONSTEXPR14 year_month_weekday(const etl::chrono::sys_days& sd) ETL_NOEXCEPT + : y(0) + , m(0U) + , wdi(etl::chrono::weekday(0), 0U) { // Extract year, month, and day year_month_day ymd = year_month_day{sd}; @@ -84,7 +87,7 @@ namespace etl // We walk backward from the given day in steps of 7 days unsigned index = 1; - for (int offset = static_cast(dy) - 7; offset > 0; offset -= 7) + for (int offset = static_cast(static_cast(dy)) - 7; offset > 0; offset -= 7) { ++index; } @@ -98,6 +101,9 @@ namespace etl /// Construct from local_days. //************************************************************************* ETL_CONSTEXPR14 year_month_weekday(const etl::chrono::local_days& ld) ETL_NOEXCEPT + : y(0) + , m(0U) + , wdi(etl::chrono::weekday(0), 0U) { year_month_weekday ymwd(sys_days(ld.time_since_epoch())); @@ -506,7 +512,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_weekday& ymwd) const { - etl::chrono::year::rep y = static_cast(static_cast(ymwd.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymwd.year())); etl::chrono::month::rep m = static_cast(static_cast(ymwd.month())); unsigned int wd = ymwd.weekday().c_encoding(); @@ -530,7 +536,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_weekday_last& ymwdl) const { - etl::chrono::year::rep y = static_cast(static_cast(ymwdl.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymwdl.year())); etl::chrono::month::rep m = static_cast(static_cast(ymwdl.month())); unsigned int wd = ymwdl.weekday().c_encoding(); diff --git a/test/test_chrono_day.cpp b/test/test_chrono_day.cpp index af9dec6c..28d90d2e 100644 --- a/test/test_chrono_day.cpp +++ b/test/test_chrono_day.cpp @@ -240,15 +240,6 @@ namespace } } -#if ETL_USING_ETL_CHRONO - //************************************************************************* - TEST(test_min_max_day) - { - CHECK_EQUAL(1U, Chrono::day::min()); - CHECK_EQUAL(31U, Chrono::day::max()); - } -#endif - #if ETL_USING_ETL_CHRONO //************************************************************************* TEST(test_literal_day) diff --git a/test/test_chrono_month.cpp b/test/test_chrono_month.cpp index 765d018f..d2363528 100644 --- a/test/test_chrono_month.cpp +++ b/test/test_chrono_month.cpp @@ -269,15 +269,6 @@ namespace } } -#if ETL_USING_ETL_CHRONO - //************************************************************************* - TEST(test_min_max_month) - { - CHECK_EQUAL(1U, Chrono::month::min()); - CHECK_EQUAL(12U, Chrono::month::max()); - } -#endif - #if ETL_USING_ETL_CHRONO //************************************************************************* TEST(test_month_compare) diff --git a/test/test_chrono_weekday_last.cpp b/test/test_chrono_weekday_last.cpp index 9b949160..14fefb92 100644 --- a/test/test_chrono_weekday_last.cpp +++ b/test/test_chrono_weekday_last.cpp @@ -59,7 +59,6 @@ namespace //************************************************************************* TEST(test_constructor_in_range) { - for (unsigned i = 1U; i < 5U; ++i) { Chrono::weekday_last weekday_last_monday(Chrono::Monday); Chrono::weekday_last weekday_last_tuesday(Chrono::Tuesday); diff --git a/test/test_chrono_year.cpp b/test/test_chrono_year.cpp index e7ec7904..4bb91b85 100644 --- a/test/test_chrono_year.cpp +++ b/test/test_chrono_year.cpp @@ -71,7 +71,7 @@ namespace etl::chrono::year year(i); CHECK_TRUE(year.ok()); - CHECK_EQUAL(i, int(year)); + CHECK_EQUAL(i, static_cast(year)); } } @@ -87,7 +87,7 @@ namespace etl::chrono::year this_year = ++year; CHECK_TRUE(year.ok()); - CHECK_EQUAL(count, year); + CHECK_EQUAL(count, static_cast(year)); CHECK_EQUAL(this_year, year); } } @@ -226,16 +226,11 @@ namespace //************************************************************************* TEST(test_year_minus_year) { - etl::chrono::year year(256); - etl::chrono::years years(2); - - for (int i = 0; i < 128; ++i) - { - year = years - year; - - CHECK_TRUE(year.ok()); - CHECK_EQUAL((256 - (2 * i)) - 2, int(year)); - } + etl::chrono::year y1(2056); + CHECK_TRUE(y1 - y1 == etl::chrono::years(0)); + etl::chrono::year y2(2); + CHECK_TRUE(y1 - y2 == etl::chrono::years(2054)); + CHECK_TRUE(y2 - y1 == etl::chrono::years(-2054)); } //************************************************************************* @@ -256,8 +251,8 @@ namespace //************************************************************************* TEST(test_min_max_year) { - CHECK_EQUAL(-32767, etl::chrono::year::min()); - CHECK_EQUAL(32767, etl::chrono::year::max()); + CHECK_EQUAL(-32767, static_cast(etl::chrono::year::min())); + CHECK_EQUAL(32767, static_cast(etl::chrono::year::max())); } #endif diff --git a/test/test_chrono_year_month.cpp b/test/test_chrono_year_month.cpp index e016e8c4..556b82ba 100644 --- a/test/test_chrono_year_month.cpp +++ b/test/test_chrono_year_month.cpp @@ -128,7 +128,7 @@ namespace Chrono::year_month ym2{Chrono::year(2001), Chrono::January}; Chrono::year_month ym3{Chrono::year(2000), Chrono::February}; - CHECK_TRUE(ym1 == ym1); // Same year/month/day + CHECK_TRUE(ym1 == ym1); // Same year/month CHECK_FALSE(ym1 == ym2); // Different year CHECK_FALSE(ym1 == ym3); // Different month } @@ -140,9 +140,80 @@ namespace Chrono::year_month ym2{Chrono::year(2001), Chrono::January}; Chrono::year_month ym3{Chrono::year(2000), Chrono::February}; - CHECK_FALSE(ym1 != ym1); // Same year/month/day + CHECK_FALSE(ym1 != ym1); // Same year/month CHECK_TRUE(ym1 != ym2); // Different year CHECK_TRUE(ym1 != ym3); // Different month } + + //************************************************************************* + TEST(test_year_month_relational_operators) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + CHECK_FALSE(ym1 < ym1); // Same year/month + CHECK_TRUE(ym1 <= ym1); + CHECK_FALSE(ym1 > ym1); + CHECK_TRUE(ym1 >= ym1); + + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + CHECK_TRUE(ym1 < ym2); // left year/month strict less + CHECK_TRUE(ym1 <= ym2); + CHECK_FALSE(ym1 > ym2); + CHECK_FALSE(ym1 >= ym2); + + CHECK_FALSE(ym2 < ym1); // left year/month strict greater + CHECK_FALSE(ym2 <= ym1); + CHECK_TRUE(ym2 > ym1); + CHECK_TRUE(ym2 >= ym1); + } + + //************************************************************************* + TEST(test_year_month_year_month_diff_operator) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + Chrono::months dms = ym1 - ym1; + CHECK_EQUAL(dms.count(), 0); + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + dms = ym2 - ym1; // positive + CHECK_EQUAL(dms.count(), (2026 - 2021) * 12 + 11); + dms = ym1 - ym2; // negative + CHECK_EQUAL(dms.count(), (2021 - 2026) * 12 - 11); + } + + //************************************************************************* + TEST(test_year_month_add_sub_months_operators) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + Chrono::months dms(0); // zero + CHECK_TRUE(dms + ym1 == ym1); + CHECK_TRUE(ym1 + dms == ym1); + CHECK_TRUE(ym1 - dms == ym1); + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + dms = ym1 - ym2; // negative + CHECK_TRUE(dms + ym2 == ym1); + CHECK_TRUE(ym2 + dms == ym1); + CHECK_TRUE(ym1 - dms == ym2); + dms = ym2 - ym1; // positive + CHECK_TRUE(dms + ym1 == ym2); + CHECK_TRUE(ym1 + dms == ym2); + CHECK_TRUE(ym2 - dms == ym1); + } + + //************************************************************************* + TEST(test_year_month_add_sub_years_operator) + { + Chrono::year_month ym(Chrono::year(2021), Chrono::January); + Chrono::years dys(0); // zero + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + dys = Chrono::years(-200); // negative + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + dys = Chrono::years(300); // positive + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + } } } diff --git a/test/test_chrono_year_month_day.cpp b/test/test_chrono_year_month_day.cpp index a5710e73..ae698465 100644 --- a/test/test_chrono_year_month_day.cpp +++ b/test/test_chrono_year_month_day.cpp @@ -151,7 +151,7 @@ namespace Chrono::year_month_day ymd{Chrono::sys_days(etl::chrono::days(10997))}; Chrono::year_month_day expected{Chrono::year(2000), Chrono::February, Chrono::day(10)}; - CHECK_EQUAL((unsigned)expected.year(), (unsigned)ymd.year()); + CHECK_EQUAL((int)expected.year(), (int)ymd.year()); CHECK_EQUAL((unsigned)expected.month(), (unsigned)ymd.month()); CHECK_EQUAL((unsigned)expected.day(), (unsigned)ymd.day()); } From 226caa30b5c349b1525667807c1e762c5abec9d6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 16 Jan 2026 09:47:32 +0100 Subject: [PATCH 002/167] Changed ETL_OR_STD:: to etl:: (#1261) Co-authored-by: John Wellbelove --- include/etl/algorithm.h | 2 +- include/etl/private/ivectorpointer.h | 4 ++-- include/etl/vector.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 88b8f7b6..a5879e2c 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -186,7 +186,7 @@ namespace etl { while (first1 != last1) { - iter_swap(first1, first2); + etl::iter_swap(first1, first2); ++first1; ++first2; } diff --git a/include/etl/private/ivectorpointer.h b/include/etl/private/ivectorpointer.h index f9f6dd7e..597fc8ab 100644 --- a/include/etl/private/ivectorpointer.h +++ b/include/etl/private/ivectorpointer.h @@ -483,7 +483,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); @@ -931,7 +931,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); diff --git a/include/etl/vector.h b/include/etl/vector.h index 92caf40c..db6d7d99 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -963,7 +963,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); From 3780070bcf171a20eb382779abf4235c9430c0fa Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 16 Jan 2026 09:51:11 +0100 Subject: [PATCH 003/167] Suppress warnings from std in optimized builds (#1259) When testing with ./run-tests.sh 23 3 10, some warnings from std surfaced which resulted in build errors. --- include/etl/algorithm.h | 2 ++ include/etl/memory.h | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index a5879e2c..74fbb8ed 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -338,7 +338,9 @@ namespace etl template ETL_CONSTEXPR20 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) { +#include "etl/private/diagnostic_array_bounds_push.h" return std::move_backward(sb, se, de); +#include "etl/private/diagnostic_pop.h" } #elif ETL_USING_CPP11 // For C++11 diff --git a/include/etl/memory.h b/include/etl/memory.h index 57b89879..1c282452 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -382,9 +382,13 @@ namespace etl ///\ingroup memory //***************************************************************************** template - TOutputIterator uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) + TOutputIterator uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { +#include "etl/private/diagnostic_array_bounds_push.h" +#include "etl/private/diagnostic_stringop_overflow_push.h" return std::uninitialized_move(i_begin, i_end, o_begin); +#include "etl/private/diagnostic_pop.h" +#include "etl/private/diagnostic_pop.h" } //***************************************************************************** @@ -398,7 +402,9 @@ namespace etl { count += int32_t(etl::distance(i_begin, i_end)); +#include "etl/private/diagnostic_array_bounds_push.h" return std::uninitialized_move(i_begin, i_end, o_begin); +#include "etl/private/diagnostic_pop.h" } #else //***************************************************************************** From 3b1ca75ba2cc6aa313d2589f687b44035091bc92 Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Fri, 16 Jan 2026 03:57:09 -0500 Subject: [PATCH 004/167] Add template deduction guide for span from vector (#1264) * Create span from vector deduction * Use ivector for deduction. Add vector_ext to test * Add vector pointer to test * Finish tests * Initialize pdata_ext and others --- include/etl/span.h | 12 +++++ test/test_span_dynamic_extent.cpp | 87 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/include/etl/span.h b/include/etl/span.h index c6f18799..8f57148f 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -1258,6 +1258,18 @@ namespace etl span(const etl::array&) -> span; + // Forward declaration of etl::ivector + template + class ivector; + + template + span(etl::ivector&) + -> span; + + template + span(const etl::ivector&) + -> span; + #if ETL_USING_STL && ETL_USING_CPP11 template span(std::array&) diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index e9045504..7fc1c8c0 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "etl/span.h" #include "etl/array.h" #include "etl/unaligned_type.h" +#include "etl/vector.h" #include #include @@ -778,6 +779,92 @@ namespace CHECK((std::is_same_v>)); } + //************************************************************************* + TEST(test_template_deduction_guide_for_etl_vector) + { + const size_t max_size = 10; + const size_t size = 4; + + int buffer1[max_size]; + int buffer2[max_size]; + int * buffer3[max_size]; + int * buffer4[max_size]; + const int * buffer5[max_size]; + const int * buffer6[max_size]; + + etl::vector data(size, 0); + const etl::vector data2(size, 0); + etl::vector_ext data_ext(size, 0, buffer1, max_size); + const etl::vector_ext data2_ext(size, 0, buffer2, max_size); + + etl::span span = data; + etl::span span2 = data2; + etl::span span_ext = data_ext; + etl::span span2_ext = data2_ext; + + CHECK_EQUAL(etl::dynamic_extent, span.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data), span.size()); + CHECK_EQUAL(etl::dynamic_extent, span2.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data2), span2.size()); + CHECK_EQUAL(etl::dynamic_extent, span_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data_ext), span_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, span2_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data2_ext), span2_ext.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + + etl::vector pdata(size, nullptr); + const etl::vector pdata2(size, nullptr); + etl::vector pdata3(size, nullptr); + const etl::vector pdata4(size, nullptr); + + etl::span pspan = pdata; + etl::span pspan2 = pdata2; + etl::span pspan3 = pdata3; + etl::span pspan4 = pdata4; + + CHECK_EQUAL(etl::dynamic_extent, pspan.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata), pspan.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan2.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata2), pspan2.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan3.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata3), pspan3.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan4.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata4), pspan4.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + + etl::vector_ext pdata_ext(size, nullptr, buffer3, max_size); + const etl::vector_ext pdata2_ext(size, nullptr, buffer4, max_size); + etl::vector_ext pdata3_ext(size, nullptr, buffer5, max_size); + const etl::vector_ext pdata4_ext(size, nullptr, buffer6, max_size); + + etl::span pspan_ext = pdata_ext; + etl::span pspan2_ext = pdata2_ext; + etl::span pspan3_ext = pdata3_ext; + etl::span pspan4_ext = pdata4_ext; + + CHECK_EQUAL(etl::dynamic_extent, pspan_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata_ext), pspan_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan2_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata2_ext), pspan2_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan3_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata3_ext), pspan3_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan4_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata4_ext), pspan4_ext.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + } + //************************************************************************* TEST(test_template_deduction_guide_for_iterators) { From c92dbc2fced059d790b503699b08673128aa8c2c Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 17 Jan 2026 14:26:16 +0100 Subject: [PATCH 005/167] Document how to implement platform specifics (#1262) Some interfaces need to be implemented in every project or platform using the ETL: * etl_get_high_resolution_clock * etl_get_system_clock * etl_get_steady_clock * etl_putchar Co-authored-by: John Wellbelove --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/README.md b/README.md index e9c9da8a..a4c26bdc 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,84 @@ add_executable(foo main.cpp) target_link_libraries(foo PRIVATE etl::etl) ``` +## Profile definition + +When using ETL in a project, there is typically an `etl_profile.h` defined to +adjust ETL to the project needs. ETL will automatically find `etl_profile.h` +if it is available in the include path(s). If it's not available, ETL will +work with default values. + +### Example + +``` +#ifndef __ETL_PROFILE_H__ +#define __ETL_PROFILE_H__ + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE + +#define ETL_NO_STL + +#endif +``` + +## Platform specific implementation + +Although ETL is generally a self-contained header-only library, some interfaces need to be +implemented in every project or platform, at least if those interfaces are actually being +used, due to project specifics: + +| ETL header | Platform specific API to be implemented | Needed when using | +|------------|-----------------------------------------|-------------------------------------| +| `chrono.h` | `etl_get_high_resolution_clock()` | `etl::high_resolution_clock::now()` | +| | `etl_get_system_clock()` | `etl::system_clock::now()` | +| | `etl_get_steady_clock()` | `etl::steady_clock::now()` | +| `print.h` | `etl_putchar()` | `etl::print()` | +| | | `etl::println()` | + +### Example + +``` +#include +#include + +extern "C" +{ + +etl::chrono::high_resolution_clock::rep etl_get_high_resolution_clock() +{ + etl::chrono::high_resolution_clock::rep(static_cast(getSystemTimeNs())); +} + +etl::chrono::system_clock::rep etl_get_system_clock() +{ + return etl::chrono::system_clock::rep(static_cast(getSystemTimeNs())); +} + +etl::chrono::system_clock::rep etl_get_steady_clock() +{ + return etl::chrono::system_clock::rep(static_cast(getSystemTimeNs())); +} + +void etl_putchar(int c) +{ + putByteToStdout(static_cast(c)); +} + +} +``` + +The following default values apply if the respective macros are not defined +(e.g. in `etl_profile.h`): + +| Macro | Default | +|-----------------------------------------------|----------------------------| +| `ETL_CHRONO_SYSTEM_CLOCK_DURATION` | `etl::chrono::nanoseconds` | +| `ETL_CHRONO_SYSTEM_CLOCK_IS_STEADY` | `true` | +| `ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION` | `etl::chrono::nanoseconds` | +| `ETL_CHRONO_HIGH_RESOLUTION_CLOCK_IS_STEADY` | `true` | +| `ETL_CHRONO_STEADY_CLOCK_DURATION` | `etl::chrono::nanoseconds` | + ## Arduino library The content of this repo is available as a library in the Arduino IDE (search for the "Embedded Template Library" in the IDE library manager). The Arduino library repository is available at ```https://github.com/ETLCPP/etl-arduino```, see there for more details. From 55503e0b97dc84087cf8fff6676cb51f6447b81d Mon Sep 17 00:00:00 2001 From: taltenbach <92919739+taltenbach@users.noreply.github.com> Date: Sat, 17 Jan 2026 23:04:52 +0100 Subject: [PATCH 006/167] Fix etl::as_bytes for etl::span (#1266) A missing 'const' in the etl::as_bytes implementation was causing a compile-time error when etl::as_bytes was called on a span of const values. Co-authored-by: John Wellbelove --- include/etl/span.h | 2 +- test/test_span_dynamic_extent.cpp | 3 ++- test/test_span_fixed_extent.cpp | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/etl/span.h b/include/etl/span.h index 8f57148f..5d03632a 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -1303,7 +1303,7 @@ namespace etl span as_bytes(span s) ETL_NOEXCEPT { - return span(reinterpret_cast(s.data()), s.size_bytes()); + return span(reinterpret_cast(s.data()), s.size_bytes()); } //************************************************************************* diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index 7fc1c8c0..586eadcb 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -1325,8 +1325,9 @@ namespace TEST(test_convert_span_any_to_span_byte) { float data[2]{3.141592f, 2.71828f }; + const float const_data[2]{3.141592f, 2.71828f }; - auto const const_bytes = etl::as_bytes(etl::span{data}); + auto const const_bytes = etl::as_bytes(etl::span{const_data}); auto const writable_bytes = etl::as_writable_bytes(etl::span{data}); CHECK_EQUAL(const_bytes.size(), sizeof(data)); diff --git a/test/test_span_fixed_extent.cpp b/test/test_span_fixed_extent.cpp index 137bd9b8..a1825c2c 100644 --- a/test/test_span_fixed_extent.cpp +++ b/test/test_span_fixed_extent.cpp @@ -1163,12 +1163,13 @@ namespace TEST(test_convert_span_any_to_span_byte) { float data[2]{3.141592f, 2.71828f}; + const float const_data[2]{3.141592f, 2.71828f}; #if ETL_USING_CPP17 - auto const const_bytes = etl::as_bytes(etl::span{ data }); + auto const const_bytes = etl::as_bytes(etl::span{ const_data }); auto const writable_bytes = etl::as_writable_bytes(etl::span{ data }); #else - auto const const_bytes = etl::as_bytes(etl::span(data)); + auto const const_bytes = etl::as_bytes(etl::span(const_data)); auto const writable_bytes = etl::as_writable_bytes(etl::span(data)); #endif From a1744add1f14c3debc91de370daaa2a51f490c6c Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 20 Jan 2026 10:35:02 +0100 Subject: [PATCH 007/167] Remove AppVeyor build status badge Removed AppVeyor build status badge from README. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e9c9da8a..43da4261 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ Embedded Template Library (ETL) ![GitHub Repo stars](https://img.shields.io/github/stars/ETLCPP/etl?style=flat) ![CI](https://github.com/ETLCPP/etl/actions/workflows/msvc.yml/badge.svg?branch=master) -[![Build status](https://ci.appveyor.com/api/projects/status/b7jgecv7unqjw4u0/branch/master?svg=true)](https://ci.appveyor.com/project/jwellbelove/etl/branch/master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++11.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++14.yml/badge.svg?branch=master) From 142dff245ccf0826318815a79a1faf5c1c4daa39 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 20 Jan 2026 10:53:08 +0100 Subject: [PATCH 008/167] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 43da4261..a762e43f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Embedded Template Library (ETL) -------------------------- +# ![alt text](https://github.com/ETLCPP/etl/blob/master/images/etl64.png?raw=true) Embedded Template Library (ETL) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/jwellbelove/etl) [![Release date](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3)](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3) From 1b1145ea4eb7928c2866720b86b834ac0f0563e2 Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:15:38 +0100 Subject: [PATCH 009/167] Remove some UB in test_vector_non_trivial.cpp (#1268) Some of the tests' UB are detectable by Gcc15 and thus give a compile error due to warnings-as-error flag. Co-authored-by: John Wellbelove --- test/test_vector_non_trivial.cpp | 41 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/test/test_vector_non_trivial.cpp b/test/test_vector_non_trivial.cpp index 1a10ac77..99772202 100644 --- a/test/test_vector_non_trivial.cpp +++ b/test/test_vector_non_trivial.cpp @@ -964,8 +964,9 @@ namespace DataNDC data; data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); - DataNDC data2; - CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + DataNDC::iterator it = data.begin(); + --it; + CHECK_THROW(data.insert(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1002,19 +1003,34 @@ namespace const std::string INITIAL_VALUE("1"); DataNDC data; - DataNDC data2; data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); - CHECK_THROW(data.emplace(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + DataNDC::const_iterator it = data.cend(); + ++it; + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* - TEST(test_emplace_out_of_range) + TEST(test_emplace_out_of_range_past_end) { DataNDC data; - DataNDC data2; + DataNDC::iterator it = data.end(); + ++it; + const std::string INITIAL_VALUE("1"); - CHECK_THROW(data.emplace(data2.end(), INITIAL_VALUE);, etl::vector_out_of_bounds); + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); + } + + //************************************************************************* + TEST(test_emplace_out_of_range_before_begin) + { + DataNDC data; + DataNDC::iterator it = data.begin(); + --it; + + const std::string INITIAL_VALUE("1"); + + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1072,10 +1088,11 @@ namespace TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) { DataNDC data; - DataNDC data2; + DataNDC::const_iterator it = data.cend(); + ++it; const NDC INITIAL_VALUE("1"); - CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds); + CHECK_THROW(data.insert(it, 1, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1163,7 +1180,7 @@ namespace DataNDC data; DataNDC data2; - CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend()), etl::vector_out_of_bounds); } //************************************************************************* @@ -1190,7 +1207,7 @@ namespace { DataNDC data(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + CHECK_THROW(data.erase(data.end()), etl::vector_out_of_bounds); } //************************************************************************* @@ -1218,7 +1235,7 @@ namespace DataNDC data(initial_data.begin(), initial_data.end()); DataNDC data2(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + CHECK_THROW(data.erase(data2.begin(), data2.end()), etl::vector_out_of_bounds); } //************************************************************************* From 2c78c3d151e8bc15ef124e9d68215fb94117c1e9 Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:36:14 +0100 Subject: [PATCH 010/167] Update C++26 deprecated constructs to ensure future standard compliance (#1267) * Update C++26 deprecated constructs to ensure future standard compliance I replaced std::is_trivial with a combination of std::is_trivially_default_constructible and std::is_trivially_copyable. Additionally, I added the required comma before the ellipsis in variadic functions to match updated language specifications. * Some additional is_trivial related changes not found directly when compiling tests in C++26 --------- Co-authored-by: John Wellbelove --- include/etl/generators/type_traits_generator.h | 4 ++-- include/etl/type_traits.h | 4 ++-- test/test_successor.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index 68c937f8..1588544f 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -1227,11 +1227,11 @@ typedef integral_constant true_type; /// is_pod ///\ingroup type_traits template - struct is_pod : std::integral_constant::value && std::is_trivial::value> {}; + struct is_pod : std::integral_constant::value && std::is_trivially_default_constructible::value && std::is_trivially_copyable::value> {}; #if ETL_USING_CPP17 template - inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivial_v; + inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivially_default_constructible_v && std::is_trivially_copyable_v; #endif #if defined(ETL_COMPILER_GCC) diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 26cd6aef..524b74eb 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -1215,11 +1215,11 @@ typedef integral_constant true_type; /// is_pod ///\ingroup type_traits template - struct is_pod : std::integral_constant::value && std::is_trivial::value> {}; + struct is_pod : std::integral_constant::value && std::is_trivially_default_constructible::value && std::is_trivially_copyable::value> {}; #if ETL_USING_CPP17 template - inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivial_v; + inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivially_default_constructible_v && std::is_trivially_copyable_v; #endif #if defined(ETL_COMPILER_GCC) diff --git a/test/test_successor.cpp b/test/test_successor.cpp index 2e42c0d1..ebbd1300 100644 --- a/test/test_successor.cpp +++ b/test/test_successor.cpp @@ -39,7 +39,7 @@ namespace { } - SuccessorBase(SuccessorBase& successors...) + SuccessorBase(SuccessorBase& successors, ...) : successor(successors) { } @@ -55,7 +55,7 @@ namespace { } - SuccessorSameBase1(SuccessorBase& successors...) + SuccessorSameBase1(SuccessorBase& successors, ...) : SuccessorBase(successors) , value(0) { From fcd50486ce9e6249acb44f3f23ce878852024fc9 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 21 Jan 2026 09:00:51 +0100 Subject: [PATCH 011/167] Update CONTRIBUTING.md Updated the instructions for contributing. --- CONTRIBUTING.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 693910fe..6231d084 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,16 @@ # How to contribute -If your are considering creating a pull request, please observe the following: +Thanks for considering a contribution! Here’s what you need to know before opening a pull request: - If you are adding or modifying a feature, add *new* unit tests that test that feature. - If you are fixing a bug, add a unit test that *fails* before the bug fix is implemented. -- Do not initiate a pull request until all of the units tests pass. -- Branches should be based on the branch `master`. +- Do not initiate a pull request until all of the units tests pass. See below for information on project files and test scripts. +- Branches should be based on the branch `master`. If `development` has pending updates, I’ll rebase the PR against it before pulling.. -There is a project file for VS2022 for C++14, 17, 20, and bash scripts that run the tests for C++11, 14, 17, 20 under Linux with GCC and Clang. +There is a project file for VS2022 for C++14, 17, 20, 23, and bash scripts that run the tests for C++11, 14, 17, 20, 23 under Linux with GCC and Clang. +There are syntax-only check bash scripts that cover C++03, 11, 14, 17, 20, 23 under Linux with GCC and Clang. If you are thinking of adding a new feature then raise this on the GitHub Issues page for discussion as the maintainers and user of the ETL may have questions or suggestions. -It is possible that the maintainer of the ETL or another contributor is already working on the same or a related feature. +It is possible that the maintainer of the ETL or another contributor is already working on the same or a related feature. + +Take a look through our current issues and see if anything sparks your interest! From 2cae4966205e7c01a498afb03bddc4a1bc9a60de Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 21 Jan 2026 09:26:48 +0100 Subject: [PATCH 012/167] Added etl::type_list to etl::observer --- include/etl/observer.h | 14 ++++++ test/test_observer.cpp | 107 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/include/etl/observer.h b/include/etl/observer.h index 3e915a59..133f8392 100644 --- a/include/etl/observer.h +++ b/include/etl/observer.h @@ -57,6 +57,7 @@ SOFTWARE. #include "exception.h" #include "error_handler.h" #include "utility.h" +#include "type_list.h" namespace etl { @@ -338,6 +339,19 @@ namespace etl virtual void notification() = 0; }; + //***************************************************************** + /// The observer class for N types. + /// Configured from a type list. + ///\ingroup observer + //***************************************************************** + template + class observer> : public observer + { + public: + + using observer::notification; + }; + #else //********************************************************************* diff --git a/test/test_observer.cpp b/test/test_observer.cpp index bf08e17b..5ae52139 100644 --- a/test/test_observer.cpp +++ b/test/test_observer.cpp @@ -68,12 +68,24 @@ namespace // The Notification2 is passed by reference. // The Notification3 is passed by const reference. //***************************************************************************** - typedef etl::observer ObserverType; + using ObserverType = etl::observer; + +#if !defined(ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION) + //***************************************************************************** + // The observer base type. + // Declare what notifications you want to observe and how they are passed to 'notification'. + // The Notification1 is passed by value. + // The Notification2 is passed by reference. + // The Notification3 is passed by const reference. + //***************************************************************************** + using NotificationList = etl::type_list; + using ObserverTypeFromTypeList = etl::observer; +#endif //***************************************************************************** // The observer base type that does not take a notification type. //***************************************************************************** - typedef etl::observer ObserverVoidIntType; + using ObserverVoidIntType = etl::observer; } //***************************************************************************** @@ -115,6 +127,29 @@ public: } }; +#if !defined(ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION) +//***************************************************************************** +// The concrete observable 3 class. +//***************************************************************************** +class Observable3 : public etl::observable +{ +public: + + Notification1 data1; + Notification2 data2; + Notification1& data3 = data1; + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(data3); + notify_observers(data2); + } +}; +#endif + //***************************************************************************** // The concrete observable 3 class. //***************************************************************************** @@ -229,6 +264,53 @@ public: int data3_count; }; +#if !defined(ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION) +//***************************************************************************** +// The third observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class Observer3 : public ObserverTypeFromTypeList +{ +public: + + Observer3() + : data1_count(0) + , data2_count(0) + , data3_count(0) + { + } + + //******************************************* + // Notification1 is passed by value. + //******************************************* + void notification(Notification1 /*data1*/) + { + ++data1_count; + } + + //******************************************* + // Notification2 is passed by reference. + //******************************************* + void notification(Notification2& /*data2*/) + { + ++data2_count; + } + + //******************************************* + // Notification3 is passed by const reference. + //******************************************* + void notification(const Notification3& /*data3*/) + { + ++data3_count; + } + + int data1_count; + int data2_count; + int data3_count; +}; +#endif + //***************************************************************************** // The third observer type. // If any one of the overloads is missing or a parameter declaration is incorrect @@ -399,6 +481,27 @@ namespace CHECK_EQUAL(3, observer2.data1_count); } +#if !defined(ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + TEST(test_observer_created_from_a_type_list) + { + // The observable objects. + Observable3 observable3; + + // The observer objects. + Observer3 observer3; + + observable3.add_observer(observer3); + + // Send the notifications. + observable3.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(1, observer3.data1_count); + CHECK_EQUAL(1, observer3.data2_count); + CHECK_EQUAL(0, observer3.data3_count); + } +#endif + //************************************************************************* TEST(test_8_notifications) { From 2862b3b247abb2727ea6724bd456879e2bfdb111 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 21 Jan 2026 09:50:15 +0100 Subject: [PATCH 013/167] Added etl::type_list to etl::nth_type --- include/etl/nth_type.h | 8 ++++++++ test/test_nth_type.cpp | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/etl/nth_type.h b/include/etl/nth_type.h index 01f2a6e8..20c4d2d9 100644 --- a/include/etl/nth_type.h +++ b/include/etl/nth_type.h @@ -31,6 +31,7 @@ SOFTWARE. #include "platform.h" #include "static_assert.h" +#include "type_list.h" #if ETL_USING_CPP11 namespace etl @@ -60,6 +61,13 @@ namespace etl using type = typename private_nth_type::nth_type_helper::type; }; + //*********************************** + template + struct nth_type> : public nth_type + { + using nth_type::type; + }; + //*********************************** template using nth_type_t = typename nth_type::type; diff --git a/test/test_nth_type.cpp b/test/test_nth_type.cpp index a5339292..843d7607 100644 --- a/test/test_nth_type.cpp +++ b/test/test_nth_type.cpp @@ -29,6 +29,7 @@ SOFTWARE. #include "unit_test_framework.h" #include "etl/nth_type.h" +#include "etl/type_list.h" #include namespace @@ -42,5 +43,15 @@ namespace CHECK((std::is_same, long>::value)); CHECK((std::is_same, double>::value)); } + + //************************************************************************* + TEST(test_nth_type_from_type_list) + { + using types = etl::type_list; + + CHECK((std::is_same, int>::value)); + CHECK((std::is_same, long>::value)); + CHECK((std::is_same, double>::value)); + } } } From 01a0b6391957fa31b14d3a1cc8473fe2137ee4f7 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 21 Jan 2026 11:26:14 +0100 Subject: [PATCH 014/167] Added missing 'typename' to type_list nth_type --- include/etl/nth_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/etl/nth_type.h b/include/etl/nth_type.h index 20c4d2d9..a38a25f5 100644 --- a/include/etl/nth_type.h +++ b/include/etl/nth_type.h @@ -65,7 +65,7 @@ namespace etl template struct nth_type> : public nth_type { - using nth_type::type; + using typename nth_type::type; }; //*********************************** From b82bf3b79d06d1b211d7fb0775eda4f86466ed1a Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:40:19 -0500 Subject: [PATCH 015/167] Fix return value of get_token_list (#1271) Co-authored-by: John Wellbelove --- include/etl/string_utilities.h | 6 ++--- test/test_string_utilities.cpp | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/etl/string_utilities.h b/include/etl/string_utilities.h index d20225c9..64e0365e 100644 --- a/include/etl/string_utilities.h +++ b/include/etl/string_utilities.h @@ -782,9 +782,9 @@ namespace etl etl::optional token; size_t count = 0; - while ((count != output.max_size()) && - (count != max_n_tokens) && - (token = etl::get_token(input, delimiters, token, ignore_empty_tokens))) + while ((token = etl::get_token(input, delimiters, token, ignore_empty_tokens)) && + (count != output.max_size()) && + (count != max_n_tokens)) { output.push_back(token.value()); ++count; diff --git a/test/test_string_utilities.cpp b/test/test_string_utilities.cpp index 0f450da3..a5df21ec 100644 --- a/test/test_string_utilities.cpp +++ b/test/test_string_utilities.cpp @@ -1115,6 +1115,48 @@ namespace CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); } + //************************************************************************* + //before the issue fix, + //the return value was false when output vector max size equaled the number of tokens + //it should be true + TEST(test_issue_1270_output_vector_max_size_equals_num_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + etl::vector views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } + + //************************************************************************* + //before the issue fix, + //the return value was false when max number of tokens equaled the number of tokens + //it should be true + TEST(test_issue_1270_max_tokens_equals_num_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + VectorOfViews7 views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true, 6); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } + //************************************************************************* TEST(test_get_token_list_to_vector_of_string_view_all_but_1_tokens_captured_ignore_empty_tokens) { From f9dc1caa94e67738f512cb9cc5dcf21cc457a2d3 Mon Sep 17 00:00:00 2001 From: Bryton Flecker Date: Wed, 21 Jan 2026 22:30:20 -0600 Subject: [PATCH 016/167] Fix etl::tuple template signature error in pair assignment operator (#1265) * Fix etl::tuple template signature error in pair assignment operator * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update etl::tuple to explicitly use etl::pair or std::pair in assignment operator * Added tests for etl::tuple assignment from pair --------- Co-authored-by: Bryton Flecker Co-authored-by: John Wellbelove --- README.md | 4 +-- include/etl/tuple.h | 20 +++++++-------- test/test_tuple.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a4c26bdc..c199268c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Embedded Template Library (ETL) -------------------------- +# ![alt text](https://github.com/ETLCPP/etl/blob/master/images/etl64.png?raw=true) Embedded Template Library (ETL) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/jwellbelove/etl) [![Release date](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3)](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3) @@ -10,7 +9,6 @@ Embedded Template Library (ETL) ![GitHub Repo stars](https://img.shields.io/github/stars/ETLCPP/etl?style=flat) ![CI](https://github.com/ETLCPP/etl/actions/workflows/msvc.yml/badge.svg?branch=master) -[![Build status](https://ci.appveyor.com/api/projects/status/b7jgecv7unqjw4u0/branch/master?svg=true)](https://ci.appveyor.com/project/jwellbelove/etl/branch/master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++11.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++14.yml/badge.svg?branch=master) diff --git a/include/etl/tuple.h b/include/etl/tuple.h index c4a9440b..ffc6db11 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -559,9 +559,9 @@ namespace etl //********************************* /// Assign from lvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(pair& p) + tuple& operator =(ETL_OR_STD::pair& p) { get_value() = p.first; get_base().get_value() = p.second; @@ -572,9 +572,9 @@ namespace etl //********************************* /// Assign from const lvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(const pair& p) + tuple& operator =(const ETL_OR_STD::pair& p) { get_value() = p.first; get_base().get_value() = p.second; @@ -585,9 +585,9 @@ namespace etl //********************************* /// Assign from rvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(pair&& p) + tuple& operator =(ETL_OR_STD::pair&& p) { get_value() = etl::forward(p.first); get_base().get_value() = etl::forward(p.second); @@ -598,12 +598,12 @@ namespace etl //********************************* /// Assign from const rvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(const pair&& p) + tuple& operator =(const ETL_OR_STD::pair&& p) { - get_value() = etl::forward(p.first); - get_base().get_value() = etl::forward(p.second); + get_value() = p.first; + get_base().get_value() = p.second; return *this; } diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index 01a4ca1f..1a292dcc 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -756,5 +756,67 @@ namespace CHECK_EQUAL(etl::get<2>(tp), s); } #endif + + //************************************************************************* + TEST(test_assign_from_lvalue_pair) + { + ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = p; + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_const_lvalue_pair) + { + const ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = p; + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_rvalue_pair) + { + etl::tuple tp(0, Data("")); + + tp = ETL_OR_STD::pair(1, Data("2")); + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_const_rvalue_pair) + { + const ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = static_cast&&>(p); + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } } } From c600605734360f851347e0caa61c81c078886ad9 Mon Sep 17 00:00:00 2001 From: Sergei Date: Thu, 22 Jan 2026 11:22:23 +0200 Subject: [PATCH 017/167] Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. --- include/etl/bip_buffer_spsc_atomic.h | 3 + test/test_bip_buffer_spsc_atomic.cpp | 119 +++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/include/etl/bip_buffer_spsc_atomic.h b/include/etl/bip_buffer_spsc_atomic.h index 14d03ca2..9a557eae 100644 --- a/include/etl/bip_buffer_spsc_atomic.h +++ b/include/etl/bip_buffer_spsc_atomic.h @@ -281,6 +281,9 @@ namespace etl else { ETL_ASSERT_OR_RETURN((windex == 0) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid)); + + // Correct wrapping point + last.store(write_index, etl::memory_order_release); } // Always update write index diff --git a/test/test_bip_buffer_spsc_atomic.cpp b/test/test_bip_buffer_spsc_atomic.cpp index 9711685d..c5f3aec5 100644 --- a/test/test_bip_buffer_spsc_atomic.cpp +++ b/test/test_bip_buffer_spsc_atomic.cpp @@ -28,6 +28,8 @@ SOFTWARE. #include "unit_test_framework.h" +#include +#include #include #include #include @@ -332,6 +334,123 @@ namespace CHECK(stream.empty()); } + //************************************************************************* + TEST(test_optimal_write_issue_1276) + { + etl::bip_buffer_spsc_atomic stream; + etl::ibip_buffer_spsc_atomic& istream = stream; + + // 1. Make all `read`, `write` and `last` in the end of the buffer. + { + const auto writer = istream.write_reserve_optimal(5); + CHECK_EQUAL(5U, writer.size()); + writer[0] = '0'; + writer[1] = '1'; + writer[2] = '2'; + writer[3] = '3'; + writer[4] = '4'; + CHECK_NO_THROW(istream.write_commit(writer)); // [0 1 2 3 4] + const auto reader = istream.read_reserve(); + CHECK_EQUAL(5U, reader.size()); + CHECK_NO_THROW(istream.read_commit(reader)); // * * * * *[] + } + // 2. Write & read 4 bytes. + { + const auto writer = istream.write_reserve_optimal(4); + CHECK_EQUAL(4U, writer.size()); + writer[0] = '5'; + writer[1] = '6'; + writer[2] = '7'; + writer[3] = '8'; + CHECK_NO_THROW(istream.write_commit(writer.subspan(0U, 4U))); // 5 6 7 8] *[ + + const auto reader = istream.read_reserve(); + CHECK_EQUAL(4U, reader.size()); + CHECK_EQUAL('5', reader[0]); + CHECK_EQUAL('6', reader[1]); + CHECK_EQUAL('7', reader[2]); + CHECK_EQUAL('8', reader[3]); + CHECK_NO_THROW(istream.read_commit(reader)); // * * * *[]* + } + // 3. Write and read 2 bytes. + { + const auto writer = istream.write_reserve_optimal(2); + CHECK_EQUAL(3U, writer.size()); + writer[0] = '9'; + writer[1] = 'A'; + CHECK_NO_THROW(istream.write_commit(writer.subspan(0, 2))); // 9 A]* *[* + + const auto reader = istream.read_reserve(); + CHECK_EQUAL(2U, reader.size()); + CHECK_EQUAL('9', reader[0]); + CHECK_EQUAL('A', reader[1]); + } + } + + //************************************************************************* + TEST(test_write_random_back_pressure) + { + // Deliberately seeded with fixed number, so that if it fails then always in the same way. + std::mt19937 mte(123); + + constexpr size_t N = 256; + etl::bip_buffer_spsc_atomic stream; + etl::ibip_buffer_spsc_atomic& istream = stream; + + auto makeRandomNumber = [&mte](const size_t n) -> size_t { return mte() % n; }; + + auto verifyIota = [&](const etl::span& seq) + { + if (!seq.empty()) + { + auto prev = seq[0]; + for (auto i = 1U; i < seq.size(); ++i) + { + const auto curr = seq[i]; + if (prev > curr) + { + CHECK(prev <= curr); + std::cerr << "prev(" << prev << ") should not be bigger than curr(" << curr << ")!\n"; + } + prev = curr; + } + } + }; + + const auto all = istream.write_reserve(N); + CHECK_EQUAL(N, all.size()); + std::fill_n(all.begin(), all.size(), 0); + + int iota = 0; + // Loop writing a bit more than reading. + // 10K iterations is enough to detect 2 failures. + for (int i = 0; i < 10000; ++i) + { + // Write [0...N/16] chunks - on average N/32. + { + const size_t toWrite = makeRandomNumber(N / 16 + 1); + const auto reserve = istream.write_reserve(toWrite); + if (reserve.size() >= toWrite) + { + ++iota; + const auto written = makeRandomNumber(toWrite + 1); + std::fill_n(reserve.begin(), written, iota); + istream.write_commit(reserve.first(written)); + verifyIota(reserve.first(written)); + } + } + + // Read a bit less [0...N/17] chunks - on average N/34. + if (const size_t toRead = makeRandomNumber(N / 17 + 1)) + { + const auto reserve = istream.read_reserve(toRead); + verifyIota(reserve); + const auto read = makeRandomNumber(reserve.size() + 1); + istream.read_commit(reserve.first(read)); + } + } + } + //************************************************************************* #if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT) #if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported From af1caa88fd1f2da58ed6b6fb67f0a64da7e4f347 Mon Sep 17 00:00:00 2001 From: Sergei Date: Thu, 22 Jan 2026 11:22:23 +0200 Subject: [PATCH 018/167] Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. --- include/etl/bip_buffer_spsc_atomic.h | 3 + test/test_bip_buffer_spsc_atomic.cpp | 119 +++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/include/etl/bip_buffer_spsc_atomic.h b/include/etl/bip_buffer_spsc_atomic.h index 14d03ca2..9a557eae 100644 --- a/include/etl/bip_buffer_spsc_atomic.h +++ b/include/etl/bip_buffer_spsc_atomic.h @@ -281,6 +281,9 @@ namespace etl else { ETL_ASSERT_OR_RETURN((windex == 0) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid)); + + // Correct wrapping point + last.store(write_index, etl::memory_order_release); } // Always update write index diff --git a/test/test_bip_buffer_spsc_atomic.cpp b/test/test_bip_buffer_spsc_atomic.cpp index 9711685d..c5f3aec5 100644 --- a/test/test_bip_buffer_spsc_atomic.cpp +++ b/test/test_bip_buffer_spsc_atomic.cpp @@ -28,6 +28,8 @@ SOFTWARE. #include "unit_test_framework.h" +#include +#include #include #include #include @@ -332,6 +334,123 @@ namespace CHECK(stream.empty()); } + //************************************************************************* + TEST(test_optimal_write_issue_1276) + { + etl::bip_buffer_spsc_atomic stream; + etl::ibip_buffer_spsc_atomic& istream = stream; + + // 1. Make all `read`, `write` and `last` in the end of the buffer. + { + const auto writer = istream.write_reserve_optimal(5); + CHECK_EQUAL(5U, writer.size()); + writer[0] = '0'; + writer[1] = '1'; + writer[2] = '2'; + writer[3] = '3'; + writer[4] = '4'; + CHECK_NO_THROW(istream.write_commit(writer)); // [0 1 2 3 4] + const auto reader = istream.read_reserve(); + CHECK_EQUAL(5U, reader.size()); + CHECK_NO_THROW(istream.read_commit(reader)); // * * * * *[] + } + // 2. Write & read 4 bytes. + { + const auto writer = istream.write_reserve_optimal(4); + CHECK_EQUAL(4U, writer.size()); + writer[0] = '5'; + writer[1] = '6'; + writer[2] = '7'; + writer[3] = '8'; + CHECK_NO_THROW(istream.write_commit(writer.subspan(0U, 4U))); // 5 6 7 8] *[ + + const auto reader = istream.read_reserve(); + CHECK_EQUAL(4U, reader.size()); + CHECK_EQUAL('5', reader[0]); + CHECK_EQUAL('6', reader[1]); + CHECK_EQUAL('7', reader[2]); + CHECK_EQUAL('8', reader[3]); + CHECK_NO_THROW(istream.read_commit(reader)); // * * * *[]* + } + // 3. Write and read 2 bytes. + { + const auto writer = istream.write_reserve_optimal(2); + CHECK_EQUAL(3U, writer.size()); + writer[0] = '9'; + writer[1] = 'A'; + CHECK_NO_THROW(istream.write_commit(writer.subspan(0, 2))); // 9 A]* *[* + + const auto reader = istream.read_reserve(); + CHECK_EQUAL(2U, reader.size()); + CHECK_EQUAL('9', reader[0]); + CHECK_EQUAL('A', reader[1]); + } + } + + //************************************************************************* + TEST(test_write_random_back_pressure) + { + // Deliberately seeded with fixed number, so that if it fails then always in the same way. + std::mt19937 mte(123); + + constexpr size_t N = 256; + etl::bip_buffer_spsc_atomic stream; + etl::ibip_buffer_spsc_atomic& istream = stream; + + auto makeRandomNumber = [&mte](const size_t n) -> size_t { return mte() % n; }; + + auto verifyIota = [&](const etl::span& seq) + { + if (!seq.empty()) + { + auto prev = seq[0]; + for (auto i = 1U; i < seq.size(); ++i) + { + const auto curr = seq[i]; + if (prev > curr) + { + CHECK(prev <= curr); + std::cerr << "prev(" << prev << ") should not be bigger than curr(" << curr << ")!\n"; + } + prev = curr; + } + } + }; + + const auto all = istream.write_reserve(N); + CHECK_EQUAL(N, all.size()); + std::fill_n(all.begin(), all.size(), 0); + + int iota = 0; + // Loop writing a bit more than reading. + // 10K iterations is enough to detect 2 failures. + for (int i = 0; i < 10000; ++i) + { + // Write [0...N/16] chunks - on average N/32. + { + const size_t toWrite = makeRandomNumber(N / 16 + 1); + const auto reserve = istream.write_reserve(toWrite); + if (reserve.size() >= toWrite) + { + ++iota; + const auto written = makeRandomNumber(toWrite + 1); + std::fill_n(reserve.begin(), written, iota); + istream.write_commit(reserve.first(written)); + verifyIota(reserve.first(written)); + } + } + + // Read a bit less [0...N/17] chunks - on average N/34. + if (const size_t toRead = makeRandomNumber(N / 17 + 1)) + { + const auto reserve = istream.read_reserve(toRead); + verifyIota(reserve); + const auto read = makeRandomNumber(reserve.size() + 1); + istream.read_commit(reserve.first(read)); + } + } + } + //************************************************************************* #if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT) #if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported From 9757860241d6a57e27abd32fab14d0e2d015ec4f Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 23 Jan 2026 19:33:08 +0100 Subject: [PATCH 019/167] Remove advance() on static spans (#1281) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Remove advance() on static spans Since the size of a static span is constant, we can't reasonably advance() on it. --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- CONTRIBUTING.md | 13 ++++++++----- include/etl/span.h | 10 ---------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 693910fe..6231d084 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,16 @@ # How to contribute -If your are considering creating a pull request, please observe the following: +Thanks for considering a contribution! Here’s what you need to know before opening a pull request: - If you are adding or modifying a feature, add *new* unit tests that test that feature. - If you are fixing a bug, add a unit test that *fails* before the bug fix is implemented. -- Do not initiate a pull request until all of the units tests pass. -- Branches should be based on the branch `master`. +- Do not initiate a pull request until all of the units tests pass. See below for information on project files and test scripts. +- Branches should be based on the branch `master`. If `development` has pending updates, I’ll rebase the PR against it before pulling.. -There is a project file for VS2022 for C++14, 17, 20, and bash scripts that run the tests for C++11, 14, 17, 20 under Linux with GCC and Clang. +There is a project file for VS2022 for C++14, 17, 20, 23, and bash scripts that run the tests for C++11, 14, 17, 20, 23 under Linux with GCC and Clang. +There are syntax-only check bash scripts that cover C++03, 11, 14, 17, 20, 23 under Linux with GCC and Clang. If you are thinking of adding a new feature then raise this on the GitHub Issues page for discussion as the maintainers and user of the ETL may have questions or suggestions. -It is possible that the maintainer of the ETL or another contributor is already working on the same or a related feature. +It is possible that the maintainer of the ETL or another contributor is already working on the same or a related feature. + +Take a look through our current issues and see if anything sparks your interest! diff --git a/include/etl/span.h b/include/etl/span.h index 5d03632a..c60a9125 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -605,16 +605,6 @@ namespace etl #endif } - //************************************************************************* - /// Moves the pointer to the first element of the span further by a specified number of elements. - ///\tparam elements Number of elements to move forward - //************************************************************************* - void advance(size_t elements) ETL_NOEXCEPT - { - elements = etl::min(elements, size()); - pbegin += elements; - } - //************************************************************************* /// Reinterpret the span as a span with different element type. //************************************************************************* From 682b1e7011c8cd75f988e85eb9be878539f24216 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 25 Jan 2026 11:09:59 +0100 Subject: [PATCH 020/167] Added type_list definitions for nth_type and observer --- include/etl/nth_type.h | 8 +++++--- include/etl/observer.h | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/etl/nth_type.h b/include/etl/nth_type.h index a38a25f5..82e58ef4 100644 --- a/include/etl/nth_type.h +++ b/include/etl/nth_type.h @@ -58,14 +58,16 @@ namespace etl { ETL_STATIC_ASSERT(Index < sizeof...(TTypes), "etl::nth_type index 'Index' out of bounds"); - using type = typename private_nth_type::nth_type_helper::type; + using type = typename private_nth_type::nth_type_helper::type; + using type_list = etl::type_list; }; //*********************************** template - struct nth_type> : public nth_type + struct nth_type> { - using typename nth_type::type; + using type = typename nth_type::type; + using type_list = typename nth_type::type_list; }; //*********************************** diff --git a/include/etl/observer.h b/include/etl/observer.h index 133f8392..d722262b 100644 --- a/include/etl/observer.h +++ b/include/etl/observer.h @@ -309,6 +309,7 @@ namespace etl using observer::notification; using observer::notification; + using type_list = etl::type_list; }; //***************************************************************** @@ -323,6 +324,8 @@ namespace etl virtual ~observer() = default; virtual void notification(T1) = 0; + + using type_list = etl::type_list; }; //***************************************************************** @@ -337,6 +340,8 @@ namespace etl virtual ~observer() = default; virtual void notification() = 0; + + using type_list = etl::type_list<>; }; //***************************************************************** @@ -350,6 +355,7 @@ namespace etl public: using observer::notification; + using type_list = etl::type_list; }; #else From 61796bee8f7ca5043e36f180bffc97d28b722acd Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 25 Jan 2026 11:10:38 +0100 Subject: [PATCH 021/167] Added etl::type_list to etl::variant --- include/etl/private/variant_variadic.h | 26 +++++++++++++---- test/test_variant_variadic.cpp | 39 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 8ec3f195..9571a2fd 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -253,7 +253,7 @@ namespace etl template struct variant_alternative> { - using type = etl::nth_type_t; + using type = etl::nth_type_t::type_list>; }; template @@ -370,7 +370,6 @@ namespace etl //*************************************************************************** /// A template class that can store any of the types defined in the template parameter list. - /// Supports up to 8 types. ///\ingroup variant //*************************************************************************** template @@ -378,6 +377,8 @@ namespace etl { public: + using type_list = etl::type_list; + //*************************************************************************** /// get() is a friend function. //*************************************************************************** @@ -1217,13 +1218,26 @@ namespace etl size_t type_id; }; + //*************************************************************************** + /// Delcare a variant using an etl::type_list. + //*************************************************************************** + template + class variant> : public etl::variant + { + public: + + using base_type = etl::variant; + using type_list = typename base_type::type_list; + using base_type::base_type; // inherit all ctors + }; + //*************************************************************************** /// Checks if the variant v holds the alternative T. //*************************************************************************** template ETL_CONSTEXPR14 bool holds_alternative(const etl::variant& v) ETL_NOEXCEPT - { - constexpr size_t Index = etl::type_list_index_of_type, T>::value; + { + constexpr size_t Index = etl::type_list_index_of_type::type_list, T>::value; return (Index == variant_npos) ? false : (v.index() == Index); } @@ -1254,7 +1268,7 @@ namespace etl get(etl::variant& v) { #if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11) - static_assert(Index < sizeof...(TTypes), "Index out of range"); + static_assert(Index < etl::type_list_size::type_list>::value, "Index out of range"); #endif ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); @@ -1427,7 +1441,7 @@ namespace etl template struct variant_size> - : etl::integral_constant + : etl::integral_constant::type_list>::value> { }; diff --git a/test/test_variant_variadic.cpp b/test/test_variant_variadic.cpp index dc8373ac..6e91fa34 100644 --- a/test/test_variant_variadic.cpp +++ b/test/test_variant_variadic.cpp @@ -462,6 +462,45 @@ namespace test_variant_t variant_etl; + CHECK_TRUE((std::is_same>::value)); + + CHECK_TRUE(etl::holds_alternative(variant_etl)); + CHECK_FALSE(etl::holds_alternative(variant_etl)); + CHECK_FALSE(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(1, etl::get<0U>(variant_etl).value); + + CHECK_TRUE(etl::holds_alternative<0U>(variant_etl)); + CHECK_FALSE(etl::holds_alternative<1U>(variant_etl)); + CHECK_FALSE(etl::holds_alternative<2U>(variant_etl)); + + CHECK_TRUE(etl::holds_alternative(0U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(1U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(2U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(99U, variant_etl)); + } + + //************************************************************************* + TEST(test_constructor_default_variant_from_type_list) + { + struct DefaultConstructible + { + DefaultConstructible() + : value(1) + { + } + + int value = 0; + }; + + using variant_types = etl::type_list; + using test_variant_t = etl::variant; + + CHECK_NO_THROW(test_variant_t variant_etl); + + test_variant_t variant_etl; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE(etl::holds_alternative(variant_etl)); CHECK_FALSE(etl::holds_alternative(variant_etl)); CHECK_FALSE(etl::holds_alternative(variant_etl)); From 1c0d7a87de3ad8084034329eb5c1f26579b20e80 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 25 Jan 2026 19:19:18 +0100 Subject: [PATCH 022/167] Updated comments --- include/etl/private/variant_variadic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 9571a2fd..ddcdd33c 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -1228,7 +1228,7 @@ namespace etl using base_type = etl::variant; using type_list = typename base_type::type_list; - using base_type::base_type; // inherit all ctors + using base_type::base_type; // Inherit all ctors }; //*************************************************************************** From c67c617d8c7a78aba872e3cbffafeae27c1593f5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 24 Dec 2025 20:01:38 +0000 Subject: [PATCH 023/167] Addedetl::type~_list to message_router, observer, visitor # Conflicts: # include/etl/observer.h # test/vs2022/etl.vcxproj.filters --- include/etl/message_router.h | 139 +++- include/etl/observer.h | 17 + include/etl/visitor.h | 36 + test/test_message_router_with_type_list.cpp | 741 +++++++++++++++++++ test/test_observer_with_type_list.cpp | 583 +++++++++++++++ test/test_visitor_with_type_list.cpp | 761 ++++++++++++++++++++ test/vs2022/etl.vcxproj | 3 + 7 files changed, 2279 insertions(+), 1 deletion(-) create mode 100644 test/test_message_router_with_type_list.cpp create mode 100644 test/test_observer_with_type_list.cpp create mode 100644 test/test_visitor_with_type_list.cpp diff --git a/include/etl/message_router.h b/include/etl/message_router.h index cc6ea40c..e08c8344 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -64,6 +64,7 @@ SOFTWARE. #include "placement_new.h" #include "successor.h" #include "type_traits.h" +#include "type_list.h" #include @@ -410,7 +411,8 @@ namespace etl { public: - typedef etl::message_packet message_packet; + using message_packet = etl::message_packet; + using type_list = etl::type_list; //********************************************** message_router() @@ -566,6 +568,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -717,6 +723,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -868,6 +878,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1018,6 +1032,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1166,6 +1184,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1313,6 +1335,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1459,6 +1485,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1604,6 +1634,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1747,6 +1781,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -1889,6 +1927,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2029,6 +2071,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2168,6 +2214,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2305,6 +2355,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2441,6 +2495,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2576,6 +2634,10 @@ namespace etl typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2710,6 +2772,10 @@ namespace etl typedef etl::message_packet< T1> message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) @@ -2830,6 +2896,77 @@ namespace etl return true; } }; + + // Helper: select type at index I from a `type_list`, or `void` if out of range. + template + struct message_router_type_or_void + { + typedef typename etl::conditional<(I < etl::type_list_size::value), + etl::type_list_type_at_index, + etl::type_identity>::type::type type; + }; + + // For C++14 and below, map the `type_list` to up to 16 message type parameters (fill with `void`). + template + class message_router, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> + : public message_router>::type, + typename etl::message_router_type_or_void<1, etl::type_list>::type, + typename etl::message_router_type_or_void<2, etl::type_list>::type, + typename etl::message_router_type_or_void<3, etl::type_list>::type, + typename etl::message_router_type_or_void<4, etl::type_list>::type, + typename etl::message_router_type_or_void<5, etl::type_list>::type, + typename etl::message_router_type_or_void<6, etl::type_list>::type, + typename etl::message_router_type_or_void<7, etl::type_list>::type, + typename etl::message_router_type_or_void<8, etl::type_list>::type, + typename etl::message_router_type_or_void<9, etl::type_list>::type, + typename etl::message_router_type_or_void<10, etl::type_list>::type, + typename etl::message_router_type_or_void<11, etl::type_list>::type, + typename etl::message_router_type_or_void<12, etl::type_list>::type, + typename etl::message_router_type_or_void<13, etl::type_list>::type, + typename etl::message_router_type_or_void<14, etl::type_list>::type, + typename etl::message_router_type_or_void<15, etl::type_list>::type> + { + // Enforce the maximum number of message types supported by the C++14 implementation. + static_assert(sizeof...(TMessageTypes) <= 16, "etl::message_router supports up to 16 message types for C++14"); + + public: + using base = message_router>::type, + typename etl::message_router_type_or_void<1, etl::type_list>::type, + typename etl::message_router_type_or_void<2, etl::type_list>::type, + typename etl::message_router_type_or_void<3, etl::type_list>::type, + typename etl::message_router_type_or_void<4, etl::type_list>::type, + typename etl::message_router_type_or_void<5, etl::type_list>::type, + typename etl::message_router_type_or_void<6, etl::type_list>::type, + typename etl::message_router_type_or_void<7, etl::type_list>::type, + typename etl::message_router_type_or_void<8, etl::type_list>::type, + typename etl::message_router_type_or_void<9, etl::type_list>::type, + typename etl::message_router_type_or_void<10, etl::type_list>::type, + typename etl::message_router_type_or_void<11, etl::type_list>::type, + typename etl::message_router_type_or_void<12, etl::type_list>::type, + typename etl::message_router_type_or_void<13, etl::type_list>::type, + typename etl::message_router_type_or_void<14, etl::type_list>::type, + typename etl::message_router_type_or_void<15, etl::type_list>::type>; + + using base::base; // Inherit constructors + using typename base::message_packet; + using type_list = etl::type_list; + }; +#endif + +#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + template + class message_router> + : public message_router + { + public: + + using this_type = message_router>; + using base_type = message_router; + using type_list = etl::type_list; + using base_type::base_type; + }; #endif } diff --git a/include/etl/observer.h b/include/etl/observer.h index d722262b..d7a75776 100644 --- a/include/etl/observer.h +++ b/include/etl/observer.h @@ -321,6 +321,8 @@ namespace etl { public: + using type_list = etl::type_list; + virtual ~observer() = default; virtual void notification(T1) = 0; @@ -337,6 +339,8 @@ namespace etl { public: + using type_list = etl::type_list<>; + virtual ~observer() = default; virtual void notification() = 0; @@ -358,6 +362,19 @@ namespace etl using type_list = etl::type_list; }; + //***************************************************************** + /// The specialised observer class for etl::type_list. + ///\ingroup observer + //**************************************************************** + template + class observer> : public observer + { + public: + + using observer::observer; + using observer::notification; + }; + #else //********************************************************************* diff --git a/include/etl/visitor.h b/include/etl/visitor.h index 2975c678..941af701 100644 --- a/include/etl/visitor.h +++ b/include/etl/visitor.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" +#include "type_list.h" //***************************************************************************** ///\defgroup visitor visitor @@ -64,6 +65,7 @@ namespace etl using visitable::accept; using visitable::accept; + using type_list = etl::type_list; }; //***************************************************************** @@ -75,11 +77,30 @@ namespace etl { public: + using type_list = etl::type_list; + virtual ~visitable() = default; virtual void accept(T1&) = 0; }; + //***************************************************************** + /// The visitable class for an etl::type_list. + /// Expands the type_list into the existing variadic visitable. + ///\ingroup visitor + //***************************************************************** + template + class visitable> : public visitable + { + ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); + + public: + + using type_list = etl::type_list; + + using visitable::accept; + }; + #else //***************************************************************** @@ -187,6 +208,21 @@ namespace etl virtual void visit(T1) = 0; }; + //***************************************************************** + /// The visitor class for an etl::type_list. + /// Expands the type_list into the existing variadic visitor. + ///\ingroup visitor + //***************************************************************** + template + class visitor> : public visitor + { + ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); + + public: + + using visitor::visit; + }; + #else //***************************************************************** diff --git a/test/test_message_router_with_type_list.cpp b/test/test_message_router_with_type_list.cpp new file mode 100644 index 00000000..b997f59f --- /dev/null +++ b/test/test_message_router_with_type_list.cpp @@ -0,0 +1,741 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/message_router.h" +#include "etl/queue.h" +#include "etl/largest.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE0, + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1, + ROUTER2, + ROUTER3 + }; + + //*********************************** + struct NotInterface + { + virtual ~NotInterface() {} + virtual int VirtualFunction() const = 0; + }; + + ////*********************************** + // Uncomment to demonstrate static assert + //struct Message0 : public etl::message + //{ + //}; + + //*********************************** + struct Message1 : public etl::message + { + Message1(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message2 : public etl::message + { + Message2(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message3 : public etl::message + { + Message3(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + int value[10]; + }; + + //*********************************** + struct Message4 : public etl::message + { + Message4(etl::imessage_router& callback_) + : callback(callback_) + { + } + + etl::imessage_router& callback; + }; + + //*********************************** + struct Message5 : public etl::message + { + }; + + Message5 message5; + + using Router1Messages = etl::type_list; + using Router2Messages = etl::type_list; + using Router3Messages = etl::type_list; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. + //*************************************************************************** + class Router1 : public etl::message_router + { + public: + + Router1() + : message_router(ROUTER1), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(const Message1& msg) + { + ++message1_count; + etl::send_message(msg.callback, message5); + //CHECK_EQUAL(1, msg.VirtualFunction()); + } + + void on_receive(const Message2& msg) + { + ++message2_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message3& msg) + { + ++message3_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message4& msg) + { + ++message4_count; + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message5&) + { + ++callback_count; + } + + void on_receive_unknown(const etl::imessage&) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class Router2 : public etl::message_router + { + public: + + Router2() + : message_router(ROUTER2), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0), + sender_id(0) + { + + } + + Router2(etl::imessage_router& successor_) + : message_router(ROUTER2, successor_), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0), + sender_id(0) + { + + } + + void on_receive(const Message1& msg) + { + ++message1_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + //CHECK_EQUAL(1, msg.VirtualFunction()); + } + + void on_receive(const Message2& msg) + { + ++message2_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message4& msg) + { + ++message4_count; + sender_id = msg.callback.get_message_router_id(); + etl::send_message(msg.callback, message5); + } + + void on_receive(const Message5&) + { + ++callback_count; + } + + void on_receive_unknown(const etl::imessage&) + { + ++message_unknown_count; + sender_id = 0; + } + + int message1_count; + int message2_count; + int message4_count; + int message_unknown_count; + int callback_count; + int sender_id; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 3. + // 'receive' is overridden. + //*************************************************************************** + class Router3 : public etl::message_router + { + public: + + using base = etl::message_router; + + Router3() + : message_router(ROUTER3) + , message1_received(false) + , message2_received(false) + , message3_received(false) + , unknown_message_received(false) + { + } + + void receive(const etl::imessage& msg) override + { + switch (msg.get_message_id()) + { + case MESSAGE1: + { + message1_received = true; + break; + } + + case MESSAGE2: + { + message2_received = true; + break; + } + + case MESSAGE3: + { + message3_received = true; + break; + } + + default: + { + unknown_message_received = true; + break; + } + } + } + + void on_receive(const Message1&) + { + } + + void on_receive(const Message2&) + { + } + + void on_receive(const Message3&) + { + } + + void on_receive_unknown(const etl::imessage&) + { + } + + bool message1_received; + bool message2_received; + bool message3_received; + bool unknown_message_received; + }; + + etl::imessage_router* p_router; + + SUITE(test_message_router_with_type_list) + { + //************************************************************************* + TEST(message_router) + { + Router1 r1; + Router2 r2; + + p_router = &r1; + + Message1 message1(r2); + Message2 message2(r2); + Message3 message3(r2); + Message4 message4(r2); + + // CHECK(!r1.is_null_router()); + CHECK(r1.is_producer()); + CHECK(r1.is_consumer()); + + p_router->receive(message1); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(1, r2.callback_count); + + p_router->receive(message2); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(2, r2.callback_count); + + p_router->receive(message3); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(3, r2.callback_count); + + p_router->receive(message4); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(1, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(4, r2.callback_count); + } + + //************************************************************************* + TEST(message_null_router) + { + Router2 router; + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + // CHECK(null_router.is_null_router()); + CHECK(!null_router.is_producer()); + CHECK(!null_router.is_consumer()); + + // Send from the null router. + etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + // Send to the null router. + etl::send_message(null_router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //************************************************************************* + TEST(message_producer) + { + Router2 router; + etl::message_producer producer(ROUTER3); + + Message1 message1(producer); + Message2 message2(producer); + Message3 message3(producer); + Message4 message4(producer); + + // CHECK(!producer.is_null_router()); + CHECK(producer.is_producer()); + CHECK(!producer.is_consumer()); + + CHECK_EQUAL(0, router.sender_id); + + // Send from the producer. + router.receive(message1); + //etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + CHECK_EQUAL(0, router.sender_id); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + CHECK_EQUAL(ROUTER3, router.sender_id); + + // Send to the producer. + etl::send_message(producer, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(producer, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //************************************************************************* + TEST(message_router_accepts) + { + Router2 r2; + + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(!r2.accepts(message3)); + CHECK(!r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + + //************************************************************************* + TEST(message_router_accepts_successors) + { + Router1 r1; // M1, M2, M3, M4, M5 + Router2 r2; // M1, M2, M4, M5 + + r2.set_successor(r1); + + etl::null_message_router null_router; + + Message1 message1(null_router); + Message2 message2(null_router); + Message3 message3(null_router); + Message4 message4(null_router); + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(r2.accepts(message3)); + CHECK(r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + +#if ETL_HAS_VIRTUAL_MESSAGES + //************************************************************************* + TEST(message_router_queue) + { + Router1 r1; + Router2 r2; + + typedef Router2::message_packet Packet; + typedef etl::queue Queue; + + Queue queue; + + etl::imessage* im; + + Message1 message1(r1); + Message2 message2(r1); + Message3 message3(r1); + Message4 message4(r1); + + // Queue some messages in the message packet queue. + im = &message1; + queue.emplace(*im); + + im = &message2; + queue.emplace(*im); + + // The router2 queue doesn't accept Message3 types. + im = &message3; + CHECK_THROW(queue.emplace(*im), etl::unhandled_message_exception); + + im = &message4; + queue.emplace(*im); + + im = &message4; + queue.emplace(*im); + + etl::imessage& imr1 = queue.front().get(); + r2.receive(imr1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + queue.pop(); + + etl::imessage& imr2 = queue.front().get(); + r2.receive(imr2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + queue.pop(); + + const etl::imessage& imr3 = queue.front().get(); + r2.receive(imr3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + queue.pop(); + + const Queue& crqueue = queue; + const etl::imessage& imr4 = crqueue.front().get(); + r2.receive(imr4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(2, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + queue.pop(); + } +#endif + + //************************************************************************* + TEST(message_router_successor) + { + Router1 r1; + Router2 r2(r1); + + etl::null_message_router null_router; + + Message1 message1(r2); + Message2 message2(r2); + Message3 message3(r2); + Message4 message4(r2); + + etl::send_message(r2, message1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + etl::send_message(r2, message2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + r2.receive(message3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + + etl::send_message(r2, message4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + + CHECK_EQUAL(0, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + } + + //************************************************************************* + TEST(message_router_with_overloaded_receive) + { + Router3 router; + + Message1 message1(router); + Message2 message2(router); + Message3 message3(router); + + router.receive(message1); + CHECK_TRUE(router.message1_received); + + router.receive(message2); + CHECK_TRUE(router.message2_received); + + router.receive(message3); + CHECK_TRUE(router.message3_received); + + CHECK_FALSE(router.unknown_message_received); + } + } +} diff --git a/test/test_observer_with_type_list.cpp b/test/test_observer_with_type_list.cpp new file mode 100644 index 00000000..e0b61f54 --- /dev/null +++ b/test/test_observer_with_type_list.cpp @@ -0,0 +1,583 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/observer.h" +#include "etl/type_list.h" + +#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + +namespace +{ + //***************************************************************************** + // Notification1 + //***************************************************************************** + struct Notification1 + { + }; + + //***************************************************************************** + // Notification2 + //***************************************************************************** + struct Notification2 + { + }; + + //***************************************************************************** + // Notification3 + //***************************************************************************** + struct Notification3 + { + }; + + //***************************************************************************** + // Generic notification. + //***************************************************************************** + template + struct Notification + { + }; + + //***************************************************************************** + // The observer base type. + // Declare what notifications you want to observe and how they are passed to 'notification'. + // The Notification1 is passed by value. + // The Notification2 is passed by reference. + // The Notification3 is passed by const reference. + //***************************************************************************** + using NotificationTypes = etl::type_list; + using ObserverType = etl::observer; + + //***************************************************************************** + // The observer base type that does not take a notification type. + //***************************************************************************** + typedef etl::observer ObserverVoidIntType; +} + +//***************************************************************************** +// The concrete observable 1 class. +//***************************************************************************** +class Observable1 : public etl::observable +{ +public: + + Notification1 data1; + Notification2 data2; + Notification1& data3 = data1; + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(data3); + notify_observers(data2); + } +}; + +//***************************************************************************** +// The concrete observable 2 class. +//***************************************************************************** +class Observable2 : public etl::observable +{ +public: + + Notification3 data3; + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(data3); + } +}; + +//***************************************************************************** +// The concrete observable 3 class. +//***************************************************************************** +class ObservableVoidInt : public etl::observable +{ +public: + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications() + { + notify_observers(); + } + + //********************************* + // Notify all of the observers. + //********************************* + void send_notifications(int n) + { + notify_observers(n); + } +}; + +//***************************************************************************** +// The first observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class Observer1 : public ObserverType +{ +public: + + Observer1() + : data1_count(0) + , data2_count(0) + , data3_count(0) + { + } + + //******************************************* + // Notification1 is passed by value. + //******************************************* + void notification(Notification1 /*data1*/) + { + ++data1_count; + } + + //******************************************* + // Notification2 is passed by reference. + //******************************************* + void notification(Notification2& /*data2*/) + { + ++data2_count; + } + + //******************************************* + // Notification3 is passed by const reference. + //******************************************* + void notification(const Notification3& /*data3*/) + { + ++data3_count; + } + + int data1_count; + int data2_count; + int data3_count; +}; + +//***************************************************************************** +// The second observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class Observer2 : public ObserverType +{ +public: + + Observer2() + : data1_count(0) + , data2_count(0) + , data3_count(0) + { + } + + //******************************************* + // Notification1 is passed by value. + //******************************************* + void notification(Notification1 /*data1*/) + { + ++data1_count; + } + + //******************************************* + // Notification2 is passed by reference. + //******************************************* + void notification(Notification2& /*data2*/) + { + ++data2_count; + } + + //******************************************* + // Notification3 is passed by const reference. + //******************************************* + void notification(const Notification3& /*data3*/) + { + ++data3_count; + } + + int data1_count; + int data2_count; + int data3_count; +}; + +//***************************************************************************** +// The third observer type. +// If any one of the overloads is missing or a parameter declaration is incorrect +// then the class will be 'abstract' and will not compile. +//***************************************************************************** +class ObserverVoidInt : public ObserverVoidIntType +{ +public: + + ObserverVoidInt() + : data1_count(0) + , data2_count(0) + { + } + + //******************************************* + // Notification1 + //******************************************* + void notification() override + { + ++data1_count; + } + + //******************************************* + // Notification2 + //******************************************* + void notification(int) override + { + ++data2_count; + } + + int data1_count; + int data2_count; +}; + +namespace +{ + SUITE(test_observer) + { + //************************************************************************* + TEST(test_2_observables_2_observers_3_notifications) + { + // The observable objects. + Observable1 observable1; + Observable2 observable2; + + // The observer objects. + Observer1 observer1; + Observer2 observer2; + + observable1.add_observer(observer1); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(0, observer2.data1_count); + CHECK_EQUAL(0, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. observeable2 has no observers yet. + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(0, observer2.data1_count); + CHECK_EQUAL(0, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + // Add an observer to both. + observable1.add_observer(observer2); + observable2.add_observer(observer2); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(1, observer2.data1_count); + CHECK_EQUAL(1, observer2.data2_count); + CHECK_EQUAL(0, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(1, observer2.data1_count); + CHECK_EQUAL(1, observer2.data2_count); + CHECK_EQUAL(1, observer2.data3_count); + + observable1.remove_observer(observer1); + + // Send the notifications. + observable1.send_notifications(); // Updates data1 & data2. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(2, observer2.data1_count); + CHECK_EQUAL(2, observer2.data2_count); + CHECK_EQUAL(1, observer2.data3_count); + + observable2.send_notifications(); // Updates data3. + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer1.data2_count); + CHECK_EQUAL(0, observer1.data3_count); + + CHECK_EQUAL(2, observer2.data1_count); + CHECK_EQUAL(2, observer2.data2_count); + CHECK_EQUAL(2, observer2.data3_count); + } + + //************************************************************************* + TEST(test_observable_2_observers_enable_disable) + { + // The observable objects. + Observable1 observable1; + + // The observer objects. + Observer1 observer1; + Observer2 observer2; + + observable1.add_observer(observer1); + observable1.add_observer(observer2); + + // Send the notifications. + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(1, observer2.data1_count); + + // Disable observer1. Send the notifications. + observable1.disable_observer(observer1); + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Disable observer2. Send the notifications. + observable1.enable_observer(observer2, false); + observable1.send_notifications(); + + CHECK_EQUAL(1, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Enable observer1. Send the notifications. + observable1.enable_observer(observer1); + observable1.send_notifications(); + + CHECK_EQUAL(2, observer1.data1_count); + CHECK_EQUAL(2, observer2.data1_count); + + // Enable observer2. Send the notifications. + observable1.enable_observer(observer2, true); + observable1.send_notifications(); + + CHECK_EQUAL(3, observer1.data1_count); + CHECK_EQUAL(3, observer2.data1_count); + } + + //************************************************************************* + TEST(test_8_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7>, Notification<8> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_7_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_6_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_5_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_notifications) + { + typedef etl::observer, Notification<2>, Notification<3>, Notification<4> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_notifications) + { + typedef etl::observer, Notification<2>, Notification<3> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_notifications) + { + typedef etl::observer, Notification<2> > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_1_notification) + { + typedef etl::observer > Observer; + + class Observable : public etl::observable + { + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_observer_list) + { + class Observer : public etl::observer + { + void notification(Notification1) {} + }; + + class Observable : public etl::observable + { + }; + + Observable observable; + + Observer observer1; + Observer observer2; + Observer observer3; + Observer observer4; + Observer observer5; + + observable.add_observer(observer1); + CHECK_EQUAL(1UL, observable.number_of_observers()); + + observable.add_observer(observer2); + CHECK_EQUAL(2UL, observable.number_of_observers()); + + observable.add_observer(observer3); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.add_observer(observer2); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.add_observer(observer4); + CHECK_EQUAL(4UL, observable.number_of_observers()); + + CHECK_THROW(observable.add_observer(observer5), etl::observer_list_full); + + CHECK(observable.remove_observer(observer3)); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + // Try again. + CHECK(!observable.remove_observer(observer3)); + CHECK_EQUAL(3UL, observable.number_of_observers()); + + observable.clear_observers(); + CHECK_EQUAL(0UL, observable.number_of_observers()); + } + + //************************************************************************* + TEST(test_void_int_observable) + { + // The observable objects. + ObservableVoidInt observable; + + // The observer objects. + ObserverVoidInt observer; + + observable.add_observer(observer); + + // Send the notifications. + observable.send_notifications(); + CHECK_EQUAL(1U, observer.data1_count); + CHECK_EQUAL(0U, observer.data2_count); + + observable.send_notifications(1); + CHECK_EQUAL(1U, observer.data1_count); + CHECK_EQUAL(1U, observer.data2_count); + } + } +} + + +#endif + diff --git a/test/test_visitor_with_type_list.cpp b/test/test_visitor_with_type_list.cpp new file mode 100644 index 00000000..04660ee9 --- /dev/null +++ b/test/test_visitor_with_type_list.cpp @@ -0,0 +1,761 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/visitor.h" + +#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + +//***************************************************************************** +// Pre-declare the data types. +//***************************************************************************** +class Square; +class Circle; +class Triangle; + +//***************************************************************************** +// What classes do you want the visitors to handle? +// Square will be passed by reference. +// Circle will be passed by reference. +// Triangle will be passed by const reference. +//***************************************************************************** +using DrawTypes = etl::type_list; +using DrawVisitorType = etl::visitor; + +//***************************************************************************** +// What classes do you want the visitors to handle? +// Square will be passed by reference. +// Triangle will be passed by const reference. +//***************************************************************************** +using LogTypes = etl::type_list; +using LogVisitorType = etl::visitor; + +//***************************************************************************** +// Base shape. +//***************************************************************************** +using VisitorTypes = etl::type_list; + +class ShapeBase : public etl::visitable +{ +}; + +//***************************************************************************** +// Square accepts draw & log visitors. +//***************************************************************************** +class Square : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType& visitor) + { + visitor.visit(*this); + } +}; + +//***************************************************************************** +// Circle only accepts draw visitors. +//***************************************************************************** +class Circle : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType&) + { + } +}; + +//***************************************************************************** +// Triangle accepts draw & log visitors. +//***************************************************************************** +class Triangle : public ShapeBase +{ +public: + + void accept(DrawVisitorType& visitor) + { + visitor.visit(*this); + } + + void accept(LogVisitorType& visitor) + { + visitor.visit(*this); + } +}; + + +//***************************************************************************** +// Generic other shapes. +//***************************************************************************** +template +class Shape : public etl::visitable +{ +public: + + void accept(TVisitor& visitor) + { + visitor.visit(*this); + } +}; + +//***************************************************************************** +class DrawVisitor : public DrawVisitorType +{ +public: + + DrawVisitor() + : square_called(false), + circle_called(false), + triangle_called(false) + { + } + + void visit(Square&) + { + square_called = true; + } + + void visit(Circle&) + { + circle_called = true; + } + + void visit(const Triangle&) + { + triangle_called = true; + } + + bool square_called; + bool circle_called; + bool triangle_called; +}; + +//***************************************************************************** +class LogVisitor : public LogVisitorType +{ +public: + + LogVisitor() + : square_called(false), + circle_called(false), + triangle_called(false) + { + } + + void visit(Square&) + { + square_called = true; + } + + // SHOULD NEVER BE CALLED. + void visit(Circle&) + { + circle_called = true; + } + + void visit(const Triangle&) + { + triangle_called = true; + } + + bool square_called; + bool circle_called; + bool triangle_called; +}; + +namespace +{ + SUITE(test_visitor) + { + //************************************************************************* + TEST(test_two_visitors_three_visitables) + { + DrawVisitor draw_visitor; + LogVisitor log_visitor; + + Square square; + Circle circle; + Triangle triangle; + + ShapeBase* pShapeBase; + + CHECK_EQUAL(false, draw_visitor.square_called); + CHECK_EQUAL(false, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(false, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + square.accept(draw_visitor); + square.accept(log_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(false, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + circle.accept(draw_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(true, draw_visitor.circle_called); + CHECK_EQUAL(false, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(false, log_visitor.triangle_called); + + pShapeBase = ▵ + pShapeBase->accept(draw_visitor); + pShapeBase->accept(log_visitor); + + CHECK_EQUAL(true, draw_visitor.square_called); + CHECK_EQUAL(true, draw_visitor.circle_called); + CHECK_EQUAL(true, draw_visitor.triangle_called); + CHECK_EQUAL(true, log_visitor.square_called); + CHECK_EQUAL(false, log_visitor.circle_called); + CHECK_EQUAL(true, log_visitor.triangle_called); + } + + //************************************************************************* + TEST(test_1_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor3 : public etl::visitor + { + void visit(AShape&) {} + }; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + void accept(ShapeVisitor3&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_visitor) + { + class AShape; + class ShapeVisitor1 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor2 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor3 : public etl::visitor + { + void visit(AShape&) {} + }; + + class ShapeVisitor4 : public etl::visitor + { + void visit(AShape&) {} + }; + + using ShapeVisitorTypes = etl::type_list; + + class AShape : public etl::visitable + { + public: + + void accept(ShapeVisitor1&) {} + void accept(ShapeVisitor2&) {} + void accept(ShapeVisitor3&) {} + void accept(ShapeVisitor4&) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_1_visitable) + { + class ShapeVisitor : public etl::visitor > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_2_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_3_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_4_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_5_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_6_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_7_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_8_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_9_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_10_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + + //************************************************************************* + TEST(test_11_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_12_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_13_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_14_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_15_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + void visit(Shape<15, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + TEST(test_16_visitable) + { + class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, + Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, + Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, + Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor>, Shape<16, ShapeVisitor> > + { + public: + + void visit(Shape<1, ShapeVisitor>) {} + void visit(Shape<2, ShapeVisitor>) {} + void visit(Shape<3, ShapeVisitor>) {} + void visit(Shape<4, ShapeVisitor>) {} + void visit(Shape<5, ShapeVisitor>) {} + void visit(Shape<6, ShapeVisitor>) {} + void visit(Shape<7, ShapeVisitor>) {} + void visit(Shape<8, ShapeVisitor>) {} + void visit(Shape<9, ShapeVisitor>) {} + void visit(Shape<10, ShapeVisitor>) {} + void visit(Shape<11, ShapeVisitor>) {} + void visit(Shape<12, ShapeVisitor>) {} + void visit(Shape<13, ShapeVisitor>) {} + void visit(Shape<14, ShapeVisitor>) {} + void visit(Shape<15, ShapeVisitor>) {} + void visit(Shape<16, ShapeVisitor>) {} + }; + + // This test just needs to compile without errors. + CHECK(true); + } + + //************************************************************************* + struct NotVisitor {}; + + TEST(test_is_visitor) + { +#if ETL_USING_CPP17 + CHECK_TRUE(etl::is_visitor_v); + CHECK_TRUE(etl::is_visitor_v); + CHECK_FALSE(etl::is_visitor_v); +#else + CHECK_TRUE(etl::is_visitor::value); + CHECK_TRUE(etl::is_visitor::value); + CHECK_FALSE(etl::is_visitor::value); +#endif + } + } +} + +#endif + diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 6396b761..09056bad 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -10357,9 +10357,11 @@ + + @@ -11433,6 +11435,7 @@ + From 92e33bb974b2c8d2bbd5caf16659a9efe3c571e8 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 24 Dec 2025 20:02:06 +0000 Subject: [PATCH 024/167] Added member type_list type to tuple --- include/etl/tuple.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/etl/tuple.h b/include/etl/tuple.h index c4a9440b..2dd4971e 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -45,6 +45,7 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" #include "functional.h" +#include "type_list.h" #include "private/tuple_element.h" #include "private/tuple_size.h" @@ -131,6 +132,7 @@ namespace etl using value_type = void; ///< The type contained by this tuple. using this_type = tuple<>; ///< The type of this tuple. using base_type = void; ///< The type of the base tuple. + using type_list = etl::type_list<>; ///< The type list for this tuple. using index_sequence_type = etl::make_index_sequence<0>; ///< The index_sequence type for this tuple. //********************************* @@ -233,6 +235,7 @@ namespace etl using value_type = THead; ///< The type contained by this tuple. using this_type = tuple; ///< The type of this tuple. using base_type = tuple; ///< The type of the base tuple. + using type_list = etl::type_list; ///< The type list for this tuple. using index_sequence_type = etl::make_index_sequence()>; ///< The index_sequence type for this tuple. //********************************* From 8320b35d4720a9613198fd51d61719cba582091d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 24 Dec 2025 20:20:13 +0000 Subject: [PATCH 025/167] Work in progress --- include/etl/message_router.h | 153 ++++++++++++++++++++++++++++++++++- test/CMakeLists.txt | 3 + test/test_tuple.cpp | 10 +++ 3 files changed, 164 insertions(+), 2 deletions(-) diff --git a/include/etl/message_router.h b/include/etl/message_router.h index e08c8344..02942c8d 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -550,9 +550,158 @@ namespace etl } } }; +#elif ETL_USING_CPP14 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************************************* + // Unified C++11/14 variadic implementation (no fold expressions). + //************************************************************************************************* + template + class message_router : public imessage_router + { + public: + typedef etl::message_packet message_packet; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + + // Constructors (inherit public base ones) + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + using etl::imessage_router::receive; + + // Route by runtime message_id with pack expansion via initializer list. + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + const etl::message_id_t id = msg.get_message_id(); + bool handled = false; + +#include "etl/private/diagnostic_array_bounds_push.h" + // Expand across TMessageTypes... and attempt cast/dispatch on matching IDs. + int dummy[] = {0, (handled = handled || try_receive_one(id, msg), 0)...}; + (void)dummy; +#include "etl/private/diagnostic_pop.h" + + if (!handled) + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + static_cast(this)->on_receive_unknown(msg); + } + } + } + + // Overload for concrete message types; forwards to on_receive or successor. + template + typename etl::enable_if::value, void>::type + receive(const TMessage& msg) + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (is_in_message_set()) + { + static_cast(this)->on_receive(msg); + } + else + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + static_cast(this)->on_receive_unknown(msg); + } + } +#include "etl/private/diagnostic_pop.h" + } + + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + bool accepted = false; + int dummy[] = {0, (accepted = accepted || accepts_one(id), 0)...}; + (void)dummy; + if (!accepted) + { + if (has_successor()) + { + return get_successor().accepts(id); + } + } + return accepted; + } + + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE { return false; } + bool is_producer() const ETL_OVERRIDE { return true; } + bool is_consumer() const ETL_OVERRIDE { return true; } + + private: + // Helper: is T in the message set? + template + static ETL_CONSTEXPR bool is_in_message_set() + { + return etl::is_one_of::value; + } + + // Try to handle one type by ID match and cast. + template + bool try_receive_one(etl::message_id_t id, const etl::imessage& msg) + { + if (TMessage::ID == id) + { + static_cast(this)->on_receive(static_cast(msg)); + return true; + } + return false; + } + + // Accepts one type by ID + template + bool accepts_one(etl::message_id_t id) const + { + return TMessage::ID == id; + } + }; + + // Convenience bridge: allow message_router> + template + class message_router> + : public message_router + { + public: + typedef message_router base_type; +#if ETL_USING_CPP11 + using type_list = etl::type_list; +#endif + + using base_type::base_type; // inherit constructors + }; #else //************************************************************************************************* -// For C++14 and below. +// For C++03. //************************************************************************************************* //*************************************************************************** // The definition for all 16 message types. @@ -2955,7 +3104,7 @@ namespace etl }; #endif -#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) template class message_router> : public message_router diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 899ae047..31b7776d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -234,6 +234,7 @@ add_executable(etl_tests test_message_bus.cpp test_message_packet.cpp test_message_router.cpp + test_message_router_with_type_list.cpp test_message_router_registry.cpp test_message_timer.cpp test_message_timer_atomic.cpp @@ -252,6 +253,7 @@ add_executable(etl_tests test_nth_type.cpp test_numeric.cpp test_observer.cpp + test_observer_with_type_list.cpp test_optional.cpp test_overload.cpp test_packet.cpp @@ -370,6 +372,7 @@ add_executable(etl_tests test_vector_pointer.cpp test_vector_pointer_external_buffer.cpp test_visitor.cpp + test_visitor_with_type_list.cpp test_xor_checksum.cpp test_xor_rotate_checksum.cpp ) diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index 01a4ca1f..ec02bdaf 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "data.h" #include "etl/tuple.h" +#include "etl/type_list.h" #include #include @@ -103,6 +104,15 @@ namespace CHECK_TRUE((std::is_same>::value)); } + //************************************************************************* + TEST(test_tuple_type_list) + { + using Tuple = etl::tuple; + using TupleTypes = etl::type_list; + + CHECK_TRUE((std::is_same::value)); + } + //************************************************************************* TEST(test_default_constructor) { From 947e89a6e979ee6590fa5c58e49e5376ac6998ad Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 26 Jan 2026 17:55:50 +0000 Subject: [PATCH 026/167] Copy changes from other source --- include/etl/message_packet.h | 140 ++++++++++++++ include/etl/message_router.h | 355 +++++++++++++---------------------- include/etl/type_list.h | 6 + 3 files changed, 273 insertions(+), 228 deletions(-) diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index 8215eeb0..aa449cb8 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -59,6 +59,7 @@ SOFTWARE. #include "largest.h" #include "alignment.h" #include "utility.h" +#include "type_list.h" #include @@ -85,6 +86,8 @@ namespace etl public: + using message_types = etl::type_list; + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -380,6 +383,18 @@ namespace etl bool valid; }; + //*************************************************************************** + // The definition for all message types. + //*************************************************************************** + template + class message_packet> : public etl::message_packet + { + public: + + using base_type = etl::message_packet; + using base_type::base_type; // Inherit all ctors + }; + #else //*************************************************************************** @@ -393,6 +408,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -717,6 +736,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -1039,6 +1062,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -1358,6 +1385,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -1673,6 +1704,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -1982,6 +2017,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -2288,6 +2327,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -2591,6 +2634,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -2890,6 +2937,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -3183,6 +3234,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -3473,6 +3528,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -3760,6 +3819,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -4043,6 +4106,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -4320,6 +4387,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -4594,6 +4665,10 @@ namespace etl { public: +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -4865,6 +4940,14 @@ namespace etl { public: + ETL_STATIC_ASSERT(!etl::is_type_list::value, + "T1 must not be an etl::type_list. " + "Use etl::message_packet> only with the C++17 variadic overload."); + +#if ETL_USING_CPP11 + using message_types = etl::type_list; +#endif + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -5124,6 +5207,63 @@ namespace etl typename etl::aligned_storage::type data; bool valid; }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template <> + class message_packet + { + public: + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; +#endif + + message_packet() + : valid(false) + { + } + + static ETL_CONSTEXPR bool accepts(etl::message_id_t) + { + return false; + } + + static ETL_CONSTEXPR bool accepts(const etl::imessage&) + { + return false; + } + + template + static ETL_CONSTEXPR bool accepts() + { + ETL_UNUSED(Id); + return false; + } + + template + static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type accepts() + { + return false; + } + + bool is_valid() const + { + return valid; + } + + enum + { + SIZE = 0U, + ALIGNMENT = 1U + }; + + private: + + bool valid; + }; #endif } diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 02942c8d..42fc65f8 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -412,7 +412,7 @@ namespace etl public: using message_packet = etl::message_packet; - using type_list = etl::type_list; + using message_types = etl::type_list; //********************************************** message_router() @@ -550,158 +550,21 @@ namespace etl } } }; -#elif ETL_USING_CPP14 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) - //************************************************************************************************* - // Unified C++11/14 variadic implementation (no fold expressions). - //************************************************************************************************* + + //*************************************************************************** + // The definition for all message types defined by a type_list. + //*************************************************************************** template - class message_router : public imessage_router + class message_router> : public message_router { - public: - typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 - using type_list = etl::type_list; -#endif + public: - // Constructors (inherit public base ones) - message_router() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - message_router(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) - { - } - - message_router(etl::message_router_id_t id_) - : imessage_router(id_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - using etl::imessage_router::receive; - - // Route by runtime message_id with pack expansion via initializer list. - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - const etl::message_id_t id = msg.get_message_id(); - bool handled = false; - -#include "etl/private/diagnostic_array_bounds_push.h" - // Expand across TMessageTypes... and attempt cast/dispatch on matching IDs. - int dummy[] = {0, (handled = handled || try_receive_one(id, msg), 0)...}; - (void)dummy; -#include "etl/private/diagnostic_pop.h" - - if (!handled) - { - if (has_successor()) - { - get_successor().receive(msg); - } - else - { - static_cast(this)->on_receive_unknown(msg); - } - } - } - - // Overload for concrete message types; forwards to on_receive or successor. - template - typename etl::enable_if::value, void>::type - receive(const TMessage& msg) - { -#include "etl/private/diagnostic_array_bounds_push.h" - if (is_in_message_set()) - { - static_cast(this)->on_receive(msg); - } - else - { - if (has_successor()) - { - get_successor().receive(msg); - } - else - { - static_cast(this)->on_receive_unknown(msg); - } - } -#include "etl/private/diagnostic_pop.h" - } - - using imessage_router::accepts; - - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - bool accepted = false; - int dummy[] = {0, (accepted = accepted || accepts_one(id), 0)...}; - (void)dummy; - if (!accepted) - { - if (has_successor()) - { - return get_successor().accepts(id); - } - } - return accepted; - } - - ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE { return false; } - bool is_producer() const ETL_OVERRIDE { return true; } - bool is_consumer() const ETL_OVERRIDE { return true; } - - private: - // Helper: is T in the message set? - template - static ETL_CONSTEXPR bool is_in_message_set() - { - return etl::is_one_of::value; - } - - // Try to handle one type by ID match and cast. - template - bool try_receive_one(etl::message_id_t id, const etl::imessage& msg) - { - if (TMessage::ID == id) - { - static_cast(this)->on_receive(static_cast(msg)); - return true; - } - return false; - } - - // Accepts one type by ID - template - bool accepts_one(etl::message_id_t id) const - { - return TMessage::ID == id; - } + using message_router::message_router; }; - // Convenience bridge: allow message_router> - template - class message_router> - : public message_router - { - public: - typedef message_router base_type; -#if ETL_USING_CPP11 - using type_list = etl::type_list; -#endif - - using base_type::base_type; // inherit constructors - }; -#else + #else //************************************************************************************************* -// For C++03. +// For C++14 and below. //************************************************************************************************* //*************************************************************************** // The definition for all 16 message types. @@ -715,10 +578,10 @@ namespace etl { public: - typedef etl::message_packet message_packet; + typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -873,7 +736,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1028,7 +891,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1182,7 +1045,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1334,7 +1197,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1485,7 +1348,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1635,7 +1498,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1784,7 +1647,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -1931,7 +1794,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2077,7 +1940,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2221,7 +2084,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2364,7 +2227,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2505,7 +2368,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2645,7 +2508,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2784,7 +2647,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -2919,10 +2782,10 @@ namespace etl { public: - typedef etl::message_packet< T1> message_packet; + typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using type_list = etl::type_list; + using message_types = etl::type_list; #endif //********************************************** @@ -3046,75 +2909,111 @@ namespace etl } }; - // Helper: select type at index I from a `type_list`, or `void` if out of range. - template - struct message_router_type_or_void + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template + class message_router + : public imessage_router { - typedef typename etl::conditional<(I < etl::type_list_size::value), - etl::type_list_type_at_index, - etl::type_identity>::type::type type; - }; - - // For C++14 and below, map the `type_list` to up to 16 message type parameters (fill with `void`). - template - class message_router, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> - : public message_router>::type, - typename etl::message_router_type_or_void<1, etl::type_list>::type, - typename etl::message_router_type_or_void<2, etl::type_list>::type, - typename etl::message_router_type_or_void<3, etl::type_list>::type, - typename etl::message_router_type_or_void<4, etl::type_list>::type, - typename etl::message_router_type_or_void<5, etl::type_list>::type, - typename etl::message_router_type_or_void<6, etl::type_list>::type, - typename etl::message_router_type_or_void<7, etl::type_list>::type, - typename etl::message_router_type_or_void<8, etl::type_list>::type, - typename etl::message_router_type_or_void<9, etl::type_list>::type, - typename etl::message_router_type_or_void<10, etl::type_list>::type, - typename etl::message_router_type_or_void<11, etl::type_list>::type, - typename etl::message_router_type_or_void<12, etl::type_list>::type, - typename etl::message_router_type_or_void<13, etl::type_list>::type, - typename etl::message_router_type_or_void<14, etl::type_list>::type, - typename etl::message_router_type_or_void<15, etl::type_list>::type> - { - // Enforce the maximum number of message types supported by the C++14 implementation. - static_assert(sizeof...(TMessageTypes) <= 16, "etl::message_router supports up to 16 message types for C++14"); - public: - using base = message_router>::type, - typename etl::message_router_type_or_void<1, etl::type_list>::type, - typename etl::message_router_type_or_void<2, etl::type_list>::type, - typename etl::message_router_type_or_void<3, etl::type_list>::type, - typename etl::message_router_type_or_void<4, etl::type_list>::type, - typename etl::message_router_type_or_void<5, etl::type_list>::type, - typename etl::message_router_type_or_void<6, etl::type_list>::type, - typename etl::message_router_type_or_void<7, etl::type_list>::type, - typename etl::message_router_type_or_void<8, etl::type_list>::type, - typename etl::message_router_type_or_void<9, etl::type_list>::type, - typename etl::message_router_type_or_void<10, etl::type_list>::type, - typename etl::message_router_type_or_void<11, etl::type_list>::type, - typename etl::message_router_type_or_void<12, etl::type_list>::type, - typename etl::message_router_type_or_void<13, etl::type_list>::type, - typename etl::message_router_type_or_void<14, etl::type_list>::type, - typename etl::message_router_type_or_void<15, etl::type_list>::type>; - using base::base; // Inherit constructors - using typename base::message_packet; - using type_list = etl::type_list; - }; + typedef etl::message_packet message_packet; + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; #endif -#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) - template - class message_router> - : public message_router - { - public: + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } - using this_type = message_router>; - using base_type = message_router; - using type_list = etl::type_list; - using base_type::base_type; + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + const size_t id = msg.get_message_id(); + +#include "etl/private/diagnostic_array_bounds_push.h" + switch (id) + { + default: + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + static_cast(this)->on_receive_unknown(msg); + } + break; + } + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + switch (id) + { + default: + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + } + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } }; #endif } diff --git a/include/etl/type_list.h b/include/etl/type_list.h index 84e241ec..2d0dcdac 100644 --- a/include/etl/type_list.h +++ b/include/etl/type_list.h @@ -53,6 +53,12 @@ namespace etl template struct type_list; + template + struct is_type_list : etl::false_type {}; + + template + struct is_type_list> : etl::true_type {}; + //*************************************************************************** /// The empty type list. //*************************************************************************** From 49d7fa80bc3924c45cca8618d79e9f82f3a1faee Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 27 Jan 2026 19:28:40 +0000 Subject: [PATCH 027/167] Removed unused tests --- test/test_message_router_with_type_list.cpp | 741 ------------------- test/test_observer_with_type_list.cpp | 583 --------------- test/test_visitor_with_type_list.cpp | 761 -------------------- 3 files changed, 2085 deletions(-) delete mode 100644 test/test_message_router_with_type_list.cpp delete mode 100644 test/test_observer_with_type_list.cpp delete mode 100644 test/test_visitor_with_type_list.cpp diff --git a/test/test_message_router_with_type_list.cpp b/test/test_message_router_with_type_list.cpp deleted file mode 100644 index b997f59f..00000000 --- a/test/test_message_router_with_type_list.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2017 John Wellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#include "unit_test_framework.h" - -#include "etl/message_router.h" -#include "etl/queue.h" -#include "etl/largest.h" - -//*************************************************************************** -// The set of messages. -//*************************************************************************** -namespace -{ - enum - { - MESSAGE0, - MESSAGE1, - MESSAGE2, - MESSAGE3, - MESSAGE4, - MESSAGE5 - }; - - enum - { - ROUTER1, - ROUTER2, - ROUTER3 - }; - - //*********************************** - struct NotInterface - { - virtual ~NotInterface() {} - virtual int VirtualFunction() const = 0; - }; - - ////*********************************** - // Uncomment to demonstrate static assert - //struct Message0 : public etl::message - //{ - //}; - - //*********************************** - struct Message1 : public etl::message - { - Message1(etl::imessage_router& callback_) - : callback(callback_) - { - } - - etl::imessage_router& callback; - }; - - //*********************************** - struct Message2 : public etl::message - { - Message2(etl::imessage_router& callback_) - : callback(callback_) - { - } - - etl::imessage_router& callback; - }; - - //*********************************** - struct Message3 : public etl::message - { - Message3(etl::imessage_router& callback_) - : callback(callback_) - { - } - - etl::imessage_router& callback; - int value[10]; - }; - - //*********************************** - struct Message4 : public etl::message - { - Message4(etl::imessage_router& callback_) - : callback(callback_) - { - } - - etl::imessage_router& callback; - }; - - //*********************************** - struct Message5 : public etl::message - { - }; - - Message5 message5; - - using Router1Messages = etl::type_list; - using Router2Messages = etl::type_list; - using Router3Messages = etl::type_list; - - //*************************************************************************** - // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. - //*************************************************************************** - class Router1 : public etl::message_router - { - public: - - Router1() - : message_router(ROUTER1), - message1_count(0), - message2_count(0), - message3_count(0), - message4_count(0), - message_unknown_count(0), - callback_count(0) - { - - } - - void on_receive(const Message1& msg) - { - ++message1_count; - etl::send_message(msg.callback, message5); - //CHECK_EQUAL(1, msg.VirtualFunction()); - } - - void on_receive(const Message2& msg) - { - ++message2_count; - etl::send_message(msg.callback, message5); - } - - void on_receive(const Message3& msg) - { - ++message3_count; - etl::send_message(msg.callback, message5); - } - - void on_receive(const Message4& msg) - { - ++message4_count; - etl::send_message(msg.callback, message5); - } - - void on_receive(const Message5&) - { - ++callback_count; - } - - void on_receive_unknown(const etl::imessage&) - { - ++message_unknown_count; - } - - int message1_count; - int message2_count; - int message3_count; - int message4_count; - int message_unknown_count; - int callback_count; - }; - - //*************************************************************************** - // Router that handles messages 1, 2, 4 and 5 and returns nothing. - //*************************************************************************** - class Router2 : public etl::message_router - { - public: - - Router2() - : message_router(ROUTER2), - message1_count(0), - message2_count(0), - message4_count(0), - message_unknown_count(0), - callback_count(0), - sender_id(0) - { - - } - - Router2(etl::imessage_router& successor_) - : message_router(ROUTER2, successor_), - message1_count(0), - message2_count(0), - message4_count(0), - message_unknown_count(0), - callback_count(0), - sender_id(0) - { - - } - - void on_receive(const Message1& msg) - { - ++message1_count; - sender_id = msg.callback.get_message_router_id(); - etl::send_message(msg.callback, message5); - //CHECK_EQUAL(1, msg.VirtualFunction()); - } - - void on_receive(const Message2& msg) - { - ++message2_count; - sender_id = msg.callback.get_message_router_id(); - etl::send_message(msg.callback, message5); - } - - void on_receive(const Message4& msg) - { - ++message4_count; - sender_id = msg.callback.get_message_router_id(); - etl::send_message(msg.callback, message5); - } - - void on_receive(const Message5&) - { - ++callback_count; - } - - void on_receive_unknown(const etl::imessage&) - { - ++message_unknown_count; - sender_id = 0; - } - - int message1_count; - int message2_count; - int message4_count; - int message_unknown_count; - int callback_count; - int sender_id; - }; - - //*************************************************************************** - // Router that handles messages 1, 2, 3. - // 'receive' is overridden. - //*************************************************************************** - class Router3 : public etl::message_router - { - public: - - using base = etl::message_router; - - Router3() - : message_router(ROUTER3) - , message1_received(false) - , message2_received(false) - , message3_received(false) - , unknown_message_received(false) - { - } - - void receive(const etl::imessage& msg) override - { - switch (msg.get_message_id()) - { - case MESSAGE1: - { - message1_received = true; - break; - } - - case MESSAGE2: - { - message2_received = true; - break; - } - - case MESSAGE3: - { - message3_received = true; - break; - } - - default: - { - unknown_message_received = true; - break; - } - } - } - - void on_receive(const Message1&) - { - } - - void on_receive(const Message2&) - { - } - - void on_receive(const Message3&) - { - } - - void on_receive_unknown(const etl::imessage&) - { - } - - bool message1_received; - bool message2_received; - bool message3_received; - bool unknown_message_received; - }; - - etl::imessage_router* p_router; - - SUITE(test_message_router_with_type_list) - { - //************************************************************************* - TEST(message_router) - { - Router1 r1; - Router2 r2; - - p_router = &r1; - - Message1 message1(r2); - Message2 message2(r2); - Message3 message3(r2); - Message4 message4(r2); - - // CHECK(!r1.is_null_router()); - CHECK(r1.is_producer()); - CHECK(r1.is_consumer()); - - p_router->receive(message1); - CHECK_EQUAL(1, r1.message1_count); - CHECK_EQUAL(0, r1.message2_count); - CHECK_EQUAL(0, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - CHECK_EQUAL(1, r2.callback_count); - - p_router->receive(message2); - CHECK_EQUAL(1, r1.message1_count); - CHECK_EQUAL(1, r1.message2_count); - CHECK_EQUAL(0, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - CHECK_EQUAL(2, r2.callback_count); - - p_router->receive(message3); - CHECK_EQUAL(1, r1.message1_count); - CHECK_EQUAL(1, r1.message2_count); - CHECK_EQUAL(1, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - CHECK_EQUAL(3, r2.callback_count); - - p_router->receive(message4); - CHECK_EQUAL(1, r1.message1_count); - CHECK_EQUAL(1, r1.message2_count); - CHECK_EQUAL(1, r1.message3_count); - CHECK_EQUAL(1, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - CHECK_EQUAL(4, r2.callback_count); - } - - //************************************************************************* - TEST(message_null_router) - { - Router2 router; - etl::null_message_router null_router; - - Message1 message1(null_router); - Message2 message2(null_router); - Message3 message3(null_router); - Message4 message4(null_router); - - // CHECK(null_router.is_null_router()); - CHECK(!null_router.is_producer()); - CHECK(!null_router.is_consumer()); - - // Send from the null router. - etl::send_message(router, message1); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(0, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(0, router.message_unknown_count); - - etl::send_message(router, message2); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(0, router.message_unknown_count); - - etl::send_message(router, message3); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(router, message4); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - // Send to the null router. - etl::send_message(null_router, message1); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(null_router, message2); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(null_router, message3); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(null_router, message4); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - } - - //************************************************************************* - TEST(message_producer) - { - Router2 router; - etl::message_producer producer(ROUTER3); - - Message1 message1(producer); - Message2 message2(producer); - Message3 message3(producer); - Message4 message4(producer); - - // CHECK(!producer.is_null_router()); - CHECK(producer.is_producer()); - CHECK(!producer.is_consumer()); - - CHECK_EQUAL(0, router.sender_id); - - // Send from the producer. - router.receive(message1); - //etl::send_message(router, message1); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(0, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(0, router.message_unknown_count); - CHECK_EQUAL(ROUTER3, router.sender_id); - - etl::send_message(router, message2); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(0, router.message_unknown_count); - CHECK_EQUAL(ROUTER3, router.sender_id); - - etl::send_message(router, message3); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(0, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - CHECK_EQUAL(0, router.sender_id); - - etl::send_message(router, message4); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - CHECK_EQUAL(ROUTER3, router.sender_id); - - // Send to the producer. - etl::send_message(producer, message1); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(producer, message2); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(producer, message3); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - - etl::send_message(producer, message4); - CHECK_EQUAL(1, router.message1_count); - CHECK_EQUAL(1, router.message2_count); - CHECK_EQUAL(1, router.message4_count); - CHECK_EQUAL(1, router.message_unknown_count); - } - - //************************************************************************* - TEST(message_router_accepts) - { - Router2 r2; - - etl::null_message_router null_router; - - Message1 message1(null_router); - Message2 message2(null_router); - Message3 message3(null_router); - Message4 message4(null_router); - - CHECK(r2.accepts(message1)); - CHECK(r2.accepts(message1.get_message_id())); - - CHECK(r2.accepts(message2)); - CHECK(r2.accepts(message2.get_message_id())); - - CHECK(!r2.accepts(message3)); - CHECK(!r2.accepts(message3.get_message_id())); - - CHECK(r2.accepts(message4)); - CHECK(r2.accepts(message4.get_message_id())); - - CHECK(r2.accepts(message5)); - CHECK(r2.accepts(message5.get_message_id())); - } - - //************************************************************************* - TEST(message_router_accepts_successors) - { - Router1 r1; // M1, M2, M3, M4, M5 - Router2 r2; // M1, M2, M4, M5 - - r2.set_successor(r1); - - etl::null_message_router null_router; - - Message1 message1(null_router); - Message2 message2(null_router); - Message3 message3(null_router); - Message4 message4(null_router); - - CHECK(r2.accepts(message1)); - CHECK(r2.accepts(message1.get_message_id())); - - CHECK(r2.accepts(message2)); - CHECK(r2.accepts(message2.get_message_id())); - - CHECK(r2.accepts(message3)); - CHECK(r2.accepts(message3.get_message_id())); - - CHECK(r2.accepts(message4)); - CHECK(r2.accepts(message4.get_message_id())); - - CHECK(r2.accepts(message5)); - CHECK(r2.accepts(message5.get_message_id())); - } - -#if ETL_HAS_VIRTUAL_MESSAGES - //************************************************************************* - TEST(message_router_queue) - { - Router1 r1; - Router2 r2; - - typedef Router2::message_packet Packet; - typedef etl::queue Queue; - - Queue queue; - - etl::imessage* im; - - Message1 message1(r1); - Message2 message2(r1); - Message3 message3(r1); - Message4 message4(r1); - - // Queue some messages in the message packet queue. - im = &message1; - queue.emplace(*im); - - im = &message2; - queue.emplace(*im); - - // The router2 queue doesn't accept Message3 types. - im = &message3; - CHECK_THROW(queue.emplace(*im), etl::unhandled_message_exception); - - im = &message4; - queue.emplace(*im); - - im = &message4; - queue.emplace(*im); - - etl::imessage& imr1 = queue.front().get(); - r2.receive(imr1); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(0, r2.message2_count); - CHECK_EQUAL(0, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - CHECK_EQUAL(1, r1.callback_count); - queue.pop(); - - etl::imessage& imr2 = queue.front().get(); - r2.receive(imr2); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(0, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - CHECK_EQUAL(2, r1.callback_count); - queue.pop(); - - const etl::imessage& imr3 = queue.front().get(); - r2.receive(imr3); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(1, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - CHECK_EQUAL(3, r1.callback_count); - queue.pop(); - - const Queue& crqueue = queue; - const etl::imessage& imr4 = crqueue.front().get(); - r2.receive(imr4); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(2, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - CHECK_EQUAL(4, r1.callback_count); - queue.pop(); - } -#endif - - //************************************************************************* - TEST(message_router_successor) - { - Router1 r1; - Router2 r2(r1); - - etl::null_message_router null_router; - - Message1 message1(r2); - Message2 message2(r2); - Message3 message3(r2); - Message4 message4(r2); - - etl::send_message(r2, message1); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(0, r2.message2_count); - CHECK_EQUAL(0, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - - CHECK_EQUAL(0, r1.message1_count); - CHECK_EQUAL(0, r1.message2_count); - CHECK_EQUAL(0, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - - etl::send_message(r2, message2); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(0, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - - CHECK_EQUAL(0, r1.message1_count); - CHECK_EQUAL(0, r1.message2_count); - CHECK_EQUAL(0, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - - r2.receive(message3); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(0, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - - CHECK_EQUAL(0, r1.message1_count); - CHECK_EQUAL(0, r1.message2_count); - CHECK_EQUAL(1, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - - etl::send_message(r2, message4); - CHECK_EQUAL(1, r2.message1_count); - CHECK_EQUAL(1, r2.message2_count); - CHECK_EQUAL(1, r2.message4_count); - CHECK_EQUAL(0, r2.message_unknown_count); - - CHECK_EQUAL(0, r1.message1_count); - CHECK_EQUAL(0, r1.message2_count); - CHECK_EQUAL(1, r1.message3_count); - CHECK_EQUAL(0, r1.message4_count); - CHECK_EQUAL(0, r1.message_unknown_count); - } - - //************************************************************************* - TEST(message_router_with_overloaded_receive) - { - Router3 router; - - Message1 message1(router); - Message2 message2(router); - Message3 message3(router); - - router.receive(message1); - CHECK_TRUE(router.message1_received); - - router.receive(message2); - CHECK_TRUE(router.message2_received); - - router.receive(message3); - CHECK_TRUE(router.message3_received); - - CHECK_FALSE(router.unknown_message_received); - } - } -} diff --git a/test/test_observer_with_type_list.cpp b/test/test_observer_with_type_list.cpp deleted file mode 100644 index e0b61f54..00000000 --- a/test/test_observer_with_type_list.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2025 John Wellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#include "unit_test_framework.h" - -#include "etl/observer.h" -#include "etl/type_list.h" - -#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) - -namespace -{ - //***************************************************************************** - // Notification1 - //***************************************************************************** - struct Notification1 - { - }; - - //***************************************************************************** - // Notification2 - //***************************************************************************** - struct Notification2 - { - }; - - //***************************************************************************** - // Notification3 - //***************************************************************************** - struct Notification3 - { - }; - - //***************************************************************************** - // Generic notification. - //***************************************************************************** - template - struct Notification - { - }; - - //***************************************************************************** - // The observer base type. - // Declare what notifications you want to observe and how they are passed to 'notification'. - // The Notification1 is passed by value. - // The Notification2 is passed by reference. - // The Notification3 is passed by const reference. - //***************************************************************************** - using NotificationTypes = etl::type_list; - using ObserverType = etl::observer; - - //***************************************************************************** - // The observer base type that does not take a notification type. - //***************************************************************************** - typedef etl::observer ObserverVoidIntType; -} - -//***************************************************************************** -// The concrete observable 1 class. -//***************************************************************************** -class Observable1 : public etl::observable -{ -public: - - Notification1 data1; - Notification2 data2; - Notification1& data3 = data1; - - //********************************* - // Notify all of the observers. - //********************************* - void send_notifications() - { - notify_observers(data3); - notify_observers(data2); - } -}; - -//***************************************************************************** -// The concrete observable 2 class. -//***************************************************************************** -class Observable2 : public etl::observable -{ -public: - - Notification3 data3; - - //********************************* - // Notify all of the observers. - //********************************* - void send_notifications() - { - notify_observers(data3); - } -}; - -//***************************************************************************** -// The concrete observable 3 class. -//***************************************************************************** -class ObservableVoidInt : public etl::observable -{ -public: - - //********************************* - // Notify all of the observers. - //********************************* - void send_notifications() - { - notify_observers(); - } - - //********************************* - // Notify all of the observers. - //********************************* - void send_notifications(int n) - { - notify_observers(n); - } -}; - -//***************************************************************************** -// The first observer type. -// If any one of the overloads is missing or a parameter declaration is incorrect -// then the class will be 'abstract' and will not compile. -//***************************************************************************** -class Observer1 : public ObserverType -{ -public: - - Observer1() - : data1_count(0) - , data2_count(0) - , data3_count(0) - { - } - - //******************************************* - // Notification1 is passed by value. - //******************************************* - void notification(Notification1 /*data1*/) - { - ++data1_count; - } - - //******************************************* - // Notification2 is passed by reference. - //******************************************* - void notification(Notification2& /*data2*/) - { - ++data2_count; - } - - //******************************************* - // Notification3 is passed by const reference. - //******************************************* - void notification(const Notification3& /*data3*/) - { - ++data3_count; - } - - int data1_count; - int data2_count; - int data3_count; -}; - -//***************************************************************************** -// The second observer type. -// If any one of the overloads is missing or a parameter declaration is incorrect -// then the class will be 'abstract' and will not compile. -//***************************************************************************** -class Observer2 : public ObserverType -{ -public: - - Observer2() - : data1_count(0) - , data2_count(0) - , data3_count(0) - { - } - - //******************************************* - // Notification1 is passed by value. - //******************************************* - void notification(Notification1 /*data1*/) - { - ++data1_count; - } - - //******************************************* - // Notification2 is passed by reference. - //******************************************* - void notification(Notification2& /*data2*/) - { - ++data2_count; - } - - //******************************************* - // Notification3 is passed by const reference. - //******************************************* - void notification(const Notification3& /*data3*/) - { - ++data3_count; - } - - int data1_count; - int data2_count; - int data3_count; -}; - -//***************************************************************************** -// The third observer type. -// If any one of the overloads is missing or a parameter declaration is incorrect -// then the class will be 'abstract' and will not compile. -//***************************************************************************** -class ObserverVoidInt : public ObserverVoidIntType -{ -public: - - ObserverVoidInt() - : data1_count(0) - , data2_count(0) - { - } - - //******************************************* - // Notification1 - //******************************************* - void notification() override - { - ++data1_count; - } - - //******************************************* - // Notification2 - //******************************************* - void notification(int) override - { - ++data2_count; - } - - int data1_count; - int data2_count; -}; - -namespace -{ - SUITE(test_observer) - { - //************************************************************************* - TEST(test_2_observables_2_observers_3_notifications) - { - // The observable objects. - Observable1 observable1; - Observable2 observable2; - - // The observer objects. - Observer1 observer1; - Observer2 observer2; - - observable1.add_observer(observer1); - - // Send the notifications. - observable1.send_notifications(); // Updates data1 & data2. - - CHECK_EQUAL(1, observer1.data1_count); - CHECK_EQUAL(1, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(0, observer2.data1_count); - CHECK_EQUAL(0, observer2.data2_count); - CHECK_EQUAL(0, observer2.data3_count); - - observable2.send_notifications(); // Updates data3. observeable2 has no observers yet. - - CHECK_EQUAL(1, observer1.data1_count); - CHECK_EQUAL(1, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(0, observer2.data1_count); - CHECK_EQUAL(0, observer2.data2_count); - CHECK_EQUAL(0, observer2.data3_count); - - // Add an observer to both. - observable1.add_observer(observer2); - observable2.add_observer(observer2); - - // Send the notifications. - observable1.send_notifications(); // Updates data1 & data2. - - CHECK_EQUAL(2, observer1.data1_count); - CHECK_EQUAL(2, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(1, observer2.data1_count); - CHECK_EQUAL(1, observer2.data2_count); - CHECK_EQUAL(0, observer2.data3_count); - - observable2.send_notifications(); // Updates data3. - - CHECK_EQUAL(2, observer1.data1_count); - CHECK_EQUAL(2, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(1, observer2.data1_count); - CHECK_EQUAL(1, observer2.data2_count); - CHECK_EQUAL(1, observer2.data3_count); - - observable1.remove_observer(observer1); - - // Send the notifications. - observable1.send_notifications(); // Updates data1 & data2. - - CHECK_EQUAL(2, observer1.data1_count); - CHECK_EQUAL(2, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(2, observer2.data1_count); - CHECK_EQUAL(2, observer2.data2_count); - CHECK_EQUAL(1, observer2.data3_count); - - observable2.send_notifications(); // Updates data3. - - CHECK_EQUAL(2, observer1.data1_count); - CHECK_EQUAL(2, observer1.data2_count); - CHECK_EQUAL(0, observer1.data3_count); - - CHECK_EQUAL(2, observer2.data1_count); - CHECK_EQUAL(2, observer2.data2_count); - CHECK_EQUAL(2, observer2.data3_count); - } - - //************************************************************************* - TEST(test_observable_2_observers_enable_disable) - { - // The observable objects. - Observable1 observable1; - - // The observer objects. - Observer1 observer1; - Observer2 observer2; - - observable1.add_observer(observer1); - observable1.add_observer(observer2); - - // Send the notifications. - observable1.send_notifications(); - - CHECK_EQUAL(1, observer1.data1_count); - CHECK_EQUAL(1, observer2.data1_count); - - // Disable observer1. Send the notifications. - observable1.disable_observer(observer1); - observable1.send_notifications(); - - CHECK_EQUAL(1, observer1.data1_count); - CHECK_EQUAL(2, observer2.data1_count); - - // Disable observer2. Send the notifications. - observable1.enable_observer(observer2, false); - observable1.send_notifications(); - - CHECK_EQUAL(1, observer1.data1_count); - CHECK_EQUAL(2, observer2.data1_count); - - // Enable observer1. Send the notifications. - observable1.enable_observer(observer1); - observable1.send_notifications(); - - CHECK_EQUAL(2, observer1.data1_count); - CHECK_EQUAL(2, observer2.data1_count); - - // Enable observer2. Send the notifications. - observable1.enable_observer(observer2, true); - observable1.send_notifications(); - - CHECK_EQUAL(3, observer1.data1_count); - CHECK_EQUAL(3, observer2.data1_count); - } - - //************************************************************************* - TEST(test_8_notifications) - { - typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7>, Notification<8> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_7_notifications) - { - typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6>, Notification<7> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_6_notifications) - { - typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5>, Notification<6> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_5_notifications) - { - typedef etl::observer, Notification<2>, Notification<3>, Notification<4>, Notification<5> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_4_notifications) - { - typedef etl::observer, Notification<2>, Notification<3>, Notification<4> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_3_notifications) - { - typedef etl::observer, Notification<2>, Notification<3> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_2_notifications) - { - typedef etl::observer, Notification<2> > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_1_notification) - { - typedef etl::observer > Observer; - - class Observable : public etl::observable - { - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_observer_list) - { - class Observer : public etl::observer - { - void notification(Notification1) {} - }; - - class Observable : public etl::observable - { - }; - - Observable observable; - - Observer observer1; - Observer observer2; - Observer observer3; - Observer observer4; - Observer observer5; - - observable.add_observer(observer1); - CHECK_EQUAL(1UL, observable.number_of_observers()); - - observable.add_observer(observer2); - CHECK_EQUAL(2UL, observable.number_of_observers()); - - observable.add_observer(observer3); - CHECK_EQUAL(3UL, observable.number_of_observers()); - - observable.add_observer(observer2); - CHECK_EQUAL(3UL, observable.number_of_observers()); - - observable.add_observer(observer4); - CHECK_EQUAL(4UL, observable.number_of_observers()); - - CHECK_THROW(observable.add_observer(observer5), etl::observer_list_full); - - CHECK(observable.remove_observer(observer3)); - CHECK_EQUAL(3UL, observable.number_of_observers()); - - // Try again. - CHECK(!observable.remove_observer(observer3)); - CHECK_EQUAL(3UL, observable.number_of_observers()); - - observable.clear_observers(); - CHECK_EQUAL(0UL, observable.number_of_observers()); - } - - //************************************************************************* - TEST(test_void_int_observable) - { - // The observable objects. - ObservableVoidInt observable; - - // The observer objects. - ObserverVoidInt observer; - - observable.add_observer(observer); - - // Send the notifications. - observable.send_notifications(); - CHECK_EQUAL(1U, observer.data1_count); - CHECK_EQUAL(0U, observer.data2_count); - - observable.send_notifications(1); - CHECK_EQUAL(1U, observer.data1_count); - CHECK_EQUAL(1U, observer.data2_count); - } - } -} - - -#endif - diff --git a/test/test_visitor_with_type_list.cpp b/test/test_visitor_with_type_list.cpp deleted file mode 100644 index 04660ee9..00000000 --- a/test/test_visitor_with_type_list.cpp +++ /dev/null @@ -1,761 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2025 John Wellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#include "unit_test_framework.h" - -#include "etl/visitor.h" - -#if ETL_USING_CPP11 && !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) - -//***************************************************************************** -// Pre-declare the data types. -//***************************************************************************** -class Square; -class Circle; -class Triangle; - -//***************************************************************************** -// What classes do you want the visitors to handle? -// Square will be passed by reference. -// Circle will be passed by reference. -// Triangle will be passed by const reference. -//***************************************************************************** -using DrawTypes = etl::type_list; -using DrawVisitorType = etl::visitor; - -//***************************************************************************** -// What classes do you want the visitors to handle? -// Square will be passed by reference. -// Triangle will be passed by const reference. -//***************************************************************************** -using LogTypes = etl::type_list; -using LogVisitorType = etl::visitor; - -//***************************************************************************** -// Base shape. -//***************************************************************************** -using VisitorTypes = etl::type_list; - -class ShapeBase : public etl::visitable -{ -}; - -//***************************************************************************** -// Square accepts draw & log visitors. -//***************************************************************************** -class Square : public ShapeBase -{ -public: - - void accept(DrawVisitorType& visitor) - { - visitor.visit(*this); - } - - void accept(LogVisitorType& visitor) - { - visitor.visit(*this); - } -}; - -//***************************************************************************** -// Circle only accepts draw visitors. -//***************************************************************************** -class Circle : public ShapeBase -{ -public: - - void accept(DrawVisitorType& visitor) - { - visitor.visit(*this); - } - - void accept(LogVisitorType&) - { - } -}; - -//***************************************************************************** -// Triangle accepts draw & log visitors. -//***************************************************************************** -class Triangle : public ShapeBase -{ -public: - - void accept(DrawVisitorType& visitor) - { - visitor.visit(*this); - } - - void accept(LogVisitorType& visitor) - { - visitor.visit(*this); - } -}; - - -//***************************************************************************** -// Generic other shapes. -//***************************************************************************** -template -class Shape : public etl::visitable -{ -public: - - void accept(TVisitor& visitor) - { - visitor.visit(*this); - } -}; - -//***************************************************************************** -class DrawVisitor : public DrawVisitorType -{ -public: - - DrawVisitor() - : square_called(false), - circle_called(false), - triangle_called(false) - { - } - - void visit(Square&) - { - square_called = true; - } - - void visit(Circle&) - { - circle_called = true; - } - - void visit(const Triangle&) - { - triangle_called = true; - } - - bool square_called; - bool circle_called; - bool triangle_called; -}; - -//***************************************************************************** -class LogVisitor : public LogVisitorType -{ -public: - - LogVisitor() - : square_called(false), - circle_called(false), - triangle_called(false) - { - } - - void visit(Square&) - { - square_called = true; - } - - // SHOULD NEVER BE CALLED. - void visit(Circle&) - { - circle_called = true; - } - - void visit(const Triangle&) - { - triangle_called = true; - } - - bool square_called; - bool circle_called; - bool triangle_called; -}; - -namespace -{ - SUITE(test_visitor) - { - //************************************************************************* - TEST(test_two_visitors_three_visitables) - { - DrawVisitor draw_visitor; - LogVisitor log_visitor; - - Square square; - Circle circle; - Triangle triangle; - - ShapeBase* pShapeBase; - - CHECK_EQUAL(false, draw_visitor.square_called); - CHECK_EQUAL(false, draw_visitor.circle_called); - CHECK_EQUAL(false, draw_visitor.triangle_called); - CHECK_EQUAL(false, log_visitor.square_called); - CHECK_EQUAL(false, log_visitor.circle_called); - CHECK_EQUAL(false, log_visitor.triangle_called); - - square.accept(draw_visitor); - square.accept(log_visitor); - - CHECK_EQUAL(true, draw_visitor.square_called); - CHECK_EQUAL(false, draw_visitor.circle_called); - CHECK_EQUAL(false, draw_visitor.triangle_called); - CHECK_EQUAL(true, log_visitor.square_called); - CHECK_EQUAL(false, log_visitor.circle_called); - CHECK_EQUAL(false, log_visitor.triangle_called); - - circle.accept(draw_visitor); - - CHECK_EQUAL(true, draw_visitor.square_called); - CHECK_EQUAL(true, draw_visitor.circle_called); - CHECK_EQUAL(false, draw_visitor.triangle_called); - CHECK_EQUAL(true, log_visitor.square_called); - CHECK_EQUAL(false, log_visitor.circle_called); - CHECK_EQUAL(false, log_visitor.triangle_called); - - pShapeBase = ▵ - pShapeBase->accept(draw_visitor); - pShapeBase->accept(log_visitor); - - CHECK_EQUAL(true, draw_visitor.square_called); - CHECK_EQUAL(true, draw_visitor.circle_called); - CHECK_EQUAL(true, draw_visitor.triangle_called); - CHECK_EQUAL(true, log_visitor.square_called); - CHECK_EQUAL(false, log_visitor.circle_called); - CHECK_EQUAL(true, log_visitor.triangle_called); - } - - //************************************************************************* - TEST(test_1_visitor) - { - class AShape; - class ShapeVisitor1 : public etl::visitor - { - void visit(AShape&) {} - }; - - class AShape : public etl::visitable - { - public: - - void accept(ShapeVisitor1&) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_2_visitor) - { - class AShape; - class ShapeVisitor1 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor2 : public etl::visitor - { - void visit(AShape&) {} - }; - - class AShape : public etl::visitable - { - public: - - void accept(ShapeVisitor1&) {} - void accept(ShapeVisitor2&) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_3_visitor) - { - class AShape; - class ShapeVisitor1 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor2 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor3 : public etl::visitor - { - void visit(AShape&) {} - }; - - class AShape : public etl::visitable - { - public: - - void accept(ShapeVisitor1&) {} - void accept(ShapeVisitor2&) {} - void accept(ShapeVisitor3&) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_4_visitor) - { - class AShape; - class ShapeVisitor1 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor2 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor3 : public etl::visitor - { - void visit(AShape&) {} - }; - - class ShapeVisitor4 : public etl::visitor - { - void visit(AShape&) {} - }; - - using ShapeVisitorTypes = etl::type_list; - - class AShape : public etl::visitable - { - public: - - void accept(ShapeVisitor1&) {} - void accept(ShapeVisitor2&) {} - void accept(ShapeVisitor3&) {} - void accept(ShapeVisitor4&) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_1_visitable) - { - class ShapeVisitor : public etl::visitor > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_2_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_3_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_4_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_5_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_6_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_7_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_8_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_9_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_10_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - - //************************************************************************* - TEST(test_11_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_12_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - void visit(Shape<12, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_13_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, - Shape<13, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - void visit(Shape<12, ShapeVisitor>) {} - void visit(Shape<13, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_14_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, - Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - void visit(Shape<12, ShapeVisitor>) {} - void visit(Shape<13, ShapeVisitor>) {} - void visit(Shape<14, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_15_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, - Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - void visit(Shape<12, ShapeVisitor>) {} - void visit(Shape<13, ShapeVisitor>) {} - void visit(Shape<14, ShapeVisitor>) {} - void visit(Shape<15, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - TEST(test_16_visitable) - { - class ShapeVisitor : public etl::visitor , Shape<2, ShapeVisitor>, Shape<3, ShapeVisitor>, Shape<4, ShapeVisitor>, - Shape<5, ShapeVisitor>, Shape<6, ShapeVisitor>, Shape<7, ShapeVisitor>, Shape<8, ShapeVisitor>, - Shape<9, ShapeVisitor>, Shape<10, ShapeVisitor>, Shape<11, ShapeVisitor>, Shape<12, ShapeVisitor>, - Shape<13, ShapeVisitor>, Shape<14, ShapeVisitor>, Shape<15, ShapeVisitor>, Shape<16, ShapeVisitor> > - { - public: - - void visit(Shape<1, ShapeVisitor>) {} - void visit(Shape<2, ShapeVisitor>) {} - void visit(Shape<3, ShapeVisitor>) {} - void visit(Shape<4, ShapeVisitor>) {} - void visit(Shape<5, ShapeVisitor>) {} - void visit(Shape<6, ShapeVisitor>) {} - void visit(Shape<7, ShapeVisitor>) {} - void visit(Shape<8, ShapeVisitor>) {} - void visit(Shape<9, ShapeVisitor>) {} - void visit(Shape<10, ShapeVisitor>) {} - void visit(Shape<11, ShapeVisitor>) {} - void visit(Shape<12, ShapeVisitor>) {} - void visit(Shape<13, ShapeVisitor>) {} - void visit(Shape<14, ShapeVisitor>) {} - void visit(Shape<15, ShapeVisitor>) {} - void visit(Shape<16, ShapeVisitor>) {} - }; - - // This test just needs to compile without errors. - CHECK(true); - } - - //************************************************************************* - struct NotVisitor {}; - - TEST(test_is_visitor) - { -#if ETL_USING_CPP17 - CHECK_TRUE(etl::is_visitor_v); - CHECK_TRUE(etl::is_visitor_v); - CHECK_FALSE(etl::is_visitor_v); -#else - CHECK_TRUE(etl::is_visitor::value); - CHECK_TRUE(etl::is_visitor::value); - CHECK_FALSE(etl::is_visitor::value); -#endif - } - } -} - -#endif - From d7dc1281ae194cd21db2a3ca415226994b8e7239 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:20:01 +0000 Subject: [PATCH 028/167] Fix iter_swap namespace --- include/etl/algorithm.h | 2 +- include/etl/private/ivectorpointer.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 88b8f7b6..a5879e2c 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -186,7 +186,7 @@ namespace etl { while (first1 != last1) { - iter_swap(first1, first2); + etl::iter_swap(first1, first2); ++first1; ++first2; } diff --git a/include/etl/private/ivectorpointer.h b/include/etl/private/ivectorpointer.h index f9f6dd7e..597fc8ab 100644 --- a/include/etl/private/ivectorpointer.h +++ b/include/etl/private/ivectorpointer.h @@ -483,7 +483,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); @@ -931,7 +931,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); From 69b741adb82fe73192a62b0080b714227e443cdb Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:22:37 +0000 Subject: [PATCH 029/167] Add type_list functionality to etl::variant using etl::variant_from_type_list --- include/etl/private/variant_variadic.h | 35 ++++++----- test/test_variant_variadic.cpp | 87 ++++++++++++++------------ 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index ddcdd33c..afbf7243 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -253,7 +253,7 @@ namespace etl template struct variant_alternative> { - using type = etl::nth_type_t::type_list>; + using type = etl::nth_type_t; }; template @@ -1218,26 +1218,13 @@ namespace etl size_t type_id; }; - //*************************************************************************** - /// Delcare a variant using an etl::type_list. - //*************************************************************************** - template - class variant> : public etl::variant - { - public: - - using base_type = etl::variant; - using type_list = typename base_type::type_list; - using base_type::base_type; // Inherit all ctors - }; - //*************************************************************************** /// Checks if the variant v holds the alternative T. //*************************************************************************** template ETL_CONSTEXPR14 bool holds_alternative(const etl::variant& v) ETL_NOEXCEPT { - constexpr size_t Index = etl::type_list_index_of_type::type_list, T>::value; + constexpr size_t Index = etl::type_list_index_of_type, T>::value; return (Index == variant_npos) ? false : (v.index() == Index); } @@ -1268,7 +1255,7 @@ namespace etl get(etl::variant& v) { #if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11) - static_assert(Index < etl::type_list_size::type_list>::value, "Index out of range"); + static_assert(Index < etl::type_list_size>::value, "Index out of range"); #endif ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); @@ -1441,7 +1428,7 @@ namespace etl template struct variant_size> - : etl::integral_constant::type_list>::value> + : etl::integral_constant>::value> { }; @@ -1867,5 +1854,19 @@ namespace etl } } #endif + + //*************************************************************************** + /// Helper to turn etl::type_list into etl::variant + template + struct variant_from_type_list; + + template + struct variant_from_type_list> + { + using type = etl::variant; + }; + + template + using variant_from_type_list_t = typename variant_from_type_list::type; } #endif diff --git a/test/test_variant_variadic.cpp b/test/test_variant_variadic.cpp index 6e91fa34..bf684bcd 100644 --- a/test/test_variant_variadic.cpp +++ b/test/test_variant_variadic.cpp @@ -427,10 +427,10 @@ namespace { TEST(test_alignment) { - typedef etl::variant test_variant_a; - typedef etl::variant test_variant_b; - typedef etl::variant test_variant_c; - typedef etl::variant test_variant_d; + using test_variant_a = etl::variant; + using test_variant_b = etl::variant; + using test_variant_c = etl::variant; + using test_variant_d = etl::variant; static test_variant_a a(char('1')); static test_variant_b b(short(2)); @@ -443,6 +443,48 @@ namespace CHECK((uintptr_t(&etl::get(d)) % uintptr_t(etl::alignment_of::value)) == 0); } + //************************************************************************* + TEST(test_variant_from_type_list) + { + struct DefaultConstructible + { + DefaultConstructible() + : value(1) + { + } + + int value = 0; + }; + + using type_list = etl::type_list; + using test_variant_t = etl::variant_from_type_list_t; + using normal_variant_t = etl::variant; + + CHECK_NO_THROW(test_variant_t variant_etl); + + test_variant_t variant_etl; + + // Are the type lists the same? + CHECK_TRUE((std::is_same::value)); + + // Are the variants the same? + CHECK_TRUE((std::is_same::value)); + + CHECK_TRUE(etl::holds_alternative(variant_etl)); + CHECK_FALSE(etl::holds_alternative(variant_etl)); + CHECK_FALSE(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(1, etl::get<0U>(variant_etl).value); + + CHECK_TRUE(etl::holds_alternative<0U>(variant_etl)); + CHECK_FALSE(etl::holds_alternative<1U>(variant_etl)); + CHECK_FALSE(etl::holds_alternative<2U>(variant_etl)); + + CHECK_TRUE(etl::holds_alternative(0U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(1U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(2U, variant_etl)); + CHECK_FALSE(etl::holds_alternative(99U, variant_etl)); + } + //************************************************************************* TEST(test_constructor_default) { @@ -479,43 +521,6 @@ namespace CHECK_FALSE(etl::holds_alternative(99U, variant_etl)); } - //************************************************************************* - TEST(test_constructor_default_variant_from_type_list) - { - struct DefaultConstructible - { - DefaultConstructible() - : value(1) - { - } - - int value = 0; - }; - - using variant_types = etl::type_list; - using test_variant_t = etl::variant; - - CHECK_NO_THROW(test_variant_t variant_etl); - - test_variant_t variant_etl; - - CHECK_TRUE((std::is_same::value)); - - CHECK_TRUE(etl::holds_alternative(variant_etl)); - CHECK_FALSE(etl::holds_alternative(variant_etl)); - CHECK_FALSE(etl::holds_alternative(variant_etl)); - CHECK_EQUAL(1, etl::get<0U>(variant_etl).value); - - CHECK_TRUE(etl::holds_alternative<0U>(variant_etl)); - CHECK_FALSE(etl::holds_alternative<1U>(variant_etl)); - CHECK_FALSE(etl::holds_alternative<2U>(variant_etl)); - - CHECK_TRUE(etl::holds_alternative(0U, variant_etl)); - CHECK_FALSE(etl::holds_alternative(1U, variant_etl)); - CHECK_FALSE(etl::holds_alternative(2U, variant_etl)); - CHECK_FALSE(etl::holds_alternative(99U, variant_etl)); - } - //************************************************************************* TEST(test_constructor_value) { From 746761124c3080c47fc24654f1164336f3e67547 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:24:45 +0000 Subject: [PATCH 030/167] Add type_list functionality to etl::message_packet using etl::message_packet_from_type_list --- include/etl/message_packet.h | 80 ++++++------------------------------ test/test_message_packet.cpp | 15 ++++++- 2 files changed, 26 insertions(+), 69 deletions(-) diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index aa449cb8..d729c940 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -384,17 +384,19 @@ namespace etl }; //*************************************************************************** - // The definition for all message types. - //*************************************************************************** - template - class message_packet> : public etl::message_packet - { - public: + /// Helper to turn etl::type_list into etl::message_packet + template + struct message_packet_from_type_list; - using base_type = etl::message_packet; - using base_type::base_type; // Inherit all ctors + template + struct message_packet_from_type_list> + { + using type = etl::message_packet; }; + template + using message_packet_from_type_list_t = typename message_packet_from_type_list::type; + #else //*************************************************************************** @@ -4940,9 +4942,8 @@ namespace etl { public: - ETL_STATIC_ASSERT(!etl::is_type_list::value, - "T1 must not be an etl::type_list. " - "Use etl::message_packet> only with the C++17 variadic overload."); + //ETL_STATIC_ASSERT(!etl::is_type_list::value, + // "message_packet does not accept an etl::type_list before C++17, or when ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION is defined"); #if ETL_USING_CPP11 using message_types = etl::type_list; @@ -5207,63 +5208,6 @@ namespace etl typename etl::aligned_storage::type data; bool valid; }; - - //*************************************************************************** - // Specialisation for 0 message types. - //*************************************************************************** - template <> - class message_packet - { - public: - -#if ETL_USING_CPP11 - using message_types = etl::type_list<>; -#endif - - message_packet() - : valid(false) - { - } - - static ETL_CONSTEXPR bool accepts(etl::message_id_t) - { - return false; - } - - static ETL_CONSTEXPR bool accepts(const etl::imessage&) - { - return false; - } - - template - static ETL_CONSTEXPR bool accepts() - { - ETL_UNUSED(Id); - return false; - } - - template - static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type accepts() - { - return false; - } - - bool is_valid() const - { - return valid; - } - - enum - { - SIZE = 0U, - ALIGNMENT = 1U - }; - - private: - - bool valid; - }; #endif } diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index 206d9f8c..3492a898 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -29,7 +29,6 @@ SOFTWARE. #include "unit_test_framework.h" #include "etl/platform.h" - #include "etl/message_packet.h" #include @@ -202,6 +201,11 @@ namespace using Packet = etl::message_packet; +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) + using MessageTypes = etl::type_list; + using PacketFromMessageTypes = etl::message_packet_from_type_list_t; +#endif + struct Object { void Push(const etl::message_packet& p) @@ -224,12 +228,21 @@ namespace Packet packet1(message1); Packet packet2(message2); +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) + PacketFromMessageTypes packet3(message3); +#else Packet packet3(message3); +#endif // Should cause a static assert. //Packet packet4(message4); //Packet packet4((Message4())); + CHECK_TRUE((std::is_same, typename Packet::message_types>::value)); +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) + CHECK_TRUE((std::is_same, typename PacketFromMessageTypes::message_types>::value)); +#endif + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); CHECK_EQUAL(MESSAGE3, packet3.get().get_message_id()); From 124309947150c765bf452b81809e2b8929d72bc2 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:25:08 +0000 Subject: [PATCH 031/167] Add type_list functionality to etl::message_router using etl::message_router_from_type_list --- include/etl/message_router.h | 17 ++++++++++------- test/test_message_router.cpp | 12 +++++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 42fc65f8..7073f38c 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -552,16 +552,19 @@ namespace etl }; //*************************************************************************** - // The definition for all message types defined by a type_list. - //*************************************************************************** - template - class message_router> : public message_router - { - public: + /// Helper to turn etl::type_list into etl::tuple + template + struct message_router_from_type_list; - using message_router::message_router; + template + struct message_router_from_type_list> + { + using type = etl::message_router; }; + template + using message_router_from_type_list_t = typename message_router_from_type_list::type; + #else //************************************************************************************************* // For C++14 and below. diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp index e7d94ac1..53da2b6b 100644 --- a/test/test_message_router.cpp +++ b/test/test_message_router.cpp @@ -121,8 +121,15 @@ namespace //*************************************************************************** // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. + // Created from a type list. //*************************************************************************** +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + using Router1Messages = etl::type_list; + + class Router1 : public etl::message_router_from_type_list_t +#else class Router1 : public etl::message_router +#endif { public: @@ -135,7 +142,6 @@ namespace message_unknown_count(0), callback_count(0) { - } void on_receive(const Message1& msg) @@ -341,7 +347,7 @@ namespace Message3 message3(r2); Message4 message4(r2); - // CHECK(!r1.is_null_router()); + CHECK(!r1.is_null_router()); CHECK(r1.is_producer()); CHECK(r1.is_consumer()); @@ -389,7 +395,7 @@ namespace Message3 message3(null_router); Message4 message4(null_router); - // CHECK(null_router.is_null_router()); + CHECK(null_router.is_null_router()); CHECK(!null_router.is_producer()); CHECK(!null_router.is_consumer()); From a669d1f46ea0c1bf330343622a01d3be8bb64d69 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:26:20 +0000 Subject: [PATCH 032/167] Add type_list functionality to etl::observer using etl::observer_from_type_list --- include/etl/observer.h | 35 +++++++++-------------------------- test/test_observer.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/include/etl/observer.h b/include/etl/observer.h index d7a75776..26f88478 100644 --- a/include/etl/observer.h +++ b/include/etl/observer.h @@ -326,8 +326,6 @@ namespace etl virtual ~observer() = default; virtual void notification(T1) = 0; - - using type_list = etl::type_list; }; //***************************************************************** @@ -344,36 +342,21 @@ namespace etl virtual ~observer() = default; virtual void notification() = 0; - - using type_list = etl::type_list<>; }; - //***************************************************************** - /// The observer class for N types. - /// Configured from a type list. - ///\ingroup observer - //***************************************************************** + //*************************************************************************** + /// Helper to turn etl::type_list into etl::observer + template + struct observer_from_type_list; + template - class observer> : public observer + struct observer_from_type_list> { - public: - - using observer::notification; - using type_list = etl::type_list; + using type = etl::observer; }; - //***************************************************************** - /// The specialised observer class for etl::type_list. - ///\ingroup observer - //**************************************************************** - template - class observer> : public observer - { - public: - - using observer::observer; - using observer::notification; - }; + template + using observer_from_type_list_t = typename observer_from_type_list::type; #else diff --git a/test/test_observer.cpp b/test/test_observer.cpp index 5ae52139..f8eb72ae 100644 --- a/test/test_observer.cpp +++ b/test/test_observer.cpp @@ -78,8 +78,8 @@ namespace // The Notification2 is passed by reference. // The Notification3 is passed by const reference. //***************************************************************************** - using NotificationList = etl::type_list; - using ObserverTypeFromTypeList = etl::observer; + using NotificationList = etl::type_list; + using ObserverFromTypeList = etl::observer_from_type_list_t; #endif //***************************************************************************** @@ -131,7 +131,7 @@ public: //***************************************************************************** // The concrete observable 3 class. //***************************************************************************** -class Observable3 : public etl::observable +class Observable3 : public etl::observable { public: @@ -270,7 +270,7 @@ public: // If any one of the overloads is missing or a parameter declaration is incorrect // then the class will be 'abstract' and will not compile. //***************************************************************************** -class Observer3 : public ObserverTypeFromTypeList +class Observer3 : public ObserverFromTypeList { public: From a4e4527669ed1bae445802f197ecc9cd5bfcb7b5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:26:57 +0000 Subject: [PATCH 033/167] Add type_list functionality to etl::tuple using etl::tuple_from_type_list --- include/etl/tuple.h | 16 +++++++++++++++- test/test_tuple.cpp | 11 +++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/etl/tuple.h b/include/etl/tuple.h index 2dd4971e..dbdbdaa2 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -132,7 +132,7 @@ namespace etl using value_type = void; ///< The type contained by this tuple. using this_type = tuple<>; ///< The type of this tuple. using base_type = void; ///< The type of the base tuple. - using type_list = etl::type_list<>; ///< The type list for this tuple. + using type_list = etl::type_list<>; ///< The type list for this tuple. using index_sequence_type = etl::make_index_sequence<0>; ///< The index_sequence type for this tuple. //********************************* @@ -1276,6 +1276,20 @@ namespace etl { lhs.swap(rhs); } + + //*************************************************************************** + /// Helper to turn etl::type_list into etl::tuple + template + struct tuple_from_type_list; + + template + struct tuple_from_type_list> + { + using type = etl::tuple; + }; + + template + using tuple_from_type_list_t = typename tuple_from_type_list::type; } namespace std diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index ec02bdaf..d84940d9 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -104,6 +104,17 @@ namespace CHECK_TRUE((std::is_same>::value)); } + //************************************************************************* + TEST(test_tuple_from_type_list) + { + using TypeList = etl::type_list; + using TupleFromTypeList = etl::tuple_from_type_list_t; + using Tuple = etl::tuple; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + //************************************************************************* TEST(test_tuple_type_list) { From a61980660f81f51795eb8df4966a136f7825a2e8 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:33:32 +0000 Subject: [PATCH 034/167] Allow etl::make_index_sequence to be created from an etl::type_list --- include/etl/utility.h | 25 ++++++++++++++++++++++++- test/test_utility.cpp | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/include/etl/utility.h b/include/etl/utility.h index c3ea993d..46dc6003 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -565,8 +565,31 @@ namespace etl template using make_index_sequence = typename private_integer_sequence::make_index_sequence>::type; + //*********************************** + // Helper to support both parameter packs and etl::type_list + // Forward declare etl::type_list to allow use without including type_list.h template - using make_index_sequence_for = typename private_integer_sequence::make_index_sequence>::type; + struct type_list; + + namespace private_make_index_sequence_for + { + // Generic pack form + template + struct impl + { + using type = typename private_integer_sequence::make_index_sequence>::type; + }; + + // etl::type_list form + template + struct impl> : impl + { + }; + } + + // Accepts either a parameter pack of types or a single etl::type_list + template + using make_index_sequence_for = typename private_make_index_sequence_for::impl::type; //*********************************** template diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 1757a499..2339587d 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -863,5 +863,39 @@ namespace CHECK_TRUE(E::B == (etl::nontype_t::value)); } #endif + + //********************************* + TEST(test_make_index_sequence_for_pack_matches_expected) + { + struct T1 {}; + struct T2 {}; + struct T3 {}; + + using seq12 = etl::make_index_sequence_for; + using seq123 = etl::make_index_sequence_for; + using expect12 = etl::index_sequence<0U, 1U>; + using expect123 = etl::index_sequence<0U, 1U, 2U>; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + + //********************************* + TEST(test_make_index_sequence_for_type_list_matches_expected) + { + struct T1 {}; + struct T2 {}; + struct T3 {}; + + using list12 = etl::type_list; + using list123 = etl::type_list; + using seq12 = etl::make_index_sequence_for; + using seq123 = etl::make_index_sequence_for; + using expect12 = etl::index_sequence<0U, 1U>; + using expect123 = etl::index_sequence<0U, 1U, 2U>; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } } } From bde8747be8b67f294390b0addfb1714c997570c0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:42:25 +0000 Subject: [PATCH 035/167] Add type_list functionality to etl::visitor using etl::visitor_from_type_list --- include/etl/visitor.h | 23 ++++++++++------------- test/etl_profile.h | 1 + test/test_visitor.cpp | 13 +++++++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/include/etl/visitor.h b/include/etl/visitor.h index 941af701..1d917c0a 100644 --- a/include/etl/visitor.h +++ b/include/etl/visitor.h @@ -84,23 +84,20 @@ namespace etl virtual void accept(T1&) = 0; }; - //***************************************************************** - /// The visitable class for an etl::type_list. - /// Expands the type_list into the existing variadic visitable. - ///\ingroup visitor - //***************************************************************** + //*************************************************************************** + /// Helper to turn etl::type_list into etl::visitable + template + struct visitable_from_type_list; + template - class visitable> : public visitable + struct visitable_from_type_list> { - ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); - - public: - - using type_list = etl::type_list; - - using visitable::accept; + using type = etl::visitable; }; + template + using visitable_from_type_list_t = typename visitable_from_type_list::type; + #else //***************************************************************** diff --git a/test/etl_profile.h b/test/etl_profile.h index b6089a40..16d73d1b 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -110,6 +110,7 @@ SOFTWARE. #define ETL_FLAT_SET_FORCE_CPP03_IMPLEMENTATION #define ETL_FLAT_MULTISET_FORCE_CPP03_IMPLEMENTATION #define ETL_VARIANT_POOL_FORCE_CPP03_IMPLEMENTATION + #define ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION #endif #if defined(ETL_FORCE_TEST_CPP11) diff --git a/test/test_visitor.cpp b/test/test_visitor.cpp index 4ea72356..db881e78 100644 --- a/test/test_visitor.cpp +++ b/test/test_visitor.cpp @@ -746,6 +746,19 @@ namespace CHECK_FALSE(etl::is_visitor::value); #endif } + +#if !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + TEST(test_visitable_from_type_list) + { + using Visitable1 = etl::visitable; + + using TypeList = etl::type_list; + using Visitable2 = etl::visitable_from_type_list_t; + + CHECK_TRUE((std::is_same::value)); + } +#endif } } From 21f68eb7b91938a301849da1b998e726a01ee141 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:42:43 +0000 Subject: [PATCH 036/167] Fix iter_swap namespace --- include/etl/vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/etl/vector.h b/include/etl/vector.h index 92caf40c..db6d7d99 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -963,7 +963,7 @@ namespace etl ivector& smaller = other.size() > this->size() ? *this : other; ivector& larger = other.size() > this->size() ? other : *this; - ETL_OR_STD::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); + etl::swap_ranges(smaller.begin(), smaller.end(), larger.begin()); typename ivector::iterator larger_itr = etl::next(larger.begin(), smaller.size()); From fed1274324aed6f11bf13830900c57b032878003 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:45:11 +0000 Subject: [PATCH 037/167] Allow creation of a message_packet with no message types --- include/etl/message_packet.h | 170 +++++++++++++++++++++++++++++++++++ test/test_message_packet.cpp | 12 +-- 2 files changed, 174 insertions(+), 8 deletions(-) diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index d729c940..a1565f40 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -383,6 +383,119 @@ namespace etl bool valid; }; + //*************************************************************************** + // The definition for no message types. + //*************************************************************************** + template <> + class message_packet<> + { + + private: + + //template + //static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + + template + static constexpr bool IsInMessageList = false; + + template + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + + public: + + using message_types = etl::type_list<>; + + //******************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet() + { + } +#include "private/diagnostic_pop.h" + + //********************************************** + message_packet(const message_packet& other) + { + } + +#if ETL_USING_CPP11 + //********************************************** + message_packet(message_packet&& other) + { + } +#endif + + //********************************************** + void copy(const message_packet& other) + { + } + + //********************************************** + void copy(message_packet&& other) + { + } + + //********************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet& operator =(const message_packet& rhs) + { + return *this; + } +#include "private/diagnostic_pop.h" + + //********************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet& operator =(message_packet&& rhs) + { + return *this; + } +#include "private/diagnostic_pop.h" + + //******************************************** + ~message_packet() + { + } + + //******************************************** + bool is_valid() const + { + return false; + } + + //********************************************** + static ETL_CONSTEXPR bool accepts(etl::message_id_t id) + { + return false; + } + + //********************************************** + static ETL_CONSTEXPR bool accepts(const etl::imessage& msg) + { + return false; + } + + //********************************************** + template + static ETL_CONSTEXPR bool accepts() + { + return false; + } + + //********************************************** + template + static ETL_CONSTEXPR + typename etl::enable_if::value, bool>::type + accepts() + { + false; + } + + enum + { + SIZE = 0, + ALIGNMENT = 1 + }; + }; + //*************************************************************************** /// Helper to turn etl::type_list into etl::message_packet template @@ -5208,6 +5321,63 @@ namespace etl typename etl::aligned_storage::type data; bool valid; }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template <> + class message_packet + { + public: + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; +#endif + + message_packet() + : valid(false) + { + } + + static ETL_CONSTEXPR bool accepts(etl::message_id_t) + { + return false; + } + + static ETL_CONSTEXPR bool accepts(const etl::imessage&) + { + return false; + } + + template + static ETL_CONSTEXPR bool accepts() + { + ETL_UNUSED(Id); + return false; + } + + template + static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type accepts() + { + return false; + } + + bool is_valid() const + { + return valid; + } + + enum + { + SIZE = 0U, + ALIGNMENT = 1U + }; + + private: + + bool valid; + }; #endif } diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index 3492a898..e77a3f5b 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -199,12 +199,12 @@ namespace { }; + using NullPacket = etl::message_packet<>; + using Packet = etl::message_packet; -#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) using MessageTypes = etl::type_list; using PacketFromMessageTypes = etl::message_packet_from_type_list_t; -#endif struct Object { @@ -228,20 +228,16 @@ namespace Packet packet1(message1); Packet packet2(message2); -#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) PacketFromMessageTypes packet3(message3); -#else - Packet packet3(message3); -#endif + NullPacket null_packet; // Should cause a static assert. //Packet packet4(message4); //Packet packet4((Message4())); CHECK_TRUE((std::is_same, typename Packet::message_types>::value)); -#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) CHECK_TRUE((std::is_same, typename PacketFromMessageTypes::message_types>::value)); -#endif + CHECK_TRUE((std::is_same, typename NullPacket::message_types>::value)); CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); From a4ee9d01aa5ec6dd02f1f2a35750268347206678 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:45:29 +0000 Subject: [PATCH 038/167] Allow creation of a message_router with no message types --- include/etl/message_router.h | 114 +++++++++++++++++++++++++++++++++++ test/test_message_router.cpp | 96 +++++++++++++++++++++++++++-- 2 files changed, 206 insertions(+), 4 deletions(-) diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 7073f38c..70a1607a 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -418,18 +418,28 @@ namespace etl message_router() : imessage_router(etl::imessage_router::MESSAGE_ROUTER) { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::imessage_router& successor_) : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -437,6 +447,10 @@ namespace etl message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) : imessage_router(id_, successor_) { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -551,6 +565,106 @@ namespace etl } }; + //*************************************************************************** + // The definition for all message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + using message_packet = etl::message_packet<>; + using message_types = etl::type_list<>; + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + } + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + // CRTP validation: Derived must inherit from this exact specialization. + ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), + "Mismatch in derived type: TDerived does not inherit from etl::message_router"); + + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + if (has_successor()) + { + get_successor().receive(msg); + } + } + + template ::value, int>::type = 0> + void receive(const TMessage& msg) + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + return false; + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; + //*************************************************************************** /// Helper to turn etl::type_list into etl::tuple template diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp index 53da2b6b..2413d067 100644 --- a/test/test_message_router.cpp +++ b/test/test_message_router.cpp @@ -49,6 +49,7 @@ namespace enum { + ROUTER0, ROUTER1, ROUTER2, ROUTER3 @@ -119,17 +120,26 @@ namespace Message5 message5; + //*************************************************************************** + // Router that handles no messages. + //*************************************************************************** + class Router0 : public etl::message_router + { + public: + + Router0() + : message_router(ROUTER0) + { + } + }; + //*************************************************************************** // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. // Created from a type list. //*************************************************************************** -#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) using Router1Messages = etl::type_list; class Router1 : public etl::message_router_from_type_list_t -#else - class Router1 : public etl::message_router -#endif { public: @@ -384,6 +394,84 @@ namespace CHECK_EQUAL(4, r2.callback_count); } + //************************************************************************* + TEST(message_router_with_no_message_types) + { + Router0 r0; + Router1 r1; + Router2 r2; + + Message1 message1(r2); + Message2 message2(r2); + Message3 message3(r2); + Message4 message4(r2); + + r0.append_successor(r1); // All messages are passed to r1. + + CHECK_TRUE((etl::is_same>::value)); + + CHECK(!r0.is_null_router()); + CHECK(r0.is_producer()); + CHECK(r0.is_consumer()); + + r1.receive(message1); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(1, r2.callback_count); + + r1.receive(message2); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(2, r2.callback_count); + + r1.receive(message3); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(3, r2.callback_count); + + r1.receive(message4); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(1, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(4, r2.callback_count); + + //// Send from the null router. + //etl::send_message(r0, message1); + //CHECK_EQUAL(1, r2.message1_count); + //CHECK_EQUAL(0, r2.message2_count); + //CHECK_EQUAL(0, r2.message4_count); + //CHECK_EQUAL(0, r2.message_unknown_count); + + //etl::send_message(r0, message2); + //CHECK_EQUAL(1, r2.message1_count); + //CHECK_EQUAL(1, r2.message2_count); + //CHECK_EQUAL(0, r2.message4_count); + //CHECK_EQUAL(0, r2.message_unknown_count); + + //etl::send_message(r0, message3); + //CHECK_EQUAL(1, r2.message1_count); + //CHECK_EQUAL(1, r2.message2_count); + //CHECK_EQUAL(0, r2.message4_count); + //CHECK_EQUAL(1, r2.message_unknown_count); + + //etl::send_message(r0, message4); + //CHECK_EQUAL(1, r2.message1_count); + //CHECK_EQUAL(1, r2.message2_count); + //CHECK_EQUAL(1, r2.message4_count); + //CHECK_EQUAL(1, r2.message_unknown_count); + } + //************************************************************************* TEST(message_null_router) { From eb1216146ccba40a969e5854250504cd8020354f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:46:10 +0000 Subject: [PATCH 039/167] Updated VS2022 project files --- test/vs2022/etl.vcxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 09056bad..6396b761 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -10357,11 +10357,9 @@ - - @@ -11435,7 +11433,6 @@ - From fa8f07ab800712a1233888fc52ff7e665e2a7b27 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 17:46:35 +0000 Subject: [PATCH 040/167] Added missing test files CMakeLists.txt --- test/CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 31b7776d..aa4e2aac 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -86,7 +86,6 @@ add_executable(etl_tests test_closure.cpp test_closure_constexpr.cpp test_compare.cpp - test_concepts.cpp test_constant.cpp test_const_map.cpp test_const_map_constexpr.cpp @@ -184,7 +183,6 @@ add_executable(etl_tests test_flat_multiset.cpp test_flat_set.cpp test_fnv_1.cpp - test_format.cpp test_format_spec.cpp test_forward_list.cpp test_forward_list_shared_pool.cpp @@ -196,12 +194,10 @@ add_executable(etl_tests test_hash.cpp test_hfsm.cpp test_hfsm_recurse_to_inner_state_on_start.cpp - test_hfsm_transition_on_enter.cpp test_histogram.cpp test_index_of_type.cpp test_indirect_vector.cpp test_indirect_vector_external_buffer.cpp - test_inplace_function.cpp test_instance_count.cpp test_integral_limits.cpp test_intrusive_forward_list.cpp @@ -210,9 +206,7 @@ add_executable(etl_tests test_intrusive_queue.cpp test_intrusive_stack.cpp test_invert.cpp - test_invoke.cpp test_io_port.cpp - test_is_invocable.cpp test_iterator.cpp test_jenkins.cpp test_largest.cpp @@ -234,7 +228,6 @@ add_executable(etl_tests test_message_bus.cpp test_message_packet.cpp test_message_router.cpp - test_message_router_with_type_list.cpp test_message_router_registry.cpp test_message_timer.cpp test_message_timer_atomic.cpp @@ -253,7 +246,6 @@ add_executable(etl_tests test_nth_type.cpp test_numeric.cpp test_observer.cpp - test_observer_with_type_list.cpp test_optional.cpp test_overload.cpp test_packet.cpp @@ -265,7 +257,6 @@ add_executable(etl_tests test_poly_span_fixed_extent.cpp test_pool.cpp test_pool_external_buffer.cpp - test_print.cpp test_priority_queue.cpp test_pseudo_moving_average.cpp test_quantize.cpp @@ -294,7 +285,6 @@ add_executable(etl_tests test_scaled_rounding.cpp test_set.cpp test_shared_message.cpp - test_signal.cpp test_singleton.cpp test_singleton_base.cpp test_smallest.cpp @@ -372,7 +362,6 @@ add_executable(etl_tests test_vector_pointer.cpp test_vector_pointer_external_buffer.cpp test_visitor.cpp - test_visitor_with_type_list.cpp test_xor_checksum.cpp test_xor_rotate_checksum.cpp ) From ff03b2807db65273dcaad1a5a1c2ed58af90ab0a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 22:24:46 +0000 Subject: [PATCH 041/167] Fix C++03 compatibility Fixed unused aregument warnings --- include/etl/message_packet.h | 23 ++++++------ include/etl/message_router.h | 71 ++++++------------------------------ test/test_message_packet.cpp | 8 ++++ test/test_message_router.cpp | 9 +++-- 4 files changed, 37 insertions(+), 74 deletions(-) diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index a1565f40..6cdf16e3 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -389,7 +389,6 @@ namespace etl template <> class message_packet<> { - private: //template @@ -413,30 +412,30 @@ namespace etl #include "private/diagnostic_pop.h" //********************************************** - message_packet(const message_packet& other) + message_packet(const message_packet& /*other*/) { } #if ETL_USING_CPP11 //********************************************** - message_packet(message_packet&& other) + message_packet(message_packet&& /*other*/) { } #endif //********************************************** - void copy(const message_packet& other) + void copy(const message_packet& /*other*/) { } //********************************************** - void copy(message_packet&& other) + void copy(message_packet&& /*other*/) { } //********************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet& operator =(const message_packet& rhs) + message_packet& operator =(const message_packet& /*rhs*/) { return *this; } @@ -444,7 +443,7 @@ namespace etl //********************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet& operator =(message_packet&& rhs) + message_packet& operator =(message_packet&& /*rhs*/) { return *this; } @@ -462,13 +461,13 @@ namespace etl } //********************************************** - static ETL_CONSTEXPR bool accepts(etl::message_id_t id) + static ETL_CONSTEXPR bool accepts(etl::message_id_t /*id*/) { return false; } //********************************************** - static ETL_CONSTEXPR bool accepts(const etl::imessage& msg) + static ETL_CONSTEXPR bool accepts(const etl::imessage& /*msg*/) { return false; } @@ -486,7 +485,7 @@ namespace etl typename etl::enable_if::value, bool>::type accepts() { - false; + return false; } enum @@ -515,7 +514,7 @@ namespace etl //*************************************************************************** // The definition for all 16 message types. //*************************************************************************** - template @@ -5353,7 +5352,7 @@ namespace etl template static ETL_CONSTEXPR bool accepts() { - ETL_UNUSED(Id); + //ETL_UNUSED(Id); return false; } diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 70a1607a..564f5fa5 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -418,28 +418,18 @@ namespace etl message_router() : imessage_router(etl::imessage_router::MESSAGE_ROUTER) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::imessage_router& successor_) : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -447,10 +437,6 @@ namespace etl message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) : imessage_router(id_, successor_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -566,7 +552,7 @@ namespace etl }; //*************************************************************************** - // The definition for all message types. + // The definition for 0 message types. //*************************************************************************** template class message_router : public imessage_router @@ -580,28 +566,18 @@ namespace etl message_router() : imessage_router(etl::imessage_router::MESSAGE_ROUTER) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::imessage_router& successor_) : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); } //********************************************** message_router(etl::message_router_id_t id_) : imessage_router(id_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -609,10 +585,6 @@ namespace etl message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) : imessage_router(id_, successor_) { - // CRTP validation: Derived must inherit from this exact specialization. - ETL_STATIC_ASSERT((etl::is_base_of, TDerived>::value), - "Mismatch in derived type: TDerived does not inherit from etl::message_router"); - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); } @@ -641,7 +613,7 @@ namespace etl //********************************************** using imessage_router::accepts; - bool accepts(etl::message_id_t id) const ETL_OVERRIDE + bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE { return false; } @@ -687,7 +659,7 @@ namespace etl // The definition for all 16 message types. //*************************************************************************** template @@ -3035,7 +3007,7 @@ namespace etl { public: - typedef etl::message_packet message_packet; + typedef etl::message_packet<> message_packet; #if ETL_USING_CPP11 using message_types = etl::type_list<>; @@ -3072,23 +3044,10 @@ namespace etl void receive(const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.get_message_id(); - #include "etl/private/diagnostic_array_bounds_push.h" - switch (id) + if (has_successor()) { - default: - { - if (has_successor()) - { - get_successor().receive(msg); - } - else - { - static_cast(this)->on_receive_unknown(msg); - } - break; - } + get_successor().receive(msg); } #include "etl/private/diagnostic_pop.h" } @@ -3098,19 +3057,13 @@ namespace etl bool accepts(etl::message_id_t id) const ETL_OVERRIDE { - switch (id) + if (has_successor()) { - default: - { - if (has_successor()) - { - return get_successor().accepts(id); - } - else - { - return false; - } - } + return get_successor().accepts(id); + } + else + { + return false; } } diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index e77a3f5b..51b0712d 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -203,8 +203,10 @@ namespace using Packet = etl::message_packet; +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) using MessageTypes = etl::type_list; using PacketFromMessageTypes = etl::message_packet_from_type_list_t; +#endif struct Object { @@ -228,7 +230,11 @@ namespace Packet packet1(message1); Packet packet2(message2); +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) PacketFromMessageTypes packet3(message3); +#else + Packet packet3(message3); +#endif NullPacket null_packet; // Should cause a static assert. @@ -236,7 +242,9 @@ namespace //Packet packet4((Message4())); CHECK_TRUE((std::is_same, typename Packet::message_types>::value)); +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) CHECK_TRUE((std::is_same, typename PacketFromMessageTypes::message_types>::value)); +#endif CHECK_TRUE((std::is_same, typename NullPacket::message_types>::value)); CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp index 2413d067..a6691297 100644 --- a/test/test_message_router.cpp +++ b/test/test_message_router.cpp @@ -137,9 +137,12 @@ namespace // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. // Created from a type list. //*************************************************************************** +#if ETL_USING_CPP17 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) using Router1Messages = etl::type_list; - class Router1 : public etl::message_router_from_type_list_t +#else + class Router1 : public etl::message_router +#endif { public: @@ -350,13 +353,13 @@ namespace Router1 r1; Router2 r2; - p_router = &r1; - Message1 message1(r2); Message2 message2(r2); Message3 message3(r2); Message4 message4(r2); + p_router = &r1; + CHECK(!r1.is_null_router()); CHECK(r1.is_producer()); CHECK(r1.is_consumer()); From 0ad0cec3428df599501e2a7272bdc9b03a7bd673 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 29 Jan 2026 10:06:42 +0000 Subject: [PATCH 042/167] Synced message_packet generator to updated code --- .../etl/generators/message_packet_generator.h | 209 +++++++++++++++++- include/etl/message_packet.h | 72 +++--- 2 files changed, 240 insertions(+), 41 deletions(-) diff --git a/include/etl/generators/message_packet_generator.h b/include/etl/generators/message_packet_generator.h index ee55c48d..f15efb03 100644 --- a/include/etl/generators/message_packet_generator.h +++ b/include/etl/generators/message_packet_generator.h @@ -71,6 +71,7 @@ cog.outl("//******************************************************************** #include "largest.h" #include "alignment.h" #include "utility.h" +#include "type_list.h" #include @@ -97,6 +98,8 @@ namespace etl public: + using message_types = etl::type_list; + //******************************************** #include "private/diagnostic_uninitialized_push.h" message_packet() @@ -260,7 +263,7 @@ namespace etl //********************************************** template static ETL_CONSTEXPR - typename etl::enable_if::value, bool>::type + typename etl::enable_if::value, bool>::type accepts() { return accepts(); @@ -392,6 +395,132 @@ namespace etl bool valid; }; + //*************************************************************************** + // The definition for no message types. + //*************************************************************************** + template <> + class message_packet<> + { + private: + + //template + //static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + + template + static constexpr bool IsInMessageList = false; + + template + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + + public: + + using message_types = etl::type_list<>; + + //******************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet() + { + } +#include "private/diagnostic_pop.h" + + //********************************************** + message_packet(const message_packet& /*other*/) + { + } + +#if ETL_USING_CPP11 + //********************************************** + message_packet(message_packet&& /*other*/) + { + } +#endif + + //********************************************** + void copy(const message_packet& /*other*/) + { + } + + //********************************************** + void copy(message_packet&& /*other*/) + { + } + + //********************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet& operator =(const message_packet& /*rhs*/) + { + return *this; + } +#include "private/diagnostic_pop.h" + + //********************************************** +#include "private/diagnostic_uninitialized_push.h" + message_packet& operator =(message_packet&& /*rhs*/) + { + return *this; + } +#include "private/diagnostic_pop.h" + + //******************************************** + ~message_packet() + { + } + + //******************************************** + bool is_valid() const + { + return false; + } + + //********************************************** + static ETL_CONSTEXPR bool accepts(etl::message_id_t /*id*/) + { + return false; + } + + //********************************************** + static ETL_CONSTEXPR bool accepts(const etl::imessage& /*msg*/) + { + return false; + } + + //********************************************** + template + static ETL_CONSTEXPR bool accepts() + { + return false; + } + + //********************************************** + template + static ETL_CONSTEXPR + typename etl::enable_if::value, bool>::type + accepts() + { + return false; + } + + enum + { + SIZE = 0, + ALIGNMENT = 1 + }; + }; + + //*************************************************************************** + /// Helper to turn etl::type_list into etl::message_packet + template + struct message_packet_from_type_list; + + template + struct message_packet_from_type_list> + { + using type = etl::message_packet; + }; + + template + using message_packet_from_type_list_t = typename message_packet_from_type_list::type; + #else /*[[[cog @@ -470,8 +599,7 @@ namespace etl cog.outl("// The definition for all %s message types." % Handlers) cog.outl("//***************************************************************************") cog.out("template <") - cog.out("typename T1, ") - for n in range(2, int(Handlers)): + for n in range(1, int(Handlers)): cog.out("typename T%s = void, " % n) if n % 4 == 0: cog.outl("") @@ -481,6 +609,15 @@ namespace etl cog.outl("{") cog.outl("public:") cog.outl("") + + cog.outl("#if ETL_USING_CPP11") + cog.out(" using message_types = etl::type_list<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>;" % int(Handlers)) + cog.outl("#endif") + cog.outl("") + cog.outl(" //********************************************") cog.outl("#include \"private/diagnostic_uninitialized_push.h\"") cog.outl(" message_packet()") @@ -785,6 +922,16 @@ namespace etl cog.outl("{") cog.outl("public:") cog.outl("") + + cog.out("#if ETL_USING_CPP11") + cog.outl("") + cog.out(" using message_types = etl::type_list<") + for t in range(1, int(n)): + cog.out("T%s, " % t) + cog.outl("T%s>;" % int(n)) + cog.outl("#endif") + cog.outl("") + cog.outl(" //********************************************") cog.outl("#include \"private/diagnostic_uninitialized_push.h\"") cog.outl(" message_packet()") @@ -1058,6 +1205,62 @@ namespace etl cog.outl("};") ]]]*/ /*[[[end]]]*/ + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template <> + class message_packet + { + public: + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; +#endif + + message_packet() + : valid(false) + { + } + + static ETL_CONSTEXPR bool accepts(etl::message_id_t) + { + return false; + } + + static ETL_CONSTEXPR bool accepts(const etl::imessage&) + { + return false; + } + + template + static ETL_CONSTEXPR bool accepts() + { + return false; + } + + template + static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type accepts() + { + return false; + } + + bool is_valid() const + { + return valid; + } + + enum + { + SIZE = 0U, + ALIGNMENT = 1U + }; + + private: + + bool valid; + }; #endif } diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index 6cdf16e3..9c6f5eb1 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -251,7 +251,7 @@ namespace etl //********************************************** template static ETL_CONSTEXPR - typename etl::enable_if::value, bool>::type + typename etl::enable_if::value, bool>::type accepts() { return accepts(); @@ -482,7 +482,7 @@ namespace etl //********************************************** template static ETL_CONSTEXPR - typename etl::enable_if::value, bool>::type + typename etl::enable_if::value, bool>::type accepts() { return false; @@ -522,9 +522,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -850,9 +850,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -1176,9 +1176,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -1499,9 +1499,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -1818,9 +1818,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -2131,9 +2131,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -2441,9 +2441,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -2748,9 +2748,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -3051,9 +3051,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -3348,9 +3348,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -3642,9 +3642,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -3933,9 +3933,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -4220,9 +4220,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -4501,9 +4501,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -4779,9 +4779,9 @@ namespace etl { public: -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -5054,12 +5054,9 @@ namespace etl { public: - //ETL_STATIC_ASSERT(!etl::is_type_list::value, - // "message_packet does not accept an etl::type_list before C++17, or when ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION is defined"); - -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //******************************************** #include "private/diagnostic_uninitialized_push.h" @@ -5352,7 +5349,6 @@ namespace etl template static ETL_CONSTEXPR bool accepts() { - //ETL_UNUSED(Id); return false; } From a7fe6bc6b0e2cba2f3bb2cfc9fa83bf1b2d7d80d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Jan 2026 09:06:54 +0000 Subject: [PATCH 043/167] Synced message_router generator to updated code --- .../etl/generators/message_router_generator.h | 25 +- include/etl/message_router.h | 263 +++--------------- 2 files changed, 57 insertions(+), 231 deletions(-) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 868a51ab..71f05dea 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -76,7 +76,7 @@ cog.outl("//******************************************************************** #include "placement_new.h" #include "successor.h" #include "type_traits.h" - +#include "type_list.h" #include namespace etl @@ -574,8 +574,7 @@ namespace etl cog.outl("//***************************************************************************") cog.outl("template message_packet;" % int(Handlers)) + cog.outl("T%s> message_packet;" % int(Handlers)) cog.outl("") + + cog.outl("#if ETL_USING_CPP11") + cog.out(" using message_types = etl::type_list<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s> message_packet;" % int(Handlers)) + cog.outl("#endif") + cog.outl("") + cog.outl(" //**********************************************") cog.outl(" message_router(etl::message_router_id_t id_)") cog.outl(" : imessage_router(id_)") @@ -765,6 +773,15 @@ namespace etl cog.out("T%s, " % t) cog.outl(" T%s> message_packet;" % n) cog.outl("") + + cog.outl("#if ETL_USING_CPP11") + cog.out(" using message_types = etl::type_list<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>;" % n) + cog.outl("#endif") + cog.outl("") + cog.outl(" //**********************************************") cog.outl(" message_router(etl::message_router_id_t id_)") cog.outl(" : imessage_router(id_)") diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 564f5fa5..1feaa3c9 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -65,7 +65,6 @@ SOFTWARE. #include "successor.h" #include "type_traits.h" #include "type_list.h" - #include namespace etl @@ -411,8 +410,7 @@ namespace etl { public: - using message_packet = etl::message_packet; - using message_types = etl::type_list; + typedef etl::message_packet message_packet; //********************************************** message_router() @@ -550,108 +548,7 @@ namespace etl } } }; - - //*************************************************************************** - // The definition for 0 message types. - //*************************************************************************** - template - class message_router : public imessage_router - { - public: - - using message_packet = etl::message_packet<>; - using message_types = etl::type_list<>; - - //********************************************** - message_router() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - //********************************************** - message_router(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) - { - } - - //********************************************** - message_router(etl::message_router_id_t id_) - : imessage_router(id_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - using etl::imessage_router::receive; - - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - if (has_successor()) - { - get_successor().receive(msg); - } - } - - template ::value, int>::type = 0> - void receive(const TMessage& msg) - { -#include "etl/private/diagnostic_array_bounds_push.h" - if (has_successor()) - { - get_successor().receive(msg); - } -#include "etl/private/diagnostic_pop.h" - } - - //********************************************** - using imessage_router::accepts; - - bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE - { - return false; - } - - //******************************************** - ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return true; - } - }; - - //*************************************************************************** - /// Helper to turn etl::type_list into etl::tuple - template - struct message_router_from_type_list; - - template - struct message_router_from_type_list> - { - using type = etl::message_router; - }; - - template - using message_router_from_type_list_t = typename message_router_from_type_list::type; - - #else +#else //************************************************************************************************* // For C++14 and below. //************************************************************************************************* @@ -669,9 +566,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 - using message_types = etl::type_list; -#endif + #if ETL_USING_CPP11 + using message_types = etl::type_list message_packet; + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -824,9 +721,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -979,9 +876,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1133,9 +1030,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1285,9 +1182,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1436,9 +1333,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1586,9 +1483,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1735,9 +1632,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -1882,9 +1779,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2028,9 +1925,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2172,9 +2069,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2315,9 +2212,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2456,9 +2353,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2596,9 +2493,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2735,9 +2632,9 @@ namespace etl typedef etl::message_packet message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2871,11 +2768,11 @@ namespace etl { public: - typedef etl::message_packet message_packet; + typedef etl::message_packet< T1> message_packet; -#if ETL_USING_CPP11 + #if ETL_USING_CPP11 using message_types = etl::type_list; -#endif + #endif //********************************************** message_router(etl::message_router_id_t id_) @@ -2997,94 +2894,6 @@ namespace etl return true; } }; - - //*************************************************************************** - // Specialisation for 0 message types. - //*************************************************************************** - template - class message_router - : public imessage_router - { - public: - - typedef etl::message_packet<> message_packet; - -#if ETL_USING_CPP11 - using message_types = etl::type_list<>; -#endif - - //********************************************** - message_router(etl::message_router_id_t id_) - : imessage_router(id_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - message_router() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - //********************************************** - message_router(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) - { - } - - //********************************************** - using etl::imessage_router::receive; - - void receive(const etl::imessage& msg) ETL_OVERRIDE - { -#include "etl/private/diagnostic_array_bounds_push.h" - if (has_successor()) - { - get_successor().receive(msg); - } -#include "etl/private/diagnostic_pop.h" - } - - //********************************************** - using imessage_router::accepts; - - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - if (has_successor()) - { - return get_successor().accepts(id); - } - else - { - return false; - } - } - - //******************************************** - ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return true; - } - }; #endif } From 53a9cde9a4b9a453e4772a3ca3b458ec25bf119c Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Jan 2026 09:06:54 +0000 Subject: [PATCH 044/167] Synced message_router generator to updated code # Conflicts: # include/etl/generators/message_router_generator.h # include/etl/message_router.h --- include/etl/generators/message_router_generator.h | 2 +- include/etl/message_router.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 71f05dea..b6259d17 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -595,7 +595,7 @@ namespace etl cog.out(" using message_types = etl::type_list<") for n in range(1, int(Handlers)): cog.out("T%s, " % n) - cog.outl("T%s> message_packet;" % int(Handlers)) + cog.outl("T%s>;" % int(Handlers)) cog.outl("#endif") cog.outl("") diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 1feaa3c9..0ac3756a 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -567,7 +567,7 @@ namespace etl typedef etl::message_packet message_packet; #if ETL_USING_CPP11 - using message_types = etl::type_list message_packet; + using message_types = etl::type_list; #endif //********************************************** From 491c648d3ee27be899387efed768d8dc8d61de96 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Jan 2026 10:58:57 +0000 Subject: [PATCH 045/167] Fixed missing zero message specialisation for <= C++14 --- .../etl/generators/message_router_generator.h | 88 +++++++++++++++++++ include/etl/message_router.h | 88 +++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index b6259d17..635254ed 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -919,6 +919,94 @@ namespace etl cog.outl("};") ]]]*/ /*[[[end]]]*/ + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + typedef etl::message_packet<> message_packet; + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; +#endif + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; #endif } diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 0ac3756a..62efe04b 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -2894,6 +2894,94 @@ namespace etl return true; } }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + typedef etl::message_packet<> message_packet; + +#if ETL_USING_CPP11 + using message_types = etl::type_list<>; +#endif + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; #endif } From 15b96484d5095bbd1f14039bc4a5114e62a755c3 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Jan 2026 10:58:57 +0000 Subject: [PATCH 046/167] Fixed missing zero message specialisation for <= C++14 --- .../etl/generators/message_router_generator.h | 101 ++++++++++++++++++ include/etl/message_router.h | 101 ++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 635254ed..6b3602ff 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -560,6 +560,107 @@ namespace etl } } }; + + //*************************************************************************** + // The definition for 0 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + using message_packet = etl::message_packet<>; + using message_types = etl::type_list<>; + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + if (has_successor()) + { + get_successor().receive(msg); + } + } + + template ::value, int>::type = 0> + void receive(const TMessage& msg) + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE + { + return false; + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; + + //*************************************************************************** + /// Helper to turn etl::type_list into etl::tuple + template + struct message_router_from_type_list; + + template + struct message_router_from_type_list> + { + using type = etl::message_router; + }; + + template + using message_router_from_type_list_t = typename message_router_from_type_list::type; + #else //************************************************************************************************* // For C++14 and below. diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 62efe04b..e46c05a9 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -548,6 +548,107 @@ namespace etl } } }; + + //*************************************************************************** + // The definition for 0 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + using message_packet = etl::message_packet<>; + using message_types = etl::type_list<>; + + //********************************************** + message_router() + : imessage_router(etl::imessage_router::MESSAGE_ROUTER) + { + } + + //********************************************** + message_router(etl::imessage_router& successor_) + : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) + { + } + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + using etl::imessage_router::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + if (has_successor()) + { + get_successor().receive(msg); + } + } + + template ::value, int>::type = 0> + void receive(const TMessage& msg) + { +#include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } +#include "etl/private/diagnostic_pop.h" + } + + //********************************************** + using imessage_router::accepts; + + bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE + { + return false; + } + + //******************************************** + ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; + + //*************************************************************************** + /// Helper to turn etl::type_list into etl::tuple + template + struct message_router_from_type_list; + + template + struct message_router_from_type_list> + { + using type = etl::message_router; + }; + + template + using message_router_from_type_list_t = typename message_router_from_type_list::type; + #else //************************************************************************************************* // For C++14 and below. From db89cc892026db80f65d5de8b34c758ec25b4bfb Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 1 Feb 2026 11:16:41 +0100 Subject: [PATCH 047/167] Add missing includes (#1286) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Add missing includes Before this change, the includes needed to be done explicitly by files using basic_string_stream.h, and be included first. This was error prone, especially if includes are reordered (e.g. via the currently defined clang-format rules). --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/basic_string_stream.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/etl/basic_string_stream.h b/include/etl/basic_string_stream.h index 2b466055..2aa1f28d 100644 --- a/include/etl/basic_string_stream.h +++ b/include/etl/basic_string_stream.h @@ -35,6 +35,10 @@ SOFTWARE. #include "platform.h" #include "to_string.h" +#include "to_u8string.h" +#include "to_u16string.h" +#include "to_u32string.h" +#include "to_wstring.h" namespace etl { From 570a7adaa33823b274749100cce5d81b0130f446 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 2 Feb 2026 11:46:00 +0100 Subject: [PATCH 048/167] Move comparison operators of etl::expected to namespace etl (#1287) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Move comparison operators of etl::expected to namespace etl --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/expected.h | 204 ++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/include/etl/expected.h b/include/etl/expected.h index 722c411e..758e2404 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -1296,132 +1296,132 @@ namespace etl } #endif }; -} -//******************************************* -/// Equivalence operators. -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::expected& rhs) -{ - if (lhs.has_value() != rhs.has_value()) + //******************************************* + /// Equivalence operators. + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::expected& rhs) { - return false; + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + if (lhs.has_value()) + { + return lhs.value() == rhs.value(); + } + return lhs.error() == rhs.error(); } - if (lhs.has_value()) + + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const TValue2& rhs) { - return lhs.value() == rhs.value(); + if (!lhs.has_value()) + { + return false; + } + return lhs.value() == rhs; } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const TValue2& rhs) -{ - if (!lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) { - return false; + if (lhs.has_value()) + { + return false; + } + return lhs.error() == rhs.error(); } - return lhs.value() == rhs; -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) -{ - if (lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::expected& rhs) { - return false; + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + if (lhs.has_value()) + { + return true; + } + return lhs.error() == rhs.error(); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::expected& rhs) -{ - if (lhs.has_value() != rhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) { - return false; + if (lhs.has_value()) + { + return false; + } + return lhs.error() == rhs.error(); } - if (lhs.has_value()) + + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::unexpected& lhs, const etl::unexpected& rhs) { - return true; + return lhs.error() == rhs.error(); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) -{ - if (lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::expected& rhs) { - return false; + return !(lhs == rhs); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::unexpected& lhs, const etl::unexpected& rhs) -{ - return lhs.error() == rhs.error(); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const TValue2& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::expected& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const TValue2& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::expected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::expected& rhs) -{ - return !(lhs == rhs); -} - -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); -} - -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::unexpected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::unexpected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } } //******************************************* From a3c8f802166d9741dee58c2be5864098ddaab1ec Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 2 Feb 2026 17:43:26 +0100 Subject: [PATCH 049/167] Make typed_storage constructor constexpr (#1291) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Make typed_storage constructor constexpr --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/alignment.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/alignment.h b/include/etl/alignment.h index 73527765..41e8a20c 100644 --- a/include/etl/alignment.h +++ b/include/etl/alignment.h @@ -367,7 +367,7 @@ namespace etl //*************************************************************************** // Default constructor //*************************************************************************** - typed_storage() ETL_NOEXCEPT + ETL_CONSTEXPR typed_storage() ETL_NOEXCEPT : valid(false) { } @@ -567,7 +567,7 @@ namespace etl //******************************* union union_type { - union_type() ETL_NOEXCEPT + ETL_CONSTEXPR union_type() ETL_NOEXCEPT : dummy() { } From b51968d6dd12d2360e34836042cafbf37d14f50c Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:35:25 -0500 Subject: [PATCH 050/167] Add basic_format_arg constructor for ibasic_string (#1288) * Allow string as format arg * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Added test string escaped * Add temporary string test --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/format.h | 5 ++++ test/test_format.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/etl/format.h b/include/etl/format.h index d090457d..95dafc8d 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -284,6 +284,11 @@ namespace etl { } + basic_format_arg(const etl::ibasic_string& v) + : data(etl::string_view(v.data(), v.size())) + { + } + basic_format_arg(const basic_format_arg& other): data(other.data) { } diff --git a/test/test_format.cpp b/test/test_format.cpp index 31bdecce..2e148bb4 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -282,6 +282,68 @@ namespace CHECK_EQUAL("\"data1\\n\"", test_format(s, "{:?}", sv)); } + //************************************************************************* + TEST(test_format_string) + { + etl::string<100> s; + etl::string<10> s_arg = "data1"; + + CHECK_EQUAL("data1", test_format(s, "{}", s_arg)); + CHECK_EQUAL("data1", test_format(s, "{:s}", s_arg)); + CHECK_THROW(test_format(s, "{:d}", s_arg), etl::bad_format_string_exception); + CHECK_EQUAL("data1 ", test_format(s, "{:10s}", s_arg)); + CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", s_arg)); + CHECK_EQUAL(" data1", test_format(s, "{:>10s}", s_arg)); + CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", s_arg)); + CHECK_EQUAL("data1", test_format(s, "{:3}", s_arg)); + CHECK_EQUAL("dat", test_format(s, "{:.3s}", s_arg)); + CHECK_EQUAL("dat", test_format(s, "{:^.3s}", s_arg)); + CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", s_arg)); + CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", s_arg)); + } + + //************************************************************************* + //this minimal derived class of etl::string is used to prove that the + //temporary lifetime is long enough for the format operation + template + class clearing_string : public etl::string + { + public: + using etl::string::string; + ~clearing_string() + { + this->clear(); + } + }; + TEST(test_format_string_temporary) + { + etl::string<100> s; + const char* data = "data1"; + using string_t = clearing_string<10>; + + CHECK_EQUAL("data1", test_format(s, "{}", string_t(data))); + CHECK_EQUAL("data1", test_format(s, "{:s}", string_t(data))); + CHECK_THROW(test_format(s, "{:d}", string_t(data)), etl::bad_format_string_exception); + CHECK_EQUAL("data1 ", test_format(s, "{:10s}", string_t(data))); + CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", string_t(data))); + CHECK_EQUAL(" data1", test_format(s, "{:>10s}", string_t(data))); + CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", string_t(data))); + CHECK_EQUAL("data1", test_format(s, "{:3}", string_t(data))); + CHECK_EQUAL("dat", test_format(s, "{:.3s}", string_t(data))); + CHECK_EQUAL("dat", test_format(s, "{:^.3s}", string_t(data))); + CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", string_t(data))); + CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", string_t(data))); + } + + //************************************************************************* + TEST(test_format_string_escaped) + { + etl::string<100> s; + etl::string<10> s_arg("data1\n"); + + CHECK_EQUAL("\"data1\\n\"", test_format(s, "{:?}", s_arg)); + } + //************************************************************************* TEST(test_format_chars) { From 21a1f58299cf48e8c7325d329c386dfda438b932 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 22:29:52 +0000 Subject: [PATCH 051/167] QR Code for Github --- images/QR Github.png | Bin 0 -> 20490 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/QR Github.png diff --git a/images/QR Github.png b/images/QR Github.png new file mode 100644 index 0000000000000000000000000000000000000000..94c76e0ef54db47ebe96a8cd7f045ee13f37eacd GIT binary patch literal 20490 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 Date: Fri, 16 Jan 2026 09:02:46 +0100 Subject: [PATCH 052/167] Fix year_month arithmetic and correct chrono API behavior (#1257) * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Fix & add more tests for year_month arithmetic * Minor addtions to previous commit * More missing values to be uninitialized * Update the default constructors to = default and correct default constructor tests accordingly * Restore default constructor behavior for chrono calender --- include/etl/private/chrono/day.h | 61 ++------------- include/etl/private/chrono/month.h | 54 ++----------- include/etl/private/chrono/weekday.h | 20 ----- include/etl/private/chrono/year.h | 66 +++++----------- include/etl/private/chrono/year_month.h | 16 ++-- include/etl/private/chrono/year_month_day.h | 20 +++-- .../etl/private/chrono/year_month_weekday.h | 12 ++- test/test_chrono_day.cpp | 9 --- test/test_chrono_month.cpp | 9 --- test/test_chrono_weekday_last.cpp | 1 - test/test_chrono_year.cpp | 23 +++--- test/test_chrono_year_month.cpp | 75 ++++++++++++++++++- test/test_chrono_year_month_day.cpp | 2 +- 13 files changed, 148 insertions(+), 220 deletions(-) diff --git a/include/etl/private/chrono/day.h b/include/etl/private/chrono/day.h index fa5bb712..6797c81f 100644 --- a/include/etl/private/chrono/day.h +++ b/include/etl/private/chrono/day.h @@ -57,39 +57,10 @@ namespace etl /// Construct from unsigned //*********************************************************************** ETL_CONSTEXPR explicit day(unsigned value_) ETL_NOEXCEPT - : value(static_cast(value_)) + : value(static_cast(value_)) { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 day(const etl::chrono::day& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::day& operator =(const etl::chrono::day& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - template - ETL_CONSTEXPR14 etl::chrono::day& operator =(const etl::chrono::duration& rhs) - { - value = etl::chrono::duration_cast(rhs); - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -105,7 +76,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day operator ++(int) ETL_NOEXCEPT { - const etl::chrono::day temp = *this; + etl::chrono::day temp = *this; ++value; return temp; @@ -126,7 +97,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day operator --(int) ETL_NOEXCEPT { - const etl::chrono::day temp = *this; + etl::chrono::day temp = *this; --value; return temp; @@ -137,7 +108,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day& operator +=(const etl::chrono::days& ds) ETL_NOEXCEPT { - value += static_cast(ds.count()); + value += static_cast(ds.count()); return *this; } @@ -147,7 +118,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::day& operator -=(const etl::chrono::days& ds) ETL_NOEXCEPT { - value -= static_cast(ds.count()); + value -= static_cast(ds.count()); return *this; } @@ -164,9 +135,9 @@ namespace etl //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator unsigned() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator unsigned() const ETL_NOEXCEPT { - return static_cast(value); + return value; } //*********************************************************************** @@ -184,24 +155,6 @@ namespace etl return 0; } - //*********************************************************************** - /// The minimum day value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::day min() ETL_NOEXCEPT - { - return etl::chrono::day(1); - } - - //*********************************************************************** - /// The maximum day value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::day max() ETL_NOEXCEPT - { - return etl::chrono::day(31); - } - private: rep value; diff --git a/include/etl/private/chrono/month.h b/include/etl/private/chrono/month.h index 1ab694d4..4f257da3 100644 --- a/include/etl/private/chrono/month.h +++ b/include/etl/private/chrono/month.h @@ -72,24 +72,6 @@ namespace etl { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 month(const etl::chrono::month& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::month& operator =(const etl::chrono::month& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -105,9 +87,9 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::month operator ++(int) ETL_NOEXCEPT { - const etl::chrono::month temp = *this; + etl::chrono::month temp = *this; - *this += etl::chrono::months(1); + ++*this; return temp; } @@ -129,7 +111,7 @@ namespace etl { etl::chrono::month temp = *this; - *this -= etl::chrono::months(1); + --*this; return temp; } @@ -155,7 +137,7 @@ namespace etl } //*********************************************************************** - /// Returns true if the month is within the valid 1 to 31 range + /// Returns true if the month is within the valid 1 to 12 range //*********************************************************************** ETL_NODISCARD ETL_CONSTEXPR14 bool ok() const ETL_NOEXCEPT @@ -178,30 +160,12 @@ namespace etl return 0; } - //*********************************************************************** - /// The minimum month value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::month min() ETL_NOEXCEPT - { - return etl::chrono::month(1); - } - - //*********************************************************************** - /// The maximum month value for which ok() will return true - //*********************************************************************** - ETL_NODISCARD - static ETL_CONSTEXPR14 etl::chrono::month max() ETL_NOEXCEPT - { - return etl::chrono::month(12); - } - //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator unsigned() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator unsigned() const ETL_NOEXCEPT { - return static_cast(value); + return value; } private: @@ -331,10 +295,8 @@ namespace etl etl::chrono::months ms(difference); // Check for validity. - if (m1 == (m2 + ms)) - { - return ms; - } + assert(m1 == (m2 + ms)); + return ms; } return etl::chrono::months(); diff --git a/include/etl/private/chrono/weekday.h b/include/etl/private/chrono/weekday.h index de511a83..19246368 100644 --- a/include/etl/private/chrono/weekday.h +++ b/include/etl/private/chrono/weekday.h @@ -362,26 +362,6 @@ namespace etl { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 weekday_indexed(const etl::chrono::weekday_indexed& other) ETL_NOEXCEPT - : wd(other.wd) - , i(other.i) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::weekday_indexed& operator =(const etl::chrono::weekday_indexed& rhs) ETL_NOEXCEPT - { - wd = rhs.wd; - i = rhs.i; - - return *this; - } - //*********************************************************************** /// Get weekday //*********************************************************************** diff --git a/include/etl/private/chrono/year.h b/include/etl/private/chrono/year.h index fd3d8096..b21c572e 100644 --- a/include/etl/private/chrono/year.h +++ b/include/etl/private/chrono/year.h @@ -54,31 +54,13 @@ namespace etl } //*********************************************************************** - /// Construct from unsigned + /// Construct from int //*********************************************************************** - ETL_CONSTEXPR explicit year(unsigned value_) ETL_NOEXCEPT + ETL_CONSTEXPR explicit year(int value_) ETL_NOEXCEPT : value(value_) { } - //*********************************************************************** - /// Copy constructor - //*********************************************************************** - ETL_CONSTEXPR14 year(const etl::chrono::year& other) ETL_NOEXCEPT - : value(other.value) - { - } - - //*********************************************************************** - /// Assignment operator - //*********************************************************************** - ETL_CONSTEXPR14 etl::chrono::year& operator =(const etl::chrono::year& rhs) ETL_NOEXCEPT - { - value = rhs.value; - - return *this; - } - //*********************************************************************** /// Pre-increment operator //*********************************************************************** @@ -94,7 +76,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year operator ++(int) ETL_NOEXCEPT { - const etl::chrono::year temp = *this; + etl::chrono::year temp = *this; ++value; return temp; @@ -115,7 +97,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year operator --(int) ETL_NOEXCEPT { - const etl::chrono::year temp = *this; + etl::chrono::year temp = *this; --value; return temp; @@ -126,7 +108,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year& operator +=(const etl::chrono::years& ys) ETL_NOEXCEPT { - value += static_cast(ys.count()); + value += ys.count(); return *this; } @@ -136,7 +118,7 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 etl::chrono::year& operator -=(const etl::chrono::years& ys) ETL_NOEXCEPT { - value -= static_cast(ys.count()); + value -= ys.count(); return *this; } @@ -182,9 +164,9 @@ namespace etl //*********************************************************************** /// Conversion operator to unsigned int //*********************************************************************** - ETL_CONSTEXPR14 operator int() const ETL_NOEXCEPT + ETL_CONSTEXPR14 /*explicit*/ operator int() const ETL_NOEXCEPT { - return static_cast(value); + return value; } //*********************************************************************** @@ -212,7 +194,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator ==(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) == static_cast(y2)); + return (static_cast(y1) == static_cast(y2)); } //*********************************************************************** @@ -228,7 +210,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator <(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) < static_cast(y2)); + return (static_cast(y1) < static_cast(y2)); } //*********************************************************************** @@ -236,7 +218,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator <=(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) <= static_cast(y2)); + return (static_cast(y1) <= static_cast(y2)); } //*********************************************************************** @@ -244,7 +226,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator >(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) > static_cast(y2)); + return (static_cast(y1) > static_cast(y2)); } //*********************************************************************** @@ -252,7 +234,7 @@ namespace etl //*********************************************************************** inline ETL_CONSTEXPR14 bool operator >=(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) >= static_cast(y2)); + return (static_cast(y1) >= static_cast(y2)); } //*********************************************************************** @@ -261,7 +243,7 @@ namespace etl #if ETL_USING_CPP20 [[nodiscard]] inline constexpr auto operator <=>(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return (static_cast(y1) <=> static_cast(y2)); + return (static_cast(y1) <=> static_cast(y2)); } #endif @@ -304,27 +286,13 @@ namespace etl return result; } - //*********************************************************************** - /// Subtract etl::chrono::year from etl::chrono::years - ///\return etl::chrono::years - //*********************************************************************** - inline ETL_CONSTEXPR14 etl::chrono::year operator -(const etl::chrono::years& ys, const etl::chrono::year& y) ETL_NOEXCEPT - { - etl::chrono::year result(y); - - result -= ys; - - return result; - } - //*********************************************************************** /// Subtract etl::chrono::year from etl::chrono::year ///\return etl::chrono::years //*********************************************************************** inline ETL_CONSTEXPR14 etl::chrono::years operator -(const etl::chrono::year& y1, const etl::chrono::year& y2) ETL_NOEXCEPT { - return etl::chrono::years(static_cast(static_cast(y1)) - - static_cast(static_cast(y2))); + return etl::chrono::years(static_cast(y1) - static_cast(y2)); } } @@ -337,7 +305,7 @@ namespace etl { size_t operator()(const etl::chrono::year& y) const { - etl::chrono::year::rep value = static_cast(static_cast(y)); + etl::chrono::year::rep value = static_cast(static_cast(y)); const uint8_t* p = reinterpret_cast(&value); return etl::private_hash::generic_hash(p, p + sizeof(value)); @@ -362,7 +330,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year operator ""_y(unsigned long long y) ETL_NOEXCEPT #endif { - return etl::chrono::year(static_cast(y)); + return etl::chrono::year(static_cast(y)); } } } diff --git a/include/etl/private/chrono/year_month.h b/include/etl/private/chrono/year_month.h index 672aadd6..36ca0526 100644 --- a/include/etl/private/chrono/year_month.h +++ b/include/etl/private/chrono/year_month.h @@ -135,7 +135,12 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator +(const etl::chrono::year_month& ym, const etl::chrono::months& dm) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() + dm); + int dmonths = static_cast(static_cast(ym.month())) - 1 + dm.count(); + int dyears = (dmonths - 11 * (dmonths < 0)) / 12; + dmonths -= dyears * 12; + ++dmonths; + return etl::chrono::year_month((ym.year() + etl::chrono::years(dyears)), + etl::chrono::month(static_cast(dmonths))); } //************************************************************************* @@ -144,7 +149,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator +(const etl::chrono::months& dm, const etl::chrono::year_month& ym) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() + dm); + return ym + dm; } //************************************************************************* @@ -162,7 +167,7 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::year_month operator -(const etl::chrono::year_month& ym, const etl::chrono::months& dm) ETL_NOEXCEPT { - return etl::chrono::year_month(ym.year(), ym.month() - dm); + return ym + -dm; } //************************************************************************* @@ -171,7 +176,8 @@ namespace etl inline ETL_CONSTEXPR14 etl::chrono::months operator -(const etl::chrono::year_month& ym1, const etl::chrono::year_month& ym2) ETL_NOEXCEPT { - return etl::chrono::months(static_cast(((int(ym1.year()) - int(ym2.year())) * 12) + (unsigned(ym1.month()) - unsigned(ym2.month())))); + return etl::chrono::months((ym1.year() - ym2.year()) + etl::chrono::months( + static_cast(static_cast(ym1.month())) - static_cast(static_cast(ym2.month())))); } //************************************************************************* @@ -273,7 +279,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month& ym) const { - etl::chrono::year::rep y = static_cast(static_cast(ym.year())); + etl::chrono::year::rep y = static_cast(static_cast(ym.year())); etl::chrono::month::rep m = static_cast(static_cast(ym.month())); uint8_t buffer[sizeof(y) + sizeof(m)]; diff --git a/include/etl/private/chrono/year_month_day.h b/include/etl/private/chrono/year_month_day.h index 6dcfa9d3..0a911a54 100644 --- a/include/etl/private/chrono/year_month_day.h +++ b/include/etl/private/chrono/year_month_day.h @@ -76,6 +76,9 @@ namespace etl /// Construct from sys_days. //************************************************************************* ETL_CONSTEXPR14 year_month_day(const etl::chrono::sys_days& sd) ETL_NOEXCEPT + : y(0) + , m(0U) + , d(0U) { // Days since 1970-01-01 int days_since_epoch = static_cast(sd.time_since_epoch().count()); @@ -101,7 +104,7 @@ namespace etl // Find the month while (true) { - unsigned char days_in_month = etl::chrono::private_chrono::days_in_month[current_month]; + unsigned char days_in_month = etl::chrono::private_chrono::days_in_month[static_cast(current_month)]; if (current_month == etl::chrono::February && current_year.is_leap()) { ++days_in_month; @@ -126,6 +129,9 @@ namespace etl /// Construct from local_days. //************************************************************************* ETL_CONSTEXPR14 year_month_day(const etl::chrono::local_days& ld) ETL_NOEXCEPT + : y(0) + , m(0) + , d(0) { etl::chrono::year_month_day ymd = sys_days(ld.time_since_epoch()); @@ -254,7 +260,7 @@ namespace etl // Add days for months in the current year for (etl::chrono::month mth(1); mth < this->month(); ++mth) { - day_count += private_chrono::days_in_month[mth]; + day_count += private_chrono::days_in_month[static_cast(mth)]; if (mth == etl::chrono::February && this->year().is_leap()) { @@ -289,7 +295,7 @@ namespace etl if (y.ok() && m.ok()) { - count = private_chrono::days_in_month[m]; + count = private_chrono::days_in_month[static_cast(m)]; if (y.is_leap() && (m == February)) { @@ -507,9 +513,9 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 etl::chrono::day day() const ETL_NOEXCEPT { - etl::chrono::day d = etl::chrono::day(etl::chrono::private_chrono::days_in_month[m]); + etl::chrono::day d = etl::chrono::day(etl::chrono::private_chrono::days_in_month[static_cast(m)]); - return (d == 28) && y.is_leap() ? etl::chrono::day(29) : d; + return (d == etl::chrono::day(28)) && y.is_leap() ? etl::chrono::day(29) : d; } //************************************************************************* @@ -788,7 +794,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_day& ymd) const { - etl::chrono::year::rep y = static_cast(static_cast(ymd.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymd.year())); etl::chrono::month::rep m = static_cast(static_cast(ymd.month())); etl::chrono::day::rep d = static_cast(static_cast(ymd.day())); @@ -812,7 +818,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_day_last& ymdl) const { - etl::chrono::year::rep y = static_cast(static_cast(ymdl.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymdl.year())); etl::chrono::month::rep m = static_cast(static_cast(ymdl.month())); etl::chrono::day::rep d = static_cast(static_cast(ymdl.day())); diff --git a/include/etl/private/chrono/year_month_weekday.h b/include/etl/private/chrono/year_month_weekday.h index ef8d9b31..909ff007 100644 --- a/include/etl/private/chrono/year_month_weekday.h +++ b/include/etl/private/chrono/year_month_weekday.h @@ -69,6 +69,9 @@ namespace etl /// Construct from sys_days. //************************************************************************* ETL_CONSTEXPR14 year_month_weekday(const etl::chrono::sys_days& sd) ETL_NOEXCEPT + : y(0) + , m(0U) + , wdi(etl::chrono::weekday(0), 0U) { // Extract year, month, and day year_month_day ymd = year_month_day{sd}; @@ -84,7 +87,7 @@ namespace etl // We walk backward from the given day in steps of 7 days unsigned index = 1; - for (int offset = static_cast(dy) - 7; offset > 0; offset -= 7) + for (int offset = static_cast(static_cast(dy)) - 7; offset > 0; offset -= 7) { ++index; } @@ -98,6 +101,9 @@ namespace etl /// Construct from local_days. //************************************************************************* ETL_CONSTEXPR14 year_month_weekday(const etl::chrono::local_days& ld) ETL_NOEXCEPT + : y(0) + , m(0U) + , wdi(etl::chrono::weekday(0), 0U) { year_month_weekday ymwd(sys_days(ld.time_since_epoch())); @@ -506,7 +512,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_weekday& ymwd) const { - etl::chrono::year::rep y = static_cast(static_cast(ymwd.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymwd.year())); etl::chrono::month::rep m = static_cast(static_cast(ymwd.month())); unsigned int wd = ymwd.weekday().c_encoding(); @@ -530,7 +536,7 @@ namespace etl { size_t operator()(const etl::chrono::year_month_weekday_last& ymwdl) const { - etl::chrono::year::rep y = static_cast(static_cast(ymwdl.year())); + etl::chrono::year::rep y = static_cast(static_cast(ymwdl.year())); etl::chrono::month::rep m = static_cast(static_cast(ymwdl.month())); unsigned int wd = ymwdl.weekday().c_encoding(); diff --git a/test/test_chrono_day.cpp b/test/test_chrono_day.cpp index af9dec6c..28d90d2e 100644 --- a/test/test_chrono_day.cpp +++ b/test/test_chrono_day.cpp @@ -240,15 +240,6 @@ namespace } } -#if ETL_USING_ETL_CHRONO - //************************************************************************* - TEST(test_min_max_day) - { - CHECK_EQUAL(1U, Chrono::day::min()); - CHECK_EQUAL(31U, Chrono::day::max()); - } -#endif - #if ETL_USING_ETL_CHRONO //************************************************************************* TEST(test_literal_day) diff --git a/test/test_chrono_month.cpp b/test/test_chrono_month.cpp index 765d018f..d2363528 100644 --- a/test/test_chrono_month.cpp +++ b/test/test_chrono_month.cpp @@ -269,15 +269,6 @@ namespace } } -#if ETL_USING_ETL_CHRONO - //************************************************************************* - TEST(test_min_max_month) - { - CHECK_EQUAL(1U, Chrono::month::min()); - CHECK_EQUAL(12U, Chrono::month::max()); - } -#endif - #if ETL_USING_ETL_CHRONO //************************************************************************* TEST(test_month_compare) diff --git a/test/test_chrono_weekday_last.cpp b/test/test_chrono_weekday_last.cpp index 9b949160..14fefb92 100644 --- a/test/test_chrono_weekday_last.cpp +++ b/test/test_chrono_weekday_last.cpp @@ -59,7 +59,6 @@ namespace //************************************************************************* TEST(test_constructor_in_range) { - for (unsigned i = 1U; i < 5U; ++i) { Chrono::weekday_last weekday_last_monday(Chrono::Monday); Chrono::weekday_last weekday_last_tuesday(Chrono::Tuesday); diff --git a/test/test_chrono_year.cpp b/test/test_chrono_year.cpp index e7ec7904..4bb91b85 100644 --- a/test/test_chrono_year.cpp +++ b/test/test_chrono_year.cpp @@ -71,7 +71,7 @@ namespace etl::chrono::year year(i); CHECK_TRUE(year.ok()); - CHECK_EQUAL(i, int(year)); + CHECK_EQUAL(i, static_cast(year)); } } @@ -87,7 +87,7 @@ namespace etl::chrono::year this_year = ++year; CHECK_TRUE(year.ok()); - CHECK_EQUAL(count, year); + CHECK_EQUAL(count, static_cast(year)); CHECK_EQUAL(this_year, year); } } @@ -226,16 +226,11 @@ namespace //************************************************************************* TEST(test_year_minus_year) { - etl::chrono::year year(256); - etl::chrono::years years(2); - - for (int i = 0; i < 128; ++i) - { - year = years - year; - - CHECK_TRUE(year.ok()); - CHECK_EQUAL((256 - (2 * i)) - 2, int(year)); - } + etl::chrono::year y1(2056); + CHECK_TRUE(y1 - y1 == etl::chrono::years(0)); + etl::chrono::year y2(2); + CHECK_TRUE(y1 - y2 == etl::chrono::years(2054)); + CHECK_TRUE(y2 - y1 == etl::chrono::years(-2054)); } //************************************************************************* @@ -256,8 +251,8 @@ namespace //************************************************************************* TEST(test_min_max_year) { - CHECK_EQUAL(-32767, etl::chrono::year::min()); - CHECK_EQUAL(32767, etl::chrono::year::max()); + CHECK_EQUAL(-32767, static_cast(etl::chrono::year::min())); + CHECK_EQUAL(32767, static_cast(etl::chrono::year::max())); } #endif diff --git a/test/test_chrono_year_month.cpp b/test/test_chrono_year_month.cpp index e016e8c4..556b82ba 100644 --- a/test/test_chrono_year_month.cpp +++ b/test/test_chrono_year_month.cpp @@ -128,7 +128,7 @@ namespace Chrono::year_month ym2{Chrono::year(2001), Chrono::January}; Chrono::year_month ym3{Chrono::year(2000), Chrono::February}; - CHECK_TRUE(ym1 == ym1); // Same year/month/day + CHECK_TRUE(ym1 == ym1); // Same year/month CHECK_FALSE(ym1 == ym2); // Different year CHECK_FALSE(ym1 == ym3); // Different month } @@ -140,9 +140,80 @@ namespace Chrono::year_month ym2{Chrono::year(2001), Chrono::January}; Chrono::year_month ym3{Chrono::year(2000), Chrono::February}; - CHECK_FALSE(ym1 != ym1); // Same year/month/day + CHECK_FALSE(ym1 != ym1); // Same year/month CHECK_TRUE(ym1 != ym2); // Different year CHECK_TRUE(ym1 != ym3); // Different month } + + //************************************************************************* + TEST(test_year_month_relational_operators) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + CHECK_FALSE(ym1 < ym1); // Same year/month + CHECK_TRUE(ym1 <= ym1); + CHECK_FALSE(ym1 > ym1); + CHECK_TRUE(ym1 >= ym1); + + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + CHECK_TRUE(ym1 < ym2); // left year/month strict less + CHECK_TRUE(ym1 <= ym2); + CHECK_FALSE(ym1 > ym2); + CHECK_FALSE(ym1 >= ym2); + + CHECK_FALSE(ym2 < ym1); // left year/month strict greater + CHECK_FALSE(ym2 <= ym1); + CHECK_TRUE(ym2 > ym1); + CHECK_TRUE(ym2 >= ym1); + } + + //************************************************************************* + TEST(test_year_month_year_month_diff_operator) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + Chrono::months dms = ym1 - ym1; + CHECK_EQUAL(dms.count(), 0); + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + dms = ym2 - ym1; // positive + CHECK_EQUAL(dms.count(), (2026 - 2021) * 12 + 11); + dms = ym1 - ym2; // negative + CHECK_EQUAL(dms.count(), (2021 - 2026) * 12 - 11); + } + + //************************************************************************* + TEST(test_year_month_add_sub_months_operators) + { + Chrono::year_month ym1(Chrono::year(2021), Chrono::January); + Chrono::months dms(0); // zero + CHECK_TRUE(dms + ym1 == ym1); + CHECK_TRUE(ym1 + dms == ym1); + CHECK_TRUE(ym1 - dms == ym1); + Chrono::year_month ym2(Chrono::year(2026), Chrono::December); + dms = ym1 - ym2; // negative + CHECK_TRUE(dms + ym2 == ym1); + CHECK_TRUE(ym2 + dms == ym1); + CHECK_TRUE(ym1 - dms == ym2); + dms = ym2 - ym1; // positive + CHECK_TRUE(dms + ym1 == ym2); + CHECK_TRUE(ym1 + dms == ym2); + CHECK_TRUE(ym2 - dms == ym1); + } + + //************************************************************************* + TEST(test_year_month_add_sub_years_operator) + { + Chrono::year_month ym(Chrono::year(2021), Chrono::January); + Chrono::years dys(0); // zero + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + dys = Chrono::years(-200); // negative + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + dys = Chrono::years(300); // positive + CHECK_TRUE((ym + dys == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((dys + ym == Chrono::year_month(ym.year() + dys, ym.month()))); + CHECK_TRUE((ym - dys == Chrono::year_month(ym.year() - dys, ym.month()))); + } } } diff --git a/test/test_chrono_year_month_day.cpp b/test/test_chrono_year_month_day.cpp index a5710e73..ae698465 100644 --- a/test/test_chrono_year_month_day.cpp +++ b/test/test_chrono_year_month_day.cpp @@ -151,7 +151,7 @@ namespace Chrono::year_month_day ymd{Chrono::sys_days(etl::chrono::days(10997))}; Chrono::year_month_day expected{Chrono::year(2000), Chrono::February, Chrono::day(10)}; - CHECK_EQUAL((unsigned)expected.year(), (unsigned)ymd.year()); + CHECK_EQUAL((int)expected.year(), (int)ymd.year()); CHECK_EQUAL((unsigned)expected.month(), (unsigned)ymd.month()); CHECK_EQUAL((unsigned)expected.day(), (unsigned)ymd.day()); } From 2a727b12b4b8aa5ac550fe0a5b608cfe61646a1f Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 16 Jan 2026 09:51:11 +0100 Subject: [PATCH 053/167] Suppress warnings from std in optimized builds (#1259) When testing with ./run-tests.sh 23 3 10, some warnings from std surfaced which resulted in build errors. --- include/etl/algorithm.h | 2 ++ include/etl/memory.h | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index a5879e2c..74fbb8ed 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -338,7 +338,9 @@ namespace etl template ETL_CONSTEXPR20 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) { +#include "etl/private/diagnostic_array_bounds_push.h" return std::move_backward(sb, se, de); +#include "etl/private/diagnostic_pop.h" } #elif ETL_USING_CPP11 // For C++11 diff --git a/include/etl/memory.h b/include/etl/memory.h index 57b89879..1c282452 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -382,9 +382,13 @@ namespace etl ///\ingroup memory //***************************************************************************** template - TOutputIterator uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) + TOutputIterator uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { +#include "etl/private/diagnostic_array_bounds_push.h" +#include "etl/private/diagnostic_stringop_overflow_push.h" return std::uninitialized_move(i_begin, i_end, o_begin); +#include "etl/private/diagnostic_pop.h" +#include "etl/private/diagnostic_pop.h" } //***************************************************************************** @@ -398,7 +402,9 @@ namespace etl { count += int32_t(etl::distance(i_begin, i_end)); +#include "etl/private/diagnostic_array_bounds_push.h" return std::uninitialized_move(i_begin, i_end, o_begin); +#include "etl/private/diagnostic_pop.h" } #else //***************************************************************************** From 45e5668782b74f8bf99347a1a85c0c0cbd02aab3 Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Fri, 16 Jan 2026 03:57:09 -0500 Subject: [PATCH 054/167] Add template deduction guide for span from vector (#1264) * Create span from vector deduction * Use ivector for deduction. Add vector_ext to test * Add vector pointer to test * Finish tests * Initialize pdata_ext and others --- include/etl/span.h | 12 +++++ test/test_span_dynamic_extent.cpp | 87 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/include/etl/span.h b/include/etl/span.h index c6f18799..8f57148f 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -1258,6 +1258,18 @@ namespace etl span(const etl::array&) -> span; + // Forward declaration of etl::ivector + template + class ivector; + + template + span(etl::ivector&) + -> span; + + template + span(const etl::ivector&) + -> span; + #if ETL_USING_STL && ETL_USING_CPP11 template span(std::array&) diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index e9045504..7fc1c8c0 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "etl/span.h" #include "etl/array.h" #include "etl/unaligned_type.h" +#include "etl/vector.h" #include #include @@ -778,6 +779,92 @@ namespace CHECK((std::is_same_v>)); } + //************************************************************************* + TEST(test_template_deduction_guide_for_etl_vector) + { + const size_t max_size = 10; + const size_t size = 4; + + int buffer1[max_size]; + int buffer2[max_size]; + int * buffer3[max_size]; + int * buffer4[max_size]; + const int * buffer5[max_size]; + const int * buffer6[max_size]; + + etl::vector data(size, 0); + const etl::vector data2(size, 0); + etl::vector_ext data_ext(size, 0, buffer1, max_size); + const etl::vector_ext data2_ext(size, 0, buffer2, max_size); + + etl::span span = data; + etl::span span2 = data2; + etl::span span_ext = data_ext; + etl::span span2_ext = data2_ext; + + CHECK_EQUAL(etl::dynamic_extent, span.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data), span.size()); + CHECK_EQUAL(etl::dynamic_extent, span2.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data2), span2.size()); + CHECK_EQUAL(etl::dynamic_extent, span_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data_ext), span_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, span2_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data2_ext), span2_ext.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + + etl::vector pdata(size, nullptr); + const etl::vector pdata2(size, nullptr); + etl::vector pdata3(size, nullptr); + const etl::vector pdata4(size, nullptr); + + etl::span pspan = pdata; + etl::span pspan2 = pdata2; + etl::span pspan3 = pdata3; + etl::span pspan4 = pdata4; + + CHECK_EQUAL(etl::dynamic_extent, pspan.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata), pspan.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan2.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata2), pspan2.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan3.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata3), pspan3.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan4.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata4), pspan4.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + + etl::vector_ext pdata_ext(size, nullptr, buffer3, max_size); + const etl::vector_ext pdata2_ext(size, nullptr, buffer4, max_size); + etl::vector_ext pdata3_ext(size, nullptr, buffer5, max_size); + const etl::vector_ext pdata4_ext(size, nullptr, buffer6, max_size); + + etl::span pspan_ext = pdata_ext; + etl::span pspan2_ext = pdata2_ext; + etl::span pspan3_ext = pdata3_ext; + etl::span pspan4_ext = pdata4_ext; + + CHECK_EQUAL(etl::dynamic_extent, pspan_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata_ext), pspan_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan2_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata2_ext), pspan2_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan3_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata3_ext), pspan3_ext.size()); + CHECK_EQUAL(etl::dynamic_extent, pspan4_ext.extent); + CHECK_EQUAL(ETL_OR_STD17::size(pdata4_ext), pspan4_ext.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + } + //************************************************************************* TEST(test_template_deduction_guide_for_iterators) { From 24421edd2952fee957ce8d5bb31f06e0352b2870 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 17 Jan 2026 14:26:16 +0100 Subject: [PATCH 055/167] Document how to implement platform specifics (#1262) Some interfaces need to be implemented in every project or platform using the ETL: * etl_get_high_resolution_clock * etl_get_system_clock * etl_get_steady_clock * etl_putchar Co-authored-by: John Wellbelove --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/README.md b/README.md index a762e43f..c199268c 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,84 @@ add_executable(foo main.cpp) target_link_libraries(foo PRIVATE etl::etl) ``` +## Profile definition + +When using ETL in a project, there is typically an `etl_profile.h` defined to +adjust ETL to the project needs. ETL will automatically find `etl_profile.h` +if it is available in the include path(s). If it's not available, ETL will +work with default values. + +### Example + +``` +#ifndef __ETL_PROFILE_H__ +#define __ETL_PROFILE_H__ + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE + +#define ETL_NO_STL + +#endif +``` + +## Platform specific implementation + +Although ETL is generally a self-contained header-only library, some interfaces need to be +implemented in every project or platform, at least if those interfaces are actually being +used, due to project specifics: + +| ETL header | Platform specific API to be implemented | Needed when using | +|------------|-----------------------------------------|-------------------------------------| +| `chrono.h` | `etl_get_high_resolution_clock()` | `etl::high_resolution_clock::now()` | +| | `etl_get_system_clock()` | `etl::system_clock::now()` | +| | `etl_get_steady_clock()` | `etl::steady_clock::now()` | +| `print.h` | `etl_putchar()` | `etl::print()` | +| | | `etl::println()` | + +### Example + +``` +#include +#include + +extern "C" +{ + +etl::chrono::high_resolution_clock::rep etl_get_high_resolution_clock() +{ + etl::chrono::high_resolution_clock::rep(static_cast(getSystemTimeNs())); +} + +etl::chrono::system_clock::rep etl_get_system_clock() +{ + return etl::chrono::system_clock::rep(static_cast(getSystemTimeNs())); +} + +etl::chrono::system_clock::rep etl_get_steady_clock() +{ + return etl::chrono::system_clock::rep(static_cast(getSystemTimeNs())); +} + +void etl_putchar(int c) +{ + putByteToStdout(static_cast(c)); +} + +} +``` + +The following default values apply if the respective macros are not defined +(e.g. in `etl_profile.h`): + +| Macro | Default | +|-----------------------------------------------|----------------------------| +| `ETL_CHRONO_SYSTEM_CLOCK_DURATION` | `etl::chrono::nanoseconds` | +| `ETL_CHRONO_SYSTEM_CLOCK_IS_STEADY` | `true` | +| `ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION` | `etl::chrono::nanoseconds` | +| `ETL_CHRONO_HIGH_RESOLUTION_CLOCK_IS_STEADY` | `true` | +| `ETL_CHRONO_STEADY_CLOCK_DURATION` | `etl::chrono::nanoseconds` | + ## Arduino library The content of this repo is available as a library in the Arduino IDE (search for the "Embedded Template Library" in the IDE library manager). The Arduino library repository is available at ```https://github.com/ETLCPP/etl-arduino```, see there for more details. From d419bbf16f7ad933eabbf0c6ffbaa4cbcaafe377 Mon Sep 17 00:00:00 2001 From: taltenbach <92919739+taltenbach@users.noreply.github.com> Date: Sat, 17 Jan 2026 23:04:52 +0100 Subject: [PATCH 056/167] Fix etl::as_bytes for etl::span (#1266) A missing 'const' in the etl::as_bytes implementation was causing a compile-time error when etl::as_bytes was called on a span of const values. Co-authored-by: John Wellbelove --- include/etl/span.h | 2 +- test/test_span_dynamic_extent.cpp | 3 ++- test/test_span_fixed_extent.cpp | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/etl/span.h b/include/etl/span.h index 8f57148f..5d03632a 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -1303,7 +1303,7 @@ namespace etl span as_bytes(span s) ETL_NOEXCEPT { - return span(reinterpret_cast(s.data()), s.size_bytes()); + return span(reinterpret_cast(s.data()), s.size_bytes()); } //************************************************************************* diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index 7fc1c8c0..586eadcb 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -1325,8 +1325,9 @@ namespace TEST(test_convert_span_any_to_span_byte) { float data[2]{3.141592f, 2.71828f }; + const float const_data[2]{3.141592f, 2.71828f }; - auto const const_bytes = etl::as_bytes(etl::span{data}); + auto const const_bytes = etl::as_bytes(etl::span{const_data}); auto const writable_bytes = etl::as_writable_bytes(etl::span{data}); CHECK_EQUAL(const_bytes.size(), sizeof(data)); diff --git a/test/test_span_fixed_extent.cpp b/test/test_span_fixed_extent.cpp index 137bd9b8..a1825c2c 100644 --- a/test/test_span_fixed_extent.cpp +++ b/test/test_span_fixed_extent.cpp @@ -1163,12 +1163,13 @@ namespace TEST(test_convert_span_any_to_span_byte) { float data[2]{3.141592f, 2.71828f}; + const float const_data[2]{3.141592f, 2.71828f}; #if ETL_USING_CPP17 - auto const const_bytes = etl::as_bytes(etl::span{ data }); + auto const const_bytes = etl::as_bytes(etl::span{ const_data }); auto const writable_bytes = etl::as_writable_bytes(etl::span{ data }); #else - auto const const_bytes = etl::as_bytes(etl::span(data)); + auto const const_bytes = etl::as_bytes(etl::span(const_data)); auto const writable_bytes = etl::as_writable_bytes(etl::span(data)); #endif From a8436506494b7c1f0478cbb12174582e2c47ccb8 Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:15:38 +0100 Subject: [PATCH 057/167] Remove some UB in test_vector_non_trivial.cpp (#1268) Some of the tests' UB are detectable by Gcc15 and thus give a compile error due to warnings-as-error flag. Co-authored-by: John Wellbelove --- test/test_vector_non_trivial.cpp | 41 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/test/test_vector_non_trivial.cpp b/test/test_vector_non_trivial.cpp index 1a10ac77..99772202 100644 --- a/test/test_vector_non_trivial.cpp +++ b/test/test_vector_non_trivial.cpp @@ -964,8 +964,9 @@ namespace DataNDC data; data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); - DataNDC data2; - CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + DataNDC::iterator it = data.begin(); + --it; + CHECK_THROW(data.insert(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1002,19 +1003,34 @@ namespace const std::string INITIAL_VALUE("1"); DataNDC data; - DataNDC data2; data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); - CHECK_THROW(data.emplace(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds); + DataNDC::const_iterator it = data.cend(); + ++it; + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* - TEST(test_emplace_out_of_range) + TEST(test_emplace_out_of_range_past_end) { DataNDC data; - DataNDC data2; + DataNDC::iterator it = data.end(); + ++it; + const std::string INITIAL_VALUE("1"); - CHECK_THROW(data.emplace(data2.end(), INITIAL_VALUE);, etl::vector_out_of_bounds); + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); + } + + //************************************************************************* + TEST(test_emplace_out_of_range_before_begin) + { + DataNDC data; + DataNDC::iterator it = data.begin(); + --it; + + const std::string INITIAL_VALUE("1"); + + CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1072,10 +1088,11 @@ namespace TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds) { DataNDC data; - DataNDC data2; + DataNDC::const_iterator it = data.cend(); + ++it; const NDC INITIAL_VALUE("1"); - CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds); + CHECK_THROW(data.insert(it, 1, INITIAL_VALUE), etl::vector_out_of_bounds); } //************************************************************************* @@ -1163,7 +1180,7 @@ namespace DataNDC data; DataNDC data2; - CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds); + CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend()), etl::vector_out_of_bounds); } //************************************************************************* @@ -1190,7 +1207,7 @@ namespace { DataNDC data(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.erase(data.end());, etl::vector_out_of_bounds); + CHECK_THROW(data.erase(data.end()), etl::vector_out_of_bounds); } //************************************************************************* @@ -1218,7 +1235,7 @@ namespace DataNDC data(initial_data.begin(), initial_data.end()); DataNDC data2(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.erase(data2.begin(), data2.end());, etl::vector_out_of_bounds); + CHECK_THROW(data.erase(data2.begin(), data2.end()), etl::vector_out_of_bounds); } //************************************************************************* From dbaffa9169d3a41fcd3d420af55e3a87d86fc3af Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:36:14 +0100 Subject: [PATCH 058/167] Update C++26 deprecated constructs to ensure future standard compliance (#1267) * Update C++26 deprecated constructs to ensure future standard compliance I replaced std::is_trivial with a combination of std::is_trivially_default_constructible and std::is_trivially_copyable. Additionally, I added the required comma before the ellipsis in variadic functions to match updated language specifications. * Some additional is_trivial related changes not found directly when compiling tests in C++26 --------- Co-authored-by: John Wellbelove --- include/etl/generators/type_traits_generator.h | 4 ++-- include/etl/type_traits.h | 4 ++-- test/test_successor.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index 68c937f8..1588544f 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -1227,11 +1227,11 @@ typedef integral_constant true_type; /// is_pod ///\ingroup type_traits template - struct is_pod : std::integral_constant::value && std::is_trivial::value> {}; + struct is_pod : std::integral_constant::value && std::is_trivially_default_constructible::value && std::is_trivially_copyable::value> {}; #if ETL_USING_CPP17 template - inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivial_v; + inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivially_default_constructible_v && std::is_trivially_copyable_v; #endif #if defined(ETL_COMPILER_GCC) diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 26cd6aef..524b74eb 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -1215,11 +1215,11 @@ typedef integral_constant true_type; /// is_pod ///\ingroup type_traits template - struct is_pod : std::integral_constant::value && std::is_trivial::value> {}; + struct is_pod : std::integral_constant::value && std::is_trivially_default_constructible::value && std::is_trivially_copyable::value> {}; #if ETL_USING_CPP17 template - inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivial_v; + inline constexpr bool is_pod_v = std::is_standard_layout_v && std::is_trivially_default_constructible_v && std::is_trivially_copyable_v; #endif #if defined(ETL_COMPILER_GCC) diff --git a/test/test_successor.cpp b/test/test_successor.cpp index 2e42c0d1..ebbd1300 100644 --- a/test/test_successor.cpp +++ b/test/test_successor.cpp @@ -39,7 +39,7 @@ namespace { } - SuccessorBase(SuccessorBase& successors...) + SuccessorBase(SuccessorBase& successors, ...) : successor(successors) { } @@ -55,7 +55,7 @@ namespace { } - SuccessorSameBase1(SuccessorBase& successors...) + SuccessorSameBase1(SuccessorBase& successors, ...) : SuccessorBase(successors) , value(0) { From 8b0fd64289dc8bca0b2b009724dace726af08dad Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:40:19 -0500 Subject: [PATCH 059/167] Fix return value of get_token_list (#1271) Co-authored-by: John Wellbelove --- include/etl/string_utilities.h | 6 ++--- test/test_string_utilities.cpp | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/etl/string_utilities.h b/include/etl/string_utilities.h index d20225c9..64e0365e 100644 --- a/include/etl/string_utilities.h +++ b/include/etl/string_utilities.h @@ -782,9 +782,9 @@ namespace etl etl::optional token; size_t count = 0; - while ((count != output.max_size()) && - (count != max_n_tokens) && - (token = etl::get_token(input, delimiters, token, ignore_empty_tokens))) + while ((token = etl::get_token(input, delimiters, token, ignore_empty_tokens)) && + (count != output.max_size()) && + (count != max_n_tokens)) { output.push_back(token.value()); ++count; diff --git a/test/test_string_utilities.cpp b/test/test_string_utilities.cpp index 0f450da3..a5df21ec 100644 --- a/test/test_string_utilities.cpp +++ b/test/test_string_utilities.cpp @@ -1115,6 +1115,48 @@ namespace CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); } + //************************************************************************* + //before the issue fix, + //the return value was false when output vector max size equaled the number of tokens + //it should be true + TEST(test_issue_1270_output_vector_max_size_equals_num_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + etl::vector views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } + + //************************************************************************* + //before the issue fix, + //the return value was false when max number of tokens equaled the number of tokens + //it should be true + TEST(test_issue_1270_max_tokens_equals_num_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + VectorOfViews7 views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true, 6); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } + //************************************************************************* TEST(test_get_token_list_to_vector_of_string_view_all_but_1_tokens_captured_ignore_empty_tokens) { From 012bbea249419ff5f5e49c51e9a59cc2c6a7ac72 Mon Sep 17 00:00:00 2001 From: Bryton Flecker Date: Wed, 21 Jan 2026 22:30:20 -0600 Subject: [PATCH 060/167] Fix etl::tuple template signature error in pair assignment operator (#1265) * Fix etl::tuple template signature error in pair assignment operator * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update etl::tuple to explicitly use etl::pair or std::pair in assignment operator * Added tests for etl::tuple assignment from pair --------- Co-authored-by: Bryton Flecker Co-authored-by: John Wellbelove --- include/etl/tuple.h | 20 +++++++-------- test/test_tuple.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/include/etl/tuple.h b/include/etl/tuple.h index dbdbdaa2..dde08d13 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -562,9 +562,9 @@ namespace etl //********************************* /// Assign from lvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(pair& p) + tuple& operator =(ETL_OR_STD::pair& p) { get_value() = p.first; get_base().get_value() = p.second; @@ -575,9 +575,9 @@ namespace etl //********************************* /// Assign from const lvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(const pair& p) + tuple& operator =(const ETL_OR_STD::pair& p) { get_value() = p.first; get_base().get_value() = p.second; @@ -588,9 +588,9 @@ namespace etl //********************************* /// Assign from rvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(pair&& p) + tuple& operator =(ETL_OR_STD::pair&& p) { get_value() = etl::forward(p.first); get_base().get_value() = etl::forward(p.second); @@ -601,12 +601,12 @@ namespace etl //********************************* /// Assign from const rvalue pair tuple type. //********************************* - template , etl::enable_if_t = 0> + template (), etl::enable_if_t = 0> ETL_CONSTEXPR14 - tuple& operator =(const pair&& p) + tuple& operator =(const ETL_OR_STD::pair&& p) { - get_value() = etl::forward(p.first); - get_base().get_value() = etl::forward(p.second); + get_value() = p.first; + get_base().get_value() = p.second; return *this; } diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index d84940d9..918541e0 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -777,5 +777,67 @@ namespace CHECK_EQUAL(etl::get<2>(tp), s); } #endif + + //************************************************************************* + TEST(test_assign_from_lvalue_pair) + { + ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = p; + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_const_lvalue_pair) + { + const ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = p; + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_rvalue_pair) + { + etl::tuple tp(0, Data("")); + + tp = ETL_OR_STD::pair(1, Data("2")); + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } + + //************************************************************************* + TEST(test_assign_from_const_rvalue_pair) + { + const ETL_OR_STD::pair p(1, Data("2")); + + etl::tuple tp(0, Data("")); + + tp = static_cast&&>(p); + + int i = etl::get<0>(tp); + Data d = etl::get<1>(tp); + + CHECK_EQUAL(1, i); + CHECK_EQUAL(std::string("2"), d.value); + } } } From 17e6167317e11aa21af69ee5af2ef64b65405f04 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 23 Jan 2026 19:33:08 +0100 Subject: [PATCH 061/167] Remove advance() on static spans (#1281) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Remove advance() on static spans Since the size of a static span is constant, we can't reasonably advance() on it. --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/span.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/etl/span.h b/include/etl/span.h index 5d03632a..c60a9125 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -605,16 +605,6 @@ namespace etl #endif } - //************************************************************************* - /// Moves the pointer to the first element of the span further by a specified number of elements. - ///\tparam elements Number of elements to move forward - //************************************************************************* - void advance(size_t elements) ETL_NOEXCEPT - { - elements = etl::min(elements, size()); - pbegin += elements; - } - //************************************************************************* /// Reinterpret the span as a span with different element type. //************************************************************************* From d8d41871762e4e10cd7c6550b1a69eb9086e7547 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 1 Feb 2026 11:16:41 +0100 Subject: [PATCH 062/167] Add missing includes (#1286) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Add missing includes Before this change, the includes needed to be done explicitly by files using basic_string_stream.h, and be included first. This was error prone, especially if includes are reordered (e.g. via the currently defined clang-format rules). --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/basic_string_stream.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/etl/basic_string_stream.h b/include/etl/basic_string_stream.h index 2b466055..2aa1f28d 100644 --- a/include/etl/basic_string_stream.h +++ b/include/etl/basic_string_stream.h @@ -35,6 +35,10 @@ SOFTWARE. #include "platform.h" #include "to_string.h" +#include "to_u8string.h" +#include "to_u16string.h" +#include "to_u32string.h" +#include "to_wstring.h" namespace etl { From 353c36c393a0027cba0bcbed881b6016d2ca30ee Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 2 Feb 2026 11:46:00 +0100 Subject: [PATCH 063/167] Move comparison operators of etl::expected to namespace etl (#1287) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Move comparison operators of etl::expected to namespace etl --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/expected.h | 204 ++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/include/etl/expected.h b/include/etl/expected.h index 722c411e..758e2404 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -1296,132 +1296,132 @@ namespace etl } #endif }; -} -//******************************************* -/// Equivalence operators. -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::expected& rhs) -{ - if (lhs.has_value() != rhs.has_value()) + //******************************************* + /// Equivalence operators. + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::expected& rhs) { - return false; + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + if (lhs.has_value()) + { + return lhs.value() == rhs.value(); + } + return lhs.error() == rhs.error(); } - if (lhs.has_value()) + + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const TValue2& rhs) { - return lhs.value() == rhs.value(); + if (!lhs.has_value()) + { + return false; + } + return lhs.value() == rhs; } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const TValue2& rhs) -{ - if (!lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) { - return false; + if (lhs.has_value()) + { + return false; + } + return lhs.error() == rhs.error(); } - return lhs.value() == rhs; -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) -{ - if (lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::expected& rhs) { - return false; + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + if (lhs.has_value()) + { + return true; + } + return lhs.error() == rhs.error(); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::expected& rhs) -{ - if (lhs.has_value() != rhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) { - return false; + if (lhs.has_value()) + { + return false; + } + return lhs.error() == rhs.error(); } - if (lhs.has_value()) + + //******************************************* + template + ETL_CONSTEXPR14 + bool operator ==(const etl::unexpected& lhs, const etl::unexpected& rhs) { - return true; + return lhs.error() == rhs.error(); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::expected& lhs, const etl::unexpected& rhs) -{ - if (lhs.has_value()) + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::expected& rhs) { - return false; + return !(lhs == rhs); } - return lhs.error() == rhs.error(); -} -//******************************************* -template -ETL_CONSTEXPR14 -bool operator ==(const etl::unexpected& lhs, const etl::unexpected& rhs) -{ - return lhs.error() == rhs.error(); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const TValue2& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::expected& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const TValue2& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::expected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); -} + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::expected& rhs) -{ - return !(lhs == rhs); -} - -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::expected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); -} - -//******************************************* -template -ETL_CONSTEXPR14 -bool operator !=(const etl::unexpected& lhs, const etl::unexpected& rhs) -{ - return !(lhs == rhs); + //******************************************* + template + ETL_CONSTEXPR14 + bool operator !=(const etl::unexpected& lhs, const etl::unexpected& rhs) + { + return !(lhs == rhs); + } } //******************************************* From 75eb6680d69f6d2bdbe3206a6572f8cf4b725311 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 2 Feb 2026 17:43:26 +0100 Subject: [PATCH 064/167] Make typed_storage constructor constexpr (#1291) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Make typed_storage constructor constexpr --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/alignment.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/alignment.h b/include/etl/alignment.h index 73527765..41e8a20c 100644 --- a/include/etl/alignment.h +++ b/include/etl/alignment.h @@ -367,7 +367,7 @@ namespace etl //*************************************************************************** // Default constructor //*************************************************************************** - typed_storage() ETL_NOEXCEPT + ETL_CONSTEXPR typed_storage() ETL_NOEXCEPT : valid(false) { } @@ -567,7 +567,7 @@ namespace etl //******************************* union union_type { - union_type() ETL_NOEXCEPT + ETL_CONSTEXPR union_type() ETL_NOEXCEPT : dummy() { } From e80623bc1a68cc385c596d136320b7ce10b38769 Mon Sep 17 00:00:00 2001 From: Mike Bloom <91038685+mike919192@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:35:25 -0500 Subject: [PATCH 065/167] Add basic_format_arg constructor for ibasic_string (#1288) * Allow string as format arg * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Added test string escaped * Add temporary string test --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/format.h | 5 ++++ test/test_format.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/etl/format.h b/include/etl/format.h index d090457d..95dafc8d 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -284,6 +284,11 @@ namespace etl { } + basic_format_arg(const etl::ibasic_string& v) + : data(etl::string_view(v.data(), v.size())) + { + } + basic_format_arg(const basic_format_arg& other): data(other.data) { } diff --git a/test/test_format.cpp b/test/test_format.cpp index 31bdecce..2e148bb4 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -282,6 +282,68 @@ namespace CHECK_EQUAL("\"data1\\n\"", test_format(s, "{:?}", sv)); } + //************************************************************************* + TEST(test_format_string) + { + etl::string<100> s; + etl::string<10> s_arg = "data1"; + + CHECK_EQUAL("data1", test_format(s, "{}", s_arg)); + CHECK_EQUAL("data1", test_format(s, "{:s}", s_arg)); + CHECK_THROW(test_format(s, "{:d}", s_arg), etl::bad_format_string_exception); + CHECK_EQUAL("data1 ", test_format(s, "{:10s}", s_arg)); + CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", s_arg)); + CHECK_EQUAL(" data1", test_format(s, "{:>10s}", s_arg)); + CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", s_arg)); + CHECK_EQUAL("data1", test_format(s, "{:3}", s_arg)); + CHECK_EQUAL("dat", test_format(s, "{:.3s}", s_arg)); + CHECK_EQUAL("dat", test_format(s, "{:^.3s}", s_arg)); + CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", s_arg)); + CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", s_arg)); + } + + //************************************************************************* + //this minimal derived class of etl::string is used to prove that the + //temporary lifetime is long enough for the format operation + template + class clearing_string : public etl::string + { + public: + using etl::string::string; + ~clearing_string() + { + this->clear(); + } + }; + TEST(test_format_string_temporary) + { + etl::string<100> s; + const char* data = "data1"; + using string_t = clearing_string<10>; + + CHECK_EQUAL("data1", test_format(s, "{}", string_t(data))); + CHECK_EQUAL("data1", test_format(s, "{:s}", string_t(data))); + CHECK_THROW(test_format(s, "{:d}", string_t(data)), etl::bad_format_string_exception); + CHECK_EQUAL("data1 ", test_format(s, "{:10s}", string_t(data))); + CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", string_t(data))); + CHECK_EQUAL(" data1", test_format(s, "{:>10s}", string_t(data))); + CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", string_t(data))); + CHECK_EQUAL("data1", test_format(s, "{:3}", string_t(data))); + CHECK_EQUAL("dat", test_format(s, "{:.3s}", string_t(data))); + CHECK_EQUAL("dat", test_format(s, "{:^.3s}", string_t(data))); + CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", string_t(data))); + CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", string_t(data))); + } + + //************************************************************************* + TEST(test_format_string_escaped) + { + etl::string<100> s; + etl::string<10> s_arg("data1\n"); + + CHECK_EQUAL("\"data1\\n\"", test_format(s, "{:?}", s_arg)); + } + //************************************************************************* TEST(test_format_chars) { From 3826e2ab2ebb3f67c34c2c49e3bf00788b4640a4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jan 2026 22:29:52 +0000 Subject: [PATCH 066/167] QR Code for Github --- images/QR Github.png | Bin 0 -> 20490 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/QR Github.png diff --git a/images/QR Github.png b/images/QR Github.png new file mode 100644 index 0000000000000000000000000000000000000000..94c76e0ef54db47ebe96a8cd7f045ee13f37eacd GIT binary patch literal 20490 zcmdVCc|6s5`#;`HBTXvJ6sCkWscfYX$1Os& zux8DgO=_wqHP@{9J{A35zYab#bB|yNAHH+cRQYX9M#IiA_`?roN@tbUtjP-EU|wZ| zKmTa2s_VFB4Ywfr{hgZTzNs~9G~(4xDrwy^n&@(Ky43DExok%DP}-%d^ZlVM_@922 z+ORHdUFyCMsz)Arw>(RU*>6kTCzRLHrPgzGq(9H%QIg9}oQ!Xbdf0K_Fk*ou*Zzp` zj)S|tU(fOC-s|t{>c7A9E5%6(pPn;ZbM)=@Nd}F+Y^KO4b`)?|yjHinek4eKB+e?M zz=LBO$8X=m8@#putS96{!O#Q6H1s{y|{BOR^4_ zZQQugyz)L{#g>n9JIU+GlPBhiU*_j6D^Iz&xDY*`pN)AIQEg#uEz)InIn$_hL-5X* zmop=`AH8AT_ydO}|)}M=4NKagt9IOs2d#dc;?-6yf>#>ZZS76{~zDiHq zpn?+a$)bJDr%#{uTFbt9^gvh?Zf}q7cDn%cW3|KC@scZ4f&cX@{(ro;m0rOswwBbk z^lZ~w?yQxC(9oZCb1ft0gAZjG6zpNlPlQcR-%Rg#k&zMk?AiW<2M)aV3$SX>P@d)E z<7@Q`uxNQ!{kip}ps=vIu#}PO5Le2}mti!TExaNv?LixUxGq{R>*nCQpHkA(BXZ0d z;jZZFMl&lEnJ1ji>C`kf24(0Q8O3Q^=TqmZH9RyM;uSNwc%}OYIfSK__`tS`=J)S| ziA18Rrzct48t(KvagS+^0>Wapw)Hk{?waQca|d-_UAd!e{ouialOq*#)b?DHy+@B8 z?J~3Nja*tP3Wxc|%rdo98-%JerU8|WwfpTEvw;v1PUe}sHB3)L=+N$ut`{~oC`PcS0YiAg2 z|MKO_=mD3_{Bpm9M@GKoJBoeb%a`gZS&j=+pLT7$aI@-5mZ(Ag;o~>^?>2bMd>$X) z7%8gHjSu+Q;*9v^AX=5fnBoADeuZXWMf~KhOFnYEU0sHS6xYvu-Z8 zZ{JSJ&AsFn)_zvHXCJA@B_=7kv$SHoD_8yV=g-%#T=`X4D)r^dqmeSO5Gm)dHmq?p4QQAM`2C0z$b?Zi z_S4Kzt){-dFoQnX?iWyA{u}g$a7n8+^U71k#>U6`oph6IOW{jh5TtU8l)Pf2ogVxslJI8^oz%F4=LKet|BUe<55 ztEG`~nP%T+|E=W3je>%GufZSf7{I_vsxSBs;i!(AzC5 z-_}G3CoXdH@K{ya`E2G3?dsB#@mwj^wjLZAsg3Dl-l(pwZmJnPX47?SF;Q`8??Dlf z4}P0S8Mf{{viduA>DoUN|M{ltJh`e)FmslaId?>SEil6JyfDk%j)X+P31lz z8Gf=HI#u){a`5n}6QM#Z~#W^E`j9qB3o)udjdDakwtOPcS6UX{`BUfOPNr z{qV~fceDTGt6S6kqvKiDLqkJKDk?rk%DC9r*fKa11A)=z{v-_%z2dB&ZCajda2k0m z4ngm0irh$h;ACc6Jg0^Vx1+%EIaHavHznsl@58Y40_)I?s59Y=p4OWxS~1%de_u7e z%Sq7dD0e)5P*k@+z_ck;uvdp$v^SS%zGfx!|2UHVS20S~t|W3ySE2Ju>&|TDG)0er zw*lEU-BJ^ss0-jGi(3e#DbJogJN4+%qkTA>zOaup5K$W?4oIdsSv`@et*s3xq&nTs z#wLBIqKAR76u^SPYN7aWKrrw{$?8#08U0_zT3}K|L6wlNM zH~00yT)g=FT!c{Et>3uCji5bl-@d&`HouWH*l>i@I6vN*$i?gG>e`g!*i-1Nmvux= zZf8BdDv(bvx)@6OsoC?~B3hyFLEY5SQX?t5-Zc5WVlVceINrI7+rQw0Syy>N>fVkG z(kC>BV=PhYfVum%!+8yK38_vT!(X#kry|IXStyqeG{L2!O@# zr=%VDiGIVDlllvk_di+RD-);5hnYLl9VC*vmcCE%`&-d40QIG!lyrSk4M2f6O9Rrj zlmp#)HZ5_n?u_~B#2^Jrg+47uYC5UrqK3R+bTmMyEUR`g1g-Ae`R*@Zth7|Y!pbTv zE9*#l$8l(K1bR_lL|K^EDY7f#YKl&QIe{*cBHm-czF0bw?2kZw5)R~ zw8WtyHB-~%!NEb8dPPRI?mqYL6HNvH)XkJkx@!Ome9A@M#L1~bwFkVN-f=)oEV9va zWmdv-g#b;FUOC&SD9$5h@ZPWQ*_r4)8VZX^B8G)p!cr7hZJ4rd^W#l^oA6{wDXE%5 zXDZR8BKBI4+{_=vOP^mtWl}tJN^a-Qk5m4=8+Pt`k?QOF}*l_w!hLpaj_x#sEV-ExyQ$ML%#}zvt&_u3JwfWfLlZ-fr|_%ORURGC2(hxUx1DX zcPx(fJbA3;c`bRBK~@p}m{MM{O)v9AD%+(h`Jf(0*K9}nJvT9Z_2h)lUe`5Y_?O4j zCu?Dy`@57RnDy@f+yY#)fcAac%?-w|sHmvYFZ-d*s_GXwn7(gmNlfgJxixj=yq?|; zeBDVs817r{tMOGfe5&yA&d$z881vAfLtfB}sRvvF1r+(~;#o)0b#|ByPIk)$W_xGn zb`kwN5gL9v>l-TQ)G%T-Y(NU%8n&0#&!xAjN}l;jMJ=aIOaIpx-+yZMe`&#`g@t-? zgc-Go-Is{Dxz&4vX&KvCx>Oi@r-i}q77)wg+ z_`*W|{P@1TFA8@>Z~Mw{4h2LKzcLzpY;0s?WWtLV2fp@rd3ky0@l$uU|CP{eT^E{= zmL`II*{^KRHR9VYjNiQ@{!r1=gK`8b^FTh_Gbm}e2Sjd!NeisndV4c~%(&G}GC8^SJ%5Dp>=xt9bD$-lHMfIy%3M_Y?uK8fZ|(Yro|UJC$RN2#)0XzmXds1ccgdZ-yAqa^z82L&i#I0)m9C;-3XJ$1thVx z!qnKlbLR*C;GJV*W1%rI!dW_Jgr(kARV6N4xx3}FPa{x+R1?2VJRRiK<;mK5={|rS z78Vvw>c7t|?H7JgxLCOS(L?Xi!-s#&dowH!>MBX<&N?$*Pq0(x&T5}O+eYXq_}JDS zyEQVDODjy$_~U9rEE%9nS562qVZ+B&i`A9ornQUEx?#$hRQip6cUey_m5VGW{NmZ8 z>ujxBVQC4EEaA0xwBGjpZ;Dg@sa5@(c7~*qxSul&i}s`58@KxGY|MTxF0QVaV$c}| zN1GBQjvRTyQmERb<>d{9J-W%BWYma;YNMc^O!rsLB#XPN*%prNXHiu_^+?qlH=b!* zLqYA+^I_>D=gyrY3S{Txz$?tn4|I_$Dk`92tlC5t1y%<<-$4Q8_LI`m(#+j^N?(0w zY1zvu|0Ni;Hux%8*&T)?UTIt4vha(z8Rk9!%BUzIdY>n`E*5tg#^vJZFttHlohFB; zQXBBP;zq9#V3r9yR6MMmt|z#@7nTdr|G~27W;L%Gk!UGr`)ac@Z<11(z9^lqMJ5vK1Hv@`fo*vdEuOUt$r`i zG1RI(Ij@)bwWQszg-){pkYF%W`~0rgd4tY zNqdw_B2iNpGK-3EFH%$e7@+LX_+9APxxh}>S+%A4;%@9oPe|C+QQ}4lG!Y^ctZz%# z=Rp|Y7cFmq)iCZ)si=5^m{rB+n4QaGbW7=Sr6)7s?@?`82Ln@k4qk1~Fr1mH;IwM= zw7cCBGx)@ZKU7BqsLj}1yK$7b`(3KqR$26DC^#uk_%;^niqv)H8Suk63snVMtg4Bo;ugpFjJ}SL9l?1J@!Fk9BcY zR#t+P2#3hL6lN5Q;228NTQq@N5j`Cp9N-I+l1`Q~hs0IrhKKCi(*ZGnG6!tE<=I(( z8V9~q-+`XhZH7jdUqEqjv3V(p;@}Um;-*d2#w$a{k1{j6$+o3-93r_uUiM`moHdxWjZMN)hno7gJ370=s6E_JG&@+3DwYHtXU8W zU8#pJ)WRZfb+P~ZDN^a2X!Mb5FajRSIv?ud9BGIJwh0sVonxcC5L6^w5s+9%3xREE z!eNl}1l9Bu)w+6OElD8F_+zM`u2SoAg}1)Xg9jjw*~gDHRO{Q7T!I5BX^amnn5|o4 z>#QdwB>XCI^k}Y0RXyIxNy|-&BFk(NSPo&fdoD+5k26PA6homFtr`RMjp@Gy|6I;? z>gVN|DDuYgn1l5}L-3dj<3t zOm-rqU>2lx0w z=p37vhzJwXfRgDgaT~hB&L6x_)UgJ7La151yEaxEiRtO0dVLtL(g(#xAgLT1FH!;h0|9aJh7b%N6z9 zlInvNO0DvDX(e={+238N`0(%Oed|1K;d z@?i4@b+KOy=5kAIs~_2Ai|A&bES=BIRJ(aI3sC!fm(>gnPu9n@w!N)hmLM+^1t=Qo z0|Nt1E6$3df>xzS21flo%+GH_`huvgQZ8^qk1vS=)#;>OAiy-`*%Jaw!8>K0RE0ep zSEoMCS4@!lpdrx;#u{RKittvI_ub0uXAMcVvD)MLjE?&5M@2z7+1W&CwF0mPK&De# z2*!_<5p5{>7gSz>h!-5b*lfOv>+<6g_JYhGsLRLFzwbOjDOoRbqL zPAGwf{1svw5vG;-*iyX67yirE-M^tDKepY=Js;*Lx`&|u|4a?ago0M#cRlIm0Kqc?sbX+$v`AyiP7IbazBiGYqAvmi z0+i{~K-l1V!I`ZVSe+KA_1!82XRYK)fqP^~$P+Gd!SBQK-W&>%6!+n_vL&YT>YC|@ zOoH+uVPQC@u|c%QP9w>JbWTBAKF|>0mFd)+Mg?K8RY2m#D==G)mm|P-Ft7Ba$*ks) zO2Do`M|H6^(<50P*SFY!zg}^F6J}|AMM+_$CCd|boB$}DF73~Rv%>zV`vygFChH!% z9a1rJ=zmt65wFb2xu|j{_o!LJ4}gzvw#NoUO}E=j`n4&Knx?;m-)@gF*Ys zo#7H&5<7KIP>1Z{PC4RkvuV>NSvUQ!l5#pwW|dbJ{{-OgGTyP9Q*P?_`Ei(awa}rT z$m0NCYZ@74$m0Oih1d}Wctg=Gf>Ngh!%wf8YVCj7$W>Wkp^UTU_3Ph3Y#Sb~0gHGa zVh2(nJMD^Jcq5bq<5yV9!NK9_qTZwrxIM~LHx?A2PKmG1h-)G~#JhLz-li4IbnSy# zojAK2vs@{je$-pE43w5#3Ju)^norQXxdHMO<;EpT8rx_K^3k$c7^*wpA8#?@m z7p~o|V2B%(kDWWik$E=ExN2gur^|{~aJ70O6G$ldEuh+w8o{j_OpY>Y_FFAonaiy0 z%C*Wh8$nGUK&n;aId}IG>)v8rHz@>zyq|#k;O0VM18uR_jQ>4AS|LUF$@g*lTY$0{ zVpqC&W1&$b{rRNUwOVUfz<{KyN$kwE265d?muk3+~2=aHW+Od z7gAGm8ZOg!9X)p7f5SWS`n=jd?>*-qIndxt&p+1H3wQ04Fux6 zrqVBh_3}%H_f+s748#2w^-FF$+e0%ln^h@6zyCW~-K#)*Enh0Mv4$S#iJxq6c1wPa=m$TT}CAmVUBTVbD85 z`0`u6mMZP@=eLaamgt+=nO(WEONV4@i2fbS@@p&SnY^;RGPm4nF|!bK}OTSwIm5Zv9{lK4Yxn_GUl;$pzmm&x-OpbAC+Icd% zhr0V#^5(~r^v?GHd!)EcmPlX{KkZ||t?8$WviWOAiu#r_K-RaYw1c9bdAB#{BNvpIbC^(tXlR0@F?5+&C*W*W;lK;i!1shD+>v1>e_~ zUU8i>mF8hjzgMIvayCZltOAJd>dMOZw5=g%Q^V+`E4U6tT!uRXY(rj%;wptrWt!_) zhW@#8fq<*5PVB zq%U8bppU}M2Ux|T;N#;DXaktKZf`{$#<3z6b#)IEx|fMgG)jT_Y8;Dq(pTq6WKpQ5 zX1@SXeX8SE7vpQ25>+r7Z2%qY`mI|aP;TJh7%CWv^KXz;2SVNC>^9eW8R9x%Fh0t3 z<1dS=m7x_*KuAQ`g|ZkN74=*mH_{j%1>9(&GbJ-Ksy;^Asu2M%Bpa098W92d{lvt?%yf{a z+#~!Udrm3*UX3$n%q#7XTE%~|txQ}O9e&p@O)AMS(1fLKG{%X>GbkfTn2=@AadS3T zp#_@4vJ~(vm=of!Y*zu~L$V2eZPQL~Wal~1Lr_7TY5-Kt3u_bz3$LIR@cc&FOk-;b z#o1A0b=av0gO$q2$mrdX#P@_w6C6jDCYO6BEgBox6{fyJWGP)9SG_(}Y&0p{raQ0T z`i)+g#$HpwkosU^%2VW_Y9k{nVCN-No+W-r(aLfKDucb~r8?RnLHJxZ)0q5*i* ze(8$^7);XxRo;uUBULa{zzHt?2m+bxhBRk9p8e9LOMur-so!gR|30Cpvkf%P{=g`( zbyEYc`1}({2i*Fkq9T1amlY~`MV(eO37{MqqriMu!?D6Ia+wH)u6Q{u%GKWfFeH8& z)Bl_vX=~G7%u!_Im>cWt0OJRk+dJskaDOHhp}y7B)dTPa&{%5lrL%m|3hr<^T>dS- z23L{jSzBA1YchZ&uT8vCh}L{1;60Nbmxmi-UviO6fl||zk+{or0nKXES`jgA=5PZq zskCjxE<1lD2qM4K=OsR(t~u*RXS@N z02~WtOp^QLR5w8y4(?*EnGm#Hwj5wZ0Iwhq$*eSH-g^)bz_NmH?;r$ZRw_VQJBs9i zME9#>k@~hFXp~4m{v~~(-Y^q714hM|r_L{n@+?rC)gwNRlzSJ6bBpRFagmet&d16+ zTM|o2y|-V&&#+SVX1SsXLUcgAbai!SD2|PSf(glwssudcmVEfF;+H-=56vzG1RM?{ zo)v9@sFe5NF9lkmKa0xMd4abZTe4ctb7vPJzj9d&3m05{@!ci|-FBd9zMMmRbp6V}e+L`FVC3UM-y&j^!lePQ5^0(7vop#nMhSmq7y3&OgIbIv2L zl2KDrylw`Gmist-AH9@bjR~j~6Z-U>*+%SDv1ZWmx@P-I=)J<-B)j&wSX77E9?Q2U z76TGeL2F7*OFQGXQZy8)KR5}NLjBsi93Gx@yr&ue?_tSLpZ=yWm!hF&3-Mp;oj4bf zCCbW*2WSCe!33&)pC7+NB=q2c8!bpTBv2cX?<|`p@A>yu^*%p92r+D{kTAD2E}pWD%JCVeWL(gplBpS zkY3CLz4stE1$xu*`bfW<=)CD#HQ|r!1&I&s?d&MYrKR_C7vQz|U4#y*W%rML6rc$> zr0-0<{t<-&=3PKz^TP6^=bmZn>TU=3a14xt#KgT1ad=w_6fDRZSM6s8Ar}zHs8jam z#)yEC5&xgn(ZuQx;NW-xH3!$h4qT%bDJj0lb@=43J=O0o4(U;@e*%Ea%%nX_0;^MbV^>wUMG>DDHZ2c9$#=dJM{8K_1X#-}2f$ zWKTg}=6l)1#L)jU&(E5STH5JQ)CR$hdBBZ-ZpYt|EJR%!z>$;79WZ zH3`N6oB+@$`ho!?TUOdZ+~71I{?#o5aduc3b`w6nU?kX$Ul+{WU=6Smn!T6JHh z8VAi(Ck=n~&D06QsE6Bc1#;@KSZloQ>O%}qgKn^%Q{Zb~m%9t5nO;8v-j^>&W#q*I zH)99G0$Br>w6uOem;J*2Ot|wZRzKN+=SF*UkJA-$^N@-@f9Vnzz39xdVH63_&!_&guXaz#1D-CuK-k2HBX*|t>2%tl_PL;8nV$o=*clcXj%uXg3 zP@P-ON~`HTnkX8H>HV^Qv5eDW7Zx1|KvEIC5)c6hS z8yd1?q?tH+u?onWx&35u&&ArAA|Se;hQ{%9c6N5n@+w^dn;w!dnC~${ZZ~o}8+WVU z_rQx}FKAUL%614vBC|eyKebHn69>=_(;`$*eek96a_Tme&pibMu?|`=*oJ_iZrwUw zD4s@-<}kNiH7ayc6Ao*Ez`@QQ9x)v~2l11(ib*wV0~40?X>4tVB$i)sXXcs!;~`7w zp*VKbOJn`PfFc7F=8M5OE}9&~E?VOFcz(CCv?Pwm@MvAE&a>$@cqL``=_>b`GiSg) zY6mIXdusPKd;r1v6E7Z8SRhIMD;A@W$0e-&1B$povI-b=8KuB+AfxHJB}8bO^v<}z zK~w_VOp$yl*jxUQcbrmi@iK4q$85FYTn%E$R5^#N*XjcA-?@d8th1%L?<|D)YSDg# znHlOy&W`+|8NfmD^4|5Nm?E zi-?L+hh!HBUFN0^pU1|0=PRC^@ByWILZ9T>qmVb)pn^YFINKcRR#&vhVpc{*MozRe zebPDM6-VloWr8Ec*|E{hYVuYU?x|$nJae|O_WmYbaNfFz7NH=4%JV`47CY}TxL3f} zc8fZ~t#Zt%3LuPaZTnGR1`>xJj0v?LU!x5db^*eBX2SU7WE3bk4~%><>T zAuoaK>oPC4(8wE%__ZMH{?T@oK!E(Nk=ukMBIEVO{h-_<9?XC1<9A~;8k!Ma;~DxA z{3lcHqFN<5F|OL%qpZR*m39rUsDJ3dfj=6mF_rO`Uw-+6CQW~w6K<*08aqNO=mg9U zuGAteL*LmsS9^S)@C(?9F@AO~HdP*n`bsi{lif}koIiUXQYX8LZ;4Gj%mY&Nd3_!V zu1oacX!(2B_mx84P`u=e=9W_DDi8_tAjQ0EW0@?Y`ekmeBt$p^i%wyn8&x$ZCEpSa z_$N@p2|JveoJK7x^fWXyUO5caffl%k7FD=Y>>S4L(ST3W$1 zzJ2=^!~+-sGa2|2btCt=OX(dCrEK(^&Osa(eEuZ{BXO~mIRlZYkeC?WdJ;q^!PaEF zmY1euIdGcHGzuTU>3+$D6Igi7ejOB76kzZN=k-rw$~vrp7oKp3fCe1)>(xKIg7*HD z-6t6~Al_jEVUwI`O*owUkr)vKP|y@;n#0PKt%l63C5MA<0ts7~J5QJOAvDBAb_Vs+ zn^WNcLS57PAY?m{hfuosl$x3vX!1I*euejXr+K0;Q6&hjFNa)JkU$g`TDtG{oqf9~ z*1#$Lkuj5)XOcflsc(;+1h=3aGP#Qu)kF7D&Sa*`D$}Aeu$v4Q9>8M|VQ??(Yo%eD ziS3=RJ&&!ol$z#$3%0Yg#jw`im3b2T)rTKCyE{wW-GV{)!q-)Q(9SgCyUQu_7peaI zCQPdDfOs`W`T6Zo@m-MR_dd)VJFvnbFjEG*IiRale*k^O3-Y6eT&v#{6f%d+OfD>> zeXQg${?K#P49t}dq$M7K<*k@~6<_0? zs^O$Wyj?c4cXBz7`Q^D{1VjkZI~Jg{_IggSd+tKfwCKlZ4=&yA>QyM@@jkLKGH<`7 z`8J@fisohz$sv=gN)$jBloj+DiT5d2AZ z;FvaPs3UVfetFz18|o7Tw{~Hukmi;aP+%a}t$F#f5SD@MGs)5+dZxGU<|LK3 zM6)V3AH;SW8(?k@LBbEHD{x)lp?hRIL?9EOrlO)!^TYi0o1ACqhx0tHfGW?obLWHk ziqTPI$bDo0!aFr`H+g2pVX--?bRS3}5Y~ki)lq_K1kZ6&sps5fPgDLh2pT+f6vF1s zGmUtDh&6qG?I0u_l$7oeru~h>AwXzl>ab(`_7KE}Ht#$RSFw6SY9LO)An?^ZShtc( z>}#zAmfrhZ@60xZgFX{Ir#O}W>-Qf$!`j-~67usqO4uIe!3xLK<4u3=_n@-uK6Kpq zb9kVHYpjC1te*cZtHEm=#v)#jx&sjOO;16T^*aG9f1~JnPy9X>Nnqv6Z%tS7IER1O zQfiKroIDg(Q<)O@ClvO7Ot*TtfmLxGS{Y0>uJjJb+!PR28GTV8a_9<6f#kMNT)dIs z4to=WP#cjLaeC{;#xaOW1VktcQwIm??M8X}JC-poFJ?>0-;H(oBPegP*yt$+-yO0C zNC-#e?21(Ge$t;e4e!HZqN^MhbEFyAk7VL}L;;N0s1Kg$yZ9HB-< zap{7L>r4{ZW2UCnh0k!+K>PM@91+zO!2qnS;ItZ1;U<2kpUX`4QFEw zwzf7g_f^}sRR@%$ft)1dPr=dr)1s^hYf;t(HZQ$kee0{6Q@qgcFS|jL?VnJP|FiP* zAJYFIB{hHeun*!UdebrbKA%2aon<^tPd~fT?a8onnC@4GVuef!NK3VK(MO@6AaV*z zIm30^A@IcQuLe<;FD=aw4;~UyT=d1ptQ1JUJn55GnI+(+(ilaK@}i=WD-&;e$TS5P zdQS46OY#(KSR*qZg}zMoii>Nk3@EOg=$(lq!CsJlH`t|}C`OBA#i&JCQ@!cPFCfqk zp%>$P$~Do5;TQ+dp~HmY37W9gAf_r0)}sWrw4cJQ6~r%p2y$hfqV1WGzX<@n%mQMM zn2?DUWy&qlY7%pJK1!b*zyA66^zWzci4%5jh>V0()FC)+j|~tVl%f>!gU|^l4h9EU zurps;G-@F!l-nuB*Fe8xAclZ_ir`oiJUQZCa$^g*~ASdQ)^#bvH|Ni{>ix;<|&@t=@ zVd<{QhBt3czPeg*9}2h&Ful{ZZ(*2!iVyjpR=#1q^g7CphCzD&5m@RFdCV{@LQ6aA zQ0_Gm5GtHWEb8*_vG~2*{wM-Y9HbfJjdl8}PyleB6(6`Lys>8B&cM6`sjdLr{~<^U z1E2&Ei^&{Oi~=~19FFy?ggy`El-ZD`1lQK0c-pCqal1Ta=sumH%CL z?>tJ9kCdaXj5%yvI7LQh<5zcO1l$|aF)1l{>qz_>?b6-zBK1FP5Un9SgoO+uGZO8WmTIVf6!KkqZ|t09Mu`!h##B=wJuN?n@0h*Ke-cJAqb&!jph6 zc(_TWw0o~Z85EG(OR}$&!5Z{UdL=cJ43Q)hwcLaD6LNA0iw+FODz?_^FETSZ%l$_* z<1H{p?RH8{PWE##ipN?)><}4wU<%L( zSqWTN<$kB(F|&1c&Y4l0K8XdH>K;j|L&>bDAzTT z-D!^5Xr*$YK31Am2-?s&nAncxv78YR5h#3j;v2yAa4c*5T0enB;$p_7P&Pq|EBVMj z{GV7MrgGV5E8Utl_iO26tRe2d&$Kk94MeKDoUTCFVM$NP!{gfqV)@i_*dnm| z$l7N_wUYo2GxRkX!h-#Ih}1!1q8pMU-as`!j|*isG&EcR!gRCUTq1X>QWV93E=|W{ zkLf{=?wOgH`HCr71r;!Mjn%2l;&({dbZrB@tIJ?M=dI`R+Q0otODv7orl;^yo^|IQ z;PSBahqjy`uKMMRs+HBt`TdzOwuNf8MH5nL>N)N{ow-&~z!Iu4kwxqBWu(deYuone zq7fvUA)_j)w{LYJX!QWxUsxdkee@lmOEuQ~(bCpF4H_D%4JfajGJA4!bFnmL#{pqs z|F4^0l){xNPo|Fn*#jc4P(44@)A1f7c+j_iywCV*5XuSe&tY*KmbLLt=aRmMx{^h+ z6iCp~qo%E?mxk##vmwo(+$c?*-3=(}wh=t=0u(1eNyqvi)(p`dw8JJOZQYT;g{tV5 zW_I<;GGhqDny#FS#>V0?(spfeKk;aV?FLcENG?kAEbs^CACf}R12xdo4gQ4but&0d z0uun#9)N4!Q^~6EET5^5WxF<-eSJ*JahT|VCL>dyDwKXXgx0ySXFa$0q?qyJT+YCY0S%gq_QSJ$9NW`MN(><-ipS$w9@l$w?RwK#FwT0M^B~>RA2?=( zRH4;5&cAV+_TqPg#;Z zdZNYPJszWA;4vUxLXgH97AN39u~Jbpz*v7{Awy_Kz&WnNEMST4^^YWB6ZIuVSe9AO z9I$V<0$A5njBWW*t=xM+a!bm}x&V()c*aEzfG0mu-*ZX7?2T{0Mq}`ZQ^l+j{ zWLh06sCP#&%8?=iqc(*LM>B{&Y8E)p#CO|})BsHW58fByc03qyN?i{gVzEWxu2cJB z=2x*CS?Suh3~dkf}O* z=FAVgQr3SI&HEyslFxLe|DW^dCiro7p@cK6|3a!s)6h^9a10o9a2Kyn_Li`q1)%7# zZacCeHd_)&B Date: Tue, 3 Feb 2026 08:58:24 +0000 Subject: [PATCH 067/167] Added etl::visitor_from_type_list --- include/etl/visitor.h | 21 ++++++++++----------- test/test_visitor.cpp | 13 +++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/include/etl/visitor.h b/include/etl/visitor.h index 1d917c0a..c9ee698e 100644 --- a/include/etl/visitor.h +++ b/include/etl/visitor.h @@ -205,21 +205,20 @@ namespace etl virtual void visit(T1) = 0; }; - //***************************************************************** - /// The visitor class for an etl::type_list. - /// Expands the type_list into the existing variadic visitor. - ///\ingroup visitor - //***************************************************************** + //*************************************************************************** + /// Helper to turn etl::type_list into etl::visitor + template + struct visitor_from_type_list; + template - class visitor> : public visitor + struct visitor_from_type_list> { - ETL_STATIC_ASSERT(sizeof...(TTypes) != 0, "etl::type_list must not be empty"); - - public: - - using visitor::visit; + using type = etl::visitor; }; + template + using visitor_from_type_list_t = typename visitor_from_type_list::type; + #else //***************************************************************** diff --git a/test/test_visitor.cpp b/test/test_visitor.cpp index db881e78..1ab34f77 100644 --- a/test/test_visitor.cpp +++ b/test/test_visitor.cpp @@ -747,6 +747,19 @@ namespace #endif } +#if !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + TEST(test_visitor_from_type_list) + { + using Visitor1 = etl::visitor; + + using TypeList = etl::type_list; + using Visitor2 = etl::visitor_from_type_list_t; + + CHECK_TRUE((std::is_same::value)); + } +#endif + #if !defined(ETL_VISITOR_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* TEST(test_visitable_from_type_list) From fc7c80bb976264a71f0996036596d3c0ec119915 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 3 Feb 2026 20:33:45 +0000 Subject: [PATCH 068/167] accepts(id) for empty router passes on to a sucessor --- include/etl/generators/message_router_generator.h | 9 ++++++++- include/etl/message_router.h | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 6b3602ff..f54df20d 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -625,7 +625,14 @@ namespace etl bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE { - return false; + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } } //******************************************** diff --git a/include/etl/message_router.h b/include/etl/message_router.h index e46c05a9..6ae44d18 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -613,7 +613,14 @@ namespace etl bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE { - return false; + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } } //******************************************** From 2e54c01c69d08920de4861bccdc261ca873d5a50 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 3 Feb 2026 20:35:44 +0000 Subject: [PATCH 069/167] Fixed incorrect comment from 'tuple' to 'message_router' --- include/etl/generators/message_router_generator.h | 2 +- include/etl/message_router.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index f54df20d..1f8e19da 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -655,7 +655,7 @@ namespace etl }; //*************************************************************************** - /// Helper to turn etl::type_list into etl::tuple + /// Helper to turn etl::type_list into etl::message_router template struct message_router_from_type_list; diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 6ae44d18..42735ab0 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -643,7 +643,7 @@ namespace etl }; //*************************************************************************** - /// Helper to turn etl::type_list into etl::tuple + /// Helper to turn etl::type_list into etl::message_router template struct message_router_from_type_list; From 1e2b69bc958da6bd31a5ede1cbc40e48a53315ef Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 5 Feb 2026 10:53:08 +0000 Subject: [PATCH 070/167] PR review changes --- .../etl/generators/message_packet_generator.h | 20 ++++---- .../etl/generators/message_router_generator.h | 2 +- include/etl/message_packet.h | 48 +++++++++---------- include/etl/message_router.h | 2 +- include/etl/type_list.h | 5 ++ test/test_message_router.cpp | 25 ---------- test/test_type_list.cpp | 18 +++++++ 7 files changed, 59 insertions(+), 61 deletions(-) diff --git a/include/etl/generators/message_packet_generator.h b/include/etl/generators/message_packet_generator.h index f15efb03..354601b9 100644 --- a/include/etl/generators/message_packet_generator.h +++ b/include/etl/generators/message_packet_generator.h @@ -88,13 +88,13 @@ namespace etl private: template - static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; template static constexpr bool IsInMessageList = etl::is_one_of_v>, TMessageTypes...>; template - static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; public: @@ -102,7 +102,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + constexpr message_packet() noexcept : valid(false) { } @@ -403,14 +403,14 @@ namespace etl { private: - //template - //static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + template + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; template static constexpr bool IsInMessageList = false; template - static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; public: @@ -418,7 +418,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + constexpr message_packet() noexcept { } #include "private/diagnostic_pop.h" @@ -620,7 +620,7 @@ namespace etl cog.outl(" //********************************************") cog.outl("#include \"private/diagnostic_uninitialized_push.h\"") - cog.outl(" message_packet()") + cog.outl(" ETL_CONSTEXPR message_packet() ETL_NOEXCEPT") cog.outl(" : valid(false)") cog.outl(" {") cog.outl(" }") @@ -934,7 +934,7 @@ namespace etl cog.outl(" //********************************************") cog.outl("#include \"private/diagnostic_uninitialized_push.h\"") - cog.outl(" message_packet()") + cog.outl(" ETL_CONSTEXPR message_packet() ETL_NOEXCEPT") cog.outl(" : valid(false)") cog.outl(" {") cog.outl(" }") @@ -1219,7 +1219,7 @@ namespace etl using message_types = etl::type_list<>; #endif - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 1f8e19da..02140088 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -623,7 +623,7 @@ namespace etl //********************************************** using imessage_router::accepts; - bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE + bool accepts(etl::message_id_t id) const ETL_OVERRIDE { if (has_successor()) { diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index 9c6f5eb1..a097d55c 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -76,13 +76,13 @@ namespace etl private: template - static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; template static constexpr bool IsInMessageList = etl::is_one_of_v>, TMessageTypes...>; template - static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; public: @@ -90,7 +90,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + constexpr message_packet() noexcept : valid(false) { } @@ -391,14 +391,14 @@ namespace etl { private: - //template - //static constexpr bool IsMessagePacket = etl::is_same_v< etl::remove_const_t>, etl::message_packet>; + template + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; template static constexpr bool IsInMessageList = false; template - static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; + static constexpr bool IsIMessage = etl::is_same_v>, etl::imessage>; public: @@ -406,7 +406,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + constexpr message_packet() noexcept { } #include "private/diagnostic_pop.h" @@ -528,7 +528,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -856,7 +856,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -1182,7 +1182,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -1505,7 +1505,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -1824,7 +1824,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -2137,7 +2137,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -2447,7 +2447,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -2754,7 +2754,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -3057,7 +3057,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -3354,7 +3354,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -3648,7 +3648,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -3939,7 +3939,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -4226,7 +4226,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -4507,7 +4507,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -4785,7 +4785,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -5060,7 +5060,7 @@ namespace etl //******************************************** #include "private/diagnostic_uninitialized_push.h" - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } @@ -5331,7 +5331,7 @@ namespace etl using message_types = etl::type_list<>; #endif - message_packet() + ETL_CONSTEXPR message_packet() ETL_NOEXCEPT : valid(false) { } diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 42735ab0..b53d9071 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -611,7 +611,7 @@ namespace etl //********************************************** using imessage_router::accepts; - bool accepts(etl::message_id_t /*id*/) const ETL_OVERRIDE + bool accepts(etl::message_id_t id) const ETL_OVERRIDE { if (has_successor()) { diff --git a/include/etl/type_list.h b/include/etl/type_list.h index 2d0dcdac..19eddc15 100644 --- a/include/etl/type_list.h +++ b/include/etl/type_list.h @@ -59,6 +59,11 @@ namespace etl template struct is_type_list> : etl::true_type {}; +#if ETL_USING_CPP17 + template + inline constexpr bool is_type_list_v = is_type_list::value; +#endif + //*************************************************************************** /// The empty type list. //*************************************************************************** diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp index a6691297..cfe2e9b1 100644 --- a/test/test_message_router.cpp +++ b/test/test_message_router.cpp @@ -448,31 +448,6 @@ namespace CHECK_EQUAL(1, r1.message4_count); CHECK_EQUAL(0, r1.message_unknown_count); CHECK_EQUAL(4, r2.callback_count); - - //// Send from the null router. - //etl::send_message(r0, message1); - //CHECK_EQUAL(1, r2.message1_count); - //CHECK_EQUAL(0, r2.message2_count); - //CHECK_EQUAL(0, r2.message4_count); - //CHECK_EQUAL(0, r2.message_unknown_count); - - //etl::send_message(r0, message2); - //CHECK_EQUAL(1, r2.message1_count); - //CHECK_EQUAL(1, r2.message2_count); - //CHECK_EQUAL(0, r2.message4_count); - //CHECK_EQUAL(0, r2.message_unknown_count); - - //etl::send_message(r0, message3); - //CHECK_EQUAL(1, r2.message1_count); - //CHECK_EQUAL(1, r2.message2_count); - //CHECK_EQUAL(0, r2.message4_count); - //CHECK_EQUAL(1, r2.message_unknown_count); - - //etl::send_message(r0, message4); - //CHECK_EQUAL(1, r2.message1_count); - //CHECK_EQUAL(1, r2.message2_count); - //CHECK_EQUAL(1, r2.message4_count); - //CHECK_EQUAL(1, r2.message_unknown_count); } //************************************************************************* diff --git a/test/test_type_list.cpp b/test/test_type_list.cpp index cd53981c..b8124dee 100644 --- a/test/test_type_list.cpp +++ b/test/test_type_list.cpp @@ -37,6 +37,24 @@ namespace #if ETL_USING_CPP11 SUITE(test_type_list) { + //************************************************************************* + TEST(test_is_type_list) + { + using t0 = etl::type_list<>; + using t1 = etl::type_list; + using t2 = int; + + CHECK_TRUE((etl::is_type_list::value)); + CHECK_TRUE((etl::is_type_list::value)); + CHECK_FALSE((etl::is_type_list::value)); + +#if ETL_USING_CPP17 + CHECK_TRUE((etl::is_type_list_v)); + CHECK_TRUE((etl::is_type_list_v)); + CHECK_FALSE((etl::is_type_list_v)); +#endif + } + //************************************************************************* TEST(test_type_list_select) { From ca6bbd50d0cf53ab18096e9ae92060cba855e9b3 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 5 Feb 2026 11:01:51 +0000 Subject: [PATCH 071/167] PR review changes --- include/etl/private/variant_variadic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index afbf7243..4363ebfa 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -1255,7 +1255,7 @@ namespace etl get(etl::variant& v) { #if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11) - static_assert(Index < etl::type_list_size>::value, "Index out of range"); + static_assert(Index < sizeof...(TTypes), "Index out of range"); #endif ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); @@ -1428,7 +1428,7 @@ namespace etl template struct variant_size> - : etl::integral_constant>::value> + : etl::integral_constant { }; From 6cec4a39712e215e0334ecdd7ae23c46b8359dad Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 5 Feb 2026 11:42:09 +0000 Subject: [PATCH 072/167] Fixed internal constexptr flag in message_packet --- include/etl/generators/message_packet_generator.h | 2 +- include/etl/message_packet.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/generators/message_packet_generator.h b/include/etl/generators/message_packet_generator.h index 354601b9..36430509 100644 --- a/include/etl/generators/message_packet_generator.h +++ b/include/etl/generators/message_packet_generator.h @@ -404,7 +404,7 @@ namespace etl private: template - static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet<>>; template static constexpr bool IsInMessageList = false; diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index a097d55c..24f1e157 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -392,7 +392,7 @@ namespace etl private: template - static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet>; + static constexpr bool IsMessagePacket = etl::is_same_v>, etl::message_packet<>>; template static constexpr bool IsInMessageList = false; From 82f168c96e2fef66dfc6a772147e1c6a1689fc9f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 5 Feb 2026 20:57:54 +0000 Subject: [PATCH 073/167] Fixed unused variable in unti test --- test/test_message_packet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index 51b0712d..b28191fa 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -235,7 +235,6 @@ namespace #else Packet packet3(message3); #endif - NullPacket null_packet; // Should cause a static assert. //Packet packet4(message4); From 2a79845dd5f78043135bbfec3bc09da781d8f636 Mon Sep 17 00:00:00 2001 From: Drew Rife Date: Fri, 6 Feb 2026 04:32:54 -0500 Subject: [PATCH 074/167] Add ref-qualifiers to basic_format_spec (#1292) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * feat: use ref-qualifiers for basic_format_spec Converted the l-value methods to ref-qualified and also added r-value ref-qualified methods. --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/basic_format_spec.h | 177 ++++++++++++++++++++++++++------ include/etl/platform.h | 2 + test/test_format_spec.cpp | 87 ++++++++++++++++ 3 files changed, 232 insertions(+), 34 deletions(-) diff --git a/include/etl/basic_format_spec.h b/include/etl/basic_format_spec.h index 36c2d74c..c374e35f 100644 --- a/include/etl/basic_format_spec.h +++ b/include/etl/basic_format_spec.h @@ -36,6 +36,7 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" #include "static_assert.h" +#include "utility.h" namespace etl { @@ -206,7 +207,7 @@ namespace etl //*************************************************************************** /// Default constructor. //*************************************************************************** - ETL_CONSTEXPR basic_format_spec() + ETL_CONSTEXPR basic_format_spec() ETL_NOEXCEPT : base_(10U) , width_(0U) , precision_(0U) @@ -228,7 +229,7 @@ namespace etl bool left_justified__, bool boolalpha__, bool show_base__, - typename TString::value_type fill__) + typename TString::value_type fill__) ETL_NOEXCEPT : base_(base__) , width_(width__) , precision_(precision__) @@ -243,7 +244,7 @@ namespace etl //*************************************************************************** /// Clears the format spec back to default. //*************************************************************************** - ETL_CONSTEXPR14 void clear() + ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT { base_ = 10U; width_ = 0U; @@ -259,56 +260,93 @@ namespace etl /// Sets the base. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& base(uint32_t b) + ETL_CONSTEXPR14 basic_format_spec& base(uint32_t b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { base_ = static_cast(b); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& base(uint32_t b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + base_ = static_cast(b); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Sets the base to binary. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& binary() + ETL_CONSTEXPR14 basic_format_spec& binary() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(2); - return *this; + return base(2); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& binary() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(2)); + } +#endif + //*************************************************************************** /// Sets the base to octal. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& octal() + ETL_CONSTEXPR14 basic_format_spec& octal() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(8); - return *this; + return base(8); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& octal() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(8)); + } +#endif + //*************************************************************************** /// Sets the base to decimal. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& decimal() + ETL_CONSTEXPR14 basic_format_spec& decimal() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(10); - return *this; + return base(10); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& decimal() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(10)); + } +#endif + //*************************************************************************** /// Sets the base to hex. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& hex() + ETL_CONSTEXPR14 basic_format_spec& hex() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(16); - return *this; + return base(16); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& hex() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(16)); + } +#endif + //*************************************************************************** /// Gets the base. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_base() const + ETL_CONSTEXPR uint32_t get_base() const ETL_NOEXCEPT { return base_; } @@ -317,16 +355,25 @@ namespace etl /// Sets the show base flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& show_base(bool b) + ETL_CONSTEXPR14 basic_format_spec& show_base(bool b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { show_base_ = b; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& show_base(bool b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + show_base_ = b; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the show base flag. //*************************************************************************** - ETL_CONSTEXPR bool is_show_base() const + ETL_CONSTEXPR bool is_show_base() const ETL_NOEXCEPT { return show_base_; } @@ -335,16 +382,25 @@ namespace etl /// Sets the width. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& width(uint32_t w) + ETL_CONSTEXPR14 basic_format_spec& width(uint32_t w) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { width_ = static_cast(w); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& width(uint32_t w) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + width_ = static_cast(w); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the width. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_width() const + ETL_CONSTEXPR uint32_t get_width() const ETL_NOEXCEPT { return width_; } @@ -353,16 +409,25 @@ namespace etl /// Sets the precision. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& precision(uint32_t p) + ETL_CONSTEXPR14 basic_format_spec& precision(uint32_t p) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { precision_ = static_cast(p); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& precision(uint32_t p) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + precision_ = static_cast(p); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the precision. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_precision() const + ETL_CONSTEXPR uint32_t get_precision() const ETL_NOEXCEPT { return precision_; } @@ -371,16 +436,25 @@ namespace etl /// Sets the upper case flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& upper_case(bool u) + ETL_CONSTEXPR14 basic_format_spec& upper_case(bool u) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { upper_case_ = u; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& upper_case(bool u) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + upper_case_ = u; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the upper case flag. //*************************************************************************** - ETL_CONSTEXPR bool is_upper_case() const + ETL_CONSTEXPR bool is_upper_case() const ETL_NOEXCEPT { return upper_case_; } @@ -389,16 +463,25 @@ namespace etl /// Sets the fill character. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& fill(typename TString::value_type c) + ETL_CONSTEXPR14 basic_format_spec& fill(typename TString::value_type c) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { fill_ = c; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& fill(typename TString::value_type c) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + fill_ = c; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the fill character. //*************************************************************************** - ETL_CONSTEXPR typename TString::value_type get_fill() const + ETL_CONSTEXPR typename TString::value_type get_fill() const ETL_NOEXCEPT { return fill_; } @@ -407,16 +490,25 @@ namespace etl /// Sets the left justify flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& left() + ETL_CONSTEXPR14 basic_format_spec& left() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { left_justified_ = true; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& left() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + left_justified_ = true; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the left justify flag. //*************************************************************************** - ETL_CONSTEXPR bool is_left() const + ETL_CONSTEXPR bool is_left() const ETL_NOEXCEPT { return left_justified_; } @@ -425,16 +517,25 @@ namespace etl /// Sets the right justify flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& right() + ETL_CONSTEXPR14 basic_format_spec& right() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { left_justified_ = false; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& right() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + left_justified_ = false; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the right justify flag. //*************************************************************************** - ETL_CONSTEXPR bool is_right() const + ETL_CONSTEXPR bool is_right() const ETL_NOEXCEPT { return !left_justified_; } @@ -443,16 +544,25 @@ namespace etl /// Sets the bool alpha flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& boolalpha(bool b) + ETL_CONSTEXPR14 basic_format_spec& boolalpha(bool b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { boolalpha_ = b; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& boolalpha(bool b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + boolalpha_ = b; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the boolalpha flag. //*************************************************************************** - ETL_CONSTEXPR bool is_boolalpha() const + ETL_CONSTEXPR bool is_boolalpha() const ETL_NOEXCEPT { return boolalpha_; } @@ -481,7 +591,6 @@ namespace etl } private: - uint_least8_t base_; uint_least8_t width_; uint_least8_t precision_; diff --git a/include/etl/platform.h b/include/etl/platform.h index 116daeb4..6db7c305 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -368,6 +368,7 @@ SOFTWARE. #define ETL_ENUM_CLASS(name) enum class name #define ETL_ENUM_CLASS_TYPE(name, type) enum class name : type #define ETL_LVALUE_REF_QUALIFIER & + #define ETL_RVALUE_REF_QUALIFIER && #if ETL_USING_EXCEPTIONS #define ETL_NOEXCEPT noexcept #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) @@ -393,6 +394,7 @@ SOFTWARE. #define ETL_ENUM_CLASS(name) enum name #define ETL_ENUM_CLASS_TYPE(name, type) enum name #define ETL_LVALUE_REF_QUALIFIER + #define ETL_RVALUE_REF_QUALIFIER #endif //************************************* diff --git a/test/test_format_spec.cpp b/test/test_format_spec.cpp index 57eb0841..d242dd79 100644 --- a/test/test_format_spec.cpp +++ b/test/test_format_spec.cpp @@ -91,6 +91,93 @@ namespace CHECK_EQUAL(true, format.is_upper_case()); } + //************************************************************************* +#if ETL_USING_CPP11 + TEST(test_format_rvalue_ref_qualifiers) + { + // Test chaining on temporary (rvalue) + auto format = etl::format_spec() + .base(16) + .boolalpha(true) + .fill('*') + .left() + .precision(3) + .show_base(true) + .upper_case(true) + .width(8); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('*', format.get_fill()); + CHECK_EQUAL(3, format.get_precision()); + CHECK_EQUAL(8, format.get_width()); + CHECK_EQUAL(true, format.is_boolalpha()); + CHECK_EQUAL(true, format.is_left()); + CHECK_EQUAL(false, format.is_right()); + CHECK_EQUAL(true, format.is_show_base()); + CHECK_EQUAL(true, format.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_lvalue_ref_qualifiers) + { + // Test chaining on lvalue + etl::format_spec format; + + format.hex().boolalpha(true).fill('#').right().precision(5).show_base(false).upper_case(false).width(12); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('#', format.get_fill()); + CHECK_EQUAL(5, format.get_precision()); + CHECK_EQUAL(12, format.get_width()); + CHECK_EQUAL(true, format.is_boolalpha()); + CHECK_EQUAL(false, format.is_left()); + CHECK_EQUAL(true, format.is_right()); + CHECK_EQUAL(false, format.is_show_base()); + CHECK_EQUAL(false, format.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_base_methods) + { + // Test binary + auto format_bin = etl::format_spec().binary().width(8).fill('0'); + CHECK_EQUAL(2, format_bin.get_base()); + CHECK_EQUAL(8, format_bin.get_width()); + CHECK_EQUAL('0', format_bin.get_fill()); + + // Test octal + auto format_oct = etl::format_spec().octal().width(6); + CHECK_EQUAL(8, format_oct.get_base()); + CHECK_EQUAL(6, format_oct.get_width()); + + // Test decimal + auto format_dec = etl::format_spec().decimal().precision(2); + CHECK_EQUAL(10, format_dec.get_base()); + CHECK_EQUAL(2, format_dec.get_precision()); + + // Test hex + auto format_hex = etl::format_spec().hex().upper_case(true); + CHECK_EQUAL(16, format_hex.get_base()); + CHECK_EQUAL(true, format_hex.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_mixed_lvalue_rvalue) + { + // Create as rvalue, then use as lvalue + auto format = etl::format_spec().hex().width(8); + + // Continue chaining on lvalue + format.fill('0').upper_case(true).show_base(true); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('0', format.get_fill()); + CHECK_EQUAL(8, format.get_width()); + CHECK_EQUAL(true, format.is_upper_case()); + CHECK_EQUAL(true, format.is_show_base()); + } +#endif + //************************************************************************* #if ETL_USING_CPP14 TEST(test_format_constexpr) From 10fd81c2be8de595bf5ba326359c1c20484f4b64 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 6 Feb 2026 11:08:17 +0100 Subject: [PATCH 075/167] Add support for size_t and unsigned long to etl::format (#1290) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Add support for size_t and unsigned long to etl::format * Document list of supported types in etl::supported_format_types * Add further types and tests for etl::format --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/format.h | 40 ++++++++++++- test/test_format.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 3 deletions(-) diff --git a/include/etl/format.h b/include/etl/format.h index 95dafc8d..3268f43b 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -123,7 +123,13 @@ namespace etl template using format_string = basic_format_string...>; - // supported types to format + // Supported types to format + // + // This is the limited number of types as defined in std::basic_format_arg + // https://en.cppreference.com/w/cpp/utility/format/basic_format_arg.html + // + // Further types to be supported are added via converting constructors in + // etl::basic_format_arg using supported_format_types = etl::variant< etl::monostate, bool, @@ -239,6 +245,21 @@ namespace etl { } + basic_format_arg(const short v) + : data(static_cast(v)) + { + } + + basic_format_arg(const unsigned short v) + : data(static_cast(v)) + { + } + + basic_format_arg(const long int v) + : data(static_cast(v)) + { + } + basic_format_arg(const unsigned int v) : data(v) { @@ -254,6 +275,13 @@ namespace etl { } + // Additional type to list of basic types as defined for std::basic_format_arg: + // Mapping unsigned long to unsigned long long int + basic_format_arg(const unsigned long v) + : data(static_cast(v)) + { + } + basic_format_arg(const char* v) : data(v) { @@ -264,6 +292,16 @@ namespace etl { } + basic_format_arg(const signed char v) + : data(static_cast(v)) + { + } + + basic_format_arg(const unsigned char v) + : data(static_cast(v)) + { + } + basic_format_arg(const float v) : data(v) { diff --git a/test/test_format.cpp b/test/test_format.cpp index 2e148bb4..a6c25eab 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -86,6 +86,62 @@ namespace CHECK_EQUAL("-1", test_format(s, "{}", -1)); } + //************************************************************************* + TEST(test_format_short) + { + etl::string<100> s; + + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1))); + CHECK_EQUAL("123", test_format(s, "{}", static_cast(123))); + CHECK_EQUAL("4123", test_format(s, "{}", static_cast(4123))); + CHECK_EQUAL("1 2", test_format(s, "{} {}", static_cast(1), static_cast(2))); + CHECK_EQUAL("-123", test_format(s, "{}", static_cast(-123))); + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0))); + CHECK_EQUAL("-1", test_format(s, "{}", static_cast(-1))); + } + + //************************************************************************* + TEST(test_format_unsigned_short) + { + etl::string<100> s; + + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1))); + CHECK_EQUAL("123", test_format(s, "{}", static_cast(123))); + CHECK_EQUAL("4123", test_format(s, "{}", static_cast(4123))); + CHECK_EQUAL("1 2", test_format(s, "{} {}", static_cast(1), static_cast(2))); + CHECK_EQUAL("60123", test_format(s, "{}", static_cast(60123))); + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0))); + CHECK_EQUAL("65500", test_format(s, "{}", static_cast(65500))); + } + + //************************************************************************* + TEST(test_format_long_int) + { + etl::string<100> s; + + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1))); + CHECK_EQUAL("123", test_format(s, "{}", static_cast(123))); + CHECK_EQUAL("4123", test_format(s, "{}", static_cast(4123))); + CHECK_EQUAL("1 2", test_format(s, "{} {}", static_cast(1), static_cast(2))); + CHECK_EQUAL("-123", test_format(s, "{}", static_cast(-123))); + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0))); + CHECK_EQUAL("-1", test_format(s, "{}", static_cast(-1))); + } + + //************************************************************************* + TEST(test_format_unsigned_long_int) + { + etl::string<100> s; + + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1))); + CHECK_EQUAL("123", test_format(s, "{}", static_cast(123))); + CHECK_EQUAL("4123", test_format(s, "{}", static_cast(4123))); + CHECK_EQUAL("1 2", test_format(s, "{} {}", static_cast(1), static_cast(2))); + CHECK_EQUAL("60123", test_format(s, "{}", static_cast(60123))); + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0))); + CHECK_EQUAL("65500", test_format(s, "{}", static_cast(65500))); + } + //************************************************************************* TEST(test_format_unsigned_int) { @@ -131,8 +187,10 @@ namespace { etl::string<100> s; - CHECK_EQUAL("34", test_format(s, "{}", static_cast(34))); - CHECK_EQUAL("-14", test_format(s, "{}", static_cast(-14))); + // mapped to unsigned char + //CHECK_EQUAL("34", test_format(s, "{}", static_cast(34))); + // mapped to signed char + //CHECK_EQUAL("-14", test_format(s, "{}", static_cast(-14))); CHECK_EQUAL("6534", test_format(s, "{}", static_cast(6534))); CHECK_EQUAL("-9414", test_format(s, "{}", static_cast(-9414))); CHECK_EQUAL("236534", test_format(s, "{}", static_cast(236534))); @@ -398,6 +456,82 @@ namespace } } + //************************************************************************* + TEST(test_format_size_t) + { + etl::string<100> s; + + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0LL))); + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1LL))); + CHECK_EQUAL("12345678", test_format(s, "{}", static_cast(12345678LL))); + CHECK_EQUAL("4123456780", test_format(s, "{}", static_cast(4123456780LL))); +#if ETL_PLATFORM_64BIT + static_assert(sizeof(size_t) == 8, "size_t is expected to be 64 bit on 64 bit platforms"); + CHECK_EQUAL("18446744073709551615", test_format(s, "{}", static_cast(18446744073709551615ULL))); + CHECK_EQUAL("1311768467463790320", test_format(s, "{}", static_cast(0x123456789ABCDEF0ULL))); +#endif + } + + //************************************************************************* + TEST(test_format_unsigned_long) + { + etl::string<100> s; + + CHECK_EQUAL("0", test_format(s, "{}", static_cast(0LL))); + CHECK_EQUAL("1", test_format(s, "{}", static_cast(1LL))); + CHECK_EQUAL("12345678", test_format(s, "{}", static_cast(12345678LL))); + CHECK_EQUAL("4123456780", test_format(s, "{}", static_cast(4123456780LL))); +#if ETL_PLATFORM_64BIT + static_assert(sizeof(unsigned long) == 8, "size_t is expected to be 64 bit on 64 bit platforms"); + CHECK_EQUAL("18446744073709551615", test_format(s, "{}", static_cast(18446744073709551615ULL))); + CHECK_EQUAL("1311768467463790320", test_format(s, "{}", static_cast(0x123456789ABCDEF0ULL))); +#endif + } + + //************************************************************************* + TEST(test_format_signed_char) + { + etl::string<100> s; + + CHECK_EQUAL("a s b", test_format(s, "a {} b", static_cast('s'))); + CHECK_EQUAL("a s b", test_format(s, "a {:c} b", static_cast('s'))); + CHECK_EQUAL("a 's' b", test_format(s, "a {:?} b", static_cast('s'))); + CHECK_EQUAL("a \t b", test_format(s, "a {} b", static_cast('\t'))); + CHECK_EQUAL("a '\\t' b", test_format(s, "a {:?} b", static_cast('\t'))); + CHECK_EQUAL("a '\\n' b", test_format(s, "a {:?} b", static_cast('\n'))); + CHECK_EQUAL("a '\\r' b", test_format(s, "a {:?} b", static_cast('\r'))); + CHECK_EQUAL("a '\\\"' b", test_format(s, "a {:?} b", static_cast('"'))); + CHECK_EQUAL("a '\\'' b", test_format(s, "a {:?} b", static_cast('\''))); + CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); + CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); + CHECK_EQUAL("a 97 b", test_format(s, "a {:d} b", static_cast('a'))); + CHECK_EQUAL("a 61 b", test_format(s, "a {:X} b", static_cast('a'))); + CHECK_EQUAL("a 61 b", test_format(s, "a {:x} b", static_cast('a'))); + CHECK_EQUAL("a 0x61 b", test_format(s, "a {:#x} b", static_cast('a'))); + } + + //************************************************************************* + TEST(test_format_unsigned_char) + { + etl::string<100> s; + + CHECK_EQUAL("a s b", test_format(s, "a {} b", static_cast('s'))); + CHECK_EQUAL("a s b", test_format(s, "a {:c} b", static_cast('s'))); + CHECK_EQUAL("a 's' b", test_format(s, "a {:?} b", static_cast('s'))); + CHECK_EQUAL("a \t b", test_format(s, "a {} b", static_cast('\t'))); + CHECK_EQUAL("a '\\t' b", test_format(s, "a {:?} b", static_cast('\t'))); + CHECK_EQUAL("a '\\n' b", test_format(s, "a {:?} b", static_cast('\n'))); + CHECK_EQUAL("a '\\r' b", test_format(s, "a {:?} b", static_cast('\r'))); + CHECK_EQUAL("a '\\\"' b", test_format(s, "a {:?} b", static_cast('"'))); + CHECK_EQUAL("a '\\'' b", test_format(s, "a {:?} b", static_cast('\''))); + CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); + CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); + CHECK_EQUAL("a 97 b", test_format(s, "a {:d} b", static_cast('a'))); + CHECK_EQUAL("a 61 b", test_format(s, "a {:X} b", static_cast('a'))); + CHECK_EQUAL("a 61 b", test_format(s, "a {:x} b", static_cast('a'))); + CHECK_EQUAL("a 0x61 b", test_format(s, "a {:#x} b", static_cast('a'))); + } + //************************************************************************* TEST(test_format_limit) { From fe1f19ce4dc6b763b4190049043c204e46e15030 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 8 Feb 2026 10:42:03 +0000 Subject: [PATCH 076/167] Added new type_list features Added make_index_sequence_with_offset --- include/etl/type_list.h | 273 +++++++++++++++++++++++++++++++++++++++- include/etl/utility.h | 17 +++ test/test_type_list.cpp | 119 ++++++++++++++++++ 3 files changed, 404 insertions(+), 5 deletions(-) diff --git a/include/etl/type_list.h b/include/etl/type_list.h index 19eddc15..667e2a06 100644 --- a/include/etl/type_list.h +++ b/include/etl/type_list.h @@ -48,11 +48,14 @@ namespace etl static ETL_CONSTANT size_t type_list_npos = etl::integral_limits::max; //*************************************************************************** - /// Type list forward declaration. + // Type list forward declaration. //*************************************************************************** template struct type_list; + //*************************************************************************** + /// Check if a type is an etl::type_list. + //*************************************************************************** template struct is_type_list : etl::false_type {}; @@ -154,8 +157,8 @@ namespace etl template struct type_list_type_at_index { - ETL_STATIC_ASSERT(Index < type_list_size::value, "etl::type_list_type_at_index out of range"); - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT(Index < type_list_size::value, "etl::type_list_type_at_index out of range"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); using type = typename type_list_type_at_index::type; }; @@ -163,6 +166,8 @@ namespace etl template struct type_list_type_at_index { + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); + using type = typename TTypeList::head; }; @@ -179,7 +184,7 @@ namespace etl (type_list_index_of_type::value == etl::type_list_npos ? etl::type_list_npos : type_list_index_of_type::value + 1)> { - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); }; template @@ -316,7 +321,7 @@ namespace etl template struct type_list_select { - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); using type = type_list...>; }; @@ -324,6 +329,23 @@ namespace etl template using type_list_select_t = typename type_list_select::type; + //*************************************************************************** + /// Declares a new type_list by selecting types from a given type_list, according to an index sequence. + //*************************************************************************** + template + struct type_list_select_from_sequence; + + template + struct type_list_select_from_sequence> + { + using type = etl::type_list_select_t; + }; + +#if ETL_USING_CPP11 + template + using type_list_select_from_sequence_t = typename type_list_select_from_sequence::type; +#endif + //*************************************************************************** /// Concatenates two or more type_lists. //*************************************************************************** @@ -345,6 +367,78 @@ namespace etl template using type_list_cat_t = typename type_list_cat::type; + //*************************************************************************** + /// Prepend a type to a type_list. + //*************************************************************************** + template + struct type_list_prepend; + + template + struct type_list_prepend, T> + { + using type = type_list; + }; + + template + struct type_list_prepend + { + using type = etl::type_list; + }; + + template + using type_list_prepend_t = typename type_list_prepend::type; + + //*************************************************************************** + /// Append a type to a type_list. + //*************************************************************************** + template + struct type_list_append; + + template + struct type_list_append, T> + { + using type = type_list; + }; + + template + struct type_list_append + { + using type = etl::type_list; + }; + + template + using type_list_append_t = typename type_list_append::type; + + //*************************************************************************** + /// Insert a type at an index in a type_list. + /// Inserts before the type currently at Index. + /// If Index == size of the type_list, the type is appended. + //*************************************************************************** + template + struct type_list_insert + { + private: + + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT(Index <= etl::type_list_size::value, "Index out of range"); + + using index_sequence_for_prefix = etl::make_index_sequence; + using index_sequence_for_suffix = etl::make_index_sequence_with_offset::value - Index>; + + using prefix = etl::type_list_select_from_sequence_t; + using suffix = etl::type_list_select_from_sequence_t; + + public: + + // Concatenate the prefix, new type, and suffix to create the new type list with T inserted at the correct position. + using type = etl::type_list_cat_t, suffix>; + }; + +#if ETL_USING_CPP11 + template + using type_list_insert_t = typename etl::type_list_insert::type; +#endif + //*************************************************************************** /// Checks that two type lists are convertible. /// Static asserts if the type lists are not the same length. @@ -373,6 +467,175 @@ namespace etl template inline constexpr bool type_lists_are_convertible_v = etl::type_lists_are_convertible::value; #endif + + namespace private_type_list + { + //********************************* + template class TCompare> + struct type_list_is_sorted_impl; + + //********************************* + // Empty list is sorted + template