From 8dc0301a6747945c263c5c5cfa678eee9f4c5edc Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 8 Apr 2026 17:58:12 +0200 Subject: [PATCH 01/27] Document etl::format_to and etl::print (#1378) * Print test names at test time (#1343) * Document etl::format_to and etl::print --------- Co-authored-by: John Wellbelove --- docs/format.md | 382 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100644 docs/format.md diff --git a/docs/format.md b/docs/format.md new file mode 100644 index 00000000..1f3a5e37 --- /dev/null +++ b/docs/format.md @@ -0,0 +1,382 @@ +# ETL Format & Print + +## 1. Overview + +ETL provides text formatting facilities modelled on C++20 `std::format` and C++23 +`std::print`. They allow type-safe, positional formatting of values into strings +or directly to a character output device — without heap allocation. + +**Minimum language standard:** C++11 (`ETL_USING_CPP11`). + +**Headers:** + +| Header | Provides | +|---|---| +| `etl/format.h` | `etl::format_to`, `etl::format_to_n`, `etl::formatted_size` | +| `etl/print.h` | `etl::print`, `etl::println` (includes `etl/format.h`) | + +## 2. `etl::format_to` + +### Generic output-iterator overload + +```cpp +template +OutputIt format_to(OutputIt out, format_string fmt, Args&&... args); +``` + +Formats `args` according to the format string `fmt` and writes the result through +the output iterator `out`. Returns an iterator past the last character written. + +`OutputIt` can be any output iterator whose dereferenced type is assignable from +`char`, for example `etl::istring::iterator` or +`etl::back_insert_iterator`. + +```cpp +etl::string<100> s; + +// Using a raw iterator — you must resize the string yourself +etl::istring::iterator result = etl::format_to(s.begin(), "{0} {1}", 34, 56); +s.uninitialized_resize(static_cast(result - s.begin())); +// s == "34 56" + +// Using a back_insert_iterator — string grows automatically +s.clear(); +etl::back_insert_iterator it(s); +etl::format_to(it, "{} {}", 65, 34); +// s == "65 34" +``` + +### `etl::istring&` overload (ETL-specific) + +```cpp +template +etl::istring::iterator format_to(etl::istring& out, + format_string fmt, + Args&&... args); +``` + +Convenience overload that writes into an `etl::istring` (or any derived +`etl::string`). The string is automatically resized to the number of +characters written, up to `out.max_size()`. Returns an iterator past the +last character written. + +```cpp +etl::string<100> s; +etl::format_to(s, "Hello, {}!", "world"); +// s == "Hello, world!" +``` + +### `etl::format_to_n` + +```cpp +template +OutputIt format_to_n(OutputIt out, size_t n, + format_string fmt, Args&&... args); +``` + +Like `format_to`, but writes **at most** `n` characters. Characters beyond the +limit are silently discarded. + +```cpp +etl::string<10> s = "abcdefghij"; +etl::format_to_n(s.begin(), 3, "xy{}", 123); +// s == "xy1defghij" (only 3 chars written) +``` + +## 3. `etl::formatted_size` + +```cpp +template +size_t formatted_size(format_string fmt, Args&&... args); +``` + +Returns the total number of characters that `format_to` would produce, without +actually writing anything. Useful for pre-computing buffer sizes. + +```cpp +size_t n; +n = etl::formatted_size(""); // 0 +n = etl::formatted_size("{}", ""); // 0 +n = etl::formatted_size("xyz{}", 12); // 5 +n = etl::formatted_size("{}", "abc"); // 3 +``` + +## 4. `etl::print` and `etl::println` + +Declared in `etl/print.h`. + +### `etl::print` + +```cpp +template +void print(etl::format_string fmt, Args&&... args); +``` + +Formats the arguments and outputs each character by calling `etl_putchar()`. + +### `etl::println` + +```cpp +// With arguments — prints formatted text followed by '\n' +template +void println(etl::format_string fmt, Args&&... args); + +// Without arguments — prints a bare newline +void println(); +``` + +### Implementing `etl_putchar` + +`etl/print.h` declares (but does not define) the following C-linkage function: + +```cpp +extern "C" void etl_putchar(int c); +``` + +You **must** provide a definition in your project. The `int` parameter follows +the convention of the standard `putchar()` and carries a single `char` value. + +Typical implementations forward to a UART, a debug probe, `putchar`, or any +other single-character output sink: + +```cpp +// Example: forward to standard putchar +extern "C" void etl_putchar(int c) +{ + putchar(c); +} +``` + +### Example + +```cpp +etl::print("x = {}, y = {}\n", 10, 20); // "x = 10, y = 20\n" +etl::println("Hello, {}!", "world"); // "Hello, world!\n" +etl::println(); // "\n" +``` + +## 5. Format String Syntax + +A format string is ordinary text with **replacement fields** delimited by braces: + +``` +"literal text {} more text {1:>10} end" +``` + +### Replacement field grammar + +``` +replacement_field ::= '{' [arg_id] [':' format_spec] '}' +arg_id ::= integer // e.g. 0, 1, 2 … +format_spec ::= [[fill]align] [sign] ['#'] ['0'] [width] ['.' precision] ['L'] [type] +``` + +| Component | Syntax | Description | +|---|---|---| +| **Argument index** | `{0}`, `{1}`, … | Manual positional indexing. Cannot be mixed with automatic indexing. | +| **Automatic index** | `{}` | Uses the next argument in order. Cannot be mixed with manual indexing. | +| **Fill character** | any character except `{` or `}` | Used together with an alignment specifier. Default is space (` `). | +| **Alignment** | `<` left, `>` right, `^` center | Aligns the formatted value within the given *width*. | +| **Sign** | `+` always, `-` negative only (default), ` ` space for positive | Controls sign display for numeric types. | +| **`#` (alt form)** | `#` | Adds `0x`/`0X` for hex, `0b`/`0B` for binary, `0` for octal. | +| **`0` (zero-pad)** | `0` | Pads the number with leading zeros (after sign/prefix). | +| **Width** | integer, or `{}` / `{n}` | Minimum field width. Supports nested replacement fields for dynamic width. | +| **Precision** | `.` integer, or `.{}` / `.{n}` | For strings: maximum characters to output. For floats: number of decimal digits. Supports nested replacement fields. | +| **`L`** | `L` | Locale-specific flag (parsed but currently ignored). | +| **Type** | see [Presentation Types](#7-presentation-types-per-argument-kind) | Selects the output representation. | + +### Examples + +```cpp +etl::format_to(s, "{:>10}", 42); // " 42" +etl::format_to(s, "{:*^10}", 42); // "****42****" +etl::format_to(s, "{:+05d}", 67); // "+00067" +etl::format_to(s, "{:#x}", 0x3f4); // "0x3f4" +etl::format_to(s, "{:.3s}", "abcdef"); // "abc" +etl::format_to(s, "{1} {0}", 1, 2); // "2 1" +``` + +## 6. Supported Argument Types + +The core set of formattable types (matching `std::basic_format_arg`): + +| Category | Types | +|---|---| +| Boolean | `bool` | +| Character | `char` | +| Signed integer | `int`, `long long int` | +| Unsigned integer | `unsigned int`, `unsigned long long int` | +| Floating-point *(opt-in)* | `float`, `double`, `long double` — requires `ETL_USING_FORMAT_FLOATING_POINT` | +| String | `const char*`, `etl::string_view` | +| Pointer | `const void*` | + +### Implicit conversions + +Types not listed above are converted automatically before formatting: + +| Source type | Stored as | +|---|---| +| `short` | `int` | +| `unsigned short`, `uint16_t` | `unsigned int` | +| `long int` | `int` or `long long int` (platform-dependent) | +| `unsigned long int`, `size_t` | `unsigned int` or `unsigned long long int` | +| `int8_t` (`signed char`) | `char` | +| `uint8_t` (`unsigned char`) | `char` | +| `int16_t` | `int` | +| `uint32_t` | `unsigned int` | +| `int32_t` | `int` | +| `etl::string` | `etl::string_view` (lifetime of the temporary is guaranteed) | +| any pointer `T*` | `const void*` | + +## 7. Presentation Types per Argument Kind + +### Integers (`int`, `unsigned int`, `long long int`, `unsigned long long int`) + +| Type | Meaning | Example | +|---|---|---| +| `d` *(default)* | Decimal | `134` → `"134"` | +| `x` | Lowercase hexadecimal | `0x3f4` → `"3f4"` | +| `X` | Uppercase hexadecimal | `0x3f4` → `"3F4"` | +| `o` | Octal | `034` → `"34"` | +| `b` | Lowercase binary | `0b1010` → `"1010"` | +| `B` | Uppercase binary | `0b1010` → `"1010"` | +| `c` | Character (value as char) | `67` → `"C"` | + +With `#`: prefixes `0x`/`0X`, `0b`/`0B`, or leading `0` for octal. + +### Characters (`char`, `signed char`, `unsigned char`) + +| Type | Meaning | Example | +|---|---|---| +| `c` *(default)* | Character itself | `'s'` → `"s"` | +| `?` | Debug / escaped | `'\n'` → `"'\\n'"` | +| `d` | Decimal code point | `'a'` → `"97"` | +| `x` / `X` | Hex code point | `'a'` → `"61"` | + +### Booleans (`bool`) + +| Type | Meaning | Example | +|---|---|---| +| *(default)* | `false` / `true` | `true` → `"true"` | +| `s` | Same as default | `true` → `"true"` | +| `d` | `0` / `1` | `true` → `"1"` | +| `x` / `X` | Hex `0` / `1` | `true` → `"1"` | +| `o` | Octal (with `#`: `01`) | `true` → `"01"` | + +### Strings (`const char*`, `etl::string_view`, `etl::string`) + +| Type | Meaning | Example | +|---|---|---| +| `s` *(default)* | String output | `"data1"` → `"data1"` | +| `?` | Debug / escaped | `"data1\n"` → `"\"data1\\n\""` | + +Width and precision apply: width sets the minimum field width; precision (`.N`) +truncates the string to at most *N* characters. + +```cpp +etl::format_to(s, "{:>10s}", "data1"); // " data1" +etl::format_to(s, "{:.3s}", "abcdef"); // "abc" +etl::format_to(s, ".{:^8.3s}!", "data1"); // ". dat !" +``` + +### Pointers (`const void*`) + +| Type | Meaning | Example | +|---|---|---| +| `p` *(default)* | Lowercase hex with `0x` prefix | `nullptr` → `"0x0"` | +| `P` | Uppercase hex with `0X` prefix | `nullptr` → `"0X0"` | + +### Floating-point (`float`, `double`, `long double`) + +Requires `ETL_USING_FORMAT_FLOATING_POINT`. + +| Type | Meaning | Example | +|---|---|---| +| *(default)* | Shortest representation | `1.5f` → `"1.5"` | +| `e` / `E` | Scientific notation | `1.0f` → `"1.000000e+00"` | +| `f` / `F` | Fixed-point notation | `1.125f` → `"1.125000"` | +| `g` / `G` | General (fixed or scientific) | `1e10f` → `"1.000000e+10"` | +| `a` / `A` | Hexadecimal floating-point | `1.5f` → `"0x1.8p+0"` | + +`nan`, `inf` (lowercase for `e`/`f`/`g`/`a`, uppercase for `E`/`F`/`G`/`A`). + +## 8. Escape Sequences and Literal Braces + +### Literal braces + +Because `{` and `}` delimit replacement fields, they must be escaped by +doubling: + +| Input | Output | +|---|---| +| `{{` | `{` | +| `}}` | `}` | + +```cpp +etl::format_to(s, "abc{{def"); // "abc{def" +etl::format_to(s, "}}abc"); // "}abc" +``` + +### Debug / escaped presentation (`?`) + +The `?` type specifier produces a debug representation: + +- **Characters** are wrapped in single quotes with C-style escape sequences: + + | Character | Output | + |---|---| + | `\t` | `'\\t'` | + | `\n` | `'\\n'` | + | `\r` | `'\\r'` | + | `"` | `'\\\"'` | + | `'` | `'\\''` | + | `\\` | `'\\\\'` | + +- **Strings** are wrapped in double quotes with the same escape sequences: + + ```cpp + etl::format_to(s, "{:?}", "data1\n"); // "\"data1\\n\"" + ``` + +## 9. Error Handling + +Invalid format strings cause an `etl::bad_format_string_exception` (derived from +`etl::format_exception`, which is derived from `etl::exception`). + +Common error conditions: + +| Condition | Example | +|---|---| +| Missing closing brace | `"a{b"` | +| Unescaped `}` without matching `{` | `"a}b"` | +| Invalid characters inside `{}` | `"a{b}"` | +| Argument index out of range | `"{1}"` with only one argument | +| Mixing manual and automatic indexing | `"{0} {}"` | +| Invalid type specifier for the argument | `"{:d}"` on a `string_view` | +| Double colon in format spec | `"{::}"` | +| Precision on an integer | `"{:+#05.5X}"` on an `int` | + +```cpp +etl::string<100> s; +// These all throw etl::bad_format_string_exception: +etl::format_to(s, "a{b}", 1); // bad index spec +etl::format_to(s, "a{b", 1); // closing brace missing +etl::format_to(s, "a}b"); // unescaped } +etl::format_to(s, "{:d}", sv); // invalid type for string_view +``` + +> **Note:** On C++20 and later, compile-time format string validation through +> `consteval` is planned but not yet fully implemented. + +## 10. Differences from `std::format` + +| Area | `std::format` (C++20/23) | ETL | +|---|---|---| +| **Output target** | Returns `std::string` | Writes through an output iterator or into `etl::istring&` — no heap allocation. | +| **`etl::istring&` overload** | Not available | `format_to(etl::istring&, ...)` automatically resizes the string. | +| **`print` / `println` output** | Writes to `FILE*` / `stdout` | Writes character-by-character via user-defined `etl_putchar(int)`. | +| **Floating-point support** | Always available | Opt-in via `ETL_USING_FORMAT_FLOATING_POINT`. | +| **User-defined formatters** | `std::formatter` specialisations | Not yet supported. | +| **Locale** | `L` flag uses `std::locale` | `L` flag is parsed but has no effect. | +| **Compile-time validation** | Enforced via `consteval` on C++20 | Planned; currently validates at run time and throws `etl::bad_format_string_exception`. | +| **`format_to_n` return type** | `std::format_to_n_result` | Returns the underlying `OutputIt` directly. | From 7971824914eb58c21868d9cf43c8b019b1c46418 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 9 Apr 2026 07:21:19 +0100 Subject: [PATCH 02/27] Add the ability to specify the callback type to etl closure (#1393) * Print test names at test time (#1343) * Modified closure to accept the callback type as a template parameter * Modified closure to accept the callback type as a template parameter * Applied clang-format * Fixed C++03 compatibility * Fixed C++03 compatibility # Conflicts: # include/etl/closure.h --------- Co-authored-by: Roland Reichwein Co-authored-by: John Wellbelove --- include/etl/closure.h | 170 +++++++------- test/CMakeLists.txt | 7 +- ...=> test_closure_with_default_delegate.cpp} | 2 +- ...osure_with_default_delegate_constexpr.cpp} | 2 +- test/test_closure_with_inplace_function.cpp | 208 ++++++++++++++++++ test/vs2022/etl.vcxproj | 5 +- test/vs2022/etl.vcxproj.filters | 13 +- 7 files changed, 311 insertions(+), 96 deletions(-) rename test/{test_closure.cpp => test_closure_with_default_delegate.cpp} (99%) rename test/{test_closure_constexpr.cpp => test_closure_with_default_delegate_constexpr.cpp} (99%) create mode 100644 test/test_closure_with_inplace_function.cpp diff --git a/include/etl/closure.h b/include/etl/closure.h index 54b0fb36..2c150ec3 100644 --- a/include/etl/closure.h +++ b/include/etl/closure.h @@ -33,53 +33,62 @@ SOFTWARE. #include "platform.h" #include "delegate.h" +#include "invoke.h" #include "tuple.h" #include "type_list.h" #include "utility.h" namespace etl { -#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* /// Base template for closure. + /// \tparam TSignature The callback signature. + /// \tparam TCallback The callback type, defaults to etl::delegate. //************************************************************************* - template + template > class closure; +#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* - /// Closure for binding arguments to a delegate and invoking it later. - /// Stores a delegate and its arguments, allowing deferred execution. + /// Closure for binding arguments to a callback and invoking it later. + /// Stores a callback and its arguments, allowing deferred execution. /// Arguments are stored in a tuple and can be rebound using bind(). /// Example usage: /// \code /// etl::closure c(my_delegate, 1, 2); /// c(); // Invokes my_delegate(1, 2) /// \endcode - /// \tparam TReturn The return type of the delegate. - /// \tparam TArgs The argument types of the delegate. + /// \tparam TReturn The return type of the callback. + /// \tparam TArgs The argument types of the callback. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - using delegate_type = etl::delegate; ///< The delegate type to be invoked. - using argument_types = etl::type_list; ///< The type list of arguments. + ETL_DEPRECATED_REASON("Use callback_type") using delegate_type = + TCallback; ///< The callback type to be invoked. Deprecated, use callback_type instead. + using callback_type = TCallback; ///< The callback type to be invoked. + using argument_types = etl::type_list; ///< The type list of arguments. + + static_assert(etl::is_invocable_r::value, "Callback is not invocable with the specified arguments"); + static_assert(etl::is_copy_constructible::value, "Callback type must be copy constructible"); //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. - /// \param args The arguments to bind to the delegate. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. + /// \param args The arguments to bind to the callback. //********************************************************************* - ETL_CONSTEXPR14 closure(const delegate_type& f, const TArgs... args) + ETL_CONSTEXPR14 closure(const callback_type& f, const TArgs... args) : m_f(f) , m_args(args...) { } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* ETL_CONSTEXPR14 TReturn operator()() const { @@ -131,7 +140,7 @@ namespace etl //********************************************************************* /// Execute the closure with the stored arguments. /// \tparam idx Index sequence for tuple unpacking. - /// \return The result of the delegate invocation. + /// \return The result of the callback invocation. //********************************************************************* template ETL_CONSTEXPR14 TReturn execute(etl::index_sequence) const @@ -139,43 +148,38 @@ namespace etl return m_f(etl::get(m_args)...); } - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. etl::tuple m_args; ///< The bound arguments. }; #else //************************************************************************* - /// Base template for closure. - //************************************************************************* - template - class closure; - - //************************************************************************* - /// Closure for binding one argument to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding one argument to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - /// The delegate type to be invoked. - typedef etl::delegate delegate_type; + /// The callback type to be invoked. + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its argument. - /// \param f The delegate to be invoked. - /// \param arg0 The argument to bind to the delegate. + /// Construct a closure with a callback and its argument. + /// \param f The callback to be invoked. + /// \param arg0 The argument to bind to the callback. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0) + closure(const callback_type& f, const TArg0 arg0) : m_f(f) , m_arg0(arg0) { } //********************************************************************* - /// Invoke the stored delegate with the bound argument. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound argument. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -184,30 +188,31 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; }; //************************************************************************* - /// Closure for binding two arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding two arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -215,8 +220,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -225,33 +230,34 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; }; //************************************************************************* - /// Closure for binding three arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding three arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -260,8 +266,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -270,36 +276,37 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; }; //************************************************************************* - /// Closure for binding four arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding four arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. /// \tparam TArg3 The type of the fourth argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. /// \param arg3 The fourth argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -309,8 +316,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -319,7 +326,7 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; @@ -327,31 +334,32 @@ namespace etl }; //************************************************************************* - /// Closure for binding five arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding five arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. /// \tparam TArg3 The type of the fourth argument. /// \tparam TArg4 The type of the fifth argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. /// \param arg3 The fourth argument to bind. /// \param arg4 The fifth argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3, const TArg4 arg4) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3, const TArg4 arg4) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -362,8 +370,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -372,7 +380,7 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a559add4..9f325bb9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -83,8 +83,9 @@ add_executable(etl_tests test_circular_buffer.cpp test_circular_buffer_external_buffer.cpp test_circular_iterator.cpp - test_closure.cpp - test_closure_constexpr.cpp + test_closure_with_default_delegate.cpp + test_closure_with_default_delegate_constexpr.cpp + test_closure_with_inplace_function.cpp test_compare.cpp test_concepts.cpp test_constant.cpp @@ -523,7 +524,7 @@ if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Cla target_link_options(etl_tests PRIVATE -fsanitize=address,undefined,bounds - ) + ) endif() endif () endif () diff --git a/test/test_closure.cpp b/test/test_closure_with_default_delegate.cpp similarity index 99% rename from test/test_closure.cpp rename to test/test_closure_with_default_delegate.cpp index 3e01ca8b..a7ef4f35 100644 --- a/test/test_closure.cpp +++ b/test/test_closure_with_default_delegate.cpp @@ -34,7 +34,7 @@ SOFTWARE. namespace { - SUITE(test_closure) + SUITE(test_closure_with_default_delegate) { int f1(int a1) { diff --git a/test/test_closure_constexpr.cpp b/test/test_closure_with_default_delegate_constexpr.cpp similarity index 99% rename from test/test_closure_constexpr.cpp rename to test/test_closure_with_default_delegate_constexpr.cpp index 73c4b68c..57dcc18d 100644 --- a/test/test_closure_constexpr.cpp +++ b/test/test_closure_with_default_delegate_constexpr.cpp @@ -34,7 +34,7 @@ SOFTWARE. namespace { - SUITE(test_closure) + SUITE(test_closure_with_default_delegate_constexpr) { static constexpr int f1(int a1) { diff --git a/test/test_closure_with_inplace_function.cpp b/test/test_closure_with_inplace_function.cpp new file mode 100644 index 00000000..cd67ffba --- /dev/null +++ b/test/test_closure_with_inplace_function.cpp @@ -0,0 +1,208 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 BMW AG, 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/closure.h" +#include "etl/inplace_function.h" + +#include + +namespace +{ + SUITE(test_closure_with_inplace_function) + { + int f1(int a1) + { + return a1 * 3; + } + + int f1_throwing(int) + { + throw std::runtime_error("throwing function"); + } + + void f1_void(int) {} + + int f1_ref(int& a1) + { + return a1 * 3; + } + + int f2(int a1, int a2) + { + return a1 * 3 + a2; + } + + int f3(int a1, int a2, int a3) + { + return a1 * 3 + a2 * a3; + } + + int f4(int a1, int a2, int a3, int a4) + { + return a1 * 3 + a2 * a3 + a4; + } + + int f5(int a1, int a2, int a3, int a4, int a5) + { + return a1 * 3 + a2 * a3 + a4 * a5; + } + + using f1_type = int(int); + using f1_ref_type = int(int&); + using f1_void_type = void(int); + using f2_type = int(int, int); + using f3_type = int(int, int, int); + using f4_type = int(int, int, int, int); + using f5_type = int(int, int, int, int, int); + + using ipf1_type = etl::inplace_function; + using ipf1_ref_type = etl::inplace_function; + using ipf1_void_type = etl::inplace_function; + using ipf2_type = etl::inplace_function; + using ipf3_type = etl::inplace_function; + using ipf4_type = etl::inplace_function; + using ipf5_type = etl::inplace_function; + + ipf1_type ipf1 = ipf1_type::create<&f1>(); + ipf1_type ipf1_throwing = ipf1_type::create<&f1_throwing>(); + ipf1_ref_type ipf1_ref = ipf1_ref_type::create<&f1_ref>(); + ipf1_void_type ipf1_void = ipf1_void_type::create<&f1_void>(); + ipf2_type ipf2 = ipf2_type::create<&f2>(); + ipf3_type ipf3 = ipf3_type::create<&f3>(); + ipf4_type ipf4 = ipf4_type::create<&f4>(); + ipf5_type ipf5 = ipf5_type::create<&f5>(); + + //************************************************************************* + TEST(test_1_arg) + { + etl::closure c1(ipf1, 4); + CHECK_EQUAL(12, c1()); + } + + //************************************************************************* + TEST(test_1_arg_reference) + { + int v1 = 4; + etl::closure c1_ref(ipf1_ref, v1); + CHECK_EQUAL(12, c1_ref()); + v1 = 5; + CHECK_EQUAL(15, c1_ref()); + } + + //************************************************************************* + TEST(test_1_arg_lambda) + { + auto l = [](int a) + { + return a + 11; + }; + ipf1_type ipf1_lambda(l); + + etl::closure c1_lambda(ipf1_lambda, 5); + CHECK_EQUAL(16, c1_lambda()); + } + + //************************************************************************* + TEST(test_throwing) + { + etl::closure c1(ipf1_throwing, 4); + CHECK_THROW(c1(), std::runtime_error); + } + + //************************************************************************* + TEST(test_void) + { + etl::closure c1(ipf1_void, 4); + c1(); + } + + //************************************************************************* + TEST(test_2_args) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + } + +#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + TEST(test_2_args_bind) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + + c2.bind<0>(7); + c2.bind<1>(8); + CHECK_EQUAL(29, c2()); + } + + //************************************************************************* + TEST(test_2_args_bind_all) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + + c2.bind(7, 8); + CHECK_EQUAL(29, c2()); + } +#endif + + //************************************************************************* + TEST(test_3_args) + { + etl::closure c3(ipf3, 4, 3, 2); + CHECK_EQUAL(18, c3()); + } + + //************************************************************************* + TEST(test_4_args) + { + etl::closure c4(ipf4, 4, 3, 2, 1); + CHECK_EQUAL(19, c4()); + } + + //************************************************************************* + TEST(test_5_args) + { + etl::closure c5(ipf5, 4, 3, 2, 1, 5); + CHECK_EQUAL(23, c5()); + } + + //************************************************************************* + TEST(test_bind_static_assert) + { + etl::closure c(ipf2, 1, 2); + + // Uncomment to generate static_assert errors. + // c.bind(1); // Argument count mismatch + // c.bind(1, 2, 3); // Argument count mismatch + // c.bind(1, std::string()); // Argument is not convertible + } + } +} // namespace diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 93ea62c4..0e0b6601 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -10273,8 +10273,9 @@ - - + + + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 4921e669..8553316d 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3647,7 +3647,7 @@ Tests\Chrono - + Tests\Callbacks & Delegates @@ -3704,7 +3704,7 @@ Tests\CRC - + Tests\Callbacks & Delegates @@ -3800,6 +3800,9 @@ Tests\Strings + + Tests\Callbacks & Delegates + @@ -3979,12 +3982,6 @@ Resource Files\CI\Github - - Documentation - - - Documentation - From ae6ca929c1d1936dd3d8127cd66e7c75988f51d0 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 11 Apr 2026 10:10:17 +0200 Subject: [PATCH 03/27] Rename _current to _current_it in ranges.h (#1387) * Print test names at test time (#1343) * Rename _current to _current_it in ranges.h Resolves conflict with _current macro from Zephyr and improves self-explanation of variable. --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/ranges.h | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/etl/ranges.h b/include/etl/ranges.h index fe62e06d..b46e92af 100644 --- a/include/etl/ranges.h +++ b/include/etl/ranges.h @@ -2960,7 +2960,7 @@ namespace etl iterator() = default; iterator(const_iterator_type current, const_iterator_type segment_end, bool is_end) - : _current(current) + : _current_it(current) , _segment_end(segment_end) , _is_end(is_end || (current == segment_end)) { @@ -2968,18 +2968,18 @@ namespace etl reference operator*() const { - return *_current; + return *_current_it; } pointer operator->() const { - return &(*_current); + return &(*_current_it); } iterator& operator++() { - ++_current; - if (_current == _segment_end) + ++_current_it; + if (_current_it == _segment_end) { _is_end = true; } @@ -3003,7 +3003,7 @@ namespace etl { return false; } - return _current == other._current; + return _current_it == other._current_it; } constexpr bool operator!=(const iterator& other) const @@ -3013,7 +3013,7 @@ namespace etl private: - const_iterator_type _current{}; + const_iterator_type _current_it{}; const_iterator_type _segment_end{}; bool _is_end = true; }; @@ -3364,7 +3364,7 @@ namespace etl concat_iterator(size_t index, concat_view& view, iterator_variant_type current) : _ranges_index{index} , _view(view) - , _current(current) + , _current_it(current) { } @@ -3372,7 +3372,7 @@ namespace etl constexpr reference operator*() const { - return _view.get_value(_ranges_index, _current); + return _view.get_value(_ranges_index, _current_it); } constexpr decltype(auto) operator[](difference_type pos) const @@ -3382,14 +3382,14 @@ namespace etl { for (difference_type i = 0; i < pos; ++i) { - tmp._view.advance(tmp._ranges_index, tmp._current, 1); + tmp._view.advance(tmp._ranges_index, tmp._current_it, 1); } } if (pos < 0) { for (difference_type i = 0; i < -pos; ++i) { - tmp._view.advance(tmp._ranges_index, tmp._current, -1); + tmp._view.advance(tmp._ranges_index, tmp._current_it, -1); } } return *tmp; @@ -3397,27 +3397,27 @@ namespace etl constexpr concat_iterator& operator++() { - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); return *this; } constexpr concat_iterator operator++(int) { auto result = *this; - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); return result; } constexpr concat_iterator& operator--() { - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); return *this; } constexpr concat_iterator operator--(int) { auto result = *this; - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); return result; } @@ -3425,7 +3425,7 @@ namespace etl { for (difference_type i = 0; i < n; ++i) { - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); } return *this; } @@ -3434,7 +3434,7 @@ namespace etl { for (difference_type i = 0; i < n; ++i) { - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); } return *this; } @@ -3442,12 +3442,12 @@ namespace etl friend constexpr bool operator==(const concat_iterator& x, etl::default_sentinel_t) { return x._ranges_index == x._view.number_of_ranges - 1 - && etl::get(x._current) == etl::get(x._view).end(); + && etl::get(x._current_it) == etl::get(x._view).end(); } friend constexpr bool operator==(const concat_iterator& x, const concat_iterator& y) { - return x._ranges_index == y._ranges_index && x._current.index() == y._current.index() && x._current == y._current; + return x._ranges_index == y._ranges_index && x._current_it.index() == y._current_it.index() && x._current_it == y._current_it; } friend constexpr bool operator!=(const concat_iterator& x, etl::default_sentinel_t) @@ -3464,7 +3464,7 @@ namespace etl size_t _ranges_index; const concat_view& _view; - iterator_variant_type _current; + iterator_variant_type _current_it; }; template @@ -5731,7 +5731,7 @@ namespace etl using iterator_category = ETL_OR_STD::forward_iterator_tag; constexpr cartesian_product_iterator(iterators_type current, iterators_type begins, iterators_type ends, bool is_end = false) - : _current(current) + : _current_it(current) , _begins(begins) , _ends(ends) , _is_end(is_end) @@ -5784,7 +5784,7 @@ namespace etl template constexpr etl::enable_if_t<(I > 0)> increment_at() { - auto& it = etl::get(_current); + auto& it = etl::get(_current_it); ++it; if (it == etl::get(_ends)) { @@ -5796,7 +5796,7 @@ namespace etl template constexpr etl::enable_if_t<(I == 0)> increment_at() { - auto& it = etl::get<0>(_current); + auto& it = etl::get<0>(_current_it); ++it; if (it == etl::get<0>(_ends)) { @@ -5807,16 +5807,16 @@ namespace etl template constexpr value_type deref(etl::index_sequence) const { - return value_type(*etl::get(_current)...); + return value_type(*etl::get(_current_it)...); } template constexpr bool all_equal(const cartesian_product_iterator& other, etl::index_sequence) const { - return ((etl::get(_current) == etl::get(other._current)) && ...); + return ((etl::get(_current_it) == etl::get(other._current_it)) && ...); } - iterators_type _current; + iterators_type _current_it; iterators_type _begins; iterators_type _ends; bool _is_end; From f118c2807afcfdc31d2e95a35624070a8afe1faf Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 11 Apr 2026 10:16:03 +0200 Subject: [PATCH 04/27] Fix broken syntax from clang-format reformat (#1385) * Print test names at test time (#1343) * Fix broken syntax from clang-format reformat --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/doxygen.h | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/include/etl/doxygen.h b/include/etl/doxygen.h index f9adce19..0251f1b6 100644 --- a/include/etl/doxygen.h +++ b/include/etl/doxygen.h @@ -27,31 +27,29 @@ SOFTWARE. ******************************************************************************/ ///\defgroup etl Embedded Template Library. -https - : // github.com/ETLCPP/etl - http - : // www.etlcpp.com +/// https://github.com/ETLCPP/etl +/// http://www.etlcpp.com - ///\defgroup containers Containers - ///\ingroup etl +///\defgroup containers Containers +///\ingroup etl - ///\defgroup utilities Utilities - /// A set of utility templates. - ///\ingroup etl +///\defgroup utilities Utilities +/// A set of utility templates. +///\ingroup etl - ///\defgroup maths Maths - /// A set of mathematical templates. - ///\ingroup etl +///\defgroup maths Maths +/// A set of mathematical templates. +///\ingroup etl - ///\defgroup patterns Patterns - /// A set of templated design patterns. - ///\ingroup etl +///\defgroup patterns Patterns +/// A set of templated design patterns. +///\ingroup etl - ///\defgroup crc CRC - /// A set of CRC calculations - ///\ingroup maths +///\defgroup crc CRC +/// A set of CRC calculations +///\ingroup maths - ///\ingroup etl - namespace etl +///\ingroup etl +namespace etl { } From beeb4cf462b748cb890fd4b9abff75bb0a981ede Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 11 Apr 2026 10:38:39 +0200 Subject: [PATCH 05/27] Fix coverage workflow for action version (#1384) * Print test names at test time (#1343) * Fix coverage workflow for action version --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- .github/workflows/coverage.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 79f9553e..5c05ebef 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -65,8 +65,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 - -# GitHub Repository settings -# -> Settings -> Pages -# -> Source: gh actions + uses: actions/deploy-pages@v5 From b14f70698f5ff309bfc49e25f96fd95beaaf0320 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 14 Apr 2026 11:48:03 +0200 Subject: [PATCH 06/27] Fix chrono.h year_month_weekday_last and year_month_weekday sysdays() (#1396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Print test names at test time (#1343) * Fix chrono.h year_month_weekday_last and year_month_weekday sysdays() Bug 1: year_month_weekday_last::operator sys_days() — wrong weekday construction The code was constructing a weekday from a raw day count using weekday(unsigned), which treats the value as a weekday encoding (0–6). The fix uses weekday(sys_days), which correctly accounts for the epoch being a Thursday (+4 offset). Bug 2: year_month_weekday::operator sys_days() — same wrong weekday construction + off-by-one in day_of_month Same weekday(unsigned) vs weekday(sys_days) issue. Additionally, the day_of_month calculation was missing the 1 + base — it computed a 0-based offset from day 1, but forgot to add the 1 back when converting to an actual day number. --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- .../etl/private/chrono/year_month_weekday.h | 6 ++--- test/test_chrono_year_month_weekday.cpp | 26 ++++++++++++++++--- test/test_chrono_year_month_weekday_last.cpp | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/etl/private/chrono/year_month_weekday.h b/include/etl/private/chrono/year_month_weekday.h index c557138a..8d7f4d52 100644 --- a/include/etl/private/chrono/year_month_weekday.h +++ b/include/etl/private/chrono/year_month_weekday.h @@ -174,11 +174,11 @@ namespace etl unsigned int target_wd = ymwd.weekday().c_encoding(); unsigned int target_index = ymwd.index(); - etl::chrono::weekday first_weekday(static_cast(sd.time_since_epoch().count())); + etl::chrono::weekday first_weekday(sd); unsigned int first_wd = first_weekday.c_encoding(); unsigned int offset = (target_wd - first_wd + 7U) % 7U; - unsigned int day_of_month = offset + (target_index - 1U) * 7U; + unsigned int day_of_month = 1U + offset + (target_index - 1U) * 7U; etl::chrono::year_month_day result(year(), month(), etl::chrono::day(day_of_month)); @@ -382,7 +382,7 @@ namespace etl { etl::chrono::year_month_day ymd(year(), month(), etl::chrono::day(d)); etl::chrono::sys_days ymd_sys_days = static_cast(ymd); - etl::chrono::weekday wd(static_cast(ymd_sys_days.time_since_epoch().count())); + etl::chrono::weekday wd(ymd_sys_days); if (wd == weekday()) { diff --git a/test/test_chrono_year_month_weekday.cpp b/test/test_chrono_year_month_weekday.cpp index 8079d813..f0ab8500 100644 --- a/test/test_chrono_year_month_weekday.cpp +++ b/test/test_chrono_year_month_weekday.cpp @@ -117,10 +117,30 @@ namespace //************************************************************************* TEST(test_to_sys_days) { - Chrono::year_month_weekday ymwd{Chrono::year(2000), Chrono::February, Chrono::weekday_indexed(Chrono::Thursday, 1)}; - Chrono::sys_days sd = Chrono::sys_days(ymwd); + // 1st Thursday of February 2000 (Feb 3) + Chrono::year_month_weekday ymwd1{Chrono::year(2000), Chrono::February, Chrono::weekday_indexed(Chrono::Thursday, 1)}; + Chrono::sys_days sd1 = Chrono::sys_days(ymwd1); + CHECK_EQUAL(10990, sd1.time_since_epoch().count()); - CHECK_EQUAL(10990, sd.time_since_epoch().count()); + // 2nd Wednesday of March 2000 (Mar 8) + Chrono::year_month_weekday ymwd2{Chrono::year(2000), Chrono::March, Chrono::weekday_indexed(Chrono::Wednesday, 2)}; + Chrono::sys_days sd2 = Chrono::sys_days(ymwd2); + CHECK_EQUAL(11024, sd2.time_since_epoch().count()); + + // 1st Sunday of January 2000 (Jan 2) + Chrono::year_month_weekday ymwd3{Chrono::year(2000), Chrono::January, Chrono::weekday_indexed(Chrono::Sunday, 1)}; + Chrono::sys_days sd3 = Chrono::sys_days(ymwd3); + CHECK_EQUAL(10958, sd3.time_since_epoch().count()); + + // 3rd Friday of June 1985 (Jun 21) + Chrono::year_month_weekday ymwd4{Chrono::year(1985), Chrono::June, Chrono::weekday_indexed(Chrono::Friday, 3)}; + Chrono::sys_days sd4 = Chrono::sys_days(ymwd4); + CHECK_EQUAL(5650, sd4.time_since_epoch().count()); + + // 2nd Wednesday of March 2024 (Mar 13) + Chrono::year_month_weekday ymwd5{Chrono::year(2024), Chrono::March, Chrono::weekday_indexed(Chrono::Wednesday, 2)}; + Chrono::sys_days sd5 = Chrono::sys_days(ymwd5); + CHECK_EQUAL(19795, sd5.time_since_epoch().count()); } //************************************************************************* diff --git a/test/test_chrono_year_month_weekday_last.cpp b/test/test_chrono_year_month_weekday_last.cpp index 7050903f..bbe92619 100644 --- a/test/test_chrono_year_month_weekday_last.cpp +++ b/test/test_chrono_year_month_weekday_last.cpp @@ -73,7 +73,7 @@ namespace Chrono::year_month_weekday_last ymwdl{Chrono::year(2000), Chrono::February, Chrono::weekday_last(Chrono::Thursday)}; Chrono::sys_days sd = Chrono::sys_days(ymwdl); - CHECK_EQUAL(11012, sd.time_since_epoch().count()); + CHECK_EQUAL(11011, sd.time_since_epoch().count()); } //************************************************************************* From f258fe4af8672d50baece68288f827f60d653514 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 14 Apr 2026 11:56:05 +0200 Subject: [PATCH 07/27] Fix operator| conflict with std::ranges (#1395) --- include/etl/ranges.h | 48 ++++++++++++++++++++++++++------------------ test/test_ranges.cpp | 8 ++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/include/etl/ranges.h b/include/etl/ranges.h index b46e92af..8e875b83 100644 --- a/include/etl/ranges.h +++ b/include/etl/ranges.h @@ -735,8 +735,23 @@ namespace etl inline constexpr private_views::repeat repeat; } // namespace views - template - class range_adapter_closure + // Non-template base so ADL finds exactly one operator| definition. + class range_adapter_closure_base + { + // Found via ADL on the RHS (any type that derives from + // range_adapter_closure_base). Placing the operator here instead of at + // global/namespace scope avoids conflicts with std::ranges::operator|. + template > + && etl::is_invocable_v, Range>>> + friend auto operator|(Range&& r, Closure&& c) + { + return etl::forward(c)(etl::forward(r)); + } + }; + + template + class range_adapter_closure : public range_adapter_closure_base { }; @@ -932,7 +947,7 @@ namespace etl { namespace private_views { - struct all + struct all : public range_adapter_closure_base { template < class Range, etl::enable_if_t>, etl::decay_t>, int> = 0> @@ -1422,7 +1437,7 @@ namespace etl { namespace private_views { - struct as_rvalue + struct as_rvalue : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -1501,7 +1516,7 @@ namespace etl { namespace private_views { - struct as_const + struct as_const : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -1726,7 +1741,7 @@ namespace etl { namespace private_views { - struct cache_latest + struct cache_latest : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -1802,7 +1817,7 @@ namespace etl { namespace private_views { - struct reverse + struct reverse : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -2397,7 +2412,7 @@ namespace etl { namespace private_views { - struct join + struct join : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -4244,7 +4259,7 @@ namespace etl { namespace private_views { - struct common + struct common : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -4404,7 +4419,7 @@ namespace etl { namespace private_views { - struct enumerate + struct enumerate : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -4569,7 +4584,7 @@ namespace etl namespace private_views { template - struct elements_fn + struct elements_fn : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -4797,7 +4812,7 @@ namespace etl namespace private_views { template - struct adjacent_fn + struct adjacent_fn : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -6064,7 +6079,7 @@ namespace etl { namespace private_views { - struct to_input + struct to_input : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const @@ -6152,13 +6167,6 @@ namespace etl namespace views = ranges::views; } // namespace etl -template < class Range, typename RangeAdaptorClosure, typename = etl::enable_if_t>> - -auto operator|(Range&& r, RangeAdaptorClosure rac) -{ - return rac(etl::forward(r)); -} - #endif #endif diff --git a/test/test_ranges.cpp b/test/test_ranges.cpp index fff3d9bc..0fe4c41b 100644 --- a/test/test_ranges.cpp +++ b/test/test_ranges.cpp @@ -37,6 +37,14 @@ SOFTWARE. #include #include +// Issue #1391: include when available to verify etl::operator| +// does not conflict with std::ranges::operator|. +#if ETL_USING_STL && ETL_USING_CPP20 && defined(__has_include) + #if __has_include() + #include + #endif +#endif + #if ETL_USING_CPP17 // C++03 does not support move semantics as used in the ranges library From 29d0cfec7cdc14481a9cced4bcf7dc661398af55 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 14 Apr 2026 12:38:59 +0200 Subject: [PATCH 08/27] Suppress false positive compiler warnings when compiling with -O3 (#1389) * Print test names at test time (#1343) * Suppress false positive compiler warnings when compiling with -O3 The CI checks currently only check everything with -O0. Wenn activating higher optimization levels, more warnings kick in. Leading to errors, depending on the configuration. --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/algorithm.h | 18 ++++++++++++++++++ include/etl/priority_queue.h | 2 ++ test/test_algorithm.cpp | 4 ++++ test/test_forward_list.cpp | 2 ++ test/test_forward_list_shared_pool.cpp | 2 ++ test/test_intrusive_forward_list.cpp | 2 ++ test/test_intrusive_list.cpp | 2 ++ test/test_multiset.cpp | 6 ++---- test/test_ranges.cpp | 2 ++ test/test_set.cpp | 4 ++-- 10 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 63bfe13b..162deaf9 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -898,6 +898,7 @@ namespace etl { TDistance parent = (value_index - 1) / 2; +#include "etl/private/diagnostic_array_bounds_push.h" while ((value_index > top_index) && compare(first[parent], value)) { first[value_index] = ETL_MOVE(first[parent]); @@ -906,6 +907,7 @@ namespace etl } first[value_index] = ETL_MOVE(value); +#include "etl/private/diagnostic_pop.h" } // Adjust Heap Helper @@ -1358,7 +1360,9 @@ namespace etl value_type temp(ETL_MOVE(*first)); // Move the rest. +#include "etl/private/diagnostic_stringop_overread_push.h" TIterator result = etl::move(etl::next(first), last, first); +#include "etl/private/diagnostic_pop.h" // Restore the first item in its rotated position. *result = ETL_MOVE(temp); @@ -2786,7 +2790,9 @@ namespace etl d_size_type d_size = etl::distance(o_begin, o_end); min_size_type min_size = etl::min(s_size, d_size); + #include "etl/private/diagnostic_null_dereference_push.h" return etl::move(i_begin, i_begin + min_size, o_begin); + #include "etl/private/diagnostic_pop.h" } //*************************************************************************** @@ -5860,12 +5866,14 @@ namespace etl } } + #include "etl/private/diagnostic_array_bounds_push.h" // Sort the heap to produce a sorted output range for (auto heap_end = heap_size - 1; heap_end > 0; --heap_end) { etl::iter_swap(result_first, result_first + heap_end); sift_down(result_first, decltype(heap_size){0}, heap_end, comp, proj2); } + #include "etl/private/diagnostic_pop.h" return {etl::move(in_last), etl::move(r)}; } @@ -6202,6 +6210,16 @@ namespace etl I left_partition = stable_partition_impl(first, middle, etl::ref(pred), etl::ref(proj), len / 2); I right_partition = stable_partition_impl(middle, last, etl::ref(pred), etl::ref(proj), len - len / 2); + if (left_partition == middle) + { + return right_partition; + } + + if (middle == right_partition) + { + return left_partition; + } + return etl::rotate(left_partition, middle, right_partition); } }; diff --git a/include/etl/priority_queue.h b/include/etl/priority_queue.h index e72d4908..2623fc07 100644 --- a/include/etl/priority_queue.h +++ b/include/etl/priority_queue.h @@ -439,7 +439,9 @@ namespace etl //************************************************************************* void clone(const ipriority_queue& other) { +#include "etl/private/diagnostic_uninitialized_push.h" assign(other.container.cbegin(), other.container.cend()); +#include "etl/private/diagnostic_pop.h" } #if ETL_USING_CPP11 diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index fa0f4f0e..abc5f734 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -2621,8 +2621,10 @@ namespace for (size_t i = 0UL; i <= initial_data.size(); ++i) { +#include "etl/private/diagnostic_null_dereference_push.h" std::vector data1(initial_data); std::vector data2(initial_data); +#include "etl/private/diagnostic_pop.h" auto std_result = std::rotate(data1.data(), data1.data() + i, data1.data() + data1.size()); auto etl_result = etl::rotate(data2.data(), data2.data() + i, data2.data() + data2.size()); @@ -2658,8 +2660,10 @@ namespace for (size_t i = 0UL; i <= initial_data.size(); ++i) { +#include "etl/private/diagnostic_null_dereference_push.h" std::vector data1(initial_data); std::vector data2(initial_data); +#include "etl/private/diagnostic_pop.h" auto std_result = std::rotate(data1.data(), data1.data() + i, data1.data() + data1.size()); diff --git a/test/test_forward_list.cpp b/test/test_forward_list.cpp index 08337c28..02d928de 100644 --- a/test/test_forward_list.cpp +++ b/test/test_forward_list.cpp @@ -42,6 +42,7 @@ SOFTWARE. namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_forward_list) { const size_t SIZE = 10UL; @@ -1444,4 +1445,5 @@ namespace } #endif } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_forward_list_shared_pool.cpp b/test/test_forward_list_shared_pool.cpp index 701bfe44..996efe7a 100644 --- a/test/test_forward_list_shared_pool.cpp +++ b/test/test_forward_list_shared_pool.cpp @@ -42,6 +42,7 @@ SOFTWARE. namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_forward_list) { const size_t SIZE = 20UL; @@ -1929,4 +1930,5 @@ namespace CHECK(data3 > data1); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index 33002fd7..5be470bc 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -129,6 +129,7 @@ namespace namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_intrusive_forward_list) { InitialDataNDC stable_sort_data; @@ -1379,4 +1380,5 @@ namespace CHECK_FALSE(data0.contains(compare_node2)); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_intrusive_list.cpp b/test/test_intrusive_list.cpp index 0c352b5d..4b2f6f85 100644 --- a/test/test_intrusive_list.cpp +++ b/test/test_intrusive_list.cpp @@ -142,6 +142,7 @@ namespace namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_intrusive_list) { InitialDataNDC stable_sort_data; @@ -1648,4 +1649,5 @@ namespace CHECK_FALSE(data0.contains(compare_node2)); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_multiset.cpp b/test/test_multiset.cpp index c040e8ac..6cf29f87 100644 --- a/test/test_multiset.cpp +++ b/test/test_multiset.cpp @@ -98,10 +98,10 @@ namespace return (lhs < rhs.k); } +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_multiset) { //************************************************************************* -#include "etl/private/diagnostic_null_dereference_push.h" template bool Check_Equal(T1 begin1, T1 end1, T2 begin2) { @@ -118,7 +118,6 @@ namespace return true; } -#include "etl/private/diagnostic_pop.h" //************************************************************************* struct SetupFixture @@ -1515,7 +1514,6 @@ namespace for (pos = data.crbegin(); pos != data.crend(); ++pos) { -#include "etl/private/diagnostic_null_dereference_push.h" if (*pos > prv) { pass = false; @@ -1523,7 +1521,6 @@ namespace } prv = *pos; -#include "etl/private/diagnostic_pop.h" } CHECK(pass); @@ -1630,4 +1627,5 @@ namespace } while (std::next_permutation(permutation.begin(), permutation.end())); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_ranges.cpp b/test/test_ranges.cpp index 0fe4c41b..01b20c95 100644 --- a/test/test_ranges.cpp +++ b/test/test_ranges.cpp @@ -157,6 +157,7 @@ namespace std namespace { + #include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_ranges) { //************************************************************************* @@ -5740,6 +5741,7 @@ namespace CHECK_EQUAL(30, v_out[2]); } } + #include "etl/private/diagnostic_pop.h" } // namespace #endif diff --git a/test/test_set.cpp b/test/test_set.cpp index f8f56d50..0fe643bf 100644 --- a/test/test_set.cpp +++ b/test/test_set.cpp @@ -103,10 +103,10 @@ namespace // return (lhs.k < rhs.k); // } +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_set) { //************************************************************************* -#include "etl/private/diagnostic_null_dereference_push.h" template bool Check_Equal(T1 begin1, T1 end1, T2 begin2) { @@ -123,7 +123,6 @@ namespace return true; } -#include "etl/private/diagnostic_pop.h" //************************************************************************* struct SetupFixture @@ -1443,4 +1442,5 @@ namespace } while (std::next_permutation(permutation.begin(), permutation.end())); } } +#include "etl/private/diagnostic_pop.h" } // namespace From 17799452d26f4dd534974aac54c5e441896becb1 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 15 Apr 2026 10:09:28 +0200 Subject: [PATCH 09/27] Add missing syntax checks (#1381) * Fix run-syntax-checks.sh to run with bash Contains bash specific syntax, and sync with the other *.sh files in this directory. * Add missing header file adaptors to the directory and CMakeLists.txt * run-syntax-checks.sh without ETL_IN_UNIT_TEST * Fix usage of make_unsigned * Removing crc.h from syntax checks because of redundancy * Remove ETL_USING_CPP11 from unit tests Unit tests are always run with at least C++11. * Add missing copyright header in test_manchester.cpp * Fixed usage of ETL_DEPRECATED_REASON(), wrong syntax by order --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/chrono.h | 4 - include/etl/closure.h | 2 +- include/etl/concepts.h | 4 - include/etl/const_map.h | 27 ++++--- include/etl/const_multimap.h | 27 ++++--- include/etl/const_multiset.h | 27 ++++--- include/etl/const_set.h | 27 ++++--- include/etl/manchester.h | 75 ++++++++++--------- include/etl/parameter_pack.h | 6 +- include/etl/result.h | 68 ++++++----------- include/etl/rounded_integral_division.h | 5 +- include/etl/signal.h | 4 - include/etl/tuple.h | 4 - test/run-syntax-checks.sh | 2 +- test/syntax_check/CMakeLists.txt | 12 +++ test/syntax_check/const_map.h.t.cpp | 29 +++++++ test/syntax_check/const_multimap.h.t.cpp | 29 +++++++ test/syntax_check/const_multiset.h.t.cpp | 29 +++++++ test/syntax_check/const_set.h.t.cpp | 29 +++++++ test/syntax_check/crc64_iso.h.t.cpp | 29 +++++++ test/syntax_check/crc8_nrsc5.h.t.cpp | 29 +++++++ test/syntax_check/etl_profile.h | 1 - test/syntax_check/index_of_type.h.t.cpp | 29 +++++++ test/syntax_check/manchester.h.t.cpp | 29 +++++++ test/syntax_check/print.h.t.cpp | 29 +++++++ test/syntax_check/ranges.h.t.cpp | 29 +++++++ .../rounded_integral_division.h.t.cpp | 29 +++++++ test/syntax_check/type_list.h.t.cpp | 29 +++++++ test/test_manchester.cpp | 28 +++++++ 29 files changed, 510 insertions(+), 161 deletions(-) create mode 100644 test/syntax_check/const_map.h.t.cpp create mode 100644 test/syntax_check/const_multimap.h.t.cpp create mode 100644 test/syntax_check/const_multiset.h.t.cpp create mode 100644 test/syntax_check/const_set.h.t.cpp create mode 100644 test/syntax_check/crc64_iso.h.t.cpp create mode 100644 test/syntax_check/crc8_nrsc5.h.t.cpp create mode 100644 test/syntax_check/index_of_type.h.t.cpp create mode 100644 test/syntax_check/manchester.h.t.cpp create mode 100644 test/syntax_check/print.h.t.cpp create mode 100644 test/syntax_check/ranges.h.t.cpp create mode 100644 test/syntax_check/rounded_integral_division.h.t.cpp create mode 100644 test/syntax_check/type_list.h.t.cpp diff --git a/include/etl/chrono.h b/include/etl/chrono.h index facde8a4..b452ca4e 100644 --- a/include/etl/chrono.h +++ b/include/etl/chrono.h @@ -35,10 +35,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #include "hash.h" diff --git a/include/etl/closure.h b/include/etl/closure.h index 2c150ec3..7f11bbcf 100644 --- a/include/etl/closure.h +++ b/include/etl/closure.h @@ -67,7 +67,7 @@ namespace etl { public: - ETL_DEPRECATED_REASON("Use callback_type") using delegate_type = + using delegate_type ETL_DEPRECATED_REASON("Use callback_type") = TCallback; ///< The callback type to be invoked. Deprecated, use callback_type instead. using callback_type = TCallback; ///< The callback type to be invoked. using argument_types = etl::type_list; ///< The type list of arguments. diff --git a/include/etl/concepts.h b/include/etl/concepts.h index ce5cec97..ac539947 100644 --- a/include/etl/concepts.h +++ b/include/etl/concepts.h @@ -36,10 +36,6 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" -#if ETL_NOT_USING_CPP20 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR BELOW C++20 -#endif - #if ETL_USING_CPP20 #if ETL_USING_STL diff --git a/include/etl/const_map.h b/include/etl/const_map.h index aa20fb4d..f96f616b 100644 --- a/include/etl/const_map.h +++ b/include/etl/const_map.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_map const_map ///\ingroup containers @@ -528,14 +526,14 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_map(TElements...) -> const_map::first_type, typename etl::nth_type_t<0, TElements...>::second_type, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -586,16 +584,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_map_ext(const etl::span&) -> const_map_ext; template const_map_ext(const TElements (&)[Size]) -> const_map_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -659,3 +657,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_multimap.h b/include/etl/const_multimap.h index 6f5f8208..dea60ee1 100644 --- a/include/etl/const_multimap.h +++ b/include/etl/const_multimap.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_multimap const_multimap ///\ingroup containers @@ -478,14 +476,14 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multimap(TPairs...) -> const_multimap::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, sizeof...(TPairs)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -536,16 +534,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multimap_ext(const etl::span&) -> const_multimap_ext; template const_multimap_ext(const TElements (&)[Size]) -> const_multimap_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -626,3 +624,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_multiset.h b/include/etl/const_multiset.h index 1fb0bd9e..6184f9e7 100644 --- a/include/etl/const_multiset.h +++ b/include/etl/const_multiset.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_multiset const_multiset ///\ingroup containers @@ -433,13 +431,13 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multiset(TElements...) -> const_multiset, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Multiset type designed for constexpr. @@ -488,16 +486,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multiset_ext(const etl::span&) -> const_multiset_ext; template const_multiset_ext(const TElements (&)[Size]) -> const_multiset_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -572,3 +570,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_set.h b/include/etl/const_set.h index e4629d71..df7f0989 100644 --- a/include/etl/const_set.h +++ b/include/etl/const_set.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_set const_set ///\ingroup containers @@ -426,13 +424,13 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_set(TElements...) -> const_set, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -481,16 +479,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_set_ext(const etl::span&) -> const_set_ext; template const_set_ext(const TElements (&)[Size]) -> const_set_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -548,3 +546,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 032d9e29..b385565d 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -35,6 +35,8 @@ SOFTWARE. #include "span.h" #include "static_assert.h" +#if ETL_USING_CPP11 + ///\defgroup manchester manchester /// Manchester encoding and decoding ///\ingroup utilities @@ -51,13 +53,13 @@ namespace etl struct is_encodable { static const bool value = -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES etl::is_same::value || -#endif + #endif etl::is_same::value -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES || etl::is_same::value -#endif + #endif ; }; @@ -69,13 +71,13 @@ namespace etl struct is_decodable { static const bool value = -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES etl::is_same::value || -#endif + #endif etl::is_same::value -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES || etl::is_same::value -#endif + #endif ; }; @@ -91,13 +93,13 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); }; -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES template <> struct encoded { typedef uint16_t type; }; -#endif + #endif template <> struct encoded @@ -105,13 +107,13 @@ namespace etl typedef uint32_t type; }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct encoded { typedef uint64_t type; }; -#endif + #endif //************************************************************************* /// Type trait to determine the decoded type for a given encoded type. @@ -125,13 +127,13 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint8_t type; }; -#endif + #endif template <> struct decoded @@ -139,24 +141,24 @@ namespace etl typedef uint16_t type; }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint32_t type; }; -#endif + #endif //************************************************************************* /// Normal Manchester encoding type (no inversion). //************************************************************************* struct manchester_type_normal { -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES static const uint64_t inversion_mask = 0x0000000000000000ULL; -#else + #else static const uint32_t inversion_mask = 0x00000000UL; -#endif + #endif }; //************************************************************************* @@ -164,11 +166,11 @@ namespace etl //************************************************************************* struct manchester_type_inverted { -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL; -#else + #else static const uint32_t inversion_mask = 0xFFFFFFFFUL; -#endif + #endif }; //************************************************************************* @@ -247,11 +249,11 @@ namespace etl ETL_STATIC_ASSERT(CHAR_BIT == etl::numeric_limits::digits, "Manchester requires uint_least8_t to have the same number of bits as CHAR (CHAR_BITS)"); - //************************************************************************* - // Encoding functions - //************************************************************************* + //************************************************************************* + // Encoding functions + //************************************************************************* -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES //************************************************************************* /// Encode a 8-bit unsigned value and return 16-bit result. ///\param decoded The value to encode. @@ -273,7 +275,7 @@ namespace etl ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask))); return encoded; } -#endif + #endif //************************************************************************* /// Encode a 16-bit unsigned value and return the 32-bit result. @@ -297,7 +299,7 @@ namespace etl return encoded; } -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES //************************************************************************* /// Encode a 32-bit unsigned value and return the 64-bit result. ///\param decoded The value to encode. @@ -320,7 +322,7 @@ namespace etl encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask); return encoded; } -#endif + #endif //************************************************************************* /// Encode a span of data with the specified chunk size. @@ -350,11 +352,11 @@ namespace etl } } - //************************************************************************* - // Decoding functions - //************************************************************************* + //************************************************************************* + // Decoding functions + //************************************************************************* -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES //************************************************************************* /// Decode a 16-bit value and return the 8-bit result. ///\param encoded The value to decode. @@ -373,7 +375,7 @@ namespace etl encoded = static_cast((static_cast(encoded) | (static_cast(encoded) >> 2)) & 0x0F0FU); return static_cast(static_cast(encoded) | (static_cast(encoded) >> 4U)); } -#endif + #endif //************************************************************************* /// Decode a 32-bit value and return the 16-bit result. @@ -394,7 +396,7 @@ namespace etl return static_cast(encoded | (encoded >> 8U)); } -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES //************************************************************************* /// Decode a 64-bit value and return the 32-bit result. ///\param encoded The value to decode. @@ -414,7 +416,7 @@ namespace etl encoded = (encoded | (encoded >> 8)) & 0x0000FFFF0000FFFFULL; return static_cast(encoded | (encoded >> 16U)); } -#endif + #endif //************************************************************************* /// Decode a span of data using the specified chunk type. @@ -500,3 +502,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/parameter_pack.h b/include/etl/parameter_pack.h index 5dd21717..267065bb 100644 --- a/include/etl/parameter_pack.h +++ b/include/etl/parameter_pack.h @@ -34,11 +34,7 @@ SOFTWARE. #include -#if ETL_CPP11_NOT_SUPPORTED - #if !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW - #endif -#else +#if ETL_CPP11_SUPPORTED namespace etl { //*************************************************************************** diff --git a/include/etl/result.h b/include/etl/result.h index 5b5fcad8..22b5f92c 100644 --- a/include/etl/result.h +++ b/include/etl/result.h @@ -38,11 +38,7 @@ SOFTWARE. #include "optional.h" #include "variant.h" -#if ETL_CPP11_NOT_SUPPORTED - #if !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW - #endif -#else +#if ETL_CPP11_SUPPORTED namespace etl { @@ -70,7 +66,6 @@ namespace etl { } - #if ETL_CPP11_SUPPORTED //******************************************* /// Move constructor //******************************************* @@ -78,7 +73,6 @@ namespace etl : data(etl::move(other.data)) { } - #endif //******************************************* // Construct from a value @@ -104,15 +98,13 @@ namespace etl { } - //******************************************* - /// Move construct from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move construct from error + //******************************************* result(TError&& error) : data(etl::move(error)) { } - #endif //******************************************* /// Copy assign @@ -141,16 +133,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from value - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from value + //******************************************* result& operator=(TValue&& value) { data = etl::move(value); return *this; } - #endif //******************************************* /// Copy assign from error @@ -161,16 +151,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from error + //******************************************* result& operator=(TError&& error) { data = etl::move(error); return *this; } - #endif //******************************************* /// true if result contains a value @@ -223,16 +211,14 @@ namespace etl return etl::get(data); } - //******************************************* - /// Returns an rvalue reference to the error. - /// Undefined if the result does not contain an error. - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Returns an rvalue reference to the error. + /// Undefined if the result does not contain an error. + //******************************************* TError&& error() { return etl::move(etl::get(data)); } - #endif private: @@ -280,15 +266,13 @@ namespace etl { } - //******************************************* - /// Move construct from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move construct from error + //******************************************* result(TError&& error) : data(etl::move(error)) { } - #endif //******************************************* /// Copy assign from error @@ -299,16 +283,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from error + //******************************************* result& operator=(TError&& error) { data = etl::move(error); return *this; } - #endif //******************************************* /// true if result contains a value @@ -343,16 +325,14 @@ namespace etl return data.value(); } - //******************************************* - /// Returns an rvalue reference to the error. - /// Undefined if the result does not contain an error. - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Returns an rvalue reference to the error. + /// Undefined if the result does not contain an error. + //******************************************* TError&& error() { return etl::move(data.value()); } - #endif private: diff --git a/include/etl/rounded_integral_division.h b/include/etl/rounded_integral_division.h index b56a9dc5..26ae700c 100644 --- a/include/etl/rounded_integral_division.h +++ b/include/etl/rounded_integral_division.h @@ -36,6 +36,8 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" +#if ETL_USING_CPP11 + namespace etl { namespace private_rounded_integral_division @@ -565,7 +567,7 @@ namespace etl // Work with magnitudes in unsigned form (avoids abs() overflow for // T::min()). - typedef typename std::make_unsigned::type utype; + typedef typename etl::make_unsigned::type utype; const utype abs_denominator = (denominator < 0) ? (utype(0) - utype(denominator)) : utype(denominator); const utype abs_remainder = (remainder < 0) ? (utype(0) - utype(remainder)) : utype(remainder); const utype half_denominator = abs_denominator / 2U; @@ -784,3 +786,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/signal.h b/include/etl/signal.h index 0f198824..3392cff6 100644 --- a/include/etl/signal.h +++ b/include/etl/signal.h @@ -35,10 +35,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #include "algorithm.h" diff --git a/include/etl/tuple.h b/include/etl/tuple.h index 31cdce5f..f76c0a62 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -31,10 +31,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #if ETL_USING_STL diff --git a/test/run-syntax-checks.sh b/test/run-syntax-checks.sh index 18a65523..8307a51d 100755 --- a/test/run-syntax-checks.sh +++ b/test/run-syntax-checks.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash clear echo -e diff --git a/test/syntax_check/CMakeLists.txt b/test/syntax_check/CMakeLists.txt index 0e2627df..a9d14be6 100644 --- a/test/syntax_check/CMakeLists.txt +++ b/test/syntax_check/CMakeLists.txt @@ -115,6 +115,10 @@ target_sources(tests PRIVATE checksum.h.t.cpp chrono.h.t.cpp concepts.h.t.cpp + const_map.h.t.cpp + const_multimap.h.t.cpp + const_multiset.h.t.cpp + const_set.h.t.cpp circular_buffer.h.t.cpp circular_iterator.h.t.cpp closure.h.t.cpp @@ -163,6 +167,7 @@ target_sources(tests PRIVATE crc32_q.h.t.cpp crc32_xfer.h.t.cpp crc64_ecma.h.t.cpp + crc64_iso.h.t.cpp crc8_ccitt.h.t.cpp crc8_cdma2000.h.t.cpp crc8_darc.h.t.cpp @@ -174,6 +179,7 @@ target_sources(tests PRIVATE crc8_j1850_zero.h.t.cpp crc8_maxim.h.t.cpp crc8_opensafety.h.t.cpp + crc8_nrsc5.h.t.cpp crc8_rohc.h.t.cpp crc8_wcdma.h.t.cpp cyclic_value.h.t.cpp @@ -215,6 +221,7 @@ target_sources(tests PRIVATE histogram.h.t.cpp ihash.h.t.cpp imemory_block_allocator.h.t.cpp + index_of_type.h.t.cpp indirect_vector.h.t.cpp initializer_list.h.t.cpp inplace_function.h.t.cpp @@ -239,6 +246,7 @@ target_sources(tests PRIVATE list.h.t.cpp log.h.t.cpp macros.h.t.cpp + manchester.h.t.cpp map.h.t.cpp math.h.t.cpp math_constants.h.t.cpp @@ -284,6 +292,7 @@ target_sources(tests PRIVATE poly_span.h.t.cpp pool.h.t.cpp power.h.t.cpp + print.h.t.cpp priority_queue.h.t.cpp pseudo_moving_average.h.t.cpp quantize.h.t.cpp @@ -295,6 +304,7 @@ target_sources(tests PRIVATE queue_spsc_locked.h.t.cpp radix.h.t.cpp random.h.t.cpp + ranges.h.t.cpp ratio.h.t.cpp reference_counted_message.h.t.cpp reference_counted_message_pool.h.t.cpp @@ -306,6 +316,7 @@ target_sources(tests PRIVATE rescale.h.t.cpp result.h.t.cpp rms.h.t.cpp + rounded_integral_division.h.t.cpp scaled_rounding.h.t.cpp scheduler.h.t.cpp set.h.t.cpp @@ -337,6 +348,7 @@ target_sources(tests PRIVATE to_wstring.h.t.cpp tuple.h.t.cpp type_def.h.t.cpp + type_list.h.t.cpp type_lookup.h.t.cpp type_select.h.t.cpp type_traits.h.t.cpp diff --git a/test/syntax_check/const_map.h.t.cpp b/test/syntax_check/const_map.h.t.cpp new file mode 100644 index 00000000..db4a753c --- /dev/null +++ b/test/syntax_check/const_map.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_multimap.h.t.cpp b/test/syntax_check/const_multimap.h.t.cpp new file mode 100644 index 00000000..da38716c --- /dev/null +++ b/test/syntax_check/const_multimap.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_multiset.h.t.cpp b/test/syntax_check/const_multiset.h.t.cpp new file mode 100644 index 00000000..12b01a8a --- /dev/null +++ b/test/syntax_check/const_multiset.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_set.h.t.cpp b/test/syntax_check/const_set.h.t.cpp new file mode 100644 index 00000000..1b73c9af --- /dev/null +++ b/test/syntax_check/const_set.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/crc64_iso.h.t.cpp b/test/syntax_check/crc64_iso.h.t.cpp new file mode 100644 index 00000000..a78f5430 --- /dev/null +++ b/test/syntax_check/crc64_iso.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/crc8_nrsc5.h.t.cpp b/test/syntax_check/crc8_nrsc5.h.t.cpp new file mode 100644 index 00000000..4dc725dd --- /dev/null +++ b/test/syntax_check/crc8_nrsc5.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/etl_profile.h b/test/syntax_check/etl_profile.h index ed633219..deee267c 100644 --- a/test/syntax_check/etl_profile.h +++ b/test/syntax_check/etl_profile.h @@ -31,7 +31,6 @@ SOFTWARE. #define ETL_TARGET_DEVICE_GENERIC #define ETL_TARGET_OS_NONE -#define ETL_IN_UNIT_TEST #define ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK #define ETL_CALLBACK_TIMER_DISABLE_INTERRUPTS #define ETL_CALLBACK_TIMER_ENABLE_INTERRUPTS diff --git a/test/syntax_check/index_of_type.h.t.cpp b/test/syntax_check/index_of_type.h.t.cpp new file mode 100644 index 00000000..0e854960 --- /dev/null +++ b/test/syntax_check/index_of_type.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/manchester.h.t.cpp b/test/syntax_check/manchester.h.t.cpp new file mode 100644 index 00000000..4e86c4f1 --- /dev/null +++ b/test/syntax_check/manchester.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/print.h.t.cpp b/test/syntax_check/print.h.t.cpp new file mode 100644 index 00000000..4fe9432b --- /dev/null +++ b/test/syntax_check/print.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/ranges.h.t.cpp b/test/syntax_check/ranges.h.t.cpp new file mode 100644 index 00000000..41861be9 --- /dev/null +++ b/test/syntax_check/ranges.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/rounded_integral_division.h.t.cpp b/test/syntax_check/rounded_integral_division.h.t.cpp new file mode 100644 index 00000000..4c2ea104 --- /dev/null +++ b/test/syntax_check/rounded_integral_division.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/type_list.h.t.cpp b/test/syntax_check/type_list.h.t.cpp new file mode 100644 index 00000000..d8fd1469 --- /dev/null +++ b/test/syntax_check/type_list.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index bd357435..a69bfdb5 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -1,3 +1,31 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 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 "etl/manchester.h" #include "unit_test_framework.h" From 866c8a315ed87c1319f96fa31bfeccd0c4728ab9 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 15 Apr 2026 10:47:52 +0200 Subject: [PATCH 10/27] Extensions for testing (#1380) * Extensions for testing Generalize run-tests.sh Test all C++ versions at once Fix combination of big endian and -Wsign-conversion Failed on s390x (as reference for big endian) Add github workflow for s390x Add armhf container files Devcontainers for i386 and riscv Add github workflows for armhf, i386 and riscv64 Add run-tests.sh for foreign architectures Document testing in doc/testing.md Adjustments from clang-format run Fix .devcontainer/s390x/Dockerfile for linebreak syntax Fix exit code of run-test.sh Previously, "exit $?" was used, actually the return value of FailedCompilation and FailedTest which are always 0. Now just using 1. In run-tests.sh at ctest, use -V for printing number of tests unconditionally While ctest suppresses individual test list by default, it didn't even print the number of tests anymore, as run_tests.sh does because it suppresses it output completely. Now, by default print number of tests, and in verbose mode, print test list in addition. * Support powerpc as foreign architecture * Add SFINAE constraints to etl::begin/end and reverse iterator free functions The unconstrained etl::begin(), etl::end(), etl::cbegin(), etl::cend(), etl::rbegin(), etl::rend(), etl::crbegin(), and etl::crend() templates in the no-STL code path were matching iterator types during ADL, causing a hard error with GCC 15's std::ranges::begin. When std::ranges performed ADL on an etl::*::iterator, it found etl::begin() as a candidate; since the iterator type has a nested iterator typedef, the return type TContainer::iterator was valid, but calling .begin() on the iterator failed. Fix: add etl::void_t SFINAE guards to each template, ensuring they only participate in overload resolution when TContainer actually has the corresponding member function (.begin(), .end(), etc.). * - Fix red unit tests on 32 bits big-endian platform. * Document powerpc architecture for testing * Use Dockerfiles in cross testing github workflows Synchronizes environment setup for github workflows to what is defined in the development Dockerfiles. So they don't need to be maintained separately. --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei Shirokov Co-authored-by: John Wellbelove --- .devcontainer/armhf/Dockerfile | 54 +++ .devcontainer/armhf/devcontainer.json | 29 ++ .devcontainer/armhf/toolchain-armhf.cmake | 21 + .devcontainer/i386/Dockerfile | 54 +++ .devcontainer/i386/devcontainer.json | 29 ++ .devcontainer/i386/toolchain-i386.cmake | 21 + .devcontainer/powerpc/Dockerfile | 71 +++ .devcontainer/powerpc/devcontainer.json | 29 ++ .devcontainer/powerpc/toolchain-powerpc.cmake | 21 + .devcontainer/riscv64/Dockerfile | 54 +++ .devcontainer/riscv64/devcontainer.json | 29 ++ .devcontainer/riscv64/toolchain-riscv64.cmake | 20 + .devcontainer/run-tests.sh | 56 +++ .devcontainer/s390x/Dockerfile | 16 +- .devcontainer/s390x/devcontainer.json | 2 +- .github/workflows/clang-c++23.yml | 14 +- .github/workflows/gcc-c++23-armhf.yml | 29 ++ .github/workflows/gcc-c++23-i386.yml | 29 ++ .github/workflows/gcc-c++23-powerpc.yml | 29 ++ .github/workflows/gcc-c++23-riscv64.yml | 29 ++ .github/workflows/gcc-c++23-s390x.yml | 29 ++ .github/workflows/gcc-c++23.yml | 8 +- docs/generators.md | 190 ++++++++ docs/testing.md | 412 ++++++++++++++++++ include/etl/algorithm.h | 3 +- include/etl/bip_buffer_spsc_atomic.h | 4 +- include/etl/ipool.h | 2 +- include/etl/iterator.h | 155 ++++++- include/etl/numeric.h | 10 +- include/etl/private/bitset_new.h | 12 +- .../private/diagnostic_sign_conversion_push.h | 44 ++ include/etl/vector.h | 4 + test/CMakeLists.txt | 3 +- test/run-tests.sh | 136 +++--- test/test_bit_stream.cpp | 2 +- test/test_bit_stream_writer_big_endian.cpp | 6 +- test/test_bit_stream_writer_little_endian.cpp | 6 +- test/test_byte_stream.cpp | 4 +- test/test_format.cpp | 2 +- test/test_hash.cpp | 29 +- test/test_histogram.cpp | 4 +- test/test_set.cpp | 8 +- 42 files changed, 1582 insertions(+), 127 deletions(-) create mode 100644 .devcontainer/armhf/Dockerfile create mode 100644 .devcontainer/armhf/devcontainer.json create mode 100644 .devcontainer/armhf/toolchain-armhf.cmake create mode 100644 .devcontainer/i386/Dockerfile create mode 100644 .devcontainer/i386/devcontainer.json create mode 100644 .devcontainer/i386/toolchain-i386.cmake create mode 100644 .devcontainer/powerpc/Dockerfile create mode 100644 .devcontainer/powerpc/devcontainer.json create mode 100644 .devcontainer/powerpc/toolchain-powerpc.cmake create mode 100644 .devcontainer/riscv64/Dockerfile create mode 100644 .devcontainer/riscv64/devcontainer.json create mode 100644 .devcontainer/riscv64/toolchain-riscv64.cmake create mode 100755 .devcontainer/run-tests.sh create mode 100644 .github/workflows/gcc-c++23-armhf.yml create mode 100644 .github/workflows/gcc-c++23-i386.yml create mode 100644 .github/workflows/gcc-c++23-powerpc.yml create mode 100644 .github/workflows/gcc-c++23-riscv64.yml create mode 100644 .github/workflows/gcc-c++23-s390x.yml create mode 100644 docs/generators.md create mode 100644 docs/testing.md create mode 100644 include/etl/private/diagnostic_sign_conversion_push.h diff --git a/.devcontainer/armhf/Dockerfile b/.devcontainer/armhf/Dockerfile new file mode 100644 index 00000000..7d5632a6 --- /dev/null +++ b/.devcontainer/armhf/Dockerfile @@ -0,0 +1,54 @@ +# armhf Test Environment for ETL +# Uses QEMU user-mode emulation to run armhf binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and armhf cross-compilation tools +RUN dpkg --add-architecture armhf && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-arm-linux-gnueabihf \ + g++-arm-linux-gnueabihf \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + file \ + libc6:armhf \ + libstdc++6:armhf \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== armhf Cross Compiler ===" && \ + arm-linux-gnueabihf-gcc --version && \ + echo "" && \ + echo "=== QEMU arm ===" && \ + qemu-arm-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/armhf/devcontainer.json b/.devcontainer/armhf/devcontainer.json new file mode 100644 index 00000000..a1dc285e --- /dev/null +++ b/.devcontainer/armhf/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "armhf (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/armhf/toolchain-armhf.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-armhf", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/armhf/toolchain-armhf.cmake b/.devcontainer/armhf/toolchain-armhf.cmake new file mode 100644 index 00000000..a7f9f00a --- /dev/null +++ b/.devcontainer/armhf/toolchain-armhf.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for armhf cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) + +# Specify the cross compiler +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) +set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) +set(CMAKE_AR arm-linux-gnueabihf-ar) +set(CMAKE_RANLIB arm-linux-gnueabihf-ranlib) +set(CMAKE_STRIP arm-linux-gnueabihf-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-arm-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/i386/Dockerfile b/.devcontainer/i386/Dockerfile new file mode 100644 index 00000000..99223eb9 --- /dev/null +++ b/.devcontainer/i386/Dockerfile @@ -0,0 +1,54 @@ +# i386 Test Environment for ETL +# Uses QEMU user-mode emulation to run i386 binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and i386 cross-compilation tools +RUN dpkg --add-architecture i386 && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-i686-linux-gnu \ + g++-i686-linux-gnu \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + file \ + libc6:i386 \ + libstdc++6:i386 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== i386 Cross Compiler ===" && \ + i686-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU i386 ===" && \ + qemu-i386-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/i386/devcontainer.json b/.devcontainer/i386/devcontainer.json new file mode 100644 index 00000000..84e28a8e --- /dev/null +++ b/.devcontainer/i386/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "i386 (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/i386/toolchain-i386.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-i386", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/i386/toolchain-i386.cmake b/.devcontainer/i386/toolchain-i386.cmake new file mode 100644 index 00000000..502e2285 --- /dev/null +++ b/.devcontainer/i386/toolchain-i386.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for i386 cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR i386) + +# Specify the cross compiler +set(CMAKE_C_COMPILER i686-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER i686-linux-gnu-g++) +set(CMAKE_AR i686-linux-gnu-ar) +set(CMAKE_RANLIB i686-linux-gnu-ranlib) +set(CMAKE_STRIP i686-linux-gnu-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-i386-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/powerpc/Dockerfile b/.devcontainer/powerpc/Dockerfile new file mode 100644 index 00000000..06bab1d0 --- /dev/null +++ b/.devcontainer/powerpc/Dockerfile @@ -0,0 +1,71 @@ +# powerpc Test Environment for ETL +# Uses QEMU user-mode emulation to run powerpc binaries on x64 host +FROM debian:sid-20260406 + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and powerpc cross-compilation tools +RUN dpkg --add-architecture powerpc && \ + apt-get update && apt-get install -y --no-install-recommends \ + binfmt-support \ + gpg \ + ca-certificates \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + file \ + debian-ports-archive-keyring \ + && rm -rf /var/lib/apt/lists/* + +RUN cat < /etc/apt/sources.list.d/powerpc.sources +Types: deb +URIs: http://snapshot.debian.org/archive/debian-ports/20260406T000000Z +Suites: sid +Components: main +Architectures: powerpc +Signed-By: /usr/share/keyrings/debian-ports-archive-keyring.gpg +EOF + +RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid + +RUN apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + gcc-powerpc-linux-gnu \ + g++-powerpc-linux-gnu \ + libc6:powerpc \ + libstdc++6:powerpc \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== powerpc Cross Compiler ===" && \ + powerpc-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU powerpc ===" && \ + qemu-ppc-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/powerpc/devcontainer.json b/.devcontainer/powerpc/devcontainer.json new file mode 100644 index 00000000..1d7a9a05 --- /dev/null +++ b/.devcontainer/powerpc/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "powerpc (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/powerpc/toolchain-powerpc.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=ON", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-powerpc", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/powerpc/toolchain-powerpc.cmake b/.devcontainer/powerpc/toolchain-powerpc.cmake new file mode 100644 index 00000000..1afea7da --- /dev/null +++ b/.devcontainer/powerpc/toolchain-powerpc.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for powerpc cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR powerpc) + +# Specify the cross compiler +set(CMAKE_C_COMPILER powerpc-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER powerpc-linux-gnu-g++) +set(CMAKE_AR powerpc-linux-gnu-ar) +set(CMAKE_RANLIB powerpc-linux-gnu-ranlib) +set(CMAKE_STRIP powerpc-linux-gnu-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-ppc CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/riscv64/Dockerfile b/.devcontainer/riscv64/Dockerfile new file mode 100644 index 00000000..081e42ed --- /dev/null +++ b/.devcontainer/riscv64/Dockerfile @@ -0,0 +1,54 @@ +# riscv64 Test Environment for ETL +# Uses QEMU user-mode emulation to run riscv64 binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and riscv64 cross-compilation tools +RUN dpkg --add-architecture riscv64 && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-riscv64-linux-gnu \ + g++-riscv64-linux-gnu \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + file \ + libc6:riscv64 \ + libstdc++6:riscv64 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== riscv64 Cross Compiler ===" && \ + riscv64-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU riscv64 ===" && \ + qemu-riscv64-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/riscv64/devcontainer.json b/.devcontainer/riscv64/devcontainer.json new file mode 100644 index 00000000..0e673f24 --- /dev/null +++ b/.devcontainer/riscv64/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "riscv64 (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/riscv64/toolchain-riscv64.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-riscv64", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/riscv64/toolchain-riscv64.cmake b/.devcontainer/riscv64/toolchain-riscv64.cmake new file mode 100644 index 00000000..adc1c7f3 --- /dev/null +++ b/.devcontainer/riscv64/toolchain-riscv64.cmake @@ -0,0 +1,20 @@ +# CMake toolchain file for riscv64 cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +# Specify the cross compiler +set(CMAKE_C_COMPILER riscv64-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER riscv64-linux-gnu-g++) +set(CMAKE_AR riscv64-linux-gnu-ar) +set(CMAKE_RANLIB riscv64-linux-gnu-ranlib) +set(CMAKE_STRIP riscv64-linux-gnu-strip) +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-riscv64-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/run-tests.sh b/.devcontainer/run-tests.sh new file mode 100755 index 00000000..218dc032 --- /dev/null +++ b/.devcontainer/run-tests.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Run tests inside the separately created docker container for different hardware architecture +# +# Strategy: +# * Create docker image +# * Enter image +# * Cross build tests +# * Run tests via QEMU +# + +set -e + +usage() +{ + echo "Usage: run-tests.sh " + echo "Architecture: armhf|i386|powerpc|riscv64|s390x" + echo "(run from project root)" +} + +ARCHLIST="armhf i386 powerpc riscv64 s390x" + +if [[ " $ARCHLIST " =~ " $1 " ]] ; then + ARCH=$1 +else + echo "Unsupported architecture: $1" + usage + exit 1 +fi + +if [ "$2" = "" ] ; then + echo "Creating docker image..." + docker build -t $ARCH .devcontainer/$ARCH + + echo "Entering container..." + docker run -it --rm -v "$PWD":/workspaces/etl -w /workspaces/etl $ARCH /bin/bash .devcontainer/run-tests.sh $ARCH inside_container + +elif [ "$2" = "inside_container" ] ; then + echo "Cross building tests..." + mkdir -p build-$ARCH + cd build-$ARCH + cmake -DCMAKE_TOOLCHAIN_FILE=../.devcontainer/$ARCH/toolchain-$ARCH.cmake \ + -DBUILD_TESTS=ON -DNO_STL=ON -DETL_CXX_STANDARD=23 \ + -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=-O0 -DETL_ENABLE_SANITIZER=Off -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF \ + ../test + export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) + cmake --build . + + echo "Running tests via CTest (using QEMU emulator from toolchain)..." + ctest -V --output-on-failure + echo "Tests successful." +else + echo "Invalid second argument: $2" + usage + exit 1 +fi diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index 21a6289c..f8c6ff87 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive # Install QEMU user-mode emulation and s390x cross-compilation tools RUN dpkg --add-architecture s390x && \ - apt-get update && apt-get install -y --no-install-recommends\ + apt-get update && apt-get install -y --no-install-recommends \ qemu-user-static \ qemu-user \ binfmt-support \ @@ -23,6 +23,14 @@ RUN dpkg --add-architecture s390x && \ libstdc++6:s390x \ && rm -rf /var/lib/apt/lists/* +# Create non-root user with stable UID/GID +ARG USERNAME=devuser +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + # Set working directory WORKDIR /workspaces/etl @@ -36,5 +44,11 @@ RUN echo "=== Host Architecture ===" && \ echo "=== QEMU s390x ===" && \ qemu-s390x-static --version | head -n1 +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + # Default command CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json index 8b7f8235..535a0799 100644 --- a/.devcontainer/s390x/devcontainer.json +++ b/.devcontainer/s390x/devcontainer.json @@ -18,7 +18,7 @@ "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/s390x/toolchain-s390x.cmake", "-DBUILD_TESTS=ON", "-DNO_STL=OFF", - "-DETL_CXX_STANDARD=17" + "-DETL_CXX_STANDARD=23" ], "cmake.buildDirectory": "${workspaceFolder}/build-s390x", "cmake.generator": "Ninja" diff --git a/.github/workflows/clang-c++23.yml b/.github/workflows/clang-c++23.yml index ffa88744..18817aaa 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -30,7 +30,7 @@ jobs: export CC=clang-17 export CXX=clang++-17 export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang-17 --version make -j $(getconf _NPROCESSORS_ONLN) @@ -59,7 +59,7 @@ jobs: export CC=clang-17 export CXX=clang++-17 export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang-17 --version make -j $(getconf _NPROCESSORS_ONLN) @@ -88,7 +88,7 @@ jobs: export CC=clang-17 export CXX=clang++-17 export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang-17 --version make -j $(getconf _NPROCESSORS_ONLN) @@ -110,7 +110,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang --version make -j $(getconf _NPROCESSORS_ONLN) @@ -132,7 +132,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang --version make -j $(getconf _NPROCESSORS_ONLN) @@ -154,7 +154,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang --version make -j $(getconf _NPROCESSORS_ONLN) @@ -176,7 +176,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang --version make -j $(getconf _NPROCESSORS_ONLN) diff --git a/.github/workflows/gcc-c++23-armhf.yml b/.github/workflows/gcc-c++23-armhf.yml new file mode 100644 index 00000000..1bd2912b --- /dev/null +++ b/.github/workflows/gcc-c++23-armhf.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-armhf +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-armhf: + name: GCC C++23 Linux - No STL - armhf + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-armhf -f .devcontainer/armhf/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-armhf bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/armhf/toolchain-armhf.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-i386.yml b/.github/workflows/gcc-c++23-i386.yml new file mode 100644 index 00000000..31bfc331 --- /dev/null +++ b/.github/workflows/gcc-c++23-i386.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-i386 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-i386: + name: GCC C++23 Linux - No STL - i386 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-i386 -f .devcontainer/i386/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-i386 bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/i386/toolchain-i386.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-powerpc.yml b/.github/workflows/gcc-c++23-powerpc.yml new file mode 100644 index 00000000..7494ae55 --- /dev/null +++ b/.github/workflows/gcc-c++23-powerpc.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-powerpc +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-powerpc: + name: GCC C++23 Linux - No STL - powerpc + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-powerpc -f .devcontainer/powerpc/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-powerpc bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/powerpc/toolchain-powerpc.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-riscv64.yml b/.github/workflows/gcc-c++23-riscv64.yml new file mode 100644 index 00000000..695056a8 --- /dev/null +++ b/.github/workflows/gcc-c++23-riscv64.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-riscv64 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-riscv64: + name: GCC C++23 Linux - No STL - riscv64 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-riscv64 -f .devcontainer/riscv64/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-riscv64 bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/riscv64/toolchain-riscv64.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-s390x.yml b/.github/workflows/gcc-c++23-s390x.yml new file mode 100644 index 00000000..f6a15aca --- /dev/null +++ b/.github/workflows/gcc-c++23-s390x.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-s390x +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-s390x: + name: GCC C++23 Linux - No STL - s390x + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-s390x -f .devcontainer/s390x/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-s390x bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/s390x/toolchain-s390x.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index f91924bd..aad4325c 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -23,7 +23,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ gcc --version make -j $(getconf _NPROCESSORS_ONLN) @@ -45,7 +45,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ gcc --version make -j $(getconf _NPROCESSORS_ONLN) @@ -67,7 +67,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ gcc --version make -j $(getconf _NPROCESSORS_ONLN) @@ -89,7 +89,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ gcc --version make -j $(getconf _NPROCESSORS_ONLN) diff --git a/docs/generators.md b/docs/generators.md new file mode 100644 index 00000000..d44a38b6 --- /dev/null +++ b/docs/generators.md @@ -0,0 +1,190 @@ +# Code Generation for Pre-C++11 Support + +ETL supports C++03 (also referred to as C++98) environments where variadic +templates, `constexpr`, and other modern features are unavailable. To +provide equivalent functionality, certain headers are **generated** using +[Cog](https://nedbatchelder.com/code/cog/), a Python-based code generation +tool that embeds Python snippets inside source files. + +This document explains how the code generation system works and how to +regenerate the headers if you modify a generator template. + +--- + +## Overview + +| Directory | Contents | +|---|---| +| `include/etl/generators/` | Generator templates (`*_generator.h`) and batch scripts | +| `include/etl/private/` | Generated output (`*_cpp03.h`) committed to the repository | +| `scripts/generator_test.py` | CI script that verifies generators match committed files | + +The generator templates contain embedded Python code (delimited by `[[[cog` +and `]]]`) that produces the repetitive C++03 boilerplate. Cog processes +these templates and writes the expanded output to `include/etl/private/`. + +--- + +## Generated Headers + +The following C++03 compatibility headers are generated: + +| Generator | Output | Purpose | +|---|---|---| +| `fsm_fwd_decl_cpp03_generator.h` | `fsm_fwd_decl_cpp03.h` | FSM forward declarations | +| `fsm_friend_decl_cpp03_generator.h` | `fsm_friend_decl_cpp03.h` | FSM friend declarations | +| `fsm_cpp03_generator.h` | `fsm_cpp03.h` | Finite state machine implementation | +| `message_router_cpp03_generator.h` | `message_router_cpp03.h` | Message router | +| `message_packet_cpp03_generator.h` | `message_packet_cpp03.h` | Message packet | +| `largest_type_cpp03_generator.h` | `largest_type_cpp03.h` | Largest type metafunction | +| `largest_alignment_cpp03_generator.h` | `largest_alignment_cpp03.h` | Largest alignment metafunction | +| `largest_cpp03_generator.h` | `largest_cpp03.h` | Largest type/size utilities | +| `smallest_cpp03_generator.h` | `smallest_cpp03.h` | Smallest type/size utilities | +| `type_traits_cpp03_generator.h` | `type_traits_cpp03.h` | Type traits (`is_one_of`, etc.) | +| `type_lookup_cpp03_generator.h` | `type_lookup_cpp03.h` | Type lookup metafunction | +| `type_select_cpp03_generator.h` | `type_select_cpp03.h` | Type selection metafunction | +| `variant_pool_cpp03_generator.h` | `variant_pool_cpp03.h` | Variant pool | + +--- + +## Generator Parameters + +Cog variables control how many template parameter overloads are generated: + +| Variable | Default | Used by | +|---|---|---| +| `Handlers` | 16 | FSM and message router generators | +| `NTypes` | 16 | Type utility generators (largest, smallest, lookup, select, variant pool) | +| `IsOneOf` | 16 | Type traits generator (`is_one_of`) | + +These defaults produce overloads supporting up to 16 types or handlers, +which is sufficient for most embedded applications while keeping compile +times reasonable. + +--- + +## Prerequisites + +* **Python 3** +* **cogapp** – install via: + + ```bash + pip install cogapp + ``` + +--- + +## Regenerating Headers + +### Using the batch scripts (Windows) + +Each generator has a corresponding `.bat` file in `include/etl/generators/`: + +```bat +cd include/etl/generators +generate.bat # Regenerate all headers +generate_fsm.bat # Regenerate FSM headers only +generate_smallest.bat # Regenerate smallest_cpp03.h only +# etc. +``` + +### Manual invocation + +Run Cog directly from the `include/etl/generators/` directory: + +```bash +cd include/etl/generators + +# Example: regenerate smallest_cpp03.h +python3 -m cogapp -d -e -o../private/smallest_cpp03.h -DNTypes=16 smallest_cpp03_generator.h + +# Example: regenerate fsm_cpp03.h +python3 -m cogapp -d -e -o../private/fsm_cpp03.h -DHandlers=16 fsm_cpp03_generator.h +``` + +Cog options used: + +| Option | Meaning | +|---|---| +| `-d` | Delete the generator markers from output | +| `-e` | Warn if the input file has no generator markers | +| `-o` | Write output to the specified file | +| `-D=` | Define a Cog variable | + +### Regenerating all headers + +The `generate.bat` script regenerates every header: + +```bash +cd include/etl/generators +./generate.bat # Windows +# or run the commands manually on Linux/macOS +``` + +On Linux/macOS you can run the commands from `generate.bat` directly in +your shell (they are standard `python3 -m cogapp` invocations). + +--- + +## Verifying Generators + +After modifying a generator template, verify the output matches the +committed file: + +```bash +python3 scripts/generator_test.py +``` + +This script: + +1. Runs Cog on every `*_generator.h` file. +2. Compares each output against the corresponding file in + `include/etl/private/`. +3. Reports success or failure. + +The `generator.yml` GitHub Actions workflow runs this automatically on +every push and pull request. + +--- + +## How Generators Work + +A generator template contains standard C++ code interspersed with Cog +directives. For example, from `smallest_cpp03_generator.h`: + +```cpp +/*[[[cog +import cog +cog.outl("template " % int(NTypes)) +]]]*/ +// Generated code appears here after running Cog +/*[[[end]]]*/ +``` + +When Cog processes this file with `-DNTypes=16`, the Python code executes +and outputs the expanded template parameter list supporting 16 types. + +--- + +## Adding a New Generator + +1. Create `include/etl/generators/_cpp03_generator.h` with Cog + directives. +2. Add a corresponding entry to `generate.bat`. +3. Run `generate.bat` (or the equivalent Cog command) to produce + `include/etl/private/_cpp03.h`. +4. Commit both the generator and the generated output. +5. Verify with `python3 scripts/generator_test.py`. + +--- + +## Troubleshooting + +| Problem | Solution | +|---|---| +| `ModuleNotFoundError: No module named 'cogapp'` | Install Cog: `pip install cogapp` | +| Generator output differs from committed file | Regenerate and commit the updated output | +| Need more than 16 types/handlers | Change `-DNTypes=` or `-DHandlers=` and regenerate | diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 00000000..c6773f6f --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,412 @@ +# Testing ETL + +This document describes how to build and run the ETL test suite locally, +inside Dev Containers, and in CI. + +## Table of Contents + +1. [Prerequisites](#prerequisites) +2. [Running Tests Locally (`test/run-tests.sh`)](#running-tests-locally) +3. [Syntax Checks (`test/run-syntax-checks.sh`)](#syntax-checks) +4. [Cross-Architecture Testing (`.devcontainer/run-tests.sh`)](#cross-architecture-testing) +5. [Dev Containers for Native Compilers](#dev-containers-for-native-compilers) +6. [CMake Options Reference](#cmake-options-reference) +7. [CI Checks (GitHub Actions)](#ci-checks-github-actions) +8. [Appveyor (Windows / MSVC)](#appveyor-windows--msvc) +9. [Code Coverage](#code-coverage) +10. [Generator Tests (`scripts/generator_test.py`)](#generator-tests) + +--- + +## Prerequisites + +* **CMake** ≥ 3.10 +* **GCC** and/or **Clang** (any version supported by the project) +* **Make** or **Ninja** (build backend) +* **Docker** (only needed for cross-architecture testing via `.devcontainer/run-tests.sh`) +* **QEMU user-mode** (installed automatically inside the cross-arch Docker images) + +The project is header-only, so there is no library to compile – the build +step compiles the test binary `etl_tests` which links against a bundled copy +of **UnitTest++**. + +--- + +## Running Tests Locally + +The main entry point for local testing is **`test/run-tests.sh`**. It +iterates over a matrix of compiler / configuration combinations, creates a +temporary `build-make` directory for each one, runs CMake + Make + CTest, +and reports coloured pass/fail output (also appended to `log.txt`). + +### Synopsis + +```bash +cd test +./run-tests.sh [Optimisation] [Threads] [Sanitizer] [Compiler] [Verbose] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ Standard | `11`, `14`, `17`, `20`, `23`, or `all` | *(required)* | +| Optimisation | `0`, `1`, `2`, `3` | `0` | +| Threads | any positive integer | `4` | +| Sanitizer | `s` (enable) / `n` (disable) | `n` (disabled) | +| Compiler | `gcc`, `clang` | all compilers | +| Verbose | `v` (enable) / `n` (disable) | `n` (disabled) | + +### Examples + +```bash +# Run all C++17 tests with GCC only, optimisation -O0, 8 threads +./run-tests.sh 17 0 8 n gcc + +# Run every standard with both compilers, sanitizers enabled, verbose +./run-tests.sh all 0 4 s "" v +``` + +### What the script does + +For every selected C++ standard the script loops over a built-in list of +configurations (STL / No STL / Force C++03 / Non-virtual messages / …) for +each selected compiler. For every combination it: + +1. Creates a fresh `build-make` directory inside the configuration's source + subdirectory. +2. Invokes `cmake` with the appropriate `-D` flags (see + [CMake Options Reference](#cmake-options-reference)). +3. Builds via `cmake --build .` (parallel level controlled by + `CMAKE_BUILD_PARALLEL_LEVEL`). +4. Runs `ctest -V`. +5. Reports success or failure and removes the build directory. + +The script exits immediately on the first compilation or test failure. + +### Test configurations exercised + +| Compiler | Configuration | +|---|---| +| GCC | STL | +| GCC | STL – Non-virtual messages | +| GCC | STL – Force C++03 | +| GCC | No STL | +| GCC | No STL – Force C++03 | +| GCC | No STL – Builtin mem functions | +| Clang | STL | +| Clang | STL – Force C++03 | +| Clang | No STL | +| Clang | No STL – Force C++03 | +| Clang | No STL – Builtin mem functions | +| GCC / Clang | Initializer list test | +| GCC / Clang | Error macros – log_errors, exceptions, log_errors_and_exceptions, assert_function | + +--- + +## Syntax Checks + +The script **`test/run-syntax-checks.sh`** performs compilation-only syntax +checks across multiple C++ standards and configurations. Unlike +`run-tests.sh`, it **does not run the test binary** – it only verifies that +the code compiles successfully. This is useful for quickly validating that +header changes do not introduce compilation errors across the supported +standard/configuration matrix. + +### Synopsis + +```bash +cd test +./run-syntax-checks.sh [Threads] [Compiler] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ Standard | `03`, `11`, `14`, `17`, `20`, `23`, or `a` (all) | *(required)* | +| Threads | any positive integer | `4` | +| Compiler | `gcc`, `clang` | all compilers | + +### Examples + +```bash +# Check C++17 syntax with GCC only, using 8 threads +./run-syntax-checks.sh 17 8 gcc + +# Check all standards with both compilers +./run-syntax-checks.sh a +``` + +### What the script does + +The script operates from the `test/syntax_check` directory and iterates over +the selected C++ standard(s). For each standard and compiler combination it: + +1. Creates fresh build directories (`bgcc` / `bclang`). +2. Invokes `cmake` with the appropriate `-D` flags for the configuration. +3. Builds via `cmake --build`. +4. Reports compilation success or failure (logged to `log.txt`). + +The script exits immediately on the first compilation failure. + +### Configurations checked per standard + +For each C++ standard the following configurations are compiled: + +| Compiler | Configuration | +|---|---| +| GCC | STL | +| GCC | No STL | +| GCC | STL – Built-in traits | +| GCC | No STL – Built-in traits | +| Clang | STL | +| Clang | No STL | +| Clang | STL – Built-in traits | +| Clang | No STL – Built-in traits | + +--- + +## Cross-Architecture Testing + +**`.devcontainer/run-tests.sh`** builds and runs the test suite for +non-x86_64 architectures using Docker and QEMU user-mode emulation. It is +designed to be run **from the project root**. + +### Supported architectures + +| Argument | Target | Endianness | QEMU binary | +|---|---|---|---| +| `armhf` | ARM hard-float (32-bit) | Little | `qemu-arm-static` | +| `i386` | x86 32-bit | Little | `qemu-i386-static` | +| `powerpc` | PowerPC 32-bit | Big | `qemu-ppc` | +| `riscv64` | RISC-V 64-bit | Little | `qemu-riscv64-static` | +| `s390x` | IBM Z (64-bit) | Big | `qemu-s390x-static` | + +### Synopsis + +```bash +# From the project root +.devcontainer/run-tests.sh +``` + +### How it works + +The script has two phases controlled by a second (internal) argument: + +1. **Outside the container** (no second argument): + * Builds a Docker image from `.devcontainer//Dockerfile`. + * Starts a container, bind-mounting the project at `/workspaces/etl`. + * Re-invokes itself *inside* the container with the `inside_container` + flag. + +2. **Inside the container** (`inside_container`): + * Creates `build-` and runs CMake with the appropriate cross- + compilation toolchain file + (`.devcontainer//toolchain-.cmake`). + * Builds with `cmake --build .` using all available cores. + * Runs the test suite via `ctest --output-on-failure`. + +The toolchain files set `CMAKE_CROSSCOMPILING_EMULATOR` so that CTest can +run the binary transparently through QEMU. + +### Example + +```bash +# Build & run the armhf test suite +.devcontainer/run-tests.sh armhf +``` + +The cross-arch containers build with the following fixed settings: + +* C++23, No STL, sanitizer off, optimisation -O0. + +--- + +## Dev Containers for Native Compilers + +The `.devcontainer/` directory also provides Dev Container definitions for a +wide range of **native** (x86_64) compiler versions. These are intended for +use with **VS Code Dev Containers** or **GitHub Codespaces**. + +| Directory | Compiler | +|---|---| +| `gcc09` – `gcc15` | GCC 9 through 15 | +| `clang7` – `clang21` | Clang 7 through 21 | + +Each subdirectory contains a `devcontainer.json` that references the shared +`Dockerfile` (`.devcontainer/Dockerfile`) and passes the appropriate base +Docker image via the `BASE_IMAGE_NAME` build argument (e.g. `gcc:15`). + +The default Dev Container (`.devcontainer/devcontainer.json`) uses the +Microsoft C++ dev-container base image. + +To use one of these containers: + +1. Open the repository in VS Code. +2. **Ctrl+Shift+P → Dev Containers: Reopen in Container** and select the + desired configuration (e.g. *Gcc 15*). +3. Use `test/run-tests.sh` inside the container as described above. + +--- + +## CMake Options Reference + +When invoking CMake for the test suite (source directory is `test/`), the +following `-D` options control the build: + +| Option | Type | Description | +|---|---|---| +| `BUILD_TESTS` | `BOOL` | Must be `ON` to compile the test binary. | +| `NO_STL` | `BOOL` | Build without the C++ Standard Library. | +| `ETL_CXX_STANDARD` | `STRING` | C++ standard: `11`, `14`, `17`, `20`, `23`. | +| `ETL_OPTIMISATION` | `STRING` | Compiler optimisation flag, e.g. `-O0`. | +| `ETL_ENABLE_SANITIZER` | `BOOL` | Enable address / undefined-behaviour sanitizers. | +| `ETL_USE_TYPE_TRAITS_BUILTINS` | `BOOL` | Use compiler built-in type traits. | +| `ETL_USER_DEFINED_TYPE_TRAITS` | `BOOL` | Use user-defined type traits. | +| `ETL_FORCE_TEST_CPP03_IMPLEMENTATION` | `BOOL` | Force the C++03 code paths even on newer standards. | +| `ETL_MESSAGES_ARE_NOT_VIRTUAL` | `BOOL` | Use non-virtual message types. | +| `ETL_USE_BUILTIN_MEM_FUNCTIONS` | `BOOL` | Use built-in memory functions in No-STL mode. | +| `CMAKE_TOOLCHAIN_FILE` | `PATH` | Toolchain file for cross-compilation. | + +### Minimal manual build example + +```bash +cd test +mkdir build && cd build +cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_CXX_STANDARD=20 .. +cmake --build . -j$(nproc) +ctest -V +``` + +--- + +## CI Checks (GitHub Actions) + +Every push or pull request to `master`, `development`, or `pull-request/*` +branches triggers a comprehensive set of GitHub Actions workflows defined in +`.github/workflows/`. + +### Workflow matrix + +| Workflow file | Compiler | Standard | Notes | +|---|---|---|---| +| `gcc-c++11.yml` | GCC | C++11 | STL, No STL, Force C++03 | +| `gcc-c++14.yml` | GCC | C++14 | STL, No STL, Force C++03 | +| `gcc-c++17.yml` | GCC | C++17 | STL, No STL, Force C++03 | +| `gcc-c++20.yml` | GCC | C++20 | STL, No STL, Force C++03 | +| `gcc-c++23.yml` | GCC | C++23 | STL, No STL, Force C++03 | +| `clang-c++11.yml` | Clang | C++11 | STL, No STL, Force C++03 | +| `clang-c++14.yml` | Clang | C++14 | STL, No STL, Force C++03 | +| `clang-c++17.yml` | Clang | C++17 | STL, No STL, Force C++03 | +| `clang-c++20.yml` | Clang | C++20 | STL, No STL, Force C++03 | +| `clang-c++23.yml` | Clang | C++23 | STL, No STL, Force C++03 | +| `gcc-syntax-checks.yml` | GCC | C++03 – C++23 | Compilation-only syntax checks (no tests run) | +| `clang-syntax-checks.yml` | Clang | C++03 – C++23 | Compilation-only syntax checks (no tests run) | +| `msvc.yml` | MSVC 2022 | C++17 | Windows, STL & No STL | +| `gcc-c++23-armhf.yml` | GCC cross | C++23 | armhf via QEMU | +| `gcc-c++23-i386.yml` | GCC cross | C++23 | i386 via QEMU | +| `gcc-c++23-powerpc.yml` | GCC cross | C++23 | powerpc via QEMU | +| `gcc-c++23-riscv64.yml` | GCC cross | C++23 | RISC-V 64 via QEMU | +| `gcc-c++23-s390x.yml` | GCC cross | C++23 | s390x via QEMU | +| `coverage.yml` | GCC | — | Generates lcov coverage report, deploys to GitHub Pages | +| `generator.yml` | — | — | Runs the code generator | +| `platformio-update.yml` | — | — | PlatformIO registry update | + +### Typical CI job structure + +Each compiler/standard workflow follows the same pattern: + +1. **Checkout** – `actions/checkout@v4`. +2. **Build** – set `CC`/`CXX`, call `cmake` with the appropriate `-D` flags, + then `make -j`. +3. **Run tests** – execute `./test/etl_tests -v` (or `ctest -V` for cross- + arch jobs). + +The cross-architecture CI jobs additionally install a cross-compiler +toolchain and QEMU inside a `debian:trixie` container, use the matching +toolchain file from `.devcontainer//`, and run tests via CTest (which +delegates to QEMU through `CMAKE_CROSSCOMPILING_EMULATOR`). + +### Branches tested + +* `master` +* `development` +* `pull-request/*` + +All workflows run on both `push` and `pull_request` events (types: opened, +synchronize, reopened). + +--- + +## Appveyor (Windows / MSVC) + +The `appveyor.yml` at the repository root provides additional Windows CI +using **Visual Studio 2022**. It builds the `master` branch only. + +Configurations tested: + +* Debug MSVC C++14 +* Debug MSVC C++14 – No STL +* Debug MSVC C++17 +* Debug MSVC C++17 – No STL +* Debug MSVC C++20 +* Debug MSVC C++20 – No STL + +The build uses the VS 2022 solution file at `test/vs2022/etl.vcxproj`. + +--- + +## Code Coverage + +The `coverage.yml` GitHub Actions workflow generates an **lcov** coverage +report: + +1. Runs `test/run-coverage.sh` which builds and tests with GCC coverage + flags. +2. Uploads the HTML report as a build artifact (retained for 30 days). +3. On pushes to `master`, deploys the report to **GitHub Pages**. + +To generate coverage locally: + +```bash +cd test +./run-coverage.sh +# Open test/build-coverage/coverage/index.html +``` + +--- + +## Generator Tests + +The script **`scripts/generator_test.py`** verifies that the code generators +in `include/etl/generators/` produce output matching the checked-in header +files in `include/etl/private/`. + +ETL uses [Cog](https://nedbatchelder.com/code/cog/) to generate certain +repetitive header files (e.g. `delegate.h`, `message_packet.h`). The +generator templates live in `include/etl/generators/*_generator.h` and the +generated output is committed to `include/etl/private/*.h`. This test +ensures the two stay in sync. + +### Prerequisites + +* **Python 3** +* **cogapp** – install via `pip install cogapp` + +### Synopsis + +```bash +python3 scripts/generator_test.py +``` + +### What the script does + +1. Iterates over every `*_generator.h` file in `include/etl/generators/`. +2. Runs Cog on each generator, outputting to `build/generator_tmp/`. +3. Compares each generated file against the corresponding file in + `include/etl/private/`. +4. Reports success if all files match, or failure if any differ. + +The script exits with code `0` on success and `1` on failure. + +### CI integration + +The `generator.yml` GitHub Actions workflow runs this script automatically +on pushes and pull requests to verify generator consistency. diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 162deaf9..b1d570e2 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -558,7 +558,8 @@ namespace etl { while (first != last) { - *first = value; + // This cast is necessary because the signedness can differ + *first = static_cast::value_type>(value); ++first; } } diff --git a/include/etl/bip_buffer_spsc_atomic.h b/include/etl/bip_buffer_spsc_atomic.h index 0901af80..783e3ea6 100644 --- a/include/etl/bip_buffer_spsc_atomic.h +++ b/include/etl/bip_buffer_spsc_atomic.h @@ -404,7 +404,7 @@ namespace etl //************************************************************************* void read_commit(const span& reserve) { - size_type rindex = etl::distance(p_buffer, reserve.data()); + size_type rindex = static_cast(etl::distance(p_buffer, reserve.data())); apply_read_reserve(rindex, reserve.size()); } @@ -438,7 +438,7 @@ namespace etl //************************************************************************* void write_commit(const span& reserve) { - size_type windex = etl::distance(p_buffer, reserve.data()); + size_type windex = static_cast(etl::distance(p_buffer, reserve.data())); apply_write_reserve(windex, reserve.size()); } diff --git a/include/etl/ipool.h b/include/etl/ipool.h index c71254bf..e53c4014 100644 --- a/include/etl/ipool.h +++ b/include/etl/ipool.h @@ -644,7 +644,7 @@ namespace etl // in debug. #if ETL_IS_DEBUG_BUILD // Is the address on a valid object boundary? - bool is_valid_address = ((distance % Item_Size) == 0); + bool is_valid_address = ((static_cast(distance) % Item_Size) == 0); #else bool is_valid_address = true; #endif diff --git a/include/etl/iterator.h b/include/etl/iterator.h index 8a09e7c0..8394c5f9 100644 --- a/include/etl/iterator.h +++ b/include/etl/iterator.h @@ -959,11 +959,16 @@ namespace etl ETL_CONSTANT bool is_random_access_iterator_concept::value; #if ETL_NOT_USING_STL || ETL_CPP11_NOT_SUPPORTED + #if ETL_CPP11_SUPPORTED //***************************************************************************** /// Get the 'begin' iterator. + /// Note: Contains SFINAE guard, ensuring they only participate in overload + /// resolution when TContainer actually has the corresponding member function. + /// This prevents ADL from matching these templates when std::ranges::begin + /// performs an unqualified call on etl:: iterator types. ///\ingroup container //***************************************************************************** - template + template ().begin())> > ETL_CONSTEXPR typename TContainer::iterator begin(TContainer& container) { return container.begin(); @@ -973,7 +978,7 @@ namespace etl /// Get the 'begin' const_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().begin())> > ETL_CONSTEXPR typename TContainer::const_iterator begin(const TContainer& container) { return container.begin(); @@ -983,7 +988,7 @@ namespace etl /// Get the 'begin' const_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().cbegin())> > ETL_CONSTEXPR typename TContainer::const_iterator cbegin(const TContainer& container) { return container.cbegin(); @@ -993,7 +998,7 @@ namespace etl /// Get the 'end' iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().end())> > ETL_CONSTEXPR typename TContainer::iterator end(TContainer& container) { return container.end(); @@ -1003,7 +1008,7 @@ namespace etl /// Get the 'end' const_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().end())> > ETL_CONSTEXPR typename TContainer::const_iterator end(const TContainer& container) { return container.end(); @@ -1013,11 +1018,73 @@ namespace etl /// Get the 'end' const_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().cend())> > ETL_CONSTEXPR typename TContainer::const_iterator cend(const TContainer& container) { return container.cend(); } + #else + // C++03 fallback: no SFINAE guards needed since std::ranges does not exist. + //***************************************************************************** + /// Get the 'begin' iterator. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::iterator begin(TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_iterator begin(const TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_iterator cbegin(const TContainer& container) + { + return container.cbegin(); + } + + //***************************************************************************** + /// Get the 'end' iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::iterator end(TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_iterator end(const TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_iterator cend(const TContainer& container) + { + return container.cend(); + } + #endif //***************************************************************************** /// Get the 'begin' pointer for an array. @@ -1081,11 +1148,13 @@ namespace etl #endif #if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED + #if ETL_CPP11_SUPPORTED //***************************************************************************** /// Get the 'begin' reverse_iterator for a container. + /// Note: Contains SFINAE guard (see begin/end above for rationale). ///\ingroup container //***************************************************************************** - template + template ().rbegin())> > ETL_CONSTEXPR typename TContainer::reverse_iterator rbegin(TContainer& container) { return container.rbegin(); @@ -1095,7 +1164,7 @@ namespace etl /// Get the 'begin' reverse_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().rbegin())> > ETL_CONSTEXPR typename TContainer::const_reverse_iterator rbegin(const TContainer& container) { return container.rbegin(); @@ -1105,7 +1174,7 @@ namespace etl /// Get the 'begin' reverse_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().crbegin())> > ETL_CONSTEXPR typename TContainer::const_reverse_iterator crbegin(const TContainer& container) { return container.crbegin(); @@ -1115,7 +1184,7 @@ namespace etl /// Get the 'end' reverse_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().rend())> > ETL_CONSTEXPR typename TContainer::reverse_iterator rend(TContainer& container) { return container.rend(); @@ -1125,7 +1194,7 @@ namespace etl /// Get the 'end' reverse_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().rend())> > ETL_CONSTEXPR typename TContainer::const_reverse_iterator rend(const TContainer& container) { return container.rend(); @@ -1135,11 +1204,73 @@ namespace etl /// Get the 'end' reverse_iterator for a container. ///\ingroup container //***************************************************************************** - template + template ().crend())> > ETL_CONSTEXPR typename TContainer::const_reverse_iterator crend(const TContainer& container) { return container.crend(); } + #else + // C++03 fallback: no SFINAE guards needed since std::ranges does not exist. + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::reverse_iterator rbegin(TContainer& container) + { + return container.rbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_reverse_iterator rbegin(const TContainer& container) + { + return container.rbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_reverse_iterator crbegin(const TContainer& container) + { + return container.crbegin(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::reverse_iterator rend(TContainer& container) + { + return container.rend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_reverse_iterator rend(const TContainer& container) + { + return container.rend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template + typename TContainer::const_reverse_iterator crend(const TContainer& container) + { + return container.crend(); + } + #endif //***************************************************************************** /// Get the 'begin' reverse_iterator for an array. diff --git a/include/etl/numeric.h b/include/etl/numeric.h index 633755e5..cc8752d3 100644 --- a/include/etl/numeric.h +++ b/include/etl/numeric.h @@ -130,11 +130,11 @@ namespace etl { if (a > b) { - return b + (etl::distance(b, a) / 2U); + return b + (etl::distance(b, a) / 2); } else { - return a + (etl::distance(a, b) / 2U); + return a + (etl::distance(a, b) / 2); } } @@ -151,11 +151,11 @@ namespace etl { if (a > b) { - return b + (etl::distance(b, a) / 2U); + return b + (etl::distance(b, a) / 2); } else { - return a + (etl::distance(a, b) / 2U); + return a + (etl::distance(a, b) / 2); } } @@ -172,7 +172,7 @@ namespace etl || etl::is_same::iterator_category, ETL_OR_STD::bidirectional_iterator_tag>::value)), int>::type = 0) { - etl::advance(a, etl::distance(a, b) / 2U); + etl::advance(a, etl::distance(a, b) / 2); return a; } diff --git a/include/etl/private/bitset_new.h b/include/etl/private/bitset_new.h index 89d4a0a8..19d21794 100644 --- a/include/etl/private/bitset_new.h +++ b/include/etl/private/bitset_new.h @@ -1078,7 +1078,7 @@ namespace etl /// Extract an value from multiple elements. //************************************************************************* template - static ETL_CONSTEXPR14 typename etl::make_unsigned::type extract_from_multiple_elements(const element_type* pbuffer, int element_index, + static ETL_CONSTEXPR14 typename etl::make_unsigned::type extract_from_multiple_elements(const element_type* pbuffer, size_t element_index, size_t active_bits_in_msb, size_t length) ETL_NOEXCEPT { typedef typename etl::make_unsigned::type unsigned_t; @@ -1133,8 +1133,8 @@ namespace etl unsigned_t value(0); - const int Msb_Element_Index = (position + length - 1) >> etl::log2::value; - const int Lsb_Element_Index = position >> etl::log2::value; + const size_t Msb_Element_Index = (position + length - 1) >> etl::log2::value; + const size_t Lsb_Element_Index = position >> etl::log2::value; // Is the value contained within one element? if (Msb_Element_Index == Lsb_Element_Index) @@ -1150,7 +1150,7 @@ namespace etl size_t active_bits_in_msb = (position + length) - (static_cast(Msb_Element_Index) * Bits_Per_Element); // Start with index of the element containing the msb. - int element_index = Msb_Element_Index; + size_t element_index = Msb_Element_Index; value = extract_from_multiple_elements(pbuffer, element_index, active_bits_in_msb, length); } @@ -1169,7 +1169,7 @@ namespace etl { typedef typename etl::make_unsigned::type unsigned_t; - const int Element_Index = (Position + Length - 1) >> etl::log2::value; + const size_t Element_Index = (Position + Length - 1) >> etl::log2::value; const unsigned_t Mask = etl::lsb_mask::value; const unsigned_t Shift = Position % Bits_Per_Element; @@ -1186,7 +1186,7 @@ namespace etl extract_from_buffer(const_pointer pbuffer) { // Start with index of the element containing the msb. - const int Msb_Element_Index = (Position + Length - 1) >> etl::log2::value; + const size_t Msb_Element_Index = (Position + Length - 1) >> etl::log2::value; // Get the number of active bits in the first element const size_t Active_Bits_In_Msb = ((Position + Length - 1) % Bits_Per_Element) + 1; diff --git a/include/etl/private/diagnostic_sign_conversion_push.h b/include/etl/private/diagnostic_sign_conversion_push.h new file mode 100644 index 00000000..50c0532e --- /dev/null +++ b/include/etl/private/diagnostic_sign_conversion_push.h @@ -0,0 +1,44 @@ +///\file + +/****************************************************************************** +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. +******************************************************************************/ + +/* + * The header include guard has been intentionally omitted. + * This file is intended to evaluated multiple times by design. + */ + +#if defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if defined(__clang__) || defined(__llvm__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-conversion" +#endif diff --git a/include/etl/vector.h b/include/etl/vector.h index ba10ac79..f014ab2f 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -479,7 +479,9 @@ namespace etl { ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + #include "private/diagnostic_sign_conversion_push.h" ::new (p_end) T(etl::forward(args)...); + #include "private/diagnostic_pop.h" ++p_end; ETL_INCREMENT_DEBUG_COUNT; return back(); @@ -668,7 +670,9 @@ namespace etl (*position_).~T(); } + #include "private/diagnostic_sign_conversion_push.h" ::new (p) T(etl::forward(args)...); + #include "private/diagnostic_pop.h" return position_; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9f325bb9..99792fce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -385,6 +385,7 @@ option(ETL_NO_STL "No STL" OFF) set(EXTRA_COMPILE_OPTIONS "" CACHE STRING "Additional compiler options") set(EXTRA_LINK_OPTIONS "" CACHE STRING "Additional linker options") set(EXTRA_LINK_LIBS "" CACHE STRING "Additional libraries to link") +set(EXTRA_TESTING_FLAGS "" CACHE STRING "Additional testing flags for ctest") if (ETL_CXX_STANDARD MATCHES "98") message(STATUS "Compiling for C++98") @@ -538,7 +539,7 @@ target_link_libraries(etl_tests PRIVATE UnitTestpp ${EXTRA_LINK_LIBS}) enable_testing() # Enable the 'make test' CMake target using the executable defined above -add_test(NAME etl_unit_tests COMMAND etl_tests) +add_test(NAME etl_unit_tests COMMAND etl_tests ${EXTRA_TESTING_FLAGS}) # Since ctest will only show you the results of the single executable # define a target that will output all of the failing or passing tests diff --git a/test/run-tests.sh b/test/run-tests.sh index 06e39400..d5fd0567 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -2,6 +2,8 @@ shopt -s xpg_echo +set -e + clear export ASAN_OPTIONS=symbol_line=1 @@ -54,7 +56,7 @@ PrintHelp() echo "$HelpColour" echo "----------------------------------------------------------------------------------------------------------" echo " Syntax : ./run-tests.sh " - echo " C++ Standard : 11, 14, 17, 20 or 23 " + echo " C++ Standard : 11, 14, 17, 20, 23 or all " echo " Optimisation : 0, 1, 2 or 3. Default = 0 " echo " Threads : Number of threads to use. Default = 4 " echo " Sanitizer : s enables sanitizer checks, n disables. Default disabled " @@ -115,15 +117,17 @@ TestsCompleted() # Set the language standard. #****************************************************************************** if [ "$1" = "11" ]; then - cxx_standard="11" + cxx_standards="11" elif [ "$1" = "14" ]; then - cxx_standard="14" + cxx_standards="14" elif [ "$1" = "17" ]; then - cxx_standard="17" + cxx_standards="17" elif [ "$1" = "20" ]; then - cxx_standard="20" + cxx_standards="20" elif [ "$1" = "23" ]; then - cxx_standard="23" + cxx_standards="23" +elif [ "$1" = "all" ]; then + cxx_standards="11 14 17 20 23" else PrintHelp exit @@ -180,10 +184,10 @@ fi #****************************************************************************** if [ "$6" = "v" ]; then verbose="On" - verbose_flag="-v" + verbose_cmake_flag="-DEXTRA_TESTING_FLAGS=-v" else verbose="Off" - verbose_flag="" + verbose_cmake_flag="" fi #****************************************************************************** @@ -196,66 +200,66 @@ etl_version=$(echo $etl_version_raw | sed -e 's/\r//g') # Remove trailing \r # Get the compiler versions #****************************************************************************** -while read i ; do - CC=`echo $i | cut -d, -f1 | sed -e 's/ *$//'` - MSG=`echo $i | cut -d, -f2 | sed -e 's/ *$//'` - DIR=`echo $i | cut -d, -f3 | sed -e 's/ *$//'` - CMD=`echo $i | cut -d, -f4 | sed -e 's/ *$//'` +for cxx_standard in $cxx_standards ; do + while read i ; do + CC=`echo $i | cut -d, -f1 | sed -e 's/ *$//'` + MSG=`echo $i | cut -d, -f2 | sed -e 's/ *$//'` + DIR=`echo $i | cut -d, -f3 | sed -e 's/ *$//'` + CMD=`echo $i | cut -d, -f4 | sed -e 's/ *$//'` - if [ "$compiler_enabled" = "$CC" ] || [ "$compiler_enabled" = "All compilers" ]; then - if [ "$CC" = "gcc" ] ; then - compiler=$(g++ --version | grep g++) - else - compiler=$(clang++ --version | grep clang) + if [ "$compiler_enabled" = "$CC" ] || [ "$compiler_enabled" = "All compilers" ]; then + if [ "$CC" = "gcc" ] ; then + compiler=$(g++ --version | grep g++) + else + compiler=$(clang++ --version | grep clang) + fi + OLD_DIR=`pwd` + cd $DIR + mkdir -p build-make || exit 1 + cd build-make || exit 1 + echo "ETL Tests" > log.txt + SetConfigurationName "$MSG" + PrintHeader + $CMD + if cmake --build .; then + PassedCompilation + else + FailedCompilation + exit 1 + fi + if ctest -V; then + PassedTests + else + FailedTests + exit 1 + fi + cd .. + rm -rf build-make + cd $OLD_DIR fi - OLD_DIR=`pwd` - cd $DIR - mkdir -p build-make || exit 1 - cd build-make || exit 1 - echo "ETL Tests" > log.txt - SetConfigurationName "$MSG" - PrintHeader - $CMD - cmake --build . - if [ $? -eq 0 ]; then - PassedCompilation - else - FailedCompilation - exit $? - fi - ./etl_tests $verbose_flag - if [ $? -eq 0 ]; then - PassedTests - else - FailedTests - exit $? - fi - cd .. - rm -rf build-make - cd $OLD_DIR - fi -done <<-EOF -gcc ,STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,STL - Non-virtual messages,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=ON .. -gcc ,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON .. -clang,STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON .. -gcc ,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. + done <<-EOF +gcc ,STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,STL - Non-virtual messages,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=ON $verbose_cmake_flag .. +gcc ,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON $verbose_cmake_flag .. +clang,STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON $verbose_cmake_flag .. +gcc ,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. EOF +done TestsCompleted diff --git a/test/test_bit_stream.cpp b/test/test_bit_stream.cpp index 2c515224..d7e1cdbc 100644 --- a/test/test_bit_stream.cpp +++ b/test/test_bit_stream.cpp @@ -869,7 +869,7 @@ namespace TEST(put_get_multiple_full_size) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085L; // 0x5AA55AA5 diff --git a/test/test_bit_stream_writer_big_endian.cpp b/test/test_bit_stream_writer_big_endian.cpp index 893a5f04..c22e66db 100644 --- a/test/test_bit_stream_writer_big_endian.cpp +++ b/test/test_bit_stream_writer_big_endian.cpp @@ -614,7 +614,7 @@ namespace TEST(test_write_multiple_full_size) { char c1 = 90; // 0x5A - char c2 = -91; // 0xA5 + char c2 = static_cast(-91); // 0xA5 unsigned short s1 = 4660; // 0x1234 unsigned short s2 = 22136; // 0x5678 int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF @@ -660,7 +660,7 @@ namespace TEST(test_write_multiple_variable_size) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits @@ -705,7 +705,7 @@ namespace Accumulator accumulator; char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660U; // 0x1234 13 bits unsigned short s2 = 22136U; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits diff --git a/test/test_bit_stream_writer_little_endian.cpp b/test/test_bit_stream_writer_little_endian.cpp index 1d6f85d5..07348253 100644 --- a/test/test_bit_stream_writer_little_endian.cpp +++ b/test/test_bit_stream_writer_little_endian.cpp @@ -702,7 +702,7 @@ namespace TEST(test_write_multiple_full_size) { char c1 = 90; // 0x5A - char c2 = -91; // 0xA5 + char c2 = static_cast(-91); // 0xA5 unsigned short s1 = 4660; // 0x1234 unsigned short s2 = 22136; // 0x5678 int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF @@ -748,7 +748,7 @@ namespace TEST(test_write_multiple_variable_size) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits @@ -791,7 +791,7 @@ namespace TEST(test_write_multiple_variable_size_with_callback) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits diff --git a/test/test_byte_stream.cpp b/test/test_byte_stream.cpp index 29570ac1..06b2a453 100644 --- a/test/test_byte_stream.cpp +++ b/test/test_byte_stream.cpp @@ -1026,7 +1026,7 @@ namespace TEST(write_read_multiple_big_endian) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085; // 0x5AA55AA5 @@ -1089,7 +1089,7 @@ namespace TEST(write_read_multiple_little_endian) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085; // 0x5AA55AA5 diff --git a/test/test_format.cpp b/test/test_format.cpp index 591d83f1..16b0ac1b 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -214,7 +214,7 @@ namespace etl::string<100> s; CHECK_EQUAL("1.0", test_format(s, "{}", 1.0)); - CHECK_EQUAL("1.234564", test_format(s, "{}", 1.234564)); + CHECK_EQUAL("1.234563", test_format(s, "{}", 1.234563)); CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678)); CHECK_EQUAL("1.5", test_format(s, "{}", 1.5)); } diff --git a/test/test_hash.cpp b/test/test_hash.cpp index 73a616f8..d1acd6b1 100644 --- a/test/test_hash.cpp +++ b/test/test_hash.cpp @@ -149,7 +149,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0xEC6A8D69UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0xEC6A8D69UL, hash); + } + else + { + CHECK_EQUAL(0x5F69FD19UL, hash); + } } if (ETL_PLATFORM_64BIT) @@ -165,7 +172,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0xEC6A8D69UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0xEC6A8D69UL, hash); + } + else + { + CHECK_EQUAL(0x5F69FD19UL, hash); + } } if (ETL_PLATFORM_64BIT) @@ -177,7 +191,7 @@ namespace //************************************************************************* TEST(test_hash_float) { - size_t hash = etl::hash()((float)(1.2345)); + size_t hash = etl::hash()(1.2345f); if (ETL_PLATFORM_32BIT) { @@ -204,7 +218,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0x86FBF224UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0x86FBF224UL, hash); + } + else + { + CHECK_EQUAL(0xD1F372DEUL, hash); + } } if (ETL_PLATFORM_64BIT) diff --git a/test/test_histogram.cpp b/test/test_histogram.cpp index 92857deb..a68970f9 100644 --- a/test/test_histogram.cpp +++ b/test/test_histogram.cpp @@ -166,7 +166,7 @@ namespace for (size_t i = 0UL; i < output1.size(); ++i) { - CHECK_EQUAL(int(output1[i]), int(histogram[i])); + CHECK_EQUAL(static_cast(output1[i]), static_cast(histogram[static_cast(i)])); } } @@ -203,7 +203,7 @@ namespace for (size_t i = 0UL; i < output1.size(); ++i) { - CHECK_EQUAL(int(output1[i]), int(histogram[i - 4])); + CHECK_EQUAL(static_cast(output1[i]), static_cast(histogram[static_cast(i) - 4])); } } diff --git a/test/test_set.cpp b/test/test_set.cpp index 0fe643bf..2fb624d4 100644 --- a/test/test_set.cpp +++ b/test/test_set.cpp @@ -594,8 +594,8 @@ namespace for (size_t i = 0; i < MAX_SIZE; ++i) { - data_result = data.insert(i); - compare_result = compare_data.insert(i); + data_result = data.insert(static_cast(i)); + compare_result = compare_data.insert(static_cast(i)); // Check that both return successful return results CHECK_EQUAL(*data_result.first, *compare_result.first); @@ -608,8 +608,8 @@ namespace // not throw error for (size_t i = 0; i < MAX_SIZE; ++i) { - data_result = data.insert(i); - compare_result = compare_data.insert(i); + data_result = data.insert(static_cast(i)); + compare_result = compare_data.insert(static_cast(i)); // Check that both return successful return results CHECK_EQUAL(*data_result.first, *compare_result.first); From f858b8a72ddff1f16d6481f543bc4ccf8e177bbb Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 15 Apr 2026 11:27:57 +0200 Subject: [PATCH 11/27] Add installed dependencies for docker, documentation (#1377) * Add development tools to docker image python3-cogapp, clang-format, treefmt Add script to run development environment in docker container Document docker use in docs/docker.md --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- .devcontainer/Dockerfile | 24 +++- docs/docker.md | 289 +++++++++++++++++++++++++++++++++++++++ scripts/run-docker.sh | 18 +++ test/run-coverage.sh | 3 +- 4 files changed, 327 insertions(+), 7 deletions(-) create mode 100644 docs/docker.md create mode 100755 scripts/run-docker.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f51b1a16..c4765d45 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -36,15 +36,27 @@ RUN set -eux \ && apt-get -y install --no-install-recommends \ python3-full \ python3-pip \ + python3-cogapp \ git \ wget \ cmake \ - && rm -rf /var/lib/apt/lists/* \ - && if pip help install | grep -q '\-\-break-system-packages'; then \ - pip install --no-cache-dir --break-system-packages cogapp; \ - else \ - pip install --no-cache-dir cogapp; \ - fi + clang-format \ + clang-format-18 \ + lcov \ + && rm -rf /var/lib/apt/lists/* + +RUN set -eux; \ + VERSION="2.4.1"; \ + case "$(uname -m)" in \ + x86_64) ARCH="amd64"; SHA256="bdaa2c0fbee03e5c2f99e605d9419386ce5d558440baac2017398faada839e04" ;; \ + aarch64) ARCH="arm64"; SHA256="0a09e1f04a0f8a86fd4e709552613f5d82adf6bc72f0a4b5e217670894e79fbf" ;; \ + *) echo "Unsupported architecture: $(uname -m)"; exit 1 ;; \ + esac; \ + wget -O treefmt.tar.gz "https://github.com/numtide/treefmt/releases/download/v${VERSION}/treefmt_${VERSION}_linux_${ARCH}.tar.gz" \ + && echo "${SHA256} treefmt.tar.gz" | sha256sum -c \ + && tar xzf treefmt.tar.gz treefmt \ + && install -m 755 treefmt /usr/bin/treefmt \ + && rm treefmt.tar.gz treefmt RUN set -eux \ && echo "Pip version: " \ diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 00000000..2dc8d25d --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,289 @@ +# Docker for Development + +## Overview + +The ETL repository ships a set of Docker-based development environments under +`.devcontainer/`. They give every contributor an identical, reproducible toolchain +regardless of host operating system. Three flavours are provided: + +| Flavour | Path | Purpose | +|---|---|---| +| **Default** | `.devcontainer/` | Day-to-day development (Microsoft C++ dev-container base image) | +| **Compiler-specific** | `.devcontainer/gcc09/` … `.devcontainer/gcc15/`, `.devcontainer/clang7/` … `.devcontainer/clang21/` | Test against a specific GCC or Clang version | +| **s390x big-endian** | `.devcontainer/s390x/` | Cross-compile and run tests on an s390x target via QEMU | + +All containers include CMake, Make, Git, Python 3, cogapp (the code generator used +by ETL), clang-format 18, and treefmt. + +## Prerequisites + +- **Docker** (or Docker Desktop) – any recent version that supports `docker build` + and `docker run`. +- **VS Code** with the + [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + extension (optional, but recommended for the smoothest experience). +- **Git** – to clone the repository. + +## Quick Start + +### Using the helper script + +The fastest way to get a shell inside the default container from the project root: + +```bash +./scripts/run-docker.sh +``` + +This script performs two steps: + +1. **Builds** the image from `.devcontainer/Dockerfile` and tags it `etl`. +2. **Runs** an interactive container that bind-mounts the repository at + `/home/vscode/etl` so that edits made inside the container are visible on + the host (and vice versa). + +You are dropped into a Bash shell as the `vscode` user with the working +directory set to the repository root. + +### Using VS Code Dev Containers + +1. Open the repository folder in VS Code. +2. When prompted, click **Reopen in Container** – or run the command + *Dev Containers: Reopen in Container* from the command palette. +3. VS Code reads `.devcontainer/devcontainer.json`, builds the image, and + attaches to the running container automatically. + +To open a **specific compiler variant** instead, run +*Dev Containers: Open Folder in Container…* and pick the sub-folder (e.g. +`.devcontainer/gcc14/`), or use the command palette action +*Dev Containers: Open Named Container Configuration…* and select the desired +name (e.g. "Gcc 14", "Clang 18"). + +## Default Development Container + +The file `.devcontainer/Dockerfile` is a multi-purpose image used by the +default configuration **and** by every compiler-specific variant (they simply +override the `BASE_IMAGE_NAME` build argument). + +### Base image + +```text +mcr.microsoft.com/devcontainers/cpp:2 +``` + +The exact digest is pinned in `devcontainer.json` so that builds are +reproducible even if the upstream tag is updated. + +### Installed tools + +The Dockerfile installs the following on top of the base image: + +| Tool | Purpose | +|---|---| +| `python3`, `pip` | Runtime for helper scripts | +| `python3-cogapp` / `cogapp` | ETL code generator | +| `git` | Version control | +| `wget` | Downloading additional tooling | +| `cmake`, `make` | Build system | +| `clang-format` (v18) | Source formatting (see [source-formatting.md](source-formatting.md)) | +| `treefmt` (v2.4.1) | Single-command formatting wrapper | + +### Reproducible builds with Debian snapshots + +The default configuration sets the build argument +`DEBIAN_SNAPSHOT=20260223T000000Z`. When this value is not `"none"`, the +Dockerfile rewrites the APT sources to point at +`snapshot.debian.org/archive/debian/`, ensuring that every +contributor installs identical package versions. Compiler-specific variants +that are based on upstream `gcc:*` or `silkeh/clang:*` images set +`DEBIAN_SNAPSHOT=none` because those images manage their own package sources. + +## Compiler-Specific Containers + +Each sub-folder under `.devcontainer/` contains a `devcontainer.json` that +reuses the **same** `Dockerfile` (`../Dockerfile`) but overrides the +`BASE_IMAGE_NAME` build argument to select a different compiler. + +### GCC variants + +| Folder | Base image | Name | +|---|---|---| +| `gcc09/` | `gcc:9` | Gcc 09 | +| `gcc10/` | `gcc:10` | Gcc 10 | +| `gcc11/` | `gcc:11` | Gcc 11 | +| `gcc12/` | `gcc:12` | Gcc 12 | +| `gcc13/` | `gcc:13` | Gcc 13 | +| `gcc14/` | `gcc:14` | Gcc 14 | +| `gcc15/` | `gcc:15` | Gcc 15 | + +### Clang variants + +| Folder | Base image | Name | +|---|---|---| +| `clang7/` | `silkeh/clang:7` | Clang 7 | +| `clang8/` | `silkeh/clang:8` | Clang 8 | +| `clang9/` | `silkeh/clang:9` | Clang 9 | +| `clang10/` | `silkeh/clang:10` | Clang 10 | +| `clang11/` | `silkeh/clang:11` | Clang 11 | +| `clang12/` | `silkeh/clang:12` | Clang 12 | +| `clang13/` | `silkeh/clang:13` | Clang 13 | +| `clang14/` | `silkeh/clang:14` | Clang 14 | +| `clang15/` | `silkeh/clang:15` | Clang 15 | +| `clang16/` | `silkeh/clang:16` | Clang 16 | +| `clang17/` | `silkeh/clang:17` | Clang 17 | +| `clang18/` | `silkeh/clang:18` | Clang 18 | +| `clang19/` | `silkeh/clang:19` | Clang 19 | +| `clang20/` | `silkeh/clang:20` | Clang 20 | +| `clang21/` | `silkeh/clang:21` | Clang 21 | + +All compiler-specific variants set `DEBIAN_SNAPSHOT` to `"none"` because they +rely on the upstream image's own package sources. + +## s390x Big-Endian Cross-Compilation + +The `s390x` container lives in `.devcontainer/s390x/` and has its **own** +Dockerfile (it does not reuse the default one). It is based on +`debian:trixie` and installs: + +- QEMU user-mode emulation (`qemu-user-static`, `qemu-user`, `binfmt-support`) +- s390x cross-compilation toolchain (`gcc-s390x-linux-gnu`, + `g++-s390x-linux-gnu`) +- CMake, Make, Ninja, Git, wget + +### Container setup + +Open `.devcontainer/s390x/` as a Dev Container in VS Code, or build manually: + +```bash +docker build -t etl-s390x .devcontainer/s390x +docker run -it --rm -v .:/workspaces/etl -w /workspaces/etl etl-s390x +``` + +### CMake toolchain + +A CMake toolchain file is provided at +`.devcontainer/s390x/toolchain-s390x.cmake`. It sets: + +- `CMAKE_SYSTEM_PROCESSOR` to `s390x` +- Cross-compilers `s390x-linux-gnu-gcc` / `g++` +- `CMAKE_CROSSCOMPILING_EMULATOR` to `/usr/bin/qemu-s390x-static` + +The VS Code Dev Container configuration already passes this toolchain file +via `cmake.configureArgs`, so CMake Tools picks it up automatically. + +### Running tests under QEMU + +Because the toolchain file sets `CMAKE_CROSSCOMPILING_EMULATOR`, CTest +automatically invokes `qemu-s390x-static` when running test binaries. +No extra flags are needed: + +```bash +cmake -S test -B build-s390x \ + -DCMAKE_TOOLCHAIN_FILE=.devcontainer/s390x/toolchain-s390x.cmake \ + -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_CXX_STANDARD=17 -G Ninja +cmake --build build-s390x +ctest --test-dir build-s390x +``` + +## Building and Running Tests + +Once inside any container (default, compiler-specific, or s390x) you can +build and run the ETL test suite. + +### Quick CMake workflow + +```bash +# Configure – build tests with C++17 +cmake -S test -B build -DBUILD_TESTS=ON -DETL_CXX_STANDARD=17 + +# Build +cmake --build build -j $(nproc) + +# Run tests +ctest --test-dir build +``` + +Change `DETL_CXX_STANDARD` to `11`, `14`, `17`, `20`, or `23` as needed. +Add `-DNO_STL=ON` to build without the standard library. + +### Using the run-tests script + +The repository also provides a convenience script in `test/`: + +```bash +cd test +./run-tests.sh [optimisation] [threads] [sanitizer] [compiler] [verbose] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ standard | `11`, `14`, `17`, `20`, `23` | *(required)* | +| Optimisation | `0`, `1`, `2`, `3` | `0` | +| Threads | any integer | `4` | +| Sanitizer | `s` (enable) / `n` (disable) | `n` | +| Compiler | `gcc` / `clang` | all | +| Verbose | `v` (enable) / `n` (disable) | `n` | + +Example – run C++17 tests at `-O2` with 8 threads using GCC: + +```bash +./run-tests.sh 17 2 8 n gcc n +``` + +## Formatting Inside the Container + +The default container ships with **clang-format 18** and **treefmt**. +See [source-formatting.md](source-formatting.md) for the full formatting guide. + +Quick reference: + +```bash +# Format all tracked C/C++ files with treefmt +treefmt + +# Or use clang-format directly via the wrapper +./scripts/clang-format-wrapper -i include/etl/*.h +``` + +The wrapper script `scripts/clang-format-wrapper` resolves the correct +clang-format binary (prefers `clang-format-18`, falls back to `clang-format` +after checking the major version). + +## Customisation + +To add extra packages or tools to the default container, edit +`.devcontainer/Dockerfile`. The image follows a straightforward +`apt-get install` pattern, so adding a new package is as simple as appending +it to the existing `apt-get` line. + +To create a new compiler variant: + +1. Create a folder under `.devcontainer/` (e.g. `.devcontainer/gcc16/`). +2. Add a `devcontainer.json` that references `"../Dockerfile"` and sets + `BASE_IMAGE_NAME` to the desired image (e.g. `gcc:16`). +3. Set `DEBIAN_SNAPSHOT` to `"none"` for upstream compiler images. + +Example: + +```jsonc +{ + "name": "Gcc 16", + "build": { + "dockerfile": "../Dockerfile", + "args": { + "BASE_IMAGE_NAME": "gcc:16", + "DEBIAN_SNAPSHOT": "none" + }, + "context": "../context" + } +} +``` + +## Troubleshooting + +| Symptom | Cause / Fix | +|---|---| +| `apt-get` fails with *"Release file … is not valid yet"* | The Debian snapshot timestamp is in the future relative to the build host clock. Either update `DEBIAN_SNAPSHOT` in `devcontainer.json` or set it to `"none"`. | +| `clang-format` reports the wrong version | The wrapper expects version **18**. Make sure the image installs `clang-format` (or `clang-format-18`) and that the binary is on `PATH`. | +| Permission errors on mounted files | The `run-docker.sh` script runs as user `vscode`. Ensure your host UID matches, or adjust the `--user` flag. | +| s390x tests crash immediately | Verify that `qemu-user-static` is installed and that `binfmt-support` is active. On some hosts you may need to register binfmt handlers with `docker run --privileged --rm tonistiigi/binfmt --install all`. | +| Build is very slow the first time | Docker is downloading and building the image from scratch. Subsequent builds use the layer cache and are much faster. | diff --git a/scripts/run-docker.sh b/scripts/run-docker.sh new file mode 100755 index 00000000..862cb436 --- /dev/null +++ b/scripts/run-docker.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Create docker image for development environment and enter container +# +# Run from project root directory +# + +set -e + +# Verify script is running from project root +if [ ! -d ".devcontainer" ]; then + echo "Error: This script must be run from the project root directory." >&2 + echo "The .devcontainer directory was not found." >&2 + exit 1 +fi + +docker build -t etl .devcontainer +docker run -it --rm -v "$(pwd)":/home/vscode/etl -u vscode -w /home/vscode/etl etl /bin/bash diff --git a/test/run-coverage.sh b/test/run-coverage.sh index ef977f17..bf074a49 100755 --- a/test/run-coverage.sh +++ b/test/run-coverage.sh @@ -76,6 +76,7 @@ for CXXSTD in 11 14 17 20 23; do done genhtml total.info --output-directory coverage --rc "genhtml_branch_coverage=1" --branch-coverage -t $COMPILER \ - --ignore-errors inconsistent + --ignore-errors inconsistent \ + --ignore-errors category cd .. From 5dc682b7ffec0fad9285b9ec6f0967019386d4ee Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 15 Apr 2026 15:53:29 +0200 Subject: [PATCH 12/27] Support for C++26 (#1375) Includes C++26 related infrastructure macros. Fixes compile errors when compiling under C++26. Initially supported C++26 features: - [[indeterminate]] - new 2022 ISO prefixes in ratio.h - atomic fetch_max() and fetch_min() - is_virtual_base_of - is_trivially_relocatable and trivially_relocate - saturation arithmetic: add_sat, sub_sat, mul_sat, div_sat, saturate_cast --- .github/workflows/clang-c++11.yml | 4 +- .github/workflows/clang-c++14.yml | 4 +- .github/workflows/clang-c++17.yml | 4 +- .github/workflows/clang-c++20.yml | 14 +- .github/workflows/clang-c++23.yml | 14 +- .github/workflows/clang-c++26.yml | 189 ++++++++ .github/workflows/clang-syntax-checks.yml | 132 ++++-- .github/workflows/gcc-c++11.yml | 4 +- .github/workflows/gcc-c++14.yml | 4 +- .github/workflows/gcc-c++17.yml | 4 +- .github/workflows/gcc-c++20.yml | 8 +- .github/workflows/gcc-c++23.yml | 8 +- .github/workflows/gcc-c++26.yml | 101 +++++ .github/workflows/gcc-syntax-checks.yml | 122 +++++- README.md | 6 +- include/etl/atomic/atomic_gcc_sync.h | 128 ++++++ include/etl/atomic/atomic_std.h | 181 ++++++-- include/etl/iterator.h | 82 +++- include/etl/memory.h | 111 +++++ include/etl/numeric.h | 278 ++++++++++++ include/etl/platform.h | 16 + include/etl/profiles/cpp20.h | 49 +++ include/etl/profiles/cpp20_no_stl.h | 50 +++ include/etl/profiles/cpp23.h | 50 +++ include/etl/profiles/cpp23_no_stl.h | 51 +++ include/etl/profiles/cpp26.h | 51 +++ include/etl/profiles/cpp26_no_stl.h | 52 +++ .../etl/profiles/determine_builtin_support.h | 18 + .../determine_compiler_language_support.h | 59 ++- include/etl/ratio.h | 24 +- include/etl/type_traits.h | 147 +++++++ test/CMakeLists.txt | 22 +- .../assert_function/CMakeLists.txt | 22 +- .../exceptions/CMakeLists.txt | 22 +- .../log_errors/CMakeLists.txt | 28 +- .../log_errors/test_error_handler.cpp | 6 +- .../log_errors_and_exceptions/CMakeLists.txt | 26 +- test/etl_initializer_list/CMakeLists.txt | 22 +- test/run-coverage.sh | 2 +- test/run-syntax-checks.sh | 260 +++++++++-- test/run-tests.sh | 6 +- test/syntax_check/CMakeLists.txt | 20 +- test/test_atomic.cpp | 66 +++ test/test_etl_traits.cpp | 5 +- test/test_memory.cpp | 320 ++++++++++++++ test/test_numeric.cpp | 406 ++++++++++++++++++ test/test_type_traits.cpp | 162 +++++++ 47 files changed, 3150 insertions(+), 210 deletions(-) create mode 100644 .github/workflows/clang-c++26.yml create mode 100644 .github/workflows/gcc-c++26.yml create mode 100644 include/etl/profiles/cpp20.h create mode 100644 include/etl/profiles/cpp20_no_stl.h create mode 100644 include/etl/profiles/cpp23.h create mode 100644 include/etl/profiles/cpp23_no_stl.h create mode 100644 include/etl/profiles/cpp26.h create mode 100644 include/etl/profiles/cpp26_no_stl.h diff --git a/.github/workflows/clang-c++11.yml b/.github/workflows/clang-c++11.yml index d511f5b7..6b73b7c1 100644 --- a/.github/workflows/clang-c++11.yml +++ b/.github/workflows/clang-c++11.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++14.yml b/.github/workflows/clang-c++14.yml index d06778b1..830832b5 100644 --- a/.github/workflows/clang-c++14.yml +++ b/.github/workflows/clang-c++14.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++17.yml b/.github/workflows/clang-c++17.yml index 9fb4611f..6ae2f4b9 100644 --- a/.github/workflows/clang-c++17.yml +++ b/.github/workflows/clang-c++17.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++20.yml b/.github/workflows/clang-c++20.yml index c68f9870..e246a795 100644 --- a/.github/workflows/clang-c++20.yml +++ b/.github/workflows/clang-c++20.yml @@ -32,7 +32,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -61,7 +61,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -90,7 +90,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -112,7 +112,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -134,7 +134,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -156,7 +156,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -178,7 +178,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++23.yml b/.github/workflows/clang-c++23.yml index 18817aaa..acd22a41 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -32,7 +32,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -61,7 +61,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -90,7 +90,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -112,7 +112,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -134,7 +134,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -156,7 +156,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -178,7 +178,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++26.yml b/.github/workflows/clang-c++26.yml new file mode 100644 index 00000000..5a2e9be0 --- /dev/null +++ b/.github/workflows/clang-c++26.yml @@ -0,0 +1,189 @@ +name: clang-c++26 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-clang-cpp26-linux-stl: + name: Clang C++26 Linux - STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-linux-no-stl: + name: Clang C++26 Linux - No STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-linux-stl-force-cpp03: + name: Clang C++26 Linux - STL - Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-linux-no-stl-force-cpp03: + name: Clang C++26 Linux - No STL - Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-stl: + name: Clang C++26 OSX - STL + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-no-stl: + name: Clang C++26 OSX - No STL + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-stl-force-cpp03: + name: Clang C++26 OSX - STL - Force C++03 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-no-stl-force-cpp03: + name: Clang C++26 OSX - No STL - Force C++03 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-syntax-checks.yml b/.github/workflows/clang-syntax-checks.yml index 700b2087..416ef290 100644 --- a/.github/workflows/clang-syntax-checks.yml +++ b/.github/workflows/clang-syntax-checks.yml @@ -23,10 +23,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp03-linux-No-STL: - name: Syntax Check - Clang C++03 Linux No STL + name: Syntax Check - Clang C++03 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -41,7 +41,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-STL: name: Syntax Check - Clang C++11 Linux STL @@ -59,10 +59,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-No-STL: - name: Syntax Check - Clang C++11 Linux No STL + name: Syntax Check - Clang C++11 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -77,7 +77,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-STL-Force-CPP03: name: Syntax Check - Clang C++11 Linux STL Force C++03 @@ -95,7 +95,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++11 Linux No STL Force C++03 @@ -113,7 +113,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-STL: name: Syntax Check - Clang C++14 Linux STL @@ -131,10 +131,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-No-STL: - name: Syntax Check - Clang C++14 Linux No STL + name: Syntax Check - Clang C++14 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -149,7 +149,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-STL-Force-CPP03: name: Syntax Check - Clang C++14 Linux STL Force C++03 @@ -167,7 +167,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++14 Linux No STL Force C++03 @@ -185,7 +185,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-STL: name: Syntax Check - Clang C++17 Linux STL @@ -203,10 +203,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-No-STL: - name: Syntax Check - Clang C++17 Linux No STL + name: Syntax Check - Clang C++17 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -221,7 +221,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-STL-Force-CPP03: name: Syntax Check - Clang C++17 Linux STL Force C++03 @@ -239,7 +239,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++17 Linux No STL Force C++03 @@ -257,7 +257,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-STL: name: Syntax Check - Clang C++20 Linux STL @@ -275,10 +275,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-No-STL: - name: Syntax Check - Clang C++20 Linux No STL + name: Syntax Check - Clang C++20 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -293,7 +293,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-STL-Force-CPP03: name: Syntax Check - Clang C++20 Linux STL Force C++03 @@ -311,7 +311,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++20 Linux No STL Force C++03 @@ -329,7 +329,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-STL: name: Syntax Check - Clang C++23 Linux STL @@ -347,10 +347,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-No-STL: - name: Syntax Check - Clang C++23 Linux No STL + name: Syntax Check - Clang C++23 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -365,7 +365,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-STL-Force-CPP03: name: Syntax Check - Clang C++23 Linux STL Force C++03 @@ -383,7 +383,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++23 Linux No STL Force C++03 @@ -401,4 +401,80 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-STL: + name: Syntax Check - Clang C++26 Linux STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check + clang++ --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-No-STL: + name: Syntax Check - Clang C++26 Linux No STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check + clang++ --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-STL-Force-CPP03: + name: Syntax Check - Clang C++26 Linux STL Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check + clang++ --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-No-STL-Force-CPP03: + name: Syntax Check - Clang C++26 Linux No STL Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check + clang++ --version + make -j "$(getconf _NPROCESSORS_ONLN)" diff --git a/.github/workflows/gcc-c++11.yml b/.github/workflows/gcc-c++11.yml index 571c6d6e..c9706aeb 100644 --- a/.github/workflows/gcc-c++11.yml +++ b/.github/workflows/gcc-c++11.yml @@ -26,7 +26,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -49,7 +49,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++14.yml b/.github/workflows/gcc-c++14.yml index f623af08..a3277b66 100644 --- a/.github/workflows/gcc-c++14.yml +++ b/.github/workflows/gcc-c++14.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++17.yml b/.github/workflows/gcc-c++17.yml index fc0ddd97..dbeef7fa 100644 --- a/.github/workflows/gcc-c++17.yml +++ b/.github/workflows/gcc-c++17.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++20.yml b/.github/workflows/gcc-c++20.yml index 5965e05e..be4e6fb2 100644 --- a/.github/workflows/gcc-c++20.yml +++ b/.github/workflows/gcc-c++20.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -69,7 +69,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -91,7 +91,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index aad4325c..654deff9 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -69,7 +69,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -91,7 +91,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++26.yml b/.github/workflows/gcc-c++26.yml new file mode 100644 index 00000000..8f3701b0 --- /dev/null +++ b/.github/workflows/gcc-c++26.yml @@ -0,0 +1,101 @@ +name: gcc-c++26 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp26-linux-stl: + name: GCC C++26 Linux - STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + export CC=gcc + export CXX=g++ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-gcc-cpp26-linux-no-stl: + name: GCC C++26 Linux - No STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + export CC=gcc + export CXX=g++ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-gcc-cpp26-linux-stl-force-cpp03: + name: GCC C++26 Linux - STL - Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + export CC=gcc + export CXX=g++ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-gcc-cpp26-linux-no-stl-force-cpp03: + name: GCC C++26 Linux - No STL - Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + export CC=gcc + export CXX=g++ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-syntax-checks.yml b/.github/workflows/gcc-syntax-checks.yml index 5f3753b1..81bfa4c4 100644 --- a/.github/workflows/gcc-syntax-checks.yml +++ b/.github/workflows/gcc-syntax-checks.yml @@ -23,10 +23,10 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp03-linux-No-STL: - name: Syntax Check - GCC C++03 Linux No STL + name: Syntax Check - GCC C++03 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -41,7 +41,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-STL: name: Syntax Check - GCC C++11 Linux STL @@ -59,7 +59,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-No-STL: name: Syntax Check - GCC C++11 Linux No STL @@ -77,7 +77,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-STL-Force-CPP03: name: Syntax Check - GCC C++11 Linux STL Force C++03 @@ -95,7 +95,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++11 Linux No STL Force C++03 @@ -113,7 +113,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-STL: name: Syntax Check - GCC C++14 Linux STL @@ -131,7 +131,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-No-STL: name: Syntax Check - GCC C++14 Linux No STL @@ -149,7 +149,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-STL-Force-CPP03: name: Syntax Check - GCC C++14 Linux STL Force C++03 @@ -167,7 +167,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++14 Linux No STL Force C++03 @@ -185,7 +185,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-STL: name: Syntax Check - GCC C++17 Linux STL @@ -203,7 +203,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-No-STL: name: Syntax Check - GCC C++17 Linux No STL @@ -221,7 +221,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-STL-Force-CPP03: name: Syntax Check - GCC C++17 Linux STL Force C++03 @@ -239,7 +239,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++17 Linux No STL Force C++03 @@ -257,7 +257,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-STL: name: Syntax Check - GCC C++20 Linux STL @@ -275,7 +275,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-No-STL: name: Syntax Check - GCC C++20 Linux No STL @@ -293,7 +293,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-STL-Force-CPP03: name: Syntax Check - GCC C++20 Linux STL Force C++03 @@ -311,7 +311,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++20 Linux No STL Force C++03 @@ -329,7 +329,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-STL: name: Syntax Check - GCC C++23 Linux STL @@ -347,7 +347,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-No-STL: name: Syntax Check - GCC C++23 Linux No STL @@ -365,7 +365,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-STL-Force-CPP03: name: Syntax Check - GCC C++23 Linux STL Force C++03 @@ -383,7 +383,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++23 Linux No STL Force C++03 @@ -401,4 +401,80 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) \ No newline at end of file + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-STL: + name: Syntax Check - GCC C++26 Linux STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=gcc + export CXX=g++ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-No-STL: + name: Syntax Check - GCC C++26 Linux No STL + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=gcc + export CXX=g++ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-STL-Force-CPP03: + name: Syntax Check - GCC C++26 Linux STL Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=gcc + export CXX=g++ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-No-STL-Force-CPP03: + name: Syntax Check - GCC C++26 Linux No STL Force C++03 + if: false # enabled when ubuntu-26.04 is available in github + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-26.04] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=gcc + export CXX=g++ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check + gcc --version + make -j "$(getconf _NPROCESSORS_ONLN)" diff --git a/README.md b/README.md index 869455a0..1af9c518 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![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) -[![Standard](https://img.shields.io/badge/c%2B%2B-98/03/11/14/17/20/23-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) +[![Standard](https://img.shields.io/badge/c%2B%2B-98/03/11/14/17/20/23/26-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) ![GitHub contributors](https://img.shields.io/github/contributors-anon/ETLCPP/etl) ![GitHub forks](https://img.shields.io/github/forks/ETLCPP/etl?style=flat) @@ -15,6 +15,7 @@ ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++17.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++20.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++23.yml/badge.svg?branch=master) +![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++26.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-syntax-checks.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++11.yml/badge.svg?branch=master) @@ -22,6 +23,7 @@ ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++17.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++20.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++23.yml/badge.svg?branch=master) +![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++26.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-syntax-checks.yml/badge.svg?branch=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3c14cd918ccf40008d0bcd7b083d5946)](https://www.codacy.com/manual/jwellbelove/etl?utm_source=github.com&utm_medium=referral&utm_content=ETLCPP/etl&utm_campaign=Badge_Grade) @@ -49,7 +51,7 @@ Its design goals include: - Offering APIs that closely resemble those of the STL, enabling familiar and consistent usage. - Maintaining compatibility with C++98 while implementing many features introduced in later standards -(C++11/14/17/20/23) where possible. +(C++11/14/17/20/23/26) where possible. - Ensuring deterministic behavior, which is critical in real-time and resource-constrained environments. diff --git a/include/etl/atomic/atomic_gcc_sync.h b/include/etl/atomic/atomic_gcc_sync.h index 087489aa..425d8707 100644 --- a/include/etl/atomic/atomic_gcc_sync.h +++ b/include/etl/atomic/atomic_gcc_sync.h @@ -341,6 +341,68 @@ namespace etl return __atomic_fetch_xor(&value, v, order); } + // Fetch max + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + // Exchange T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) { @@ -1234,6 +1296,72 @@ namespace etl return __sync_fetch_and_xor(&value, v); } + // Fetch max + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + // Exchange T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) { diff --git a/include/etl/atomic/atomic_std.h b/include/etl/atomic/atomic_std.h index ee765a70..06fcef6c 100644 --- a/include/etl/atomic/atomic_std.h +++ b/include/etl/atomic/atomic_std.h @@ -40,11 +40,98 @@ namespace etl { //*************************************************************************** // ETL Atomic type for compilers that support std::atomic. - // etl::atomic is a simple wrapper around std::atomic. + // etl::atomic is a wrapper around std::atomic that adds fetch_max and + // fetch_min if the standard library does not yet provide them. //*************************************************************************** +#if ETL_HAS_STD_ATOMIC_MIN_MAX + // The standard library already provides fetch_max/fetch_min. template using atomic = std::atomic; +#else + template + class atomic : public std::atomic + { + using base_type = std::atomic; + + public: + + atomic() ETL_NOEXCEPT = default; + + ETL_CONSTEXPR atomic(T desired) ETL_NOEXCEPT + : base_type(desired) + { + } + + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + using base_type::operator=; + + // Fetch max + T fetch_max(T v, std::memory_order order = std::memory_order_seq_cst) + { + T old = this->load(order); + + while (v > old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, std::memory_order order = std::memory_order_seq_cst) volatile + { + T old = this->load(order); + + while (v > old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, std::memory_order order = std::memory_order_seq_cst) + { + T old = this->load(order); + + while (v < old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, std::memory_order order = std::memory_order_seq_cst) volatile + { + T old = this->load(order); + + while (v < old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + }; +#endif using memory_order = std::memory_order; @@ -55,66 +142,66 @@ namespace etl static ETL_CONSTANT etl::memory_order memory_order_acq_rel = std::memory_order_acq_rel; static ETL_CONSTANT etl::memory_order memory_order_seq_cst = std::memory_order_seq_cst; - using atomic_bool = std::atomic; - using atomic_char = std::atomic; - using atomic_schar = std::atomic; - using atomic_uchar = std::atomic; - using atomic_short = std::atomic; - using atomic_ushort = std::atomic; - using atomic_int = std::atomic; - using atomic_uint = std::atomic; - using atomic_long = std::atomic; - using atomic_ulong = std::atomic; - using atomic_llong = std::atomic; - using atomic_ullong = std::atomic; - using atomic_wchar_t = std::atomic; + using atomic_bool = etl::atomic; + using atomic_char = etl::atomic; + using atomic_schar = etl::atomic; + using atomic_uchar = etl::atomic; + using atomic_short = etl::atomic; + using atomic_ushort = etl::atomic; + using atomic_int = etl::atomic; + using atomic_uint = etl::atomic; + using atomic_long = etl::atomic; + using atomic_ulong = etl::atomic; + using atomic_llong = etl::atomic; + using atomic_ullong = etl::atomic; + using atomic_wchar_t = etl::atomic; #if ETL_HAS_NATIVE_CHAR8_T - using atomic_char8_t = std::atomic; + using atomic_char8_t = etl::atomic; #endif #if ETL_HAS_NATIVE_CHAR16_T - using atomic_char16_t = std::atomic; + using atomic_char16_t = etl::atomic; #endif #if ETL_HAS_NATIVE_CHAR32_T - using atomic_char32_t = std::atomic; + using atomic_char32_t = etl::atomic; #endif #if ETL_USING_8BIT_TYPES - using atomic_uint8_t = std::atomic; - using atomic_int8_t = std::atomic; + using atomic_uint8_t = etl::atomic; + using atomic_int8_t = etl::atomic; #endif - using atomic_uint16_t = std::atomic; - using atomic_int16_t = std::atomic; - using atomic_uint32_t = std::atomic; - using atomic_int32_t = std::atomic; + using atomic_uint16_t = etl::atomic; + using atomic_int16_t = etl::atomic; + using atomic_uint32_t = etl::atomic; + using atomic_int32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_uint64_t = std::atomic; - using atomic_int64_t = std::atomic; + using atomic_uint64_t = etl::atomic; + using atomic_int64_t = etl::atomic; #endif - using atomic_int_least8_t = std::atomic; - using atomic_uint_least8_t = std::atomic; - using atomic_int_least16_t = std::atomic; - using atomic_uint_least16_t = std::atomic; - using atomic_int_least32_t = std::atomic; - using atomic_uint_least32_t = std::atomic; + using atomic_int_least8_t = etl::atomic; + using atomic_uint_least8_t = etl::atomic; + using atomic_int_least16_t = etl::atomic; + using atomic_uint_least16_t = etl::atomic; + using atomic_int_least32_t = etl::atomic; + using atomic_uint_least32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_int_least64_t = std::atomic; - using atomic_uint_least64_t = std::atomic; + using atomic_int_least64_t = etl::atomic; + using atomic_uint_least64_t = etl::atomic; #endif - using atomic_int_fast8_t = std::atomic; - using atomic_uint_fast8_t = std::atomic; - using atomic_int_fast16_t = std::atomic; - using atomic_uint_fast16_t = std::atomic; - using atomic_int_fast32_t = std::atomic; - using atomic_uint_fast32_t = std::atomic; + using atomic_int_fast8_t = etl::atomic; + using atomic_uint_fast8_t = etl::atomic; + using atomic_int_fast16_t = etl::atomic; + using atomic_uint_fast16_t = etl::atomic; + using atomic_int_fast32_t = etl::atomic; + using atomic_uint_fast32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_int_fast64_t = std::atomic; - using atomic_uint_fast64_t = std::atomic; + using atomic_int_fast64_t = etl::atomic; + using atomic_uint_fast64_t = etl::atomic; #endif - using atomic_intptr_t = std::atomic; - using atomic_uintptr_t = std::atomic; - using atomic_size_t = std::atomic; - using atomic_ptrdiff_t = std::atomic; - using atomic_intmax_t = std::atomic; - using atomic_uintmax_t = std::atomic; + using atomic_intptr_t = etl::atomic; + using atomic_uintptr_t = etl::atomic; + using atomic_size_t = etl::atomic; + using atomic_ptrdiff_t = etl::atomic; + using atomic_intmax_t = etl::atomic; + using atomic_uintmax_t = etl::atomic; } // namespace etl #endif diff --git a/include/etl/iterator.h b/include/etl/iterator.h index 8394c5f9..263ab5c6 100644 --- a/include/etl/iterator.h +++ b/include/etl/iterator.h @@ -958,8 +958,43 @@ namespace etl template ETL_CONSTANT bool is_random_access_iterator_concept::value; +#if ETL_USING_CPP11 + //*************************************************************************** + /// Trait to detect if a type is a container (has iterator and begin/end) + /// but is not itself an iterator. + /// Used to constrain begin()/end() free functions in C++26. + //*************************************************************************** + namespace private_iterator + { + // Check if T has iterator_category (i.e., is an iterator) + template + struct has_iterator_category : etl::false_type + { + }; + + template + struct has_iterator_category> : etl::true_type + { + }; + + // is_container: has iterator/const_iterator/begin/end but does NOT have iterator_category + template + struct is_container : etl::false_type + { + }; + + template + struct is_container< + T, etl::void_t< typename T::iterator, typename T::const_iterator, decltype(etl::declval().begin()), decltype(etl::declval().end()) >> + : etl::bool_constant::value> + { + }; + } // namespace private_iterator +#endif + #if ETL_NOT_USING_STL || ETL_CPP11_NOT_SUPPORTED - #if ETL_CPP11_SUPPORTED + #if ETL_USING_CPP11 + //***************************************************************************** /// Get the 'begin' iterator. /// Note: Contains SFINAE guard, ensuring they only participate in overload @@ -969,7 +1004,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().begin())> > - ETL_CONSTEXPR typename TContainer::iterator begin(TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::iterator>::type + begin(TContainer& container) { return container.begin(); } @@ -979,7 +1015,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().begin())> > - ETL_CONSTEXPR typename TContainer::const_iterator begin(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + begin(const TContainer& container) { return container.begin(); } @@ -989,7 +1026,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().cbegin())> > - ETL_CONSTEXPR typename TContainer::const_iterator cbegin(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + cbegin(const TContainer& container) { return container.cbegin(); } @@ -999,7 +1037,7 @@ namespace etl ///\ingroup container //***************************************************************************** template ().end())> > - ETL_CONSTEXPR typename TContainer::iterator end(TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::iterator>::type end(TContainer& container) { return container.end(); } @@ -1009,7 +1047,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().end())> > - ETL_CONSTEXPR typename TContainer::const_iterator end(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + end(const TContainer& container) { return container.end(); } @@ -1019,12 +1058,15 @@ namespace etl ///\ingroup container //***************************************************************************** template ().cend())> > - ETL_CONSTEXPR typename TContainer::const_iterator cend(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + cend(const TContainer& container) { return container.cend(); } #else - // C++03 fallback: no SFINAE guards needed since std::ranges does not exist. + // C++03 fallback: + // - no SFINAE guards needed since std::ranges does not exist + // - no constraint needed as C++26 ADL issue doesn't apply //***************************************************************************** /// Get the 'begin' iterator. ///\ingroup container @@ -1148,14 +1190,15 @@ namespace etl #endif #if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED - #if ETL_CPP11_SUPPORTED + #if ETL_USING_CPP11 //***************************************************************************** /// Get the 'begin' reverse_iterator for a container. /// Note: Contains SFINAE guard (see begin/end above for rationale). ///\ingroup container //***************************************************************************** template ().rbegin())> > - ETL_CONSTEXPR typename TContainer::reverse_iterator rbegin(TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::reverse_iterator>::type + rbegin(TContainer& container) { return container.rbegin(); } @@ -1165,7 +1208,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().rbegin())> > - ETL_CONSTEXPR typename TContainer::const_reverse_iterator rbegin(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + rbegin(const TContainer& container) { return container.rbegin(); } @@ -1175,7 +1219,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().crbegin())> > - ETL_CONSTEXPR typename TContainer::const_reverse_iterator crbegin(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + crbegin(const TContainer& container) { return container.crbegin(); } @@ -1185,7 +1230,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().rend())> > - ETL_CONSTEXPR typename TContainer::reverse_iterator rend(TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::reverse_iterator>::type + rend(TContainer& container) { return container.rend(); } @@ -1195,7 +1241,8 @@ namespace etl ///\ingroup container //***************************************************************************** template ().rend())> > - ETL_CONSTEXPR typename TContainer::const_reverse_iterator rend(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + rend(const TContainer& container) { return container.rend(); } @@ -1205,12 +1252,15 @@ namespace etl ///\ingroup container //***************************************************************************** template ().crend())> > - ETL_CONSTEXPR typename TContainer::const_reverse_iterator crend(const TContainer& container) + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + crend(const TContainer& container) { return container.crend(); } #else - // C++03 fallback: no SFINAE guards needed since std::ranges does not exist. + // C++03 fallback: + // - no SFINAE guards needed since std::ranges does not exist. + // - no constraint needed as C++26 ADL issue doesn't apply //***************************************************************************** /// Get the 'begin' reverse_iterator for a container. ///\ingroup container diff --git a/include/etl/memory.h b/include/etl/memory.h index b1456298..0bf9e3d6 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1798,6 +1798,117 @@ namespace etl } // namespace ranges #endif +#if ETL_USING_CPP11 + //***************************************************************************** + /// Trivially relocate a range of objects. + /// This function relocates objects by copying their bytes using memmove. + /// The source objects' lifetimes are ended without calling destructors. + /// Based on C++26 P2786R13. + /// https://en.cppreference.com/w/cpp/memory/trivially_relocate + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value && !etl::is_const::value, T*>::type trivially_relocate(T* first, T* last, + T* result) + { + if (first == result) + { + return last; + } + + const size_t count = static_cast(last - first); + + if (count > 0) + { + // Use memmove to handle overlapping ranges + ::memmove(static_cast(result), static_cast(first), count * sizeof(T)); + } + + return result + count; + } + + //***************************************************************************** + /// Relocate implementation for trivially relocatable types. + /// Delegates to etl::trivially_relocate. + /// Uses SFINAE (enable_if) so that etl::trivially_relocate is never + /// instantiated for non-trivially relocatable types on pre-C++17 compilers, + /// avoiding the ill-formed instantiation that would occur with a plain + /// ETL_IF_CONSTEXPR branch. + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value, T*>::type relocate_impl(T* first, T* last, T* result) + { + return etl::trivially_relocate(first, last, result); + } + + //***************************************************************************** + /// Relocate implementation for non-trivially relocatable types. + /// Uses move construction + destroy. + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value, T*>::type relocate_impl(T* first, T* last, T* result) + { + const ptrdiff_t count = last - first; + + // Check if ranges overlap and handle accordingly + if (result < first || result >= last) + { + // No overlap or destination is after source - iterate forward + T* src = first; + T* dst = result; + while (src != last) + { + ::new (static_cast(dst)) T(etl::move(*src)); + src->~T(); + ++src; + ++dst; + } + } + else + { + // Destination overlaps with source from below - iterate backward + T* src = last; + T* dst = result + count; + while (src != first) + { + --src; + --dst; + ::new (static_cast(dst)) T(etl::move(*src)); + src->~T(); + } + } + + return result + count; + } + + //***************************************************************************** + /// Relocate a range of objects. + /// For trivially relocatable types, uses trivially_relocate via relocate_impl. + /// For other nothrow relocatable types, uses move + destroy via relocate_impl. + /// Delegates to SFINAE-guarded relocate_impl overloads instead of using + /// ETL_IF_CONSTEXPR, so that etl::trivially_relocate is never instantiated + /// for non-trivially relocatable types on pre-C++17 compilers. + /// Based on C++26 P2786R13. + /// https://en.cppreference.com/w/cpp/memory/relocate + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value && !etl::is_const::value, T*>::type relocate(T* first, T* last, T* result) + { + // Handle trivial relocation case + if (first == result || first == last) + { + return (first == result) ? last : result; + } + + // SFINAE on etl::is_trivially_relocatable selects the correct overload + // so that etl::trivially_relocate is only instantiated when valid. + return relocate_impl(first, last, result); + } +#endif + //***************************************************************************** /// Default deleter. ///\tparam T The pointed to type type. diff --git a/include/etl/numeric.h b/include/etl/numeric.h index cc8752d3..7e740839 100644 --- a/include/etl/numeric.h +++ b/include/etl/numeric.h @@ -204,6 +204,284 @@ namespace etl return typecast_a(a) + (typecast_t(t) * (typecast_b(b) - typecast_a(a))); } + + //*************************************************************************** + /// Saturating addition for unsigned integers. + /// Returns x + y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type add_sat(T x, T y) ETL_NOEXCEPT + { + T result = static_cast(x + y); + // Overflow occurred if result < x + if (result < x) + { + return etl::numeric_limits::max(); + } + return result; + } + + //*************************************************************************** + /// Saturating addition for signed integers. + /// Returns x + y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type add_sat(T x, T y) ETL_NOEXCEPT + { + // Check for overflow: both operands have same sign and result has different sign + if (y > T(0)) + { + // Positive overflow check + if (x > (etl::numeric_limits::max() - y)) + { + return etl::numeric_limits::max(); + } + } + else + { + // Negative overflow check + if (x < (etl::numeric_limits::min() - y)) + { + return etl::numeric_limits::min(); + } + } + + return static_cast(x + y); + } + + //*************************************************************************** + /// Saturating subtraction for unsigned integers. + /// Returns x - y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type sub_sat(T x, T y) ETL_NOEXCEPT + { + // Underflow occurred if y > x + if (y > x) + { + return T(0); + } + return static_cast(x - y); + } + + //*************************************************************************** + /// Saturating subtraction for signed integers. + /// Returns x - y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type sub_sat(T x, T y) ETL_NOEXCEPT + { + // Check for overflow/underflow + if (y > T(0)) + { + // Subtracting positive: check for underflow + if (x < (etl::numeric_limits::min() + y)) + { + return etl::numeric_limits::min(); + } + } + else + { + // Subtracting negative (adding): check for overflow + if (x > (etl::numeric_limits::max() + y)) + { + return etl::numeric_limits::max(); + } + } + + return static_cast(x - y); + } + + //*************************************************************************** + /// Saturating multiplication for unsigned integers. + /// Returns x * y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type mul_sat(T x, T y) ETL_NOEXCEPT + { + if ((x == T(0)) || (y == T(0))) + { + return T(0); + } + + // Check for overflow: x * y > max => x > max / y + if (x > (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + + return static_cast(x * y); + } + + //*************************************************************************** + /// Saturating multiplication for signed integers. + /// Returns x * y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type mul_sat(T x, T y) ETL_NOEXCEPT + { + if ((x == T(0)) || (y == T(0))) + { + return T(0); + } + + // Both positive + if ((x > T(0)) && (y > T(0))) + { + if (x > (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + } + // Both negative + else if ((x < T(0)) && (y < T(0))) + { + if (x < (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + } + // Different signs (x positive, y negative) + else if ((x > T(0)) && (y < T(0))) + { + if (y < (etl::numeric_limits::min() / x)) + { + return etl::numeric_limits::min(); + } + } + // Different signs (x negative, y positive) + else + { + if (x < (etl::numeric_limits::min() / y)) + { + return etl::numeric_limits::min(); + } + } + + return static_cast(x * y); + } + + //*************************************************************************** + /// Saturating division for unsigned integers. + /// Returns x / y. For unsigned types, no saturation is needed. + /// \pre y != 0 (undefined behaviour if y is zero, matching C++26). + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type div_sat(T x, T y) ETL_NOEXCEPT + { + return static_cast(x / y); + } + + //*************************************************************************** + /// Saturating division for signed integers. + /// Returns x / y, clamped to the range of T. + /// The only case of overflow is min / -1. + /// \pre y != 0 (undefined behaviour if y is zero, matching C++26). + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type div_sat(T x, T y) ETL_NOEXCEPT + { + // The only overflow case: min / -1 would be max + 1 + if ((x == etl::numeric_limits::min()) && (y == T(-1))) + { + return etl::numeric_limits::max(); + } + + return static_cast(x / y); + } + + //*************************************************************************** + /// saturate_cast + /// Converts an integer value to another integer type, clamping the value + /// to the representable range of the destination type. + /// C++26 equivalent of std::saturate_cast. + /// + /// When the source value is within the range of R, returns the value as R. + /// When the source value is below R's minimum, returns numeric_limits::min(). + /// When the source value is above R's maximum, returns numeric_limits::max(). + //*************************************************************************** + + // Case 1: Both unsigned. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_unsigned::value && etl::is_unsigned::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // If sizeof(R) >= sizeof(T), all values of T fit in R. + // If sizeof(R) < sizeof(T), clamp to R's max. The comparison is safe + // because R's max fits in T when T is wider. + if ((sizeof(R) < sizeof(T)) && (value > static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } + + // Case 2: Both signed. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_signed::value && etl::is_signed::value, R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // Only need to clamp when narrowing (R is smaller than T). + // When sizeof(R) >= sizeof(T), all values of T fit in R. + if (sizeof(R) < sizeof(T)) + { + if (value > static_cast(etl::numeric_limits::max())) + { + return etl::numeric_limits::max(); + } + if (value < static_cast(etl::numeric_limits::min())) + { + return etl::numeric_limits::min(); + } + } + return static_cast(value); + } + + // Case 3: Signed source -> Unsigned destination. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_unsigned::value && etl::is_signed::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + if (value < T(0)) + { + return R(0); + } + + typedef typename etl::make_unsigned::type unsigned_t; + unsigned_t uvalue = static_cast(value); + + // Compare in unsigned domain. R's max is always representable as unsigned_t + // when sizeof(T) > sizeof(R), and when sizeof(R) >= sizeof(T) all positive + // values of T fit in R. + if ((sizeof(R) < sizeof(T)) && (uvalue > static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } + + // Case 4: Unsigned source -> Signed destination. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_signed::value && etl::is_unsigned::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // R's max is positive, so we can safely represent it as T (unsigned) when + // sizeof(T) >= sizeof(R). When sizeof(T) < sizeof(R), all values of T fit. + typedef typename etl::make_unsigned::type unsigned_r; + + if (value > static_cast(static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } } // namespace etl #endif diff --git a/include/etl/platform.h b/include/etl/platform.h index a9918b24..bbf3022c 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -489,6 +489,18 @@ SOFTWARE. #define ETL_ASSUME ETL_DO_NOTHING #endif +//************************************* +// C++26 +#if defined(__has_cpp_attribute) + #if __has_cpp_attribute(indeterminate) + #define ETL_INDETERMINATE [[indeterminate]] + #else + #define ETL_INDETERMINATE + #endif +#else + #define ETL_INDETERMINATE +#endif + //************************************* // Determine if the ETL can use char8_t type. #if ETL_NO_SMALL_CHAR_SUPPORT @@ -650,6 +662,7 @@ namespace etl static ETL_CONSTANT bool using_cpp17 = (ETL_USING_CPP17 == 1); static ETL_CONSTANT bool using_cpp20 = (ETL_USING_CPP20 == 1); static ETL_CONSTANT bool using_cpp23 = (ETL_USING_CPP23 == 1); + static ETL_CONSTANT bool using_cpp26 = (ETL_USING_CPP26 == 1); static ETL_CONSTANT bool using_gcc_compiler = (ETL_USING_GCC_COMPILER == 1); static ETL_CONSTANT bool using_microsoft_compiler = (ETL_USING_MICROSOFT_COMPILER == 1); static ETL_CONSTANT bool using_arm5_compiler = (ETL_USING_ARM5_COMPILER == 1); @@ -697,6 +710,9 @@ namespace etl static ETL_CONSTANT bool has_chrono_literals_microseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_chrono_literals_nanoseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_std_byteswap = (ETL_HAS_STD_BYTESWAP == 1); + static ETL_CONSTANT bool has_std_is_virtual_base_of = (ETL_HAS_STD_IS_VIRTUAL_BASE_OF == 1); + static ETL_CONSTANT bool has_std_trivially_relocatable = (ETL_HAS_STD_TRIVIALLY_RELOCATABLE == 1); + static ETL_CONSTANT bool has_std_atomic_min_max = (ETL_HAS_STD_ATOMIC_MIN_MAX == 1); static ETL_CONSTANT bool has_noexcept_function_type = (ETL_HAS_NOEXCEPT_FUNCTION_TYPE == 1); // Is... diff --git a/include/etl/profiles/cpp20.h b/include/etl/profiles/cpp20.h new file mode 100644 index 00000000..ea1fa98a --- /dev/null +++ b/include/etl/profiles/cpp20.h @@ -0,0 +1,49 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP20_INCLUDED +#define ETL_CPP20_INCLUDED + +//***************************************************************************** +// Generic C++20 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp20_no_stl.h b/include/etl/profiles/cpp20_no_stl.h new file mode 100644 index 00000000..c997cdc8 --- /dev/null +++ b/include/etl/profiles/cpp20_no_stl.h @@ -0,0 +1,50 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP20_NO_STL_INCLUDED +#define ETL_CPP20_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++20 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/cpp23.h b/include/etl/profiles/cpp23.h new file mode 100644 index 00000000..21fc36f0 --- /dev/null +++ b/include/etl/profiles/cpp23.h @@ -0,0 +1,50 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP23_INCLUDED +#define ETL_CPP23_INCLUDED + +//***************************************************************************** +// Generic C++23 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp23_no_stl.h b/include/etl/profiles/cpp23_no_stl.h new file mode 100644 index 00000000..d06a8545 --- /dev/null +++ b/include/etl/profiles/cpp23_no_stl.h @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP23_NO_STL_INCLUDED +#define ETL_CPP23_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++23 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/cpp26.h b/include/etl/profiles/cpp26.h new file mode 100644 index 00000000..8ba60ee3 --- /dev/null +++ b/include/etl/profiles/cpp26.h @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP26_INCLUDED +#define ETL_CPP26_INCLUDED + +//***************************************************************************** +// Generic C++26 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_CPP26_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp26_no_stl.h b/include/etl/profiles/cpp26_no_stl.h new file mode 100644 index 00000000..76dcf143 --- /dev/null +++ b/include/etl/profiles/cpp26_no_stl.h @@ -0,0 +1,52 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP26_NO_STL_INCLUDED +#define ETL_CPP26_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++26 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_CPP26_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index 4a303fc0..b048922e 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -132,6 +132,14 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_MEMCHR) #define ETL_USING_BUILTIN_MEMCHR __has_builtin(__builtin_memchr) #endif + + #if !defined(ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF) + #define ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF __has_builtin(__is_virtual_base_of) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE __has_builtin(__is_trivially_relocatable) + #endif #endif // The default. Set to 0, if not already set. @@ -183,6 +191,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_MEMCHR 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF) + #define ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE 0 +#endif + namespace etl { namespace traits @@ -201,6 +217,8 @@ namespace etl static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1); static ETL_CONSTANT bool using_builtin_memcmp = (ETL_USING_BUILTIN_MEMCMP == 1); static ETL_CONSTANT bool using_builtin_memchr = (ETL_USING_BUILTIN_MEMCHR == 1); + static ETL_CONSTANT bool using_builtin_is_virtual_base_of = (ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_relocatable = (ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE == 1); } // namespace traits } // namespace etl diff --git a/include/etl/profiles/determine_compiler_language_support.h b/include/etl/profiles/determine_compiler_language_support.h index 645bd06d..58bda6ef 100644 --- a/include/etl/profiles/determine_compiler_language_support.h +++ b/include/etl/profiles/determine_compiler_language_support.h @@ -35,6 +35,31 @@ SOFTWARE. #include "determine_compiler.h" +// Determine C++26 support +#if !defined(ETL_CPP26_SUPPORTED) + #if defined(__cplusplus) + #if defined(ETL_COMPILER_MICROSOFT) + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #elif defined(ETL_COMPILER_ARM5) + #define ETL_CPP26_SUPPORTED 0 + #elif defined(ETL_COMPILER_GCC) + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #else + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #endif + #else + #define ETL_CPP26_SUPPORTED 0 + #endif +#endif + +#if ETL_CPP26_SUPPORTED + #define ETL_CPP11_SUPPORTED 1 + #define ETL_CPP14_SUPPORTED 1 + #define ETL_CPP17_SUPPORTED 1 + #define ETL_CPP20_SUPPORTED 1 + #define ETL_CPP23_SUPPORTED 1 +#endif + // Determine C++23 support #if !defined(ETL_CPP23_SUPPORTED) #if defined(__cplusplus) @@ -162,6 +187,7 @@ SOFTWARE. #define ETL_CPP17_NOT_SUPPORTED (!ETL_CPP17_SUPPORTED) #define ETL_CPP20_NOT_SUPPORTED (!ETL_CPP20_SUPPORTED) #define ETL_CPP23_NOT_SUPPORTED (!ETL_CPP23_SUPPORTED) +#define ETL_CPP26_NOT_SUPPORTED (!ETL_CPP26_SUPPORTED) // 'Using' macros #define ETL_USING_CPP11 (ETL_CPP11_SUPPORTED == 1) @@ -169,12 +195,14 @@ SOFTWARE. #define ETL_USING_CPP17 (ETL_CPP17_SUPPORTED == 1) #define ETL_USING_CPP20 (ETL_CPP20_SUPPORTED == 1) #define ETL_USING_CPP23 (ETL_CPP23_SUPPORTED == 1) +#define ETL_USING_CPP26 (ETL_CPP26_SUPPORTED == 1) #define ETL_NOT_USING_CPP11 (ETL_CPP11_SUPPORTED == 0) #define ETL_NOT_USING_CPP14 (ETL_CPP14_SUPPORTED == 0) #define ETL_NOT_USING_CPP17 (ETL_CPP17_SUPPORTED == 0) #define ETL_NOT_USING_CPP20 (ETL_CPP20_SUPPORTED == 0) #define ETL_NOT_USING_CPP23 (ETL_CPP23_SUPPORTED == 0) +#define ETL_NOT_USING_CPP26 (ETL_CPP26_SUPPORTED == 0) #if !defined(ETL_NO_NULLPTR_SUPPORT) #define ETL_NO_NULLPTR_SUPPORT ETL_NOT_USING_CPP11 @@ -198,7 +226,9 @@ SOFTWARE. // Language standard #if !defined(ETL_LANGUAGE_STANDARD) - #if ETL_USING_CPP23 + #if ETL_USING_CPP26 + #define ETL_LANGUAGE_STANDARD 26 + #elif ETL_USING_CPP23 #define ETL_LANGUAGE_STANDARD 23 #elif ETL_USING_CPP20 #define ETL_LANGUAGE_STANDARD 20 @@ -227,10 +257,37 @@ SOFTWARE. #define ETL_HAS_STD_BYTESWAP 1 #endif #endif + + #if defined(__cpp_lib_is_virtual_base_of) + #if __cpp_lib_is_virtual_base_of != 0 + #define ETL_HAS_STD_IS_VIRTUAL_BASE_OF 1 + #endif + #endif + + #if defined(__cpp_lib_trivially_relocatable) + #if __cpp_lib_trivially_relocatable != 0 + #define ETL_HAS_STD_TRIVIALLY_RELOCATABLE 1 + #endif + #endif + + #if defined(__cpp_lib_atomic_min_max) + #if __cpp_lib_atomic_min_max != 0 + #define ETL_HAS_STD_ATOMIC_MIN_MAX 1 + #endif + #endif #endif #endif #ifndef ETL_HAS_STD_BYTESWAP #define ETL_HAS_STD_BYTESWAP 0 #endif +#ifndef ETL_HAS_STD_IS_VIRTUAL_BASE_OF + #define ETL_HAS_STD_IS_VIRTUAL_BASE_OF 0 +#endif +#ifndef ETL_HAS_STD_TRIVIALLY_RELOCATABLE + #define ETL_HAS_STD_TRIVIALLY_RELOCATABLE 0 +#endif +#ifndef ETL_HAS_STD_ATOMIC_MIN_MAX + #define ETL_HAS_STD_ATOMIC_MIN_MAX 0 +#endif #endif diff --git a/include/etl/ratio.h b/include/etl/ratio.h index f4476dff..21a2d894 100644 --- a/include/etl/ratio.h +++ b/include/etl/ratio.h @@ -161,12 +161,20 @@ namespace etl #endif //*********************************************************************** -/// Predefined ration types. +/// Predefined ratio types. //*********************************************************************** #if INT_MAX > INT32_MAX - typedef ratio<1, 1000000000000000000> atto; - typedef ratio<1, 1000000000000000> femto; - typedef ratio<1, 1000000000000> pico; + // 2022 SI prefix (10^-30) + typedef ratio<1, 1000000000000000000LL * 1000000000000LL> quecto; + // 2022 SI prefix (10^-27) + typedef ratio<1, 1000000000000000000LL * 1000000000LL> ronto; + // 10^-24 + typedef ratio<1, 1000000000000000000LL * 1000000LL> yocto; + // 10^-21 + typedef ratio<1, 1000000000000000000LL * 1000LL> zepto; + typedef ratio<1, 1000000000000000000> atto; + typedef ratio<1, 1000000000000000> femto; + typedef ratio<1, 1000000000000> pico; #endif #if (INT_MAX >= INT32_MAX) @@ -192,6 +200,14 @@ namespace etl typedef ratio<1000000000000, 1> tera; typedef ratio<1000000000000000, 1> peta; typedef ratio<1000000000000000000, 1> exa; + // 10^21 + typedef ratio<1000000000000000000LL * 1000LL, 1> zetta; + // 10^24 + typedef ratio<1000000000000000000LL * 1000000LL, 1> yotta; + // 2022 SI prefix (10^27) + typedef ratio<1000000000000000000LL * 1000000000LL, 1> ronna; + // 2022 SI prefix (10^30) + typedef ratio<1000000000000000000LL * 1000000000000LL, 1> quetta; #endif /// An approximation of Pi. diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 411632ff..ad775db1 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -1170,6 +1170,21 @@ namespace etl inline constexpr bool is_base_of_v = is_base_of::value; #endif + //*************************************************************************** + /// is_virtual_base_of + /// Determines if TBase is a virtual base class of TDerived + #if ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : etl::bool_constant<__is_virtual_base_of(TBase, TDerived)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; + #endif + #endif + //*************************************************************************** /// add_lvalue_reference template @@ -2017,6 +2032,32 @@ namespace etl inline constexpr bool is_base_of_v = std::is_base_of_v; #endif + //*************************************************************************** + /// is_virtual_base_of + /// Determines if TBase is a virtual base class of TDerived + ///\ingroup type_traits + #if ETL_HAS_STD_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : std::is_virtual_base_of + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = std::is_virtual_base_of_v; + #endif + #elif ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : etl::bool_constant<__is_virtual_base_of(TBase, TDerived)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; + #endif + #endif + //*************************************************************************** /// is_class template @@ -2647,6 +2688,37 @@ namespace etl using is_trivially_copyable = etl::bool_constant::value || etl::is_pointer::value>; #endif + //********************************************* + // is_trivially_relocatable + #if ETL_HAS_STD_TRIVIALLY_RELOCATABLE && ETL_USING_STL + template + using is_trivially_relocatable = std::is_trivially_relocatable; + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + template + using is_trivially_relocatable = etl::bool_constant<__is_trivially_relocatable(T)>; + #else + template + using is_trivially_relocatable = etl::bool_constant::value && etl::is_trivially_destructible::value>; + #endif + + //********************************************* + // is_nothrow_relocatable + // A type is nothrow relocatable if it is trivially relocatable, or + // if it has a nothrow move constructor and nothrow destructor. + #if ETL_HAS_STD_TRIVIALLY_RELOCATABLE && ETL_USING_STL + template + using is_nothrow_relocatable = std::is_nothrow_relocatable; + #elif ETL_USING_STL + template + using is_nothrow_relocatable = etl::bool_constant< etl::is_trivially_relocatable::value + || (std::is_nothrow_move_constructible::type>::value + && std::is_nothrow_destructible::type>::value)>; + #else + // Fallback: only trivially relocatable types are known to be nothrow relocatable + template + using is_nothrow_relocatable = etl::is_trivially_relocatable; + #endif + #elif defined(ETL_USE_TYPE_TRAITS_BUILTINS) && !defined(ETL_USER_DEFINED_TYPE_TRAITS) //********************************************* @@ -2800,6 +2872,29 @@ namespace etl static ETL_CONSTANT bool value = __is_trivially_copyable(T); }; + //********************************************* + // is_trivially_relocatable + template + struct is_trivially_relocatable + { + #if ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + static ETL_CONSTANT bool value = __is_trivially_relocatable(T); + #else + static ETL_CONSTANT bool value = etl::is_trivially_copyable::value && etl::is_trivially_destructible::value; + #endif + }; + + //********************************************* + // is_nothrow_relocatable + // A type is nothrow relocatable if it is trivially relocatable, or + // if it has a nothrow move constructor and nothrow destructor. + template + struct is_nothrow_relocatable + { + // In builtins mode, conservatively use trivially_relocatable as the definition + static ETL_CONSTANT bool value = etl::is_trivially_relocatable::value; + }; + #elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS) //********************************************* @@ -2959,6 +3054,33 @@ namespace etl template struct is_trivially_copyable; + //********************************************* + // is_trivially_relocatable + template ::value || etl::is_pointer::value> + struct is_trivially_relocatable; + + template + struct is_trivially_relocatable : public etl::true_type + { + }; + + template + struct is_trivially_relocatable; + + //********************************************* + // is_nothrow_relocatable + // In user-defined mode, users must specialize for non-trivially-relocatable types + template ::value || etl::is_pointer::value> + struct is_nothrow_relocatable; + + template + struct is_nothrow_relocatable : public etl::true_type + { + }; + + template + struct is_nothrow_relocatable; + #else //********************************************* @@ -3126,6 +3248,25 @@ namespace etl { }; + //********************************************* + // is_trivially_relocatable + template + #if ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + struct is_trivially_relocatable : public etl::bool_constant<__is_trivially_relocatable(T)> + #else + struct is_trivially_relocatable : public etl::bool_constant::value && etl::is_trivially_destructible::value> + #endif + { + }; + + //********************************************* + // is_nothrow_relocatable + // Fallback: only trivially relocatable types are known to be nothrow relocatable + template + struct is_nothrow_relocatable : public etl::is_trivially_relocatable + { + }; + #endif template @@ -3195,6 +3336,12 @@ namespace etl template inline constexpr bool is_trivially_copyable_v = etl::is_trivially_copyable::value; + template + inline constexpr bool is_trivially_relocatable_v = etl::is_trivially_relocatable::value; + + template + inline constexpr bool is_nothrow_relocatable_v = etl::is_nothrow_relocatable::value; + #endif #if ETL_USING_CPP11 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99792fce..a7e61fb9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -406,10 +406,26 @@ elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) elseif (ETL_CXX_STANDARD MATCHES "23") - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Unsupported C++ standard") + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (NO_STL OR ETL_NO_STL) diff --git a/test/etl_error_handler/assert_function/CMakeLists.txt b/test/etl_error_handler/assert_function/CMakeLists.txt index babd03cc..f9ac1b49 100644 --- a/test/etl_error_handler/assert_function/CMakeLists.txt +++ b/test/etl_error_handler/assert_function/CMakeLists.txt @@ -34,9 +34,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") diff --git a/test/etl_error_handler/exceptions/CMakeLists.txt b/test/etl_error_handler/exceptions/CMakeLists.txt index 2da119b0..eac58405 100644 --- a/test/etl_error_handler/exceptions/CMakeLists.txt +++ b/test/etl_error_handler/exceptions/CMakeLists.txt @@ -32,9 +32,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") diff --git a/test/etl_error_handler/log_errors/CMakeLists.txt b/test/etl_error_handler/log_errors/CMakeLists.txt index 337e6546..4c96e4de 100644 --- a/test/etl_error_handler/log_errors/CMakeLists.txt +++ b/test/etl_error_handler/log_errors/CMakeLists.txt @@ -18,7 +18,7 @@ if (ETL_CXX_STANDARD MATCHES "98") message(STATUS "Compiling for C++98") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) elseif (ETL_CXX_STANDARD MATCHES "03") - message(STATUS "Compiling for C++98") + message(STATUS "Compiling for C++03") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) elseif (ETL_CXX_STANDARD MATCHES "11") message(STATUS "Compiling for C++11") @@ -32,9 +32,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") @@ -121,7 +139,3 @@ add_test(etl_error_handler_unit_tests etl_tests) # as they appear from UnitTest++ add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) - -#RSG -set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) - diff --git a/test/etl_error_handler/log_errors/test_error_handler.cpp b/test/etl_error_handler/log_errors/test_error_handler.cpp index 01381e36..61d35125 100644 --- a/test/etl_error_handler/log_errors/test_error_handler.cpp +++ b/test/etl_error_handler/log_errors/test_error_handler.cpp @@ -117,12 +117,12 @@ bool AssertFailAndReturnValue() return false; } +static ErrorLog error_log; + //***************************************************************************** int main() { - static ErrorLog error_log; - - etl::error_handler::set_callback(); + etl::error_handler::set_callback(error_log); Assert(false); Assert(true); diff --git a/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt b/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt index cad344d4..3a7100df 100644 --- a/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt +++ b/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt @@ -33,9 +33,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") @@ -120,7 +138,3 @@ add_test(etl_error_handler_unit_tests etl_tests) # as they appear from UnitTest++ add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) - -#RSG -set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) - diff --git a/test/etl_initializer_list/CMakeLists.txt b/test/etl_initializer_list/CMakeLists.txt index f29b5515..90437cdf 100644 --- a/test/etl_initializer_list/CMakeLists.txt +++ b/test/etl_initializer_list/CMakeLists.txt @@ -48,9 +48,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() target_include_directories(etl_tests diff --git a/test/run-coverage.sh b/test/run-coverage.sh index bf074a49..9266cd1b 100755 --- a/test/run-coverage.sh +++ b/test/run-coverage.sh @@ -44,7 +44,7 @@ mkdir -p "$BUILD" cd "$BUILD" || exit 1 touch total.info -for CXXSTD in 11 14 17 20 23; do +for CXXSTD in 11 14 17 20 23 26; do for NOSTL in OFF ON; do rm -rf CMakeFiles cmake -DEXTRA_COMPILE_OPTIONS="--coverage" \ diff --git a/test/run-syntax-checks.sh b/test/run-syntax-checks.sh index 8307a51d..f2cc75e5 100755 --- a/test/run-syntax-checks.sh +++ b/test/run-syntax-checks.sh @@ -47,7 +47,7 @@ PrintHelp() echo "$HelpColour" echo "----------------------------------------------------------------------------------" echo " Syntax : ./runtests.sh " - echo " C++ Standard : a, 03, 11, 14, 17, 20 or 23 (a = All standards) " + echo " C++ Standard : a, 03, 11, 14, 17, 20, 23 or 26 (a = All standards) " echo " Threads : Number of threads to use. Default = 4 " echo " Compiler select : gcc or clang. Default All compilers " echo "----------------------------------------------------------------------------------" @@ -101,6 +101,8 @@ elif [ "$1" = "20" ]; then requested_cxx_standard="20" elif [ "$1" = "23" ]; then requested_cxx_standard="23" +elif [ "$1" = "26" ]; then + requested_cxx_standard="26" elif [ "$1" = "A" ]; then requested_cxx_standard="All" elif [ "$1" = "a" ]; then @@ -288,8 +290,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -305,8 +307,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -533,8 +535,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -550,8 +552,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -777,8 +779,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -794,8 +796,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1021,8 +1023,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1038,8 +1040,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1265,8 +1267,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1282,8 +1284,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1509,8 +1511,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1526,7 +1528,30 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +fi + +############################################################################### +if [ "$requested_cxx_standard" = "26" ] || [ "$requested_cxx_standard" = "All" ]; then +SetCxxStandard "26" + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. cmake --build bgcc if [ $? -eq 0 ]; then PassedCompilation @@ -1536,6 +1561,193 @@ else fi fi +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Force C++03" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Force C++03" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Force C++03" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Force C++03" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Built-in traits" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Built-in traits" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Built-in traits" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Built-in traits" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + fi ChecksCompleted diff --git a/test/run-tests.sh b/test/run-tests.sh index d5fd0567..0381ac75 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -56,7 +56,7 @@ PrintHelp() echo "$HelpColour" echo "----------------------------------------------------------------------------------------------------------" echo " Syntax : ./run-tests.sh " - echo " C++ Standard : 11, 14, 17, 20, 23 or all " + echo " C++ Standard : 11, 14, 17, 20, 23, 26 or all " echo " Optimisation : 0, 1, 2 or 3. Default = 0 " echo " Threads : Number of threads to use. Default = 4 " echo " Sanitizer : s enables sanitizer checks, n disables. Default disabled " @@ -126,8 +126,10 @@ elif [ "$1" = "20" ]; then cxx_standards="20" elif [ "$1" = "23" ]; then cxx_standards="23" +elif [ "$1" = "26" ]; then + cxx_standards="26" elif [ "$1" = "all" ]; then - cxx_standards="11 14 17 20 23" + cxx_standards="11 14 17 20 23 26" else PrintHelp exit diff --git a/test/syntax_check/CMakeLists.txt b/test/syntax_check/CMakeLists.txt index a9d14be6..a7e87697 100644 --- a/test/syntax_check/CMakeLists.txt +++ b/test/syntax_check/CMakeLists.txt @@ -74,9 +74,25 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET tests PROPERTY CXX_STANDARD 26) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET tests PROPERTY CXX_STANDARD 23) + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET tests PROPERTY CXX_STANDARD 17) endif() target_sources(tests PRIVATE diff --git a/test/test_atomic.cpp b/test/test_atomic.cpp index 2128332b..9870caf8 100644 --- a/test/test_atomic.cpp +++ b/test/test_atomic.cpp @@ -488,6 +488,72 @@ namespace CHECK_EQUAL(compare.fetch_xor(0x55AA55AAUL), test.fetch_xor(0x55AA55AAUL)); } + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_greater) + { + etl::atomic test(10); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(10, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_less) + { + etl::atomic test(30); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(30, old_value); + CHECK_EQUAL(30, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_equal) + { + etl::atomic test(20); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(20, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_less) + { + etl::atomic test(30); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(30, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_greater) + { + etl::atomic test(10); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(10, old_value); + CHECK_EQUAL(10, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_equal) + { + etl::atomic test(20); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(20, old_value); + CHECK_EQUAL(20, test.load()); + } + //************************************************************************* TEST(test_atomic_integer_exchange) { diff --git a/test/test_etl_traits.cpp b/test/test_etl_traits.cpp index 3ddb93fa..a90f073c 100644 --- a/test/test_etl_traits.cpp +++ b/test/test_etl_traits.cpp @@ -49,6 +49,7 @@ namespace CHECK_EQUAL((ETL_USING_CPP17 == 1), etl::traits::using_cpp17); CHECK_EQUAL((ETL_USING_CPP20 == 1), etl::traits::using_cpp20); CHECK_EQUAL((ETL_USING_CPP23 == 1), etl::traits::using_cpp23); + CHECK_EQUAL((ETL_USING_CPP26 == 1), etl::traits::using_cpp26); CHECK_EQUAL((ETL_USING_EXCEPTIONS == 1), etl::traits::using_exceptions); CHECK_EQUAL((ETL_USING_LIBC_WCHAR_H == 1), etl::traits::using_libc_wchar_h); CHECK_EQUAL((ETL_USING_GCC_COMPILER == 1), etl::traits::using_gcc_compiler); @@ -92,7 +93,9 @@ namespace CHECK_EQUAL(ETL_VERSION_MINOR, etl::traits::version_minor); CHECK_EQUAL(ETL_VERSION_PATCH, etl::traits::version_patch); CHECK_EQUAL(ETL_VERSION_VALUE, etl::traits::version); -#if ETL_USING_CPP23 +#if ETL_USING_CPP26 + CHECK_EQUAL(26, etl::traits::language_standard); +#elif ETL_USING_CPP23 CHECK_EQUAL(23, etl::traits::language_standard); #elif ETL_USING_CPP20 CHECK_EQUAL(20, etl::traits::language_standard); diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 9513e778..eeddc426 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -47,6 +47,64 @@ SOFTWARE. #include #include +//*************************************************************************** +/// A non-trivially-relocatable type that tracks moves and destructions. +/// Used to exercise the manual move-and-destroy path of etl::relocate. +//*************************************************************************** +struct relocatable_t +{ + int value; + bool was_moved_into; ///< true when this object was constructed via move + + static int destructor_count; + + static void reset_counts() + { + destructor_count = 0; + } + + explicit relocatable_t(int v = 0) + : value(v) + , was_moved_into(false) + { + } + + relocatable_t(relocatable_t&& other) ETL_NOEXCEPT + : value(other.value) + , was_moved_into(true) + { + other.value = -1; // mark source as moved-from + } + + ~relocatable_t() + { + ++destructor_count; + } + + // Non-copyable to make the intent clear. + relocatable_t(const relocatable_t&) = delete; + relocatable_t& operator=(const relocatable_t&) = delete; + relocatable_t& operator=(relocatable_t&&) = delete; +}; + +int relocatable_t::destructor_count = 0; + +// In configurations where etl::is_nothrow_relocatable is a class template +// (non-STL builds), we must provide an explicit specialisation so that +// etl::relocate is enabled for relocatable_t. When the STL is available the +// trait is a type alias that already evaluates to true for types with a +// nothrow move constructor and a nothrow destructor, so no specialisation is +// needed (or even possible). +#if !(ETL_USING_STL && ETL_USING_CPP11) +namespace etl +{ + template <> + struct is_nothrow_relocatable : public etl::true_type + { + }; +} // namespace etl +#endif + namespace { typedef std::string non_trivial_t; @@ -2660,5 +2718,267 @@ namespace CHECK(result == p); } #endif + +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_trivially_relocate_trivial) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Initialize source + for (size_t i = 0; i < SIZE; ++i) + { + src[i] = test_data_trivial[i]; + } + + // Relocate + trivial_t* result = etl::trivially_relocate(src, src + SIZE, dst); + + // Check result + CHECK(result == dst + SIZE); + + // Check destination values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], dst[i]); + } + } + + //************************************************************************* + TEST(test_trivially_relocate_same_location) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * SIZE]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate to same location should return last + trivial_t* result = etl::trivially_relocate(p, p + SIZE, p); + + CHECK(result == p + SIZE); + + // Values should be unchanged + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i]); + } + } + + //************************************************************************* + TEST(test_trivially_relocate_empty_range) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Relocate empty range + trivial_t* result = etl::trivially_relocate(src, src, dst); + + CHECK(result == dst); + } + + //************************************************************************* + TEST(test_trivially_relocate_overlapping_forward) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * (SIZE + 2)]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate forward (overlapping) - shift elements by 2 + trivial_t* result = etl::trivially_relocate(p, p + SIZE, p + 2); + + CHECK(result == p + SIZE + 2); + + // Check values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i + 2]); + } + } + + //************************************************************************* + TEST(test_relocate_trivial) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Initialize source + for (size_t i = 0; i < SIZE; ++i) + { + src[i] = test_data_trivial[i]; + } + + // Relocate + trivial_t* result = etl::relocate(src, src + SIZE, dst); + + // Check result + CHECK(result == dst + SIZE); + + // Check destination values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], dst[i]); + } + } + + //************************************************************************* + TEST(test_relocate_same_location) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * SIZE]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate to same location should return last + trivial_t* result = etl::relocate(p, p + SIZE, p); + + CHECK(result == p + SIZE); + + // Values should be unchanged + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i]); + } + } + + //************************************************************************* + TEST(test_relocate_empty_range) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Relocate empty range + trivial_t* result = etl::relocate(src, src, dst); + + CHECK(result == dst); + } + + //************************************************************************* + TEST(test_relocate_non_trivial) + { + const size_t N = 5; + + alignas(relocatable_t) unsigned char src_buffer[sizeof(relocatable_t) * N]; + alignas(relocatable_t) unsigned char dst_buffer[sizeof(relocatable_t) * N]; + + relocatable_t* src = reinterpret_cast(src_buffer); + relocatable_t* dst = reinterpret_cast(dst_buffer); + + // Placement-new source objects + for (size_t i = 0; i < N; ++i) + { + ::new (static_cast(src + i)) relocatable_t(static_cast(i + 1)); + } + + relocatable_t::reset_counts(); + + // Relocate (non-trivial path: move-construct into dst, destroy src) + relocatable_t* result = etl::relocate(src, src + N, dst); + + // Returned pointer must be one-past-end of destination + CHECK(result == dst + N); + + // Destination objects were move-constructed with correct values + for (size_t i = 0; i < N; ++i) + { + CHECK_EQUAL(static_cast(i + 1), dst[i].value); + CHECK(dst[i].was_moved_into); + } + + // Destructors were called for the N source objects + CHECK_EQUAL(static_cast(N), relocatable_t::destructor_count); + + // Clean up destination objects + relocatable_t::reset_counts(); + for (size_t i = 0; i < N; ++i) + { + dst[i].~relocatable_t(); + } + } + + //************************************************************************* + TEST(test_relocate_non_trivial_same_location) + { + const size_t N = 5; + + alignas(relocatable_t) unsigned char buffer[sizeof(relocatable_t) * N]; + relocatable_t* p = reinterpret_cast(buffer); + + // Placement-new objects + for (size_t i = 0; i < N; ++i) + { + ::new (static_cast(p + i)) relocatable_t(static_cast(i + 1)); + } + + relocatable_t::reset_counts(); + + // Relocating to the same location should be a no-op (early return) + relocatable_t* result = etl::relocate(p, p + N, p); + + CHECK(result == p + N); + + // No destructors should have been called (no move-and-destroy performed) + CHECK_EQUAL(0, relocatable_t::destructor_count); + + // Values should be unchanged + for (size_t i = 0; i < N; ++i) + { + CHECK_EQUAL(static_cast(i + 1), p[i].value); + CHECK(!p[i].was_moved_into); + } + + // Clean up + relocatable_t::reset_counts(); + for (size_t i = 0; i < N; ++i) + { + p[i].~relocatable_t(); + } + } + + //************************************************************************* + TEST(test_relocate_non_trivial_empty_range) + { + alignas(relocatable_t) unsigned char src_buffer[sizeof(relocatable_t)]; + alignas(relocatable_t) unsigned char dst_buffer[sizeof(relocatable_t)]; + + relocatable_t* src = reinterpret_cast(src_buffer); + relocatable_t* dst = reinterpret_cast(dst_buffer); + + relocatable_t::reset_counts(); + + // Empty range: first == last + relocatable_t* result = etl::relocate(src, src, dst); + + CHECK(result == dst); + + // No destructors should have been called + CHECK_EQUAL(0, relocatable_t::destructor_count); + } +#endif } } // namespace diff --git a/test/test_numeric.cpp b/test/test_numeric.cpp index 1f6980bc..f7407fef 100644 --- a/test/test_numeric.cpp +++ b/test/test_numeric.cpp @@ -206,5 +206,411 @@ namespace CHECK_CLOSE(10.0, etl::lerp(10.0, 10.0, 1), 0.001); CHECK_CLOSE(10.0, etl::lerp(10, 10, 1), 0.001); } + + //************************************************************************* + TEST(test_add_sat_unsigned) + { + // Normal addition (no overflow) + CHECK_EQUAL(uint8_t(0), etl::add_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(3), etl::add_sat(uint8_t(1), uint8_t(2))); + CHECK_EQUAL(uint8_t(254), etl::add_sat(uint8_t(127), uint8_t(127))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(200), uint8_t(55))); + + // Overflow saturates to max + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(1), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(200), uint8_t(200))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(128), uint8_t(128))); + + // Identity: adding zero + CHECK_EQUAL(uint8_t(42), etl::add_sat(uint8_t(42), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::add_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(0))); + + // uint16_t + CHECK_EQUAL(uint16_t(65535), etl::add_sat(uint16_t(65535), uint16_t(1))); + CHECK_EQUAL(uint16_t(65535), etl::add_sat(uint16_t(65535), uint16_t(65535))); + CHECK_EQUAL(uint16_t(1000), etl::add_sat(uint16_t(500), uint16_t(500))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(100), etl::add_sat(uint32_t(60), uint32_t(40))); + } + + //************************************************************************* + TEST(test_add_sat_signed) + { + // Normal addition (no overflow) + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(3), etl::add_sat(int8_t(1), int8_t(2))); + CHECK_EQUAL(int8_t(-3), etl::add_sat(int8_t(-1), int8_t(-2))); + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(126), etl::add_sat(int8_t(63), int8_t(63))); + + // Positive overflow saturates to max + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(1))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(1), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(100), int8_t(100))); + + // Negative overflow saturates to min + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(-1))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-1), int8_t(-128))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(-128))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-100), int8_t(-100))); + + // Mixed signs: no overflow possible + CHECK_EQUAL(int8_t(-1), etl::add_sat(int8_t(127), int8_t(-128))); + CHECK_EQUAL(int8_t(-1), etl::add_sat(int8_t(-128), int8_t(127))); + CHECK_EQUAL(int8_t(27), etl::add_sat(int8_t(127), int8_t(-100))); + CHECK_EQUAL(int8_t(-28), etl::add_sat(int8_t(-128), int8_t(100))); + + // Identity: adding zero + CHECK_EQUAL(int8_t(42), etl::add_sat(int8_t(42), int8_t(0))); + CHECK_EQUAL(int8_t(-42), etl::add_sat(int8_t(-42), int8_t(0))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(0))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(0))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::add_sat(int16_t(32767), int16_t(1))); + CHECK_EQUAL(int16_t(-32768), etl::add_sat(int16_t(-32768), int16_t(-1))); + CHECK_EQUAL(int16_t(32767), etl::add_sat(int16_t(32767), int16_t(32767))); + CHECK_EQUAL(int16_t(-32768), etl::add_sat(int16_t(-32768), int16_t(-32768))); + CHECK_EQUAL(int16_t(1000), etl::add_sat(int16_t(500), int16_t(500))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::add_sat(std::numeric_limits::min(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::add_sat(std::numeric_limits::min(), std::numeric_limits::min())); + CHECK_EQUAL(int32_t(100), etl::add_sat(int32_t(60), int32_t(40))); + } + + //************************************************************************* + TEST(test_sub_sat_unsigned) + { + // Normal subtraction (no underflow) + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(1), etl::sub_sat(uint8_t(3), uint8_t(2))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(2), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::sub_sat(uint8_t(255), uint8_t(0))); + CHECK_EQUAL(uint8_t(128), etl::sub_sat(uint8_t(255), uint8_t(127))); + + // Underflow saturates to 0 + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(1), uint8_t(2))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(100), uint8_t(200))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(127), uint8_t(255))); + + // Identity: subtracting zero + CHECK_EQUAL(uint8_t(42), etl::sub_sat(uint8_t(42), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(255), etl::sub_sat(uint8_t(255), uint8_t(0))); + + // uint16_t + CHECK_EQUAL(uint16_t(0), etl::sub_sat(uint16_t(0), uint16_t(1))); + CHECK_EQUAL(uint16_t(0), etl::sub_sat(uint16_t(0), uint16_t(65535))); + CHECK_EQUAL(uint16_t(100), etl::sub_sat(uint16_t(500), uint16_t(400))); + + // uint32_t + CHECK_EQUAL(uint32_t(0), etl::sub_sat(uint32_t(0), uint32_t(1))); + CHECK_EQUAL(uint32_t(0), etl::sub_sat(uint32_t(0), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(1), etl::sub_sat(std::numeric_limits::max(), std::numeric_limits::max() - 1)); + CHECK_EQUAL(uint32_t(20), etl::sub_sat(uint32_t(60), uint32_t(40))); + } + + //************************************************************************* + TEST(test_sub_sat_signed) + { + // Normal subtraction (no overflow) + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(1), etl::sub_sat(int8_t(3), int8_t(2))); + CHECK_EQUAL(int8_t(-1), etl::sub_sat(int8_t(2), int8_t(3))); + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-2), etl::sub_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(2), etl::sub_sat(int8_t(1), int8_t(-1))); + + // Positive overflow: subtracting large negative from positive saturates to max + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(-1))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(1), int8_t(-127))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(-128))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(100), int8_t(-100))); + + // Negative overflow: subtracting large positive from negative saturates to min + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(1))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-1), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-100), int8_t(100))); + + // No overflow when same sign + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(-128), int8_t(-128))); + CHECK_EQUAL(int8_t(-1), etl::sub_sat(int8_t(-128), int8_t(-127))); + + // Identity: subtracting zero + CHECK_EQUAL(int8_t(42), etl::sub_sat(int8_t(42), int8_t(0))); + CHECK_EQUAL(int8_t(-42), etl::sub_sat(int8_t(-42), int8_t(0))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(0))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(0))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::sub_sat(int16_t(32767), int16_t(-1))); + CHECK_EQUAL(int16_t(-32768), etl::sub_sat(int16_t(-32768), int16_t(1))); + CHECK_EQUAL(int16_t(32767), etl::sub_sat(int16_t(32767), int16_t(-32768))); + CHECK_EQUAL(int16_t(-32768), etl::sub_sat(int16_t(-32768), int16_t(32767))); + CHECK_EQUAL(int16_t(100), etl::sub_sat(int16_t(500), int16_t(400))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::sub_sat(std::numeric_limits::max(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::sub_sat(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::sub_sat(std::numeric_limits::max(), std::numeric_limits::min())); + CHECK_EQUAL(std::numeric_limits::min(), etl::sub_sat(std::numeric_limits::min(), std::numeric_limits::max())); + CHECK_EQUAL(int32_t(20), etl::sub_sat(int32_t(60), int32_t(40))); + } + + //************************************************************************* + TEST(test_mul_sat_unsigned) + { + // Normal multiplication (no overflow) + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(255), uint8_t(0))); + CHECK_EQUAL(uint8_t(6), etl::mul_sat(uint8_t(2), uint8_t(3))); + CHECK_EQUAL(uint8_t(1), etl::mul_sat(uint8_t(1), uint8_t(1))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(250), etl::mul_sat(uint8_t(25), uint8_t(10))); + + // Overflow saturates to max + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(2), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(128), uint8_t(3))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(16), uint8_t(16))); + + // uint16_t + CHECK_EQUAL(uint16_t(65535), etl::mul_sat(uint16_t(65535), uint16_t(2))); + CHECK_EQUAL(uint16_t(65535), etl::mul_sat(uint16_t(65535), uint16_t(65535))); + CHECK_EQUAL(uint16_t(10000), etl::mul_sat(uint16_t(100), uint16_t(100))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), uint32_t(2))); + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(600), etl::mul_sat(uint32_t(20), uint32_t(30))); + } + + //************************************************************************* + TEST(test_mul_sat_signed) + { + // Normal multiplication (no overflow) + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(127))); + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(-128))); + CHECK_EQUAL(int8_t(6), etl::mul_sat(int8_t(2), int8_t(3))); + CHECK_EQUAL(int8_t(-6), etl::mul_sat(int8_t(2), int8_t(-3))); + CHECK_EQUAL(int8_t(-6), etl::mul_sat(int8_t(-2), int8_t(3))); + CHECK_EQUAL(int8_t(6), etl::mul_sat(int8_t(-2), int8_t(-3))); + CHECK_EQUAL(int8_t(1), etl::mul_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-1), etl::mul_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(1), etl::mul_sat(int8_t(-1), int8_t(-1))); + CHECK_EQUAL(int8_t(100), etl::mul_sat(int8_t(10), int8_t(10))); + + // Positive overflow: both positive + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(127), int8_t(2))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(2), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(127), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(64), int8_t(3))); + + // Positive overflow: both negative + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-128), int8_t(-2))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-2), int8_t(-128))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-128), int8_t(-128))); + + // Negative overflow: positive * negative + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(127), int8_t(-2))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(2), int8_t(-127))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(127), int8_t(-128))); + + // Negative overflow: negative * positive + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-128), int8_t(2))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-2), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-128), int8_t(127))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::mul_sat(int16_t(32767), int16_t(2))); + CHECK_EQUAL(int16_t(-32768), etl::mul_sat(int16_t(32767), int16_t(-2))); + CHECK_EQUAL(int16_t(32767), etl::mul_sat(int16_t(-32768), int16_t(-2))); + CHECK_EQUAL(int16_t(-32768), etl::mul_sat(int16_t(-32768), int16_t(2))); + CHECK_EQUAL(int16_t(10000), etl::mul_sat(int16_t(100), int16_t(100))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), int32_t(2))); + CHECK_EQUAL(std::numeric_limits::min(), etl::mul_sat(std::numeric_limits::max(), int32_t(-2))); + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::min(), int32_t(-2))); + CHECK_EQUAL(std::numeric_limits::min(), etl::mul_sat(std::numeric_limits::min(), int32_t(2))); + CHECK_EQUAL(int32_t(600), etl::mul_sat(int32_t(20), int32_t(30))); + } + + //************************************************************************* + TEST(test_div_sat_unsigned) + { + // Normal division + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(0), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(1), etl::div_sat(uint8_t(1), uint8_t(1))); + CHECK_EQUAL(uint8_t(3), etl::div_sat(uint8_t(6), uint8_t(2))); + CHECK_EQUAL(uint8_t(127), etl::div_sat(uint8_t(255), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::div_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(1), uint8_t(2))); + + // uint16_t + CHECK_EQUAL(uint16_t(32767), etl::div_sat(uint16_t(65535), uint16_t(2))); + CHECK_EQUAL(uint16_t(65535), etl::div_sat(uint16_t(65535), uint16_t(1))); + CHECK_EQUAL(uint16_t(100), etl::div_sat(uint16_t(1000), uint16_t(10))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(1), etl::div_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(30), etl::div_sat(uint32_t(600), uint32_t(20))); + } + + //************************************************************************* + TEST(test_div_sat_signed) + { + // Normal division + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(0), int8_t(1))); + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(0), int8_t(-1))); + CHECK_EQUAL(int8_t(1), etl::div_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-1), etl::div_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(-1), etl::div_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(1), etl::div_sat(int8_t(-1), int8_t(-1))); + CHECK_EQUAL(int8_t(3), etl::div_sat(int8_t(6), int8_t(2))); + CHECK_EQUAL(int8_t(-3), etl::div_sat(int8_t(6), int8_t(-2))); + CHECK_EQUAL(int8_t(-3), etl::div_sat(int8_t(-6), int8_t(2))); + CHECK_EQUAL(int8_t(3), etl::div_sat(int8_t(-6), int8_t(-2))); + CHECK_EQUAL(int8_t(127), etl::div_sat(int8_t(127), int8_t(1))); + CHECK_EQUAL(int8_t(-127), etl::div_sat(int8_t(127), int8_t(-1))); + CHECK_EQUAL(int8_t(-128), etl::div_sat(int8_t(-128), int8_t(1))); + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(1), int8_t(2))); + + // The only overflow case: min / -1 saturates to max + CHECK_EQUAL(int8_t(127), etl::div_sat(int8_t(-128), int8_t(-1))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::div_sat(int16_t(-32768), int16_t(-1))); + CHECK_EQUAL(int16_t(-32768), etl::div_sat(int16_t(-32768), int16_t(1))); + CHECK_EQUAL(int16_t(100), etl::div_sat(int16_t(1000), int16_t(10))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::min(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::div_sat(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::div_sat(std::numeric_limits::max(), std::numeric_limits::min())); + CHECK_EQUAL(int32_t(30), etl::div_sat(int32_t(600), int32_t(20))); + } + + //************************************************************************* + TEST(test_saturate_cast_unsigned_to_unsigned) + { + // Fits + CHECK_EQUAL(uint8_t(42), (etl::saturate_cast(uint16_t(42)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(uint16_t(0)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(255)))); + + // Overflow: clamp to max + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(256)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(1000)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(65535)))); + + // Widening (always fits) + CHECK_EQUAL(uint16_t(42), (etl::saturate_cast(uint8_t(42)))); + CHECK_EQUAL(uint16_t(255), (etl::saturate_cast(uint8_t(255)))); + } + + //************************************************************************* + TEST(test_saturate_cast_signed_to_signed) + { + // Fits + CHECK_EQUAL(int8_t(42), (etl::saturate_cast(int16_t(42)))); + CHECK_EQUAL(int8_t(-42), (etl::saturate_cast(int16_t(-42)))); + CHECK_EQUAL(int8_t(0), (etl::saturate_cast(int16_t(0)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(127)))); + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-128)))); + + // Overflow: clamp to max + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(128)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(1000)))); + + // Underflow: clamp to min + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-129)))); + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-1000)))); + + // Widening (always fits) + CHECK_EQUAL(int16_t(42), (etl::saturate_cast(int8_t(42)))); + CHECK_EQUAL(int16_t(-128), (etl::saturate_cast(int8_t(-128)))); + } + + //************************************************************************* + TEST(test_saturate_cast_signed_to_unsigned) + { + // Fits + CHECK_EQUAL(uint8_t(42), (etl::saturate_cast(int16_t(42)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(0)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(255)))); + + // Negative source: clamp to 0 + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(-1)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(-1000)))); + CHECK_EQUAL(uint16_t(0), (etl::saturate_cast(int16_t(-1)))); + + // Overflow: clamp to max + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(256)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(1000)))); + } + + //************************************************************************* + TEST(test_saturate_cast_unsigned_to_signed) + { + // Fits + CHECK_EQUAL(int8_t(42), (etl::saturate_cast(uint16_t(42)))); + CHECK_EQUAL(int8_t(0), (etl::saturate_cast(uint16_t(0)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(127)))); + + // Overflow: clamp to max + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(128)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(1000)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(65535)))); + + // Widening (always fits) + CHECK_EQUAL(int16_t(255), (etl::saturate_cast(uint8_t(255)))); + CHECK_EQUAL(int16_t(0), (etl::saturate_cast(uint8_t(0)))); + } + + //************************************************************************* + TEST(test_saturate_cast_same_type) + { + // Same type, no conversion needed + CHECK_EQUAL(int32_t(42), (etl::saturate_cast(int32_t(42)))); + CHECK_EQUAL(uint32_t(42), (etl::saturate_cast(uint32_t(42)))); + CHECK_EQUAL(int32_t(-42), (etl::saturate_cast(int32_t(-42)))); + } + + //************************************************************************* + TEST(test_saturate_cast_boundary_values) + { + // int32_t max -> uint16_t + CHECK_EQUAL(uint16_t(65535), (etl::saturate_cast(int32_t(2147483647)))); + + // int32_t min -> uint16_t + CHECK_EQUAL(uint16_t(0), (etl::saturate_cast(std::numeric_limits::min()))); + + // uint32_t max -> int32_t + CHECK_EQUAL(std::numeric_limits::max(), (etl::saturate_cast(std::numeric_limits::max()))); + + // uint32_t max -> int16_t + CHECK_EQUAL(int16_t(32767), (etl::saturate_cast(std::numeric_limits::max()))); + } } } // namespace diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index c49b2eda..9f6c7bfc 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -1007,6 +1007,64 @@ namespace CHECK((std::is_base_of::value) == (etl::is_base_of::value)); } +#if ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + //************************************************************************* + TEST(test_is_virtual_base_of) + { + struct A + { + }; + struct B : public A // Non-virtual base + { + }; + struct C : virtual public A // Virtual base + { + }; + struct D + : public B + , virtual public A // A is both virtual and non-virtual base + { + }; + struct E : public C // A is indirect virtual base + { + }; + struct F // Unrelated class + { + }; + + // A is not a virtual base of A (same class) + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // A is NOT a virtual base of B (it's a non-virtual base) + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of C + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of D (even though it's also a non-virtual base via B) + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of E (indirect virtual base) + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // Unrelated classes + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // Fundamental types + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + #if ETL_USING_CPP17 + // Test the _v helper + CHECK_EQUAL(false, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + #endif + } +#endif + //************************************************************************* TEST(test_types) { @@ -1574,6 +1632,110 @@ namespace #endif } + //************************************************************************* + TEST(test_is_trivially_relocatable) + { + // Trivially relocatable types (trivially copyable and trivially destructible) + // Primitive types should always be detected as trivially relocatable + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + + // POD struct should be trivially relocatable when proper detection is available + struct TrivialStruct + { + int x; + double y; + }; + + // Struct with non-trivial destructor should NOT be trivially relocatable + struct NonTrivialDestructor + { + ~NonTrivialDestructor() {} + }; + CHECK_FALSE(etl::is_trivially_relocatable::value); + + // Struct with non-trivial copy constructor should NOT be trivially relocatable + struct NonTrivialCopy + { + NonTrivialCopy() = default; + NonTrivialCopy(const NonTrivialCopy&) {} + NonTrivialCopy& operator=(const NonTrivialCopy&) = default; + }; + CHECK_FALSE(etl::is_trivially_relocatable::value); + +#if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + // These tests require STL or compiler builtins to correctly detect struct/array triviality + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); +#endif + +#if ETL_USING_CPP17 + // Test the _v helper variable + CHECK_TRUE(etl::is_trivially_relocatable_v); + CHECK_TRUE(etl::is_trivially_relocatable_v); + CHECK_TRUE(etl::is_trivially_relocatable_v); + #if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + CHECK_TRUE(etl::is_trivially_relocatable_v); + #endif + CHECK_FALSE(etl::is_trivially_relocatable_v); + CHECK_FALSE(etl::is_trivially_relocatable_v); +#endif + + // Verify consistency: if a type is trivially_copyable AND trivially_destructible, + // then it should be trivially_relocatable. The reverse may not hold when compiler + // builtins provide more accurate detection than the fallback implementations. + CHECK_TRUE(!(etl::is_trivially_copyable::value && etl::is_trivially_destructible::value) + || etl::is_trivially_relocatable::value); + CHECK_TRUE(!(etl::is_trivially_copyable::value && etl::is_trivially_destructible::value) + || etl::is_trivially_relocatable::value); + // Non-trivially destructible types should never be trivially relocatable + CHECK_FALSE(etl::is_trivially_relocatable::value); + // Non-trivially copyable types should never be trivially relocatable + CHECK_FALSE(etl::is_trivially_relocatable::value); + } + + //************************************************************************* + TEST(test_is_nothrow_relocatable) + { + // Trivially relocatable types should always be nothrow relocatable + // Primitive types should always be detected correctly + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + + // POD struct should be nothrow relocatable when proper detection is available + struct TrivialStruct + { + int x; + double y; + }; + +#if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + // These tests require STL or compiler builtins to correctly detect struct/array triviality + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); +#endif + +#if ETL_USING_CPP17 + // Test the _v helper variable + CHECK_TRUE(etl::is_nothrow_relocatable_v); + CHECK_TRUE(etl::is_nothrow_relocatable_v); + CHECK_TRUE(etl::is_nothrow_relocatable_v); + #if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + CHECK_TRUE(etl::is_nothrow_relocatable_v); + #endif +#endif + + // Verify consistency: nothrow_relocatable should be at least as permissive as trivially_relocatable + CHECK_TRUE(!etl::is_trivially_relocatable::value || etl::is_nothrow_relocatable::value); + CHECK_TRUE(!etl::is_trivially_relocatable::value || etl::is_nothrow_relocatable::value); + } + //************************************************************************* TEST(test_is_base_of_any) { From ff65c753d6a7218e296c49e007af38424236a535 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 18 Apr 2026 17:13:43 +0200 Subject: [PATCH 13/27] =?UTF-8?q?Actually=20use=20ETL=5FUSE=5FBUILTIN=5FME?= =?UTF-8?q?M=5FFUNCTIONS=20to=20decide=20about=20macro=20defi=E2=80=A6=20(?= =?UTF-8?q?#1398)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Actually use ETL_USE_BUILTIN_MEM_FUNCTIONS to decide about macro definitions --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/profiles/determine_builtin_support.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index b048922e..843a8741 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -60,7 +60,10 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED) #define ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED 1 #endif +#endif +#if defined(ETL_USE_BUILTIN_MEM_FUNCTIONS) // Set all of them to be true if not + // already defined #if !defined(ETL_USING_BUILTIN_MEMCPY) #define ETL_USING_BUILTIN_MEMCPY 1 #endif From bbf74c5334ed6812f50b9f674b4b7e15bc8e36d9 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 19 Apr 2026 13:19:53 +0200 Subject: [PATCH 14/27] Optimize formatting in format.h for float values (#1379) When formatting float, fix the -0.0 case format.h float format: Fix rounding issues on all platforms --- include/etl/format.h | 112 ++++++++++++++++++++++++------------------- test/test_format.cpp | 95 +++++++++++++++++++++++++++++++++--- 2 files changed, 153 insertions(+), 54 deletions(-) diff --git a/include/etl/format.h b/include/etl/format.h index 72c79be0..8ee8514e 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -1039,22 +1039,27 @@ namespace etl { const size_t fractional_decimals = 6; // default - T integral; - T fractional = modf(value, &integral); - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; - if (integral < 0.0) + // Detect sign using signbit to correctly handle -0.0 + bool sign = signbit(value); + + T integral; + T fractional = modf(value, &integral); + + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1071,9 +1076,8 @@ namespace etl static const size_t exponent_decimals = 1; long long int exponent_int = 0; - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; + // Detect sign using signbit to correctly handle -0.0 + bool sign = signbit(value); T integral; T fractional = modf(value, &integral); @@ -1092,17 +1096,21 @@ namespace etl fractional = modf(value, &integral); } - if (integral < 0.0) + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(static_cast(0x10), fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(0x10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(static_cast(0x10), fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1133,9 +1141,8 @@ namespace etl static const size_t exponent_decimals = 2; long long int exponent_int = 0; - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; + // Detect sign using signbit to correctly handle -0.0 + bool sign = std::signbit(value); T integral; T fractional = modf(value, &integral); @@ -1154,17 +1161,21 @@ namespace etl fractional = modf(value, &integral); } - if (integral < 0.0) + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1186,22 +1197,27 @@ namespace etl { const size_t fractional_decimals = 6; // default - T integral; - T fractional = modf(value, &integral); - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; - if (integral < 0.0) + // Detect sign using signbit to correctly handle -0.0 + bool sign = std::signbit(value); + + T integral; + T fractional = modf(value, &integral); + + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); diff --git a/test/test_format.cpp b/test/test_format.cpp index 16b0ac1b..1a5e1476 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -203,8 +203,8 @@ namespace etl::string<100> s; CHECK_EQUAL("1.0", test_format(s, "{}", 1.0f)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.234567f)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678f)); + CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345674f)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.2345676f)); CHECK_EQUAL("1.125", test_format(s, "{}", 1.125f)); } @@ -214,8 +214,8 @@ namespace etl::string<100> s; CHECK_EQUAL("1.0", test_format(s, "{}", 1.0)); - CHECK_EQUAL("1.234563", test_format(s, "{}", 1.234563)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678)); + CHECK_EQUAL("1.234567", test_format(s, "{}", 1.234567499)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.234567501)); CHECK_EQUAL("1.5", test_format(s, "{}", 1.5)); } @@ -227,7 +227,7 @@ namespace CHECK_EQUAL("1.0", test_format(s, "{}", 1.0l)); auto& result = test_format(s, "{}", 1.234567l); CHECK("1.234567" == result || "1.234566" == result); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678l)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.2345678l)); CHECK_EQUAL("1.25", test_format(s, "{}", 1.25l)); } @@ -261,11 +261,94 @@ namespace CHECK_EQUAL("inf", test_format(s, "{:g}", INFINITY)); CHECK_EQUAL("INF", test_format(s, "{:0.3G}", INFINITY)); CHECK_EQUAL("0x1.8p+0", test_format(s, "{:a}", 1.5f)); - CHECK_EQUAL("0X1.4CCCCCCCCCP+0", test_format(s, "{:A}", 1.3l)); + CHECK_EQUAL("0X1.4CCCCCCCCDP+0", test_format(s, "{:A}", 1.3l)); CHECK_EQUAL("0x2.49fp+4", test_format(s, "{:a}", 150000.0)); CHECK_EQUAL("0x1.92a738p-5", test_format(s, "{:a}", 0.0000015f)); CHECK_EQUAL("0x1.6345785d8ap+e", test_format(s, "{:a}", 100000000000000000.l)); } + + //************************************************************************* + TEST(test_format_negative_zero) + { + etl::string<100> s; + + // Test negative zero handling - signbit() correctly detects -0.0 + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0)); + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0f)); + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0L)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0f)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0L)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0f)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0L)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0f)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0L)); + } + + //************************************************************************* + // Tests for fractional rounding carry: + // When round(fractional * scale) == scale the fractional part must wrap + // to 0 and the integral part must be incremented by 1. + //************************************************************************* + TEST(test_format_floating_default_rounding_carry) + { + etl::string<100> s; + + // 1.9999999: fractional 0.9999999, round(0.9999999 * 1e6) == 1000000 + // => must carry: integral 1 -> 2, fractional -> 0 + CHECK_EQUAL("2.0", test_format(s, "{}", 1.9999999)); + CHECK_EQUAL("-2.0", test_format(s, "{}", -1.9999999)); + + // 0.9999999: integral 0, fractional rounds up => becomes 1.0 + CHECK_EQUAL("1.0", test_format(s, "{}", 0.9999999)); + + // 99.9999999: integral 99, fractional rounds up => becomes 100.0 + CHECK_EQUAL("100.0", test_format(s, "{}", 99.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_f_rounding_carry) + { + etl::string<100> s; + + // Same values using {:f} which uses format_floating_f (6 fractional decimals) + CHECK_EQUAL("2.000000", test_format(s, "{:f}", 1.9999999)); + CHECK_EQUAL("-2.000000", test_format(s, "{:f}", -1.9999999)); + CHECK_EQUAL("1.000000", test_format(s, "{:f}", 0.9999999)); + CHECK_EQUAL("100.000000", test_format(s, "{:f}", 99.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_e_rounding_carry) + { + etl::string<100> s; + + // 9.9999999: after normalization integral=9, fractional=0.9999999 + // round(0.9999999 * 1e6) == 1000000 => must carry: 10.000000e+00 + CHECK_EQUAL("10.000000e+00", test_format(s, "{:e}", 9.9999999)); + CHECK_EQUAL("-10.000000e+00", test_format(s, "{:e}", -9.9999999)); + + // 1.9999999: after normalization integral=1, fractional=0.9999999 + CHECK_EQUAL("2.000000e+00", test_format(s, "{:e}", 1.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_a_rounding_carry) + { + etl::string<100> s; + + // 1.5 + (1.0 - 2^-52) * 0.5 ≈ value whose hex fractional part rounds up. + // Use a value where hex fractional is all 0xF...F and rounds up. + // 2.0 - epsilon: in hex, 0x1.FFFFFFFFFFFFFp+0 (for double) + // After modf: integral=1, fractional ≈ 0.999... + // round(fractional * 16^10) should equal 16^10 => carry + double almost_two = 1.9999999999999998; // nextafter(2.0, 0.0) or very close + auto& result = test_format(s, "{:a}", almost_two); + // After carry, integral becomes 2, fractional becomes 0 + CHECK_EQUAL("0x2.0p+0", result); + } #endif //************************************************************************* From b860326b267832dc5b21e853f9bb4948b92d7dc4 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 21 Apr 2026 15:27:43 +0200 Subject: [PATCH 15/27] Fix delegate not being cleared by assigning empty braces (#1401) * Fix delegate not being cleared by assigning empty braces Fixes issue #1399. The non-capturing lambda support (PR#1295) added a non-explicit delegate(function_ptr) constructor and operator=(function_ptr). This caused `delegate = {}` to implicitly convert `{}` to a null function pointer and bind it via function_ptr_stub, leaving the delegate appearing valid (stub != nullptr) but invoking through a null pointer (undefined behavior). Fix: - Mark delegate(function_ptr) constructor explicit to prevent implicit conversion from `{}` during initialization. - In operator=(function_ptr), clear the delegate when fp is null instead of binding a null pointer through function_ptr_stub. Added tests verifying that both `delegate d = {}` and `d = {}` produce an invalid (cleared) delegate. * Fix Dockerfile for powerpc cross build Debian snapshot sources were mixed with plain sid sources which mismatched after a while. Now, aligning all sources from snapshot server. --- .devcontainer/powerpc/Dockerfile | 8 ++++++++ include/etl/private/delegate_cpp11.h | 11 +++++++++-- test/test_delegate.cpp | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/.devcontainer/powerpc/Dockerfile b/.devcontainer/powerpc/Dockerfile index 06bab1d0..a74cb690 100644 --- a/.devcontainer/powerpc/Dockerfile +++ b/.devcontainer/powerpc/Dockerfile @@ -20,6 +20,14 @@ RUN dpkg --add-architecture powerpc && \ debian-ports-archive-keyring \ && rm -rf /var/lib/apt/lists/* +RUN cat < /etc/apt/sources.list.d/debian.sources +Types: deb +URIs: http://snapshot.debian.org/archive/debian/20260406T000000Z +Suites: sid +Components: main +Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp +EOF + RUN cat < /etc/apt/sources.list.d/powerpc.sources Types: deb URIs: http://snapshot.debian.org/archive/debian-ports/20260406T000000Z diff --git a/include/etl/private/delegate_cpp11.h b/include/etl/private/delegate_cpp11.h index 33d993e2..9664797b 100644 --- a/include/etl/private/delegate_cpp11.h +++ b/include/etl/private/delegate_cpp11.h @@ -172,7 +172,7 @@ namespace etl //************************************************************************* // Construct from a function pointer. //************************************************************************* - delegate(function_ptr fp) ETL_NOEXCEPT + explicit delegate(function_ptr fp) ETL_NOEXCEPT { assign(fp, function_ptr_stub); } @@ -534,7 +534,14 @@ namespace etl //************************************************************************* delegate& operator=(function_ptr fp) ETL_NOEXCEPT { - assign(fp, function_ptr_stub); + if (fp == ETL_NULLPTR) + { + invocation.clear(); + } + else + { + assign(fp, function_ptr_stub); + } return *this; } diff --git a/test/test_delegate.cpp b/test/test_delegate.cpp index b8445166..d57ad1f8 100644 --- a/test/test_delegate.cpp +++ b/test/test_delegate.cpp @@ -372,6 +372,27 @@ namespace CHECK_FALSE(d.is_valid()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_is_valid_after_init_empty_braces) + { + etl::delegate d = {}; + + CHECK_FALSE(d.is_valid()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_is_valid_after_assign_empty_braces) + { + auto lambda = [] { + }; + + etl::delegate d(lambda); + + CHECK_TRUE(d.is_valid()); + d = {}; + CHECK_FALSE(d.is_valid()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_free_void) { From 2b1dec0e7976b2d6cdaae42853e01abd3b45f7ef Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 22 Apr 2026 11:31:51 +0200 Subject: [PATCH 16/27] Run generator_test.py in CI checks (#1376) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Run generator_test.py in CI checks * Remove running generator.bat in CI checks --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- .github/workflows/generator.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/generator.yml b/.github/workflows/generator.yml index 032ffd1e..1829c342 100644 --- a/.github/workflows/generator.yml +++ b/.github/workflows/generator.yml @@ -14,12 +14,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Generate + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y python3-cogapp - cd include/etl/generators && bash generate.bat - - name: Check Generated Headers For Changes + - name: Run generator_test.py run: | - git diff --exit-code + cd scripts && python3 generator_test.py From a97817010ec436327e3b28110f7e9f40823e02c2 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 22 Apr 2026 12:37:53 +0200 Subject: [PATCH 17/27] Make etl::variant and etl::vector methods noexcept (#1383) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Make etl::optional, etl::variant and etl::vector methods noexcept Adding type traits supporting the respective conditional noexcept Fix missing etl::move() in etl::optional move constructors --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/optional.h | 113 ++++---- include/etl/private/variant_variadic.h | 25 +- .../etl/profiles/determine_builtin_support.h | 26 ++ include/etl/type_traits.h | 270 ++++++++++++++++++ include/etl/vector.h | 30 +- test/test_optional.cpp | 160 +++++++++++ test/test_type_traits.cpp | 161 ++++++++++- test/test_variant_variadic.cpp | 125 ++++++++ 8 files changed, 825 insertions(+), 85 deletions(-) diff --git a/include/etl/optional.h b/include/etl/optional.h index fc0db4f7..c7958dfb 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -127,7 +127,7 @@ namespace etl /// Constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl() + optional_impl() ETL_NOEXCEPT : storage() { } @@ -136,7 +136,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(etl::nullopt_t) + optional_impl(etl::nullopt_t) ETL_NOEXCEPT : storage() { } @@ -146,7 +146,7 @@ namespace etl /// Copy constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(const optional_impl& other) + optional_impl(const optional_impl& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { if (other.has_value()) { @@ -160,7 +160,7 @@ namespace etl /// Move constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(optional_impl&& other) + optional_impl(optional_impl&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { if (other.has_value()) { @@ -177,7 +177,7 @@ namespace etl typename etl::enable_if< etl::is_constructible::value && !etl::is_same::type, etl::in_place_t>::value && !etl::is_same::type, optional_impl>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional_impl(U&& value_) + ETL_CONSTEXPR20_STL optional_impl(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(value_)); } @@ -186,7 +186,7 @@ namespace etl /// Constructor from variadic args. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, TArgs&&... args) + ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, TArgs&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(args)...); } @@ -197,6 +197,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { storage.construct(ilist, etl::forward(args)...); } @@ -207,7 +208,7 @@ namespace etl /// Destructor. //*************************************************************************** ETL_CONSTEXPR20_STL - ~optional_impl() + ~optional_impl() ETL_NOEXCEPT { storage.destroy(); } @@ -216,7 +217,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(etl::nullopt_t) + optional_impl& operator=(etl::nullopt_t) ETL_NOEXCEPT { if (has_value()) { @@ -230,7 +231,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(const optional_impl& other) + optional_impl& operator=(const optional_impl& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { if (this != &other) { @@ -252,7 +253,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(optional_impl&& other) + optional_impl& operator=(optional_impl&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { if (this != &other) { @@ -277,7 +278,7 @@ namespace etl template ::value && !etl::is_same::type, optional_impl>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) + ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(value_)); @@ -488,7 +489,7 @@ namespace etl /// Reset back to invalid. //*************************************************************************** ETL_CONSTEXPR20_STL - void reset() + void reset() ETL_NOEXCEPT { storage.destroy(); } @@ -518,7 +519,7 @@ namespace etl template < typename U, typename... URest, typename etl::enable_if< !etl::is_base_of< optional_impl, typename etl::remove_cv< typename etl::remove_reference::type>::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL T& emplace(U&& first, URest&&... rest) + ETL_CONSTEXPR20_STL T& emplace(U&& first, URest&&... rest) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(first), etl::forward(rest)...); @@ -529,7 +530,7 @@ namespace etl /// Emplaces with zero arguments, i.e. default construct emplace. //************************************************************************* ETL_CONSTEXPR20_STL - T& emplace() + T& emplace() ETL_NOEXCEPT_IF(etl::is_nothrow_default_constructible::value) { storage.construct(); @@ -735,7 +736,7 @@ namespace etl //*************************************************************************** /// Constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl() + ETL_CONSTEXPR14 optional_impl() ETL_NOEXCEPT : storage() { } @@ -743,7 +744,7 @@ namespace etl //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(etl::nullopt_t) + ETL_CONSTEXPR14 optional_impl(etl::nullopt_t) ETL_NOEXCEPT : storage() { } @@ -752,7 +753,7 @@ namespace etl //*************************************************************************** /// Copy constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(const optional_impl& other) + ETL_CONSTEXPR14 optional_impl(const optional_impl& other) ETL_NOEXCEPT { if (other.has_value()) { @@ -765,7 +766,7 @@ namespace etl //*************************************************************************** /// Move constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(optional_impl&& other) + ETL_CONSTEXPR14 optional_impl(optional_impl&& other) ETL_NOEXCEPT { if (other.has_value()) { @@ -776,7 +777,7 @@ namespace etl //*************************************************************************** /// Constructor from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(const T& value_) + ETL_CONSTEXPR14 optional_impl(const T& value_) ETL_NOEXCEPT { storage.construct(value_); } @@ -784,7 +785,7 @@ namespace etl //*************************************************************************** /// Constructor from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(T&& value_) + ETL_CONSTEXPR14 optional_impl(T&& value_) ETL_NOEXCEPT { storage.construct(etl::move(value_)); } @@ -793,7 +794,7 @@ namespace etl /// Constructor from variadic args. //*************************************************************************** template - ETL_CONSTEXPR14 optional_impl(etl::in_place_t, TArgs&&... args) + ETL_CONSTEXPR14 optional_impl(etl::in_place_t, TArgs&&... args) ETL_NOEXCEPT { storage.construct(etl::forward(args)...); } @@ -803,7 +804,7 @@ namespace etl /// Construct from initializer_list and arguments. //******************************************* template - ETL_CONSTEXPR14 optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_CONSTEXPR14 optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) ETL_NOEXCEPT { storage.construct(ilist, etl::forward(args)...); } @@ -813,7 +814,7 @@ namespace etl //*************************************************************************** /// Assignment operator from nullopt. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(etl::nullopt_t) + ETL_CONSTEXPR14 optional_impl& operator=(etl::nullopt_t) ETL_NOEXCEPT { if (has_value()) { @@ -826,7 +827,7 @@ namespace etl //*************************************************************************** /// Assignment operator from optional_impl. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(const optional_impl& other) + ETL_CONSTEXPR14 optional_impl& operator=(const optional_impl& other) ETL_NOEXCEPT { if (this != &other) { @@ -847,7 +848,7 @@ namespace etl //*************************************************************************** /// Assignment operator from optional_impl. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(optional_impl&& other) + ETL_CONSTEXPR14 optional_impl& operator=(optional_impl&& other) ETL_NOEXCEPT { if (this != &other) { @@ -868,7 +869,7 @@ namespace etl //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(const T& value_) + ETL_CONSTEXPR14 optional_impl& operator=(const T& value_) ETL_NOEXCEPT { storage.construct(value_); @@ -879,7 +880,7 @@ namespace etl //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(T&& value_) + ETL_CONSTEXPR14 optional_impl& operator=(T&& value_) ETL_NOEXCEPT { storage.construct(etl::move(value_)); @@ -1058,7 +1059,7 @@ namespace etl //*************************************************************************** /// Swaps this value with another. //*************************************************************************** - ETL_CONSTEXPR14 void swap(optional_impl& other) + ETL_CONSTEXPR14 void swap(optional_impl& other) ETL_NOEXCEPT { optional_impl temp(*this); *this = other; @@ -1068,7 +1069,7 @@ namespace etl //*************************************************************************** /// Reset back to invalid. //*************************************************************************** - ETL_CONSTEXPR14 void reset() + ETL_CONSTEXPR14 void reset() ETL_NOEXCEPT { storage.destroy(); } @@ -1094,7 +1095,7 @@ namespace etl ///\param args The arguments to construct with. //************************************************************************* template - ETL_CONSTEXPR14 T& emplace(TArgs&&... args) + ETL_CONSTEXPR14 T& emplace(TArgs&&... args) ETL_NOEXCEPT { storage.construct(etl::forward(args)...); @@ -1286,7 +1287,7 @@ namespace etl /// Constructor. //*************************************************************************** template - ETL_CONSTEXPR14 optional() + ETL_CONSTEXPR14 optional() ETL_NOEXCEPT : impl_t() { } @@ -1295,12 +1296,12 @@ namespace etl /// Constructor. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional() + ETL_CONSTEXPR20_STL optional() ETL_NOEXCEPT : impl_t() { } #else - optional() + optional() ETL_NOEXCEPT : impl_t() { } @@ -1311,7 +1312,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** template - ETL_CONSTEXPR14 optional(etl::nullopt_t) + ETL_CONSTEXPR14 optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } @@ -1320,7 +1321,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional(etl::nullopt_t) + ETL_CONSTEXPR20_STL optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } @@ -1328,7 +1329,7 @@ namespace etl //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** - optional(etl::nullopt_t) + optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } @@ -1340,7 +1341,7 @@ namespace etl /// Copy constructor. //*************************************************************************** template - ETL_CONSTEXPR14 optional(const optional& other) + ETL_CONSTEXPR14 optional(const optional& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) : impl_t(other) { } @@ -1349,7 +1350,7 @@ namespace etl /// Copy constructor. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional(const optional& other) + ETL_CONSTEXPR20_STL optional(const optional& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) : impl_t(other) { } @@ -1369,8 +1370,8 @@ namespace etl /// Move constructor. //*************************************************************************** template - ETL_CONSTEXPR14 optional(optional&& other) - : impl_t(other) + ETL_CONSTEXPR14 optional(optional&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) + : impl_t(etl::move(other)) { } @@ -1378,8 +1379,8 @@ namespace etl /// Move constructor. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional(optional&& other) - : impl_t(other) + ETL_CONSTEXPR20_STL optional(optional&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) + : impl_t(etl::move(other)) { } #endif @@ -1396,7 +1397,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR14 optional(U&& value_) + ETL_CONSTEXPR14 optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::forward(value_)) { } @@ -1410,7 +1411,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && !etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional(U&& value_) + ETL_CONSTEXPR20_STL optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::forward(value_)) { } @@ -1429,7 +1430,7 @@ namespace etl /// Emplace construct from arguments. //*************************************************************************** template - ETL_CONSTEXPR14 explicit optional(etl::in_place_t, Args&&... args) + ETL_CONSTEXPR14 explicit optional(etl::in_place_t, Args&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::in_place_t{}, etl::forward(args)...) { } @@ -1438,7 +1439,7 @@ namespace etl /// Emplace construct from arguments. //*************************************************************************** template - ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, Args&&... args) + ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, Args&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::in_place_t{}, etl::forward(args)...) { } @@ -1449,6 +1450,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR14 explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } @@ -1458,6 +1460,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } @@ -1469,7 +1472,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** template - ETL_CONSTEXPR14 optional& operator=(etl::nullopt_t) + ETL_CONSTEXPR14 optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1480,7 +1483,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional& operator=(etl::nullopt_t) + ETL_CONSTEXPR20_STL optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1490,7 +1493,7 @@ namespace etl //*************************************************************************** /// Assignment operator from nullopt. //*************************************************************************** - optional& operator=(etl::nullopt_t) + optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1503,7 +1506,7 @@ namespace etl /// Assignment operator from optional. //*************************************************************************** template - ETL_CONSTEXPR14 optional& operator=(const optional& other) + ETL_CONSTEXPR14 optional& operator=(const optional& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { impl_t::operator=(other); @@ -1514,7 +1517,7 @@ namespace etl /// Assignment operator from optional. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional& operator=(const optional& other) + ETL_CONSTEXPR20_STL optional& operator=(const optional& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { impl_t::operator=(other); @@ -1537,7 +1540,7 @@ namespace etl /// Move assignment operator from optional. //*************************************************************************** template - ETL_CONSTEXPR14 optional& operator=(optional&& other) + ETL_CONSTEXPR14 optional& operator=(optional&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { impl_t::operator=(etl::move(other)); @@ -1548,7 +1551,7 @@ namespace etl /// Move assignment operator from optional. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional& operator=(optional&& other) + ETL_CONSTEXPR20_STL optional& operator=(optional&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { impl_t::operator=(etl::move(other)); @@ -1565,7 +1568,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR14 optional& operator=(U&& value_) + ETL_CONSTEXPR14 optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { impl_t::operator=(etl::forward(value_)); @@ -1580,7 +1583,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && !etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional& operator=(U&& value_) + ETL_CONSTEXPR20_STL optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { impl_t::operator=(etl::forward(value_)); diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 5598f896..3a95502a 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -486,7 +486,7 @@ namespace etl /// alternative (index() is zero). //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant() + ETL_CONSTEXPR14 variant() ETL_NOEXCEPT_IF(etl::is_nothrow_default_constructible >::value) { using type = type_from_index<0U>; @@ -501,7 +501,7 @@ namespace etl //*************************************************************************** #include "diagnostic_uninitialized_push.h" template , variant>::value, int> = 0> - ETL_CONSTEXPR14 variant(T&& value) + ETL_CONSTEXPR14 variant(T&& value) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, T&&>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -518,6 +518,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -534,6 +535,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : type_id(Index) { using type = type_from_index; @@ -552,6 +554,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, std::initializer_list init, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -568,6 +571,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t, std::initializer_list init, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) : type_id(Index) { using type = type_from_index; @@ -585,7 +589,7 @@ namespace etl ///\param other The other variant object to copy. //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(const variant& other) + ETL_CONSTEXPR14 variant(const variant& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) : operation(other.operation) , type_id(other.type_id) { @@ -605,7 +609,7 @@ namespace etl ///\param other The other variant object to copy. //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(variant&& other) + ETL_CONSTEXPR14 variant(variant&& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) : operation(other.operation) , type_id(other.type_id) { @@ -623,7 +627,7 @@ namespace etl //*************************************************************************** /// Destructor. //*************************************************************************** - ~variant() + ~variant() ETL_NOEXCEPT { if (!valueless_by_exception()) { @@ -638,7 +642,7 @@ namespace etl /// Emplace by type with variadic constructor parameters. //*************************************************************************** template - T& emplace(TArgs&&... args) + T& emplace(TArgs&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { static_assert(etl::is_one_of::value, "Unsupported type"); @@ -664,6 +668,7 @@ namespace etl //*************************************************************************** template T& emplace(std::initializer_list il, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) { static_assert(etl::is_one_of::value, "Unsupported type"); @@ -689,6 +694,7 @@ namespace etl //*************************************************************************** template typename etl::variant_alternative_t >& emplace(TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { static_assert(Index < sizeof...(TTypes), "Index out of range"); @@ -714,6 +720,7 @@ namespace etl //*************************************************************************** template typename etl::variant_alternative_t >& emplace(std::initializer_list il, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) { static_assert(Index < sizeof...(TTypes), "Index out of range"); @@ -739,7 +746,7 @@ namespace etl ///\param value The value to assign. //*************************************************************************** template , variant>::value, int> = 0> - variant& operator=(T&& value) + variant& operator=(T&& value) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, T&&>::value)) { using type = etl::remove_cvref_t; @@ -762,7 +769,7 @@ namespace etl /// Assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(const variant& other) + variant& operator=(const variant& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) { if (this != &other) { @@ -791,7 +798,7 @@ namespace etl /// Assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(variant&& other) + variant& operator=(variant&& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) { if (this != &other) { diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index 843a8741..f2be5693 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -41,6 +41,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE 1 #endif + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE 1 + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1 #endif @@ -96,6 +104,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE __has_builtin(__is_constructible) #endif + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE __has_builtin(__is_nothrow_constructible) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE __has_builtin(__is_nothrow_assignable) + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE (__has_builtin(__has_trivial_constructor) || __has_builtin(__is_trivially_constructible)) #endif @@ -154,6 +170,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE 0 +#endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0 #endif @@ -210,6 +234,8 @@ namespace etl static ETL_CONSTANT bool using_builtin_is_assignable = (ETL_USING_BUILTIN_IS_ASSIGNABLE == 1); static ETL_CONSTANT bool using_builtin_is_constructible = (ETL_USING_BUILTIN_IS_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_constructible = (ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_assignable = (ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE == 1); static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1); static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1); static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1); diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index ad775db1..5732f935 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -2635,6 +2635,41 @@ namespace etl template using is_move_assignable = std::is_move_assignable; + //********************************************* + // is_nothrow_constructible + template + using is_nothrow_constructible = std::is_nothrow_constructible; + + //********************************************* + // is_nothrow_default_constructible + template + using is_nothrow_default_constructible = std::is_nothrow_default_constructible; + + //********************************************* + // is_nothrow_copy_constructible + template + using is_nothrow_copy_constructible = std::is_nothrow_copy_constructible; + + //********************************************* + // is_nothrow_move_constructible + template + using is_nothrow_move_constructible = std::is_nothrow_move_constructible; + + //********************************************* + // is_nothrow_assignable + template + using is_nothrow_assignable = std::is_nothrow_assignable; + + //********************************************* + // is_nothrow_copy_assignable + template + using is_nothrow_copy_assignable = std::is_nothrow_copy_assignable; + + //********************************************* + // is_nothrow_move_assignable + template + using is_nothrow_move_assignable = std::is_nothrow_move_assignable; + //********************************************* // is_trivially_constructible #if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED @@ -2795,6 +2830,71 @@ namespace etl }; #endif + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible + { + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + static ETL_CONSTANT bool value = __is_nothrow_constructible(T, TArgs...); + #else + static ETL_CONSTANT bool value = etl::is_arithmetic::value || etl::is_pointer::value; + #endif + }; + + //********************************************* + // is_nothrow_default_constructible + template + struct is_nothrow_default_constructible : public etl::is_nothrow_constructible + { + }; + + //********************************************* + // is_nothrow_copy_constructible + template + struct is_nothrow_copy_constructible : public etl::is_nothrow_constructible::type> + { + }; + + //********************************************* + // is_nothrow_move_constructible + template + struct is_nothrow_move_constructible : public etl::is_nothrow_constructible::type> + { + }; + #endif + + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_assignable + template + struct is_nothrow_assignable + { + #if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE + static ETL_CONSTANT bool value = __is_nothrow_assignable(T, U); + #else + static ETL_CONSTANT bool value = etl::is_arithmetic::value || etl::is_pointer::value; + #endif + }; + + //********************************************* + // is_nothrow_copy_assignable + template + struct is_nothrow_copy_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_lvalue_reference::type> + { + }; + + //********************************************* + // is_nothrow_move_assignable + template + struct is_nothrow_move_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_rvalue_reference::type> + { + }; + #endif + #if ETL_USING_CPP11 //********************************************* // is_trivially_constructible @@ -2989,6 +3089,104 @@ namespace etl template struct is_move_assignable; + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible_helper; + + template + struct is_nothrow_constructible_helper : public etl::true_type + { + }; + + template + struct is_nothrow_constructible_helper; + + template + struct is_nothrow_constructible : public is_nothrow_constructible_helper::value || etl::is_pointer::value, TArgs...> + { + }; + + //********************************************* + // is_nothrow_default_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_default_constructible; + + template + struct is_nothrow_default_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_default_constructible; + + //********************************************* + // is_nothrow_copy_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_copy_constructible; + + template + struct is_nothrow_copy_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_copy_constructible; + + //********************************************* + // is_nothrow_move_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_move_constructible; + + template + struct is_nothrow_move_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_move_constructible; + + //********************************************* + // is_nothrow_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_assignable; + + template + struct is_nothrow_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_assignable; + + //********************************************* + // is_nothrow_copy_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_copy_assignable; + + template + struct is_nothrow_copy_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_copy_assignable; + + //********************************************* + // is_nothrow_move_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_move_assignable; + + template + struct is_nothrow_move_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_move_assignable; + #endif + //********************************************* // is_trivially_constructible template ::value || etl::is_pointer::value> @@ -3209,6 +3407,57 @@ namespace etl }; #endif + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_default_constructible + template + struct is_nothrow_default_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_copy_constructible + template + struct is_nothrow_copy_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_move_constructible + template + struct is_nothrow_move_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_assignable + template + struct is_nothrow_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_copy_assignable + template + struct is_nothrow_copy_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_move_assignable + template + struct is_nothrow_move_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + #endif + //********************************************* // is_trivially_constructible template @@ -3321,6 +3570,27 @@ namespace etl template inline constexpr bool is_move_assignable_v = etl::is_move_assignable::value; + template + inline constexpr bool is_nothrow_constructible_v = etl::is_nothrow_constructible::value; + + template + inline constexpr bool is_nothrow_default_constructible_v = etl::is_nothrow_default_constructible::value; + + template + inline constexpr bool is_nothrow_copy_constructible_v = etl::is_nothrow_copy_constructible::value; + + template + inline constexpr bool is_nothrow_move_constructible_v = etl::is_nothrow_move_constructible::value; + + template + inline constexpr bool is_nothrow_assignable_v = etl::is_nothrow_assignable::value; + + template + inline constexpr bool is_nothrow_copy_assignable_v = etl::is_nothrow_copy_assignable::value; + + template + inline constexpr bool is_nothrow_move_assignable_v = etl::is_nothrow_move_assignable::value; + template inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible::value; diff --git a/include/etl/vector.h b/include/etl/vector.h index f014ab2f..ebdc5d1e 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -1018,7 +1018,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - ivector& operator=(ivector&& rhs) + ivector& operator=(ivector&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1085,7 +1085,7 @@ namespace etl //********************************************************************* /// Constructor. //********************************************************************* - ivector(T* p_buffer_, size_t MAX_SIZE) + ivector(T* p_buffer_, size_t MAX_SIZE) ETL_NOEXCEPT : vector_base(MAX_SIZE) , p_buffer(p_buffer_) , p_end(p_buffer_) @@ -1288,7 +1288,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector() + vector() ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { this->initialise(); @@ -1367,7 +1367,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector(vector&& other) + vector(vector&& other) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { if (this != &other) @@ -1388,7 +1388,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector& operator=(vector&& rhs) + vector& operator=(vector&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1413,7 +1413,7 @@ namespace etl #ifdef ETL_IVECTOR_REPAIR_ENABLE virtual #endif - ~vector() + ~vector() ETL_NOEXCEPT { this->clear(); } @@ -1470,7 +1470,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector_ext(void* buffer, size_t max_size) + vector_ext(void* buffer, size_t max_size) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(buffer), max_size) { this->initialise(); @@ -1550,7 +1550,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector_ext(vector_ext&& other, void* buffer, size_t max_size) + vector_ext(vector_ext&& other, void* buffer, size_t max_size) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) : etl::ivector(reinterpret_cast(buffer), max_size) { if (this != &other) @@ -1571,7 +1571,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector_ext& operator=(vector_ext&& rhs) + vector_ext& operator=(vector_ext&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1594,7 +1594,7 @@ namespace etl //************************************************************************* /// Destructor. //************************************************************************* - ~vector_ext() + ~vector_ext() ETL_NOEXCEPT { this->clear(); } @@ -1629,7 +1629,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector() + vector() ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { this->initialise(); @@ -1705,7 +1705,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector(vector&& other) + vector(vector&& other) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { (void)etl::ivector::operator=(etl::move(other)); @@ -1714,7 +1714,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector& operator=(vector&& rhs) + vector& operator=(vector&& rhs) ETL_NOEXCEPT { (void)etl::ivector::operator=(etl::move(rhs)); @@ -1769,7 +1769,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector_ext(void* buffer, size_t max_size) + vector_ext(void* buffer, size_t max_size) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(buffer), max_size) { this->initialise(); @@ -1876,7 +1876,7 @@ namespace etl //************************************************************************* /// Destructor. //************************************************************************* - ~vector_ext() + ~vector_ext() ETL_NOEXCEPT { this->clear(); } diff --git a/test/test_optional.cpp b/test/test_optional.cpp index a848b0cb..88242053 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include #include #include +#include #include #include "data.h" @@ -1176,5 +1177,164 @@ namespace CHECK_EQUAL(99, opt->_some); } #endif + + //************************************************************************* + // Tests for noexcept properties of etl::optional + // The noexcept specs only take effect when ETL_USING_EXCEPTIONS is enabled, + // because ETL_NOEXCEPT_IF expands to nothing otherwise. + // The etl::is_nothrow_* traits only work with STL or builtins. + //************************************************************************* +#if ETL_USING_CPP11 && ETL_USING_EXCEPTIONS && (defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS))) + struct NothrowCopyMove + { + NothrowCopyMove() noexcept {} + NothrowCopyMove(const NothrowCopyMove&) noexcept {} + NothrowCopyMove(NothrowCopyMove&&) noexcept {} + NothrowCopyMove& operator=(const NothrowCopyMove&) noexcept + { + return *this; + } + NothrowCopyMove& operator=(NothrowCopyMove&&) noexcept + { + return *this; + } + }; + + struct ThrowingCopy + { + ThrowingCopy() noexcept {} + ThrowingCopy(const ThrowingCopy&) {} // may throw + ThrowingCopy(ThrowingCopy&&) noexcept {} + ThrowingCopy& operator=(const ThrowingCopy&) + { + return *this; + } // may throw + ThrowingCopy& operator=(ThrowingCopy&&) noexcept + { + return *this; + } + }; + + struct ThrowingMove + { + ThrowingMove() noexcept {} + ThrowingMove(const ThrowingMove&) noexcept {} + ThrowingMove(ThrowingMove&&) {} // may throw + ThrowingMove& operator=(const ThrowingMove&) noexcept + { + return *this; + } + ThrowingMove& operator=(ThrowingMove&&) + { + return *this; + } // may throw + }; + + struct ThrowingBoth + { + ThrowingBoth() noexcept {} + ThrowingBoth(const ThrowingBoth&) {} // may throw + ThrowingBoth(ThrowingBoth&&) {} // may throw + ThrowingBoth& operator=(const ThrowingBoth&) + { + return *this; + } + ThrowingBoth& operator=(ThrowingBoth&&) + { + return *this; + } + }; + + TEST(test_optional_nothrow_copy_constructible) + { + // When T is nothrow copy constructible, optional should be too + static_assert(etl::is_nothrow_copy_constructible>::value, "optional should be nothrow copy constructible"); + static_assert(etl::is_nothrow_copy_constructible>::value, + "optional should be nothrow copy constructible"); + + // When T is NOT nothrow copy constructible, optional should not be either + static_assert(!etl::is_nothrow_copy_constructible>::value, + "optional should NOT be nothrow copy constructible"); + static_assert(!etl::is_nothrow_copy_constructible>::value, + "optional should NOT be nothrow copy constructible"); + + // ThrowingMove has nothrow copy but throwing move + static_assert(etl::is_nothrow_copy_constructible>::value, + "optional should be nothrow copy constructible"); + + CHECK(true); // Placeholder for the static_asserts above + } + + TEST(test_optional_nothrow_move_constructible) + { + // When T is nothrow move constructible, optional should be too + static_assert(etl::is_nothrow_move_constructible>::value, "optional should be nothrow move constructible"); + static_assert(etl::is_nothrow_move_constructible>::value, + "optional should be nothrow move constructible"); + + // When T is NOT nothrow move constructible, optional should not be either + static_assert(!etl::is_nothrow_move_constructible>::value, + "optional should NOT be nothrow move constructible"); + static_assert(!etl::is_nothrow_move_constructible>::value, + "optional should NOT be nothrow move constructible"); + + // ThrowingCopy has nothrow move but throwing copy + static_assert(etl::is_nothrow_move_constructible>::value, + "optional should be nothrow move constructible"); + + CHECK(true); // Placeholder for the static_asserts above + } + + TEST(test_optional_nothrow_default_constructible) + { + // Default construction of optional should always be noexcept + static_assert(etl::is_nothrow_default_constructible>::value, "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + + CHECK(true); + } + + TEST(test_optional_nothrow_constructible_from_value) + { + // optional(U&&) should be noexcept iff T is nothrow constructible from U&& + static_assert(etl::is_nothrow_constructible, int>::value, "optional should be nothrow constructible from int"); + static_assert(etl::is_nothrow_constructible, int&&>::value, "optional should be nothrow constructible from int&&"); + + CHECK(true); + } + + TEST(test_optional_nothrow_copy_assignable) + { + // Copy assignment should propagate noexcept from T + static_assert(etl::is_nothrow_copy_assignable>::value, "optional should be nothrow copy assignable"); + static_assert(etl::is_nothrow_copy_assignable>::value, + "optional should be nothrow copy assignable"); + + // ThrowingCopy has a throwing copy constructor, so copy assignment should not be noexcept + static_assert(!etl::is_nothrow_copy_assignable>::value, + "optional should NOT be nothrow copy assignable"); + + CHECK(true); + } + + TEST(test_optional_nothrow_move_assignable) + { + // Move assignment should propagate noexcept from T + static_assert(etl::is_nothrow_move_assignable>::value, "optional should be nothrow move assignable"); + static_assert(etl::is_nothrow_move_assignable>::value, + "optional should be nothrow move assignable"); + + // ThrowingMove has a throwing move constructor, so move assignment should not be noexcept + static_assert(!etl::is_nothrow_move_assignable>::value, + "optional should NOT be nothrow move assignable"); + + CHECK(true); + } +#endif } } // namespace diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index 9f6c7bfc..f6ef4cda 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -102,8 +102,8 @@ namespace return *this; } - Copyable(Copyable&&) = delete; - Copyable& operator=(Copyable&) = delete; + Copyable(Copyable&&) = delete; + Copyable& operator=(Copyable&&) = delete; }; //********************************************* @@ -146,8 +146,8 @@ namespace return *this; } - NotDefaultConstructible(NotDefaultConstructible&&) = delete; - NotDefaultConstructible& operator=(NotDefaultConstructible&) = delete; + NotDefaultConstructible(NotDefaultConstructible&&) = delete; + NotDefaultConstructible& operator=(NotDefaultConstructible&&) = delete; }; // A function to test etl::type_identity. @@ -344,7 +344,7 @@ using etl::is_move_constructible; //************************* template <> -struct etl::is_assignable : public etl::true_type +struct etl::is_assignable : public etl::false_type { }; @@ -364,7 +364,7 @@ struct etl::is_copy_assignable : public etl::true_type }; template <> -struct etl::is_move_assignable : public etl::true_type +struct etl::is_move_assignable : public etl::false_type { }; @@ -1548,6 +1548,155 @@ namespace #endif } + //************************************************************************* + TEST(test_is_nothrow_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_constructible::value) == true); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_default_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_default_constructible::value) == true); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_copy_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_copy_constructible::value) == true); + CHECK((etl::is_nothrow_copy_constructible::value) == true); + CHECK((etl::is_nothrow_copy_constructible::value) == false); + CHECK((etl::is_nothrow_copy_constructible::value) == false); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_move_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == false); + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == false); + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) + == (std::is_nothrow_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK( + (etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_copy_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_copy_assignable::value) == true); + CHECK((etl::is_nothrow_copy_assignable::value) == true); + CHECK((etl::is_nothrow_copy_assignable::value) == false); + CHECK((etl::is_nothrow_copy_assignable::value) == false); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_move_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == false); + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + #endif +#endif + } + //************************************************************************* TEST(test_is_trivially_constructible) { diff --git a/test/test_variant_variadic.cpp b/test/test_variant_variadic.cpp index f8b8fe5f..1a1410ba 100644 --- a/test/test_variant_variadic.cpp +++ b/test/test_variant_variadic.cpp @@ -2243,6 +2243,131 @@ namespace CHECK(etl::holds_alternative(v1)); CHECK(etl::get_if(&v1) != nullptr); } + + //************************************************************************* + // Tests for noexcept properties of etl::variant + // The noexcept specs only take effect when ETL_USING_EXCEPTIONS is enabled, + // because ETL_NOEXCEPT_IF expands to nothing otherwise. + // The etl::is_nothrow_* traits only work with STL or builtins. + //************************************************************************* + #if ETL_USING_EXCEPTIONS && (defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS))) + + struct VariantNothrowType + { + VariantNothrowType() noexcept {} + VariantNothrowType(const VariantNothrowType&) noexcept {} + VariantNothrowType(VariantNothrowType&&) noexcept {} + VariantNothrowType& operator=(const VariantNothrowType&) noexcept + { + return *this; + } + VariantNothrowType& operator=(VariantNothrowType&&) noexcept + { + return *this; + } + }; + + struct VariantThrowingCopy + { + VariantThrowingCopy() noexcept {} + VariantThrowingCopy(const VariantThrowingCopy&) {} // may throw + VariantThrowingCopy(VariantThrowingCopy&&) noexcept {} + VariantThrowingCopy& operator=(const VariantThrowingCopy&) + { + return *this; + } + VariantThrowingCopy& operator=(VariantThrowingCopy&&) noexcept + { + return *this; + } + }; + + struct VariantThrowingMove + { + VariantThrowingMove() noexcept {} + VariantThrowingMove(const VariantThrowingMove&) noexcept {} + VariantThrowingMove(VariantThrowingMove&&) {} // may throw + VariantThrowingMove& operator=(const VariantThrowingMove&) noexcept + { + return *this; + } + VariantThrowingMove& operator=(VariantThrowingMove&&) + { + return *this; + } + }; + + TEST(test_variant_nothrow_copy_constructible) + { + // variant is nothrow copy constructible only if all Ts are + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_copy_constructible::value, "variant should be nothrow copy constructible"); + + using HasThrowingCopy = etl::variant; + static_assert(!etl::is_nothrow_copy_constructible::value, + "variant should NOT be nothrow copy constructible"); + + using HasThrowingMove = etl::variant; + static_assert(etl::is_nothrow_copy_constructible::value, + "variant should be nothrow copy constructible (copy is nothrow)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_move_constructible) + { + // variant is nothrow move constructible only if all Ts are + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_move_constructible::value, "variant should be nothrow move constructible"); + + using HasThrowingMove = etl::variant; + static_assert(!etl::is_nothrow_move_constructible::value, + "variant should NOT be nothrow move constructible"); + + using HasThrowingCopy = etl::variant; + static_assert(etl::is_nothrow_move_constructible::value, + "variant should be nothrow move constructible (move is nothrow)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_default_constructible) + { + // variant default-constructs the first alternative + using NothrowFirst = etl::variant; + static_assert(etl::is_nothrow_default_constructible::value, + "variant should be nothrow default constructible (int is nothrow)"); + + using ThrowingFirst = etl::variant; + // VariantThrowingCopy has noexcept default ctor, so this should be nothrow + static_assert(etl::is_nothrow_default_constructible::value, + "variant should be nothrow default constructible (ThrowingCopy has noexcept default ctor)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_copy_assignable) + { + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_copy_assignable::value, "variant should be nothrow copy assignable"); + + using HasThrowingCopy = etl::variant; + static_assert(!etl::is_nothrow_copy_assignable::value, "variant should NOT be nothrow copy assignable"); + + CHECK(true); + } + + TEST(test_variant_nothrow_move_assignable) + { + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_move_assignable::value, "variant should be nothrow move assignable"); + + using HasThrowingMove = etl::variant; + static_assert(!etl::is_nothrow_move_assignable::value, "variant should NOT be nothrow move assignable"); + + CHECK(true); + } + #endif } } // namespace From fbd738db691c41804cee60ffe87e5f94528c3fa3 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 22 Apr 2026 13:28:47 +0200 Subject: [PATCH 18/27] Replace deprecated builtin __is_trivially_relocatable if possible (#1402) Fixes: #1400 --- .../etl/profiles/determine_builtin_support.h | 43 ++++++++++++------- include/etl/type_traits.h | 11 ++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index f2be5693..da15062a 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -159,6 +159,12 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE __has_builtin(__is_trivially_relocatable) #endif + + // __builtin_is_cpp_trivially_relocatable replaces __is_trivially_relocatable by an + // effort of standardization for newer C++ standards + #if !defined(ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE __has_builtin(__builtin_is_cpp_trivially_relocatable) + #endif #endif // The default. Set to 0, if not already set. @@ -226,28 +232,33 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE 0 #endif +#if !defined(ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE 0 +#endif + namespace etl { namespace traits { // Documentation: https://www.etlcpp.com/etl_traits.html - static ETL_CONSTANT bool using_builtin_is_assignable = (ETL_USING_BUILTIN_IS_ASSIGNABLE == 1); - static ETL_CONSTANT bool using_builtin_is_constructible = (ETL_USING_BUILTIN_IS_CONSTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_nothrow_constructible = (ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_nothrow_assignable = (ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1); - static ETL_CONSTANT bool using_builtin_underlying_type = (ETL_USING_BUILTIN_UNDERLYING_TYPE == 1); - static ETL_CONSTANT bool using_builtin_is_constant_evaluated = (ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED == 1); - static ETL_CONSTANT bool using_builtin_memcpy = (ETL_USING_BUILTIN_MEMCPY == 1); - static ETL_CONSTANT bool using_builtin_memmove = (ETL_USING_BUILTIN_MEMMOVE == 1); - static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1); - static ETL_CONSTANT bool using_builtin_memcmp = (ETL_USING_BUILTIN_MEMCMP == 1); - static ETL_CONSTANT bool using_builtin_memchr = (ETL_USING_BUILTIN_MEMCHR == 1); - static ETL_CONSTANT bool using_builtin_is_virtual_base_of = (ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_relocatable = (ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE == 1); + static ETL_CONSTANT bool using_builtin_is_assignable = (ETL_USING_BUILTIN_IS_ASSIGNABLE == 1); + static ETL_CONSTANT bool using_builtin_is_constructible = (ETL_USING_BUILTIN_IS_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_constructible = (ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_assignable = (ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1); + static ETL_CONSTANT bool using_builtin_underlying_type = (ETL_USING_BUILTIN_UNDERLYING_TYPE == 1); + static ETL_CONSTANT bool using_builtin_is_constant_evaluated = (ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED == 1); + static ETL_CONSTANT bool using_builtin_memcpy = (ETL_USING_BUILTIN_MEMCPY == 1); + static ETL_CONSTANT bool using_builtin_memmove = (ETL_USING_BUILTIN_MEMMOVE == 1); + static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1); + static ETL_CONSTANT bool using_builtin_memcmp = (ETL_USING_BUILTIN_MEMCMP == 1); + static ETL_CONSTANT bool using_builtin_memchr = (ETL_USING_BUILTIN_MEMCHR == 1); + static ETL_CONSTANT bool using_builtin_is_virtual_base_of = (ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_relocatable = (ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE == 1); + static ETL_CONSTANT bool using_builtin_builtin_is_cpp_trivially_relocatable = (ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE == 1); } // namespace traits } // namespace etl diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 5732f935..2600da96 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -2728,6 +2728,9 @@ namespace etl #if ETL_HAS_STD_TRIVIALLY_RELOCATABLE && ETL_USING_STL template using is_trivially_relocatable = std::is_trivially_relocatable; + #elif ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + template + using is_trivially_relocatable = etl::bool_constant<__builtin_is_cpp_trivially_relocatable(T)>; #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE template using is_trivially_relocatable = etl::bool_constant<__is_trivially_relocatable(T)>; @@ -2977,7 +2980,9 @@ namespace etl template struct is_trivially_relocatable { - #if ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + #if ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + static ETL_CONSTANT bool value = __builtin_is_cpp_trivially_relocatable(T); + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE static ETL_CONSTANT bool value = __is_trivially_relocatable(T); #else static ETL_CONSTANT bool value = etl::is_trivially_copyable::value && etl::is_trivially_destructible::value; @@ -3500,7 +3505,9 @@ namespace etl //********************************************* // is_trivially_relocatable template - #if ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + #if ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + struct is_trivially_relocatable : public etl::bool_constant<__builtin_is_cpp_trivially_relocatable(T)> + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE struct is_trivially_relocatable : public etl::bool_constant<__is_trivially_relocatable(T)> #else struct is_trivially_relocatable : public etl::bool_constant::value && etl::is_trivially_destructible::value> From b96c2a9ecd5e38d946af21d4e990ee87e817d87a Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 27 Apr 2026 22:49:39 +0200 Subject: [PATCH 19/27] Consolidate Dockerfile non-root user to vscode (#1417) Previously, we had differently named default users in the containers. --- .devcontainer/armhf/Dockerfile | 2 +- .devcontainer/i386/Dockerfile | 2 +- .devcontainer/powerpc/Dockerfile | 2 +- .devcontainer/riscv64/Dockerfile | 2 +- .devcontainer/s390x/Dockerfile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.devcontainer/armhf/Dockerfile b/.devcontainer/armhf/Dockerfile index 7d5632a6..7d555f36 100644 --- a/.devcontainer/armhf/Dockerfile +++ b/.devcontainer/armhf/Dockerfile @@ -24,7 +24,7 @@ RUN dpkg --add-architecture armhf && \ && rm -rf /var/lib/apt/lists/* # Create non-root user with stable UID/GID -ARG USERNAME=devuser +ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=1000 diff --git a/.devcontainer/i386/Dockerfile b/.devcontainer/i386/Dockerfile index 99223eb9..bace68cd 100644 --- a/.devcontainer/i386/Dockerfile +++ b/.devcontainer/i386/Dockerfile @@ -24,7 +24,7 @@ RUN dpkg --add-architecture i386 && \ && rm -rf /var/lib/apt/lists/* # Create non-root user with stable UID/GID -ARG USERNAME=devuser +ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=1000 diff --git a/.devcontainer/powerpc/Dockerfile b/.devcontainer/powerpc/Dockerfile index a74cb690..faa94096 100644 --- a/.devcontainer/powerpc/Dockerfile +++ b/.devcontainer/powerpc/Dockerfile @@ -49,7 +49,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # Create non-root user with stable UID/GID -ARG USERNAME=devuser +ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=1000 diff --git a/.devcontainer/riscv64/Dockerfile b/.devcontainer/riscv64/Dockerfile index 081e42ed..7d07cdda 100644 --- a/.devcontainer/riscv64/Dockerfile +++ b/.devcontainer/riscv64/Dockerfile @@ -24,7 +24,7 @@ RUN dpkg --add-architecture riscv64 && \ && rm -rf /var/lib/apt/lists/* # Create non-root user with stable UID/GID -ARG USERNAME=devuser +ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=1000 diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index f8c6ff87..5656bc1d 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -24,7 +24,7 @@ RUN dpkg --add-architecture s390x && \ && rm -rf /var/lib/apt/lists/* # Create non-root user with stable UID/GID -ARG USERNAME=devuser +ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=1000 From 43e97b7f3cdcb0aefbeff4934ab746b9594941c9 Mon Sep 17 00:00:00 2001 From: Joris Putcuyps Date: Tue, 28 Apr 2026 09:30:23 +0200 Subject: [PATCH 20/27] Expected actually doesn't require a monostate. (#1413) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Expected actually doesn't require a monostate. * Better naming, since uninitialised isn't an option for expected. --------- Co-authored-by: Roland Reichwein Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/expected.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/etl/expected.h b/include/etl/expected.h index 2bb2ca9a..503b08ba 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -827,13 +827,12 @@ namespace etl enum { - Uninitialised, Value_Type, Error_Type }; - typedef etl::variant storage_type; - storage_type storage; + typedef etl::variant storage_type; + storage_type storage; #if ETL_USING_CPP11 template < typename F, typename TExp, typename TRet, typename TValueRef, typename = typename etl::enable_if::value>::type> @@ -1189,7 +1188,7 @@ namespace etl enum { - Uninitialised, + Void_Type, Error_Type }; From ff772d4bd15ede7574088ac8e844ed509ef1f8aa Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 28 Apr 2026 09:57:21 +0200 Subject: [PATCH 21/27] Move operators for etl::unique_ptr to etl namespace (#1408) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Move operators for etl::unique_ptr to etl namespace This is in accordance with the operators of std::unique_ptr. Also, it doesn't pollute the global namespace, and also works together with ADL, finding the operators in the etl namespace now. --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/memory.h | 68 +++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/include/etl/memory.h b/include/etl/memory.h index 0bf9e3d6..e4301260 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -2370,47 +2370,43 @@ namespace etl pointer p; TDeleter deleter; }; -} // namespace etl -//***************************************************************************** -// Global functions for unique_ptr -//***************************************************************************** -template -bool operator==(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return lhs.get() == rhs.get(); -} + //***************************************************************************** + // Comparison operators for unique_ptr + //***************************************************************************** + template + bool operator==(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return lhs.get() == rhs.get(); + } -//********************************* -template -bool operator<(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); -} + //********************************* + template + bool operator<(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); + } -//********************************* -template -bool operator<=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return !(rhs < lhs); -} + //********************************* + template + bool operator<=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return !(rhs < lhs); + } -//********************************* -template -bool operator>(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return (rhs < lhs); -} + //********************************* + template + bool operator>(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return (rhs < lhs); + } -//********************************* -template -bool operator>=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return !(lhs < rhs); -} - -namespace etl -{ + //********************************* + template + bool operator>=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return !(lhs < rhs); + } //***************************************************************************** /// Default construct an item at address p. ///\ingroup memory From 5ccbc6fbff06f523c44fbc563681a0a9fe28a93f Mon Sep 17 00:00:00 2001 From: Joris Putcuyps Date: Tue, 28 Apr 2026 10:23:52 +0200 Subject: [PATCH 22/27] Swap can be part of the etl namespace and let ADL do its thing (#1414) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Swap can be part of the etl namespace and let ADL do its thing --------- Co-authored-by: Roland Reichwein Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/expected.h | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/include/etl/expected.h b/include/etl/expected.h index 503b08ba..a8335247 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -1380,24 +1380,25 @@ namespace etl { return !(lhs == rhs); } + + //******************************************* + /// Swap etl::expected. + //******************************************* + template + ETL_CONSTEXPR14 void swap(etl::expected& lhs, etl::expected& rhs) + { + lhs.swap(rhs); + } + + //******************************************* + /// Swap etl::unexpected. + //******************************************* + template + ETL_CONSTEXPR14 void swap(etl::unexpected& lhs, etl::unexpected& rhs) + { + lhs.swap(rhs); + } + } // namespace etl -//******************************************* -/// Swap etl::expected. -//******************************************* -template -ETL_CONSTEXPR14 void swap(etl::expected& lhs, etl::expected& rhs) -{ - lhs.swap(rhs); -} - -//******************************************* -/// Swap etl::unexpected. -//******************************************* -template -ETL_CONSTEXPR14 void swap(etl::unexpected& lhs, etl::unexpected& rhs) -{ - lhs.swap(rhs); -} - #endif From fe7b2da10cabfad4aa2f0808b36fc6c60224301b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 28 Apr 2026 11:03:25 +0200 Subject: [PATCH 23/27] Fix missing tuple_size (#1407) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Fix missing tuple_size In case of certain clang versions, a wrong combination of activated and deactivated template forward declarations and specializations were provided. This led to redefinition errors and specialization errors. Now aligning those combinations, and providing definitions from from std in the STL using case. --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/tuple.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/etl/tuple.h b/include/etl/tuple.h index f76c0a62..0a419374 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -35,6 +35,7 @@ SOFTWARE. #if ETL_USING_STL #include + #include #endif #include "functional.h" @@ -1179,7 +1180,9 @@ namespace etl namespace std { - #if ETL_NOT_USING_STL && !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000)) && defined(ETL_COMPILER_CLANG)) + #if ETL_NOT_USING_STL \ + && !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000) && (ETL_COMPILER_FULL_VERSION < 220000)) \ + && defined(ETL_COMPILER_CLANG)) template struct tuple_size; From ee0d4740b3a27aaefbcd6b8e6960080202836d4b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 28 Apr 2026 11:43:54 +0200 Subject: [PATCH 24/27] Add begin() and end() to etl::expected (#1410) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Add begin() and end() to etl::expected * Adding error_or() to etl::expected --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/expected.h | 129 ++++++++++++++++++++++++++++++++++++++ test/test_expected.cpp | 139 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) diff --git a/include/etl/expected.h b/include/etl/expected.h index a8335247..829c4247 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -604,6 +604,38 @@ namespace etl return etl::move(etl::get(storage)); } + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) const& + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return error(); + } + } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) && + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return etl::move(error()); + } + } + //******************************************* /// Swap with another etl::expected. //******************************************* @@ -661,6 +693,22 @@ namespace etl { return etl::get(storage); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + error_type error_or(const G& default_error) const + { + if (has_value()) + { + return static_cast(default_error); + } + else + { + return error(); + } + } #endif //******************************************* @@ -725,6 +773,39 @@ namespace etl } #endif + //******************************************* + /// Returns a pointer to the value if has_value(), otherwise returns nullptr. + /// Allows expected to be used as a range of 0 or 1 elements. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 value_type* begin() ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) : ETL_NULLPTR; + } + + //******************************************* + /// Returns a pointer past the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 value_type* end() ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) + 1 : ETL_NULLPTR; + } + + //******************************************* + /// Returns a const pointer to the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 const value_type* begin() const ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) : ETL_NULLPTR; + } + + //******************************************* + /// Returns a const pointer past the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 const value_type* end() const ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) + 1 : ETL_NULLPTR; + } + #if ETL_USING_CPP11 template ::type>::type> auto transform(F&& f) & -> expected @@ -1065,6 +1146,38 @@ namespace etl { return etl::move(etl::get(storage)); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) const& + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return error(); + } + } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) && + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return etl::move(error()); + } + } #else //******************************************* /// Returns the error @@ -1074,6 +1187,22 @@ namespace etl { return etl::get(storage); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + error_type error_or(const G& default_error) const + { + if (has_value()) + { + return static_cast(default_error); + } + else + { + return error(); + } + } #endif //******************************************* diff --git a/test/test_expected.cpp b/test/test_expected.cpp index 024ecf47..a28e2f54 100644 --- a/test/test_expected.cpp +++ b/test/test_expected.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "etl/expected.h" #include "etl/type_traits.h" +#include #include #include @@ -1477,5 +1478,143 @@ namespace auto with_error_type_check = check_expected_type_helper(unexpected_out); CHECK_TRUE(with_error_type_check); } + + //************************************************************************* + TEST(test_begin_end_with_value) + { + etl::expected exp(std::string("hello")); + + CHECK_TRUE(exp.begin() != exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 1); + CHECK_EQUAL(*exp.begin(), std::string("hello")); + } + + //************************************************************************* + TEST(test_begin_end_with_error) + { + etl::expected exp(etl::unexpected(Error("err"))); + + CHECK_TRUE(exp.begin() == exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 0); + } + + //************************************************************************* + TEST(test_begin_end_const_with_value) + { + const etl::expected exp(std::string("world")); + + CHECK_TRUE(exp.begin() != exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 1); + CHECK_EQUAL(*exp.begin(), std::string("world")); + } + + //************************************************************************* + TEST(test_begin_end_const_with_error) + { + const etl::expected exp(etl::unexpected(Error("err"))); + + CHECK_TRUE(exp.begin() == exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 0); + } + + //************************************************************************* + TEST(test_range_for_with_value) + { + etl::expected exp(42); + + int count = 0; + int sum = 0; + for (auto& v : exp) + { + ++count; + sum += v; + } + + CHECK_EQUAL(1, count); + CHECK_EQUAL(42, sum); + } + + //************************************************************************* + TEST(test_range_for_with_error) + { + etl::expected exp(etl::unexpected(Error("err"))); + + int count = 0; + for (auto& v : exp) + { + (void)v; + ++count; + } + + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_error_or_with_value) + { + etl::expected exp(42); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_with_error) + { + etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_const_with_value) + { + const etl::expected exp(42); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_const_with_error) + { + const etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_rvalue_with_value) + { + Error result = etl::expected(42).error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_rvalue_with_error) + { + Error result = etl::expected(etl::unexpected(Error("real_error"))).error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_void_value_with_value) + { + etl::expected exp; + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_void_value_with_error) + { + etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } } } // namespace From 15ca12649e9273f6243cf69183038b4fff63fa38 Mon Sep 17 00:00:00 2001 From: Joris Putcuyps Date: Tue, 28 Apr 2026 14:13:55 +0200 Subject: [PATCH 25/27] Global namespace bitset free functions cleanup (#1411) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Keep comparison and swap free functions out of the global namespace and let ADL do its thing. * Apply the same global to etl namespace move on overlooked functions --------- Co-authored-by: Roland Reichwein Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/private/bitset_legacy.h | 18 +- include/etl/private/bitset_new.h | 498 ++++++++++++++-------------- 2 files changed, 256 insertions(+), 260 deletions(-) diff --git a/include/etl/private/bitset_legacy.h b/include/etl/private/bitset_legacy.h index 7fa70ce3..8846e034 100644 --- a/include/etl/private/bitset_legacy.h +++ b/include/etl/private/bitset_legacy.h @@ -1523,16 +1523,16 @@ namespace etl { return !(lhs == rhs); } -} // namespace etl -//************************************************************************* -/// swap -//************************************************************************* -template -void swap(etl::bitset& lhs, etl::bitset& rhs) -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + void swap(etl::bitset& lhs, etl::bitset& rhs) + { + lhs.swap(rhs); + } +} // namespace etl #include "minmax_pop.h" diff --git a/include/etl/private/bitset_new.h b/include/etl/private/bitset_new.h index 19d21794..e33f3b10 100644 --- a/include/etl/private/bitset_new.h +++ b/include/etl/private/bitset_new.h @@ -2519,32 +2519,30 @@ namespace etl temp ^= rhs; return temp; } -} // namespace etl -//*************************************************************************** -/// operator != -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } -//************************************************************************* -/// swap -//************************************************************************* -template -ETL_CONSTEXPR14 void swap(etl::bitset& lhs, etl::bitset& rhs) ETL_NOEXCEPT -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + ETL_CONSTEXPR14 void swap(etl::bitset& lhs, etl::bitset& rhs) ETL_NOEXCEPT + { + lhs.swap(rhs); + } + + //*************************************************************************** + /// bitset_ext + //*************************************************************************** -//*************************************************************************** -/// bitset_ext -//*************************************************************************** -namespace etl -{ //*************************************************************************** template class bitset_ext; @@ -3396,29 +3394,26 @@ namespace etl // Pointer to the storage for the bitset. element_type* pbuffer; }; -} // namespace etl -//*************************************************************************** -/// operator != -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } -//************************************************************************* -/// swap -//************************************************************************* -template -ETL_CONSTEXPR14 void swap(etl::bitset_ext& lhs, etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + ETL_CONSTEXPR14 void swap(etl::bitset_ext& lhs, etl::bitset_ext& rhs) ETL_NOEXCEPT + { + lhs.swap(rhs); + } -namespace etl -{ namespace private_bitset { //************************************************************************* @@ -3464,216 +3459,217 @@ namespace etl return true; } } // namespace private_bitset + + //*************************************************************************** + /// operator == + /// bitset + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset_ext + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset compared with bitset_ext, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + const char Storage_Model = etl::bitset::Storage_Model; + const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; + + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + typedef etl::bitset_impl implementation; + + return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); + } + + //*************************************************************************** + /// operator != + /// bitset compared with bitset_ext, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext compared with bitset, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + const char Storage_Model = etl::bitset::Storage_Model; + const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; + + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + typedef etl::bitset_impl implementation; + + return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); + } + + //*************************************************************************** + /// operator != + /// bitset_ext compared with bitset, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset compared with bitset_ext, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset compared with bitset_ext, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext compared with bitset, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset_ext compared with bitset, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + } // namespace etl -//*************************************************************************** -/// operator == -/// bitset -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset_ext -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset compared with bitset_ext, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - const char Storage_Model = etl::bitset::Storage_Model; - const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; - - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - typedef etl::bitset_impl implementation; - - return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); -} - -//*************************************************************************** -/// operator != -/// bitset compared with bitset_ext, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext compared with bitset, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - const char Storage_Model = etl::bitset::Storage_Model; - const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; - - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - typedef etl::bitset_impl implementation; - - return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); -} - -//*************************************************************************** -/// operator != -/// bitset_ext compared with bitset, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset compared with bitset_ext, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset compared with bitset_ext, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext compared with bitset, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset_ext compared with bitset, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - #include "minmax_pop.h" #endif From 943e8e60891aacf37e0dfd29badaf44b50ccaba2 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 28 Apr 2026 15:35:21 +0200 Subject: [PATCH 26/27] Add invocable and further missing concepts to concepts.h (#1412) * Print test names at test time (#1343) * Fix operator| conflict with std::ranges (#1395) * Add concept invocable and further missing concepts to concepts.h --------- Co-authored-by: John Wellbelove Co-authored-by: John Wellbelove --- include/etl/concepts.h | 126 ++++++++++++++++++++ include/etl/type_traits.h | 25 ++++ test/test_concepts.cpp | 237 ++++++++++++++++++++++++++++++++++++++ test/test_type_traits.cpp | 38 ++++++ 4 files changed, 426 insertions(+) diff --git a/include/etl/concepts.h b/include/etl/concepts.h index ac539947..9376264b 100644 --- a/include/etl/concepts.h +++ b/include/etl/concepts.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" +#include "invoke.h" #include "type_traits.h" #include "utility.h" @@ -50,12 +51,31 @@ namespace etl using std::assignable_from; using std::common_reference_with; using std::common_with; + using std::constructible_from; using std::convertible_to; + using std::copy_constructible; + using std::copyable; + using std::default_initializable; using std::derived_from; + using std::destructible; + using std::equality_comparable; + using std::equivalence_relation; using std::floating_point; using std::integral; + using std::invocable; + using std::movable; + using std::move_constructible; + using std::predicate; + using std::regular; + using std::regular_invocable; + using std::relation; using std::same_as; + using std::semiregular; using std::signed_integral; + using std::strict_weak_order; + using std::swappable; + using std::swappable_with; + using std::totally_ordered; using std::unsigned_integral; #else // not ETL_USING_STL @@ -114,6 +134,112 @@ namespace etl { lhs = etl::forward(rhs) } -> etl::same_as; }; + //*************************************************************************** + template + concept invocable = etl::is_invocable_v; + + //*************************************************************************** + template + concept regular_invocable = etl::invocable; + + //*************************************************************************** + template + concept destructible = requires(T& t) { + { t.~T() } noexcept; + }; + + //*************************************************************************** + template + concept constructible_from = etl::destructible && etl::is_constructible_v; + + //*************************************************************************** + template + concept default_initializable = etl::constructible_from && requires { + T{}; + ::new T; + }; + + //*************************************************************************** + template + concept move_constructible = etl::constructible_from && etl::convertible_to; + + //*************************************************************************** + template + concept copy_constructible = + etl::move_constructible && etl::constructible_from && etl::convertible_to && etl::constructible_from + && etl::convertible_to && etl::constructible_from && etl::convertible_to; + + //*************************************************************************** + namespace private_concepts + { + template + concept boolean_testable = etl::convertible_to && requires(T&& t) { + { !etl::forward(t) } -> etl::convertible_to; + }; + } // namespace private_concepts + + //*************************************************************************** + template + concept equality_comparable = requires(const etl::remove_reference_t& a, const etl::remove_reference_t& b) { + { a == b } -> private_concepts::boolean_testable; + { a != b } -> private_concepts::boolean_testable; + }; + + //*************************************************************************** + template + concept totally_ordered = etl::equality_comparable && requires(const etl::remove_reference_t& a, const etl::remove_reference_t& b) { + { a < b } -> private_concepts::boolean_testable; + { a > b } -> private_concepts::boolean_testable; + { a <= b } -> private_concepts::boolean_testable; + { a >= b } -> private_concepts::boolean_testable; + }; + + //*************************************************************************** + template + concept swappable = requires(T& a, T& b) { etl::swap(a, b); }; + + //*************************************************************************** + template + concept swappable_with = etl::common_reference_with&, etl::remove_reference_t&> && requires(T&& t, U&& u) { + etl::swap(etl::forward(t), etl::forward(t)); + etl::swap(etl::forward(u), etl::forward(u)); + etl::swap(etl::forward(t), etl::forward(u)); + etl::swap(etl::forward(u), etl::forward(t)); + }; + + //*************************************************************************** + template + concept movable = etl::is_object_v && etl::move_constructible && etl::assignable_from && etl::swappable; + + //*************************************************************************** + template + concept copyable = etl::copy_constructible && etl::movable && etl::assignable_from && etl::assignable_from + && etl::assignable_from; + + //*************************************************************************** + template + concept semiregular = etl::copyable && etl::default_initializable; + + //*************************************************************************** + template + concept regular = etl::semiregular && etl::equality_comparable; + + //*************************************************************************** + template + concept predicate = etl::regular_invocable && private_concepts::boolean_testable >; + + //*************************************************************************** + template + concept relation = etl::predicate && etl::predicate && etl::predicate && etl::predicate; + + //*************************************************************************** + template + concept equivalence_relation = etl::relation; + + //*************************************************************************** + template + concept strict_weak_order = etl::relation; + #endif } // namespace etl #endif diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 2600da96..2b4372af 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -649,6 +649,18 @@ namespace etl struct is_void : true_type { }; + template <> + struct is_void : true_type + { + }; + template <> + struct is_void : true_type + { + }; + template <> + struct is_void : true_type + { + }; #if ETL_USING_CPP17 template @@ -3977,6 +3989,19 @@ namespace etl template inline constexpr bool is_function_v = etl::is_function::value; #endif + + //*************************************************************************** + /// is_object + //*************************************************************************** + template + struct is_object : etl::bool_constant::value && !etl::is_reference::value && !etl::is_void::value> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_object_v = etl::is_object::value; + #endif #endif #if ETL_USING_CPP11 diff --git a/test/test_concepts.cpp b/test/test_concepts.cpp index 347ec8fb..a6b03830 100644 --- a/test/test_concepts.cpp +++ b/test/test_concepts.cpp @@ -29,6 +29,7 @@ SOFTWARE. #include "unit_test_framework.h" #include +#include #include #if ETL_USING_CPP20 @@ -52,6 +53,65 @@ namespace { }; + struct NotDestructible + { + ~NotDestructible() = delete; + }; + + struct NotDefaultConstructible + { + NotDefaultConstructible(int) {} + }; + + struct NotCopyable + { + NotCopyable() = default; + NotCopyable(const NotCopyable&) = delete; + NotCopyable(NotCopyable&&) = default; + NotCopyable& operator=(const NotCopyable&) = delete; + NotCopyable& operator=(NotCopyable&&) = default; + }; + + struct NotMovable + { + NotMovable() = default; + NotMovable(const NotMovable&) = delete; + NotMovable(NotMovable&&) = delete; + NotMovable& operator=(const NotMovable&) = delete; + NotMovable& operator=(NotMovable&&) = delete; + }; + + struct NotEqualityComparable + { + }; + + struct EqualityComparableType + { + bool operator==(const EqualityComparableType&) const = default; + }; + + struct OrderedType + { + int value; + auto operator<=>(const OrderedType&) const = default; + }; + + struct BoolPredicate + { + bool operator()(int) const + { + return true; + } + }; + + struct IntRelation + { + bool operator()(int, int) const + { + return true; + } + }; + SUITE(test_concepts) { //************************************************************************* @@ -140,6 +200,183 @@ namespace static_assert(etl::assignable_from == false); static_assert(etl::assignable_from&, int> == false); } + + //************************************************************************* + TEST(test_invocable) + { + struct Functor + { + void operator()() {} + }; + struct FunctorWithArgs + { + int operator()(int, double) + { + return 0; + } + }; + + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == false); + static_assert(etl::invocable == false); + } + + //************************************************************************* + TEST(test_regular_invocable) + { + struct Functor + { + void operator()() {} + }; + + static_assert(etl::regular_invocable == true); + static_assert(etl::regular_invocable == true); + static_assert(etl::regular_invocable == false); + } + + //************************************************************************* + TEST(test_destructible) + { + static_assert(etl::destructible == true); + static_assert(etl::destructible == true); + static_assert(etl::destructible == false); + } + + //************************************************************************* + TEST(test_constructible_from) + { + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == false); + } + + //************************************************************************* + TEST(test_default_initializable) + { + static_assert(etl::default_initializable == true); + static_assert(etl::default_initializable == true); + static_assert(etl::default_initializable == false); + } + + //************************************************************************* + TEST(test_move_constructible) + { + static_assert(etl::move_constructible == true); + static_assert(etl::move_constructible == true); + static_assert(etl::move_constructible == false); + } + + //************************************************************************* + TEST(test_copy_constructible) + { + static_assert(etl::copy_constructible == true); + static_assert(etl::copy_constructible == true); + static_assert(etl::copy_constructible == false); + } + + //************************************************************************* + TEST(test_equality_comparable) + { + static_assert(etl::equality_comparable == true); + static_assert(etl::equality_comparable == true); + static_assert(etl::equality_comparable == false); + } + + //************************************************************************* + TEST(test_totally_ordered) + { + static_assert(etl::totally_ordered == true); + static_assert(etl::totally_ordered == true); + static_assert(etl::totally_ordered == false); + } + + //************************************************************************* + TEST(test_swappable) + { + static_assert(etl::swappable == true); + static_assert(etl::swappable == true); + static_assert(etl::swappable == false); + } + + //************************************************************************* + TEST(test_swappable_with) + { + // Positive cases: same-type lvalue references that are swappable + static_assert(etl::swappable_with == true); + static_assert(etl::swappable_with == true); + + // Negative cases: unrelated types (no valid swap overload) + static_assert(etl::swappable_with == false); + + // Negative case: non-movable type cannot be swapped + static_assert(etl::swappable_with == false); + } + + //************************************************************************* + TEST(test_movable) + { + static_assert(etl::movable == true); + static_assert(etl::movable == true); + static_assert(etl::movable == false); + } + + //************************************************************************* + TEST(test_copyable) + { + static_assert(etl::copyable == true); + static_assert(etl::copyable == true); + static_assert(etl::copyable == false); + } + + //************************************************************************* + TEST(test_semiregular) + { + static_assert(etl::semiregular == true); + static_assert(etl::semiregular == true); + static_assert(etl::semiregular == false); + } + + //************************************************************************* + TEST(test_regular) + { + static_assert(etl::regular == true); + static_assert(etl::regular == true); + static_assert(etl::regular == false); + } + + //************************************************************************* + TEST(test_predicate) + { + static_assert(etl::predicate == true); + static_assert(etl::predicate == true); + static_assert(etl::predicate == false); + } + + //************************************************************************* + TEST(test_relation) + { + static_assert(etl::relation == true); + static_assert(etl::relation, int, int> == true); + static_assert(etl::relation == false); + } + + //************************************************************************* + TEST(test_equivalence_relation) + { + static_assert(etl::equivalence_relation, int, int> == true); + static_assert(etl::equivalence_relation == false); + } + + //************************************************************************* + TEST(test_strict_weak_order) + { + static_assert(etl::strict_weak_order, int, int> == true); + static_assert(etl::strict_weak_order == false); + } } } // namespace #endif diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index f6ef4cda..bb4d73f1 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -2211,5 +2211,43 @@ namespace CHECK_FALSE((etl::is_function::value)); CHECK_FALSE((etl::is_function::value)); // pointer, not function } + + //************************************************************************* + TEST(test_is_object) + { + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + + CHECK_TRUE((etl::is_void::value)); + CHECK_TRUE((etl::is_void::value)); + CHECK_TRUE((etl::is_void::value)); + +#if ETL_USING_CPP17 + CHECK_TRUE((etl::is_object_v)); + CHECK_TRUE((etl::is_object_v)); + CHECK_TRUE((etl::is_object_v)); + + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); +#endif + } } } // namespace From a1cd6a5569afab04439a5c0e20b4786fb1a04bec Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 29 Apr 2026 09:33:56 +0200 Subject: [PATCH 27/27] Activate -O3 in CI builds for C++23 (#1415) * Activate -O3 in CI builds for C++23 For good coverage of potential warnings triggered by -O3, activate it for: * .github/workflows/clang-c++23.yml * .github/workflows/gcc-c++23.yml So additionally necessary CPU resources are limited. * Use Ubuntu-24.04 to test C++23 --------- Co-authored-by: John Wellbelove --- .github/workflows/clang-c++23.yml | 59 ++++++++++--------------------- .github/workflows/gcc-c++23.yml | 16 ++++----- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/.github/workflows/clang-c++23.yml b/.github/workflows/clang-c++23.yml index acd22a41..0c2d8c9b 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -13,25 +13,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ - clang-17 --version + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests @@ -42,25 +35,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ - clang-17 --version + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests @@ -71,25 +57,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ - clang-17 --version + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests @@ -110,7 +89,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -132,7 +111,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -154,7 +133,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -176,7 +155,7 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version make -j "$(getconf _NPROCESSORS_ONLN)" diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index 654deff9..9ca6baf0 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -23,7 +23,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -35,7 +35,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -45,7 +45,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -57,7 +57,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -67,7 +67,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version make -j "$(getconf _NPROCESSORS_ONLN)" @@ -79,7 +79,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -89,7 +89,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version make -j "$(getconf _NPROCESSORS_ONLN)"