Merge branch 'development' into issue/clean-up-the-use-of-type-traits

This commit is contained in:
John Wellbelove 2026-07-19 09:52:14 +01:00 committed by GitHub
commit 1415ddac0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 859 additions and 170 deletions

View File

@ -314,3 +314,42 @@ operator >=
```
**Description**
`true` if the contents of the lhs are lexicographically greater than or equal to the contents of the rhs, otherwise `false`.
---
```cpp
template <size_t Index, typename T, size_t Size>
T& get(etl::array<T, Size>& a)
template <size_t Index, typename T, size_t Size>
const T& get(const etl::array<T, Size>& a)
```
**Description**
Gets a reference to the element at `Index` in the array.
## Structured bindings
`etl::array` provides the tuple-like interface required for C++17 structured bindings.
```cpp
etl::array<int, 3> a = { 1, 2, 3 };
auto& [x, y, z] = a; // x, y, z are references to a[0], a[1], a[2]
```
```cpp
template <typename T, size_t Size>
struct tuple_size<etl::array<T, Size>>
```
**Description**
Gets the number of elements in the array.
Specialised in namespaces `etl` and `std` (the `std` specialisation allows the use of C++ structured bindings).
---
```cpp
template <size_t Index, typename T, size_t Size>
struct tuple_element<Index, etl::array<T, Size>>
```
**Description**
Gets the type of the element at `Index` in the array.
Specialised in namespaces `etl` and `std` (the `std` specialisation allows the use of C++ structured bindings).

View File

@ -249,3 +249,21 @@ template <typename T, typename... Types>
ETL_CONSTEXPR14
const T&& get(const tuple<Types...>&&);
```
---
```cpp
template <typename TFunction, typename TTuple>
ETL_CONSTEXPR14
auto apply(TFunction&& f, TTuple&& t);
```
Invokes the callable object `f` (via `etl::invoke`) with the elements of the tuple `t` expanded as its arguments. Equivalent to `std::apply`.
```cpp
int add(int a, int b, int c) { return a + b + c; }
auto t = etl::make_tuple(1, 2, 3);
int sum = etl::apply(add, t); // sum == 6
```

View File

@ -1,112 +0,0 @@
---
title: "type_id"
---
{{< callout type="info">}}
Header: `type_id.h`
Since: `TBC`
{{< /callout >}}
Below is a concise, technical overview of the `etl::type_id` facility, suitable for design documentation or code review context.
## Overview:
`etl::type_id` is a lightweight, RTTI-free mechanism for uniquely identifying C++ types at runtime. It is designed for environments where standard RTTI (`typeid`, `std::type_info`) is unavailable, undesirable, or too costly—such as embedded systems or performance-constrained platforms.
The implementation guarantees uniqueness per type within a program image while remaining constexpr-friendly and requiring no dynamic allocation.
## Design Concept
The core idea is to associate each distinct type `T` with the address of a unique static object. That address serves as the types identifier.
This is achieved through:
```cpp
template <typename T>
struct type_id_anchor
{
static char value;
};
```
Each instantiation of `type_id_anchor<T>` owns its own `static char value`, and the address of that variable is guaranteed to be unique for each distinct `T`. The address is stable for the lifetime of the program.
## Key Components
### Type Normalization
When requesting a type ID via `type_id::get<T>()`, the type is first normalised:
```cpp
using type = typename etl::remove_cvref<T>::type;
```
This ensures that:
* `T`, `const T`, `T&`, and `T&&` all map to the same `type_id`
* Only the underlying type identity matters
### Type ID Generation
```cpp
template <typename T>
static ETL_CONSTEXPR type_id get() ETL_NOEXCEPT;
```
* Returns a `type_id` that uniquely represents `T`
* Internally stores the address of `type_id_anchor<T>::value`
* Requires no RTTI, no dynamic memory, and no runtime registration
### Invalid Type ID
```cpp
static ETL_CONSTEXPR type_id invalid_id() ETL_NOEXCEPT;
```
* Represents an invalid or uninitialised type ID
* Implemented as a null pointer (`id == nullptr`)
* Default constructor produces this state
## `type_id` Class Semantics
### Storage
```cpp
const void* id;
```
* The identifier is stored as a pointer
* Comparison is purely pointer comparison (fast and deterministic)
### Supported Operations
| Operation | Behavior |
| ------------------ | -------------------------------------------------- |
| Equality (`==`) | True if both type IDs refer to the same type |
| Inequality (`!=`) | Logical negation of equality |
| Ordering (`<`) | Pointer comparison (useful for ordered containers) |
| Boolean conversion | `true` if valid, `false` if invalid |
| Integer conversion | Explicit conversion to `intptr_t` / `uintptr_t` |
### Copy and Assignment
* Copyable and assignable
* Copy semantics preserve identity (pointer value)
## Guarantees and Properties
* **Uniqueness**: Each distinct type has exactly one unique `type_id`
* **Stability**: Type IDs remain valid for the entire program lifetime
* **Zero overhead**: No dynamic allocation, no lookup tables
* **RTTI-free**: Suitable for builds with RTTI disabled
* **Comparable**: Can be used as keys in associative containers
## Typical Use Cases
* Type-safe containers (e.g., variant, any, message buses)
* Plugin or component systems
* Compile-time / runtime type discrimination in embedded systems
* Replacement for `std::type_index` in restricted environments
## Summary
`etl::type_id` provides a robust, minimal, and efficient alternative to C++ RTTI by encoding type identity as the address of a unique static object. Its design is particularly well-suited to embedded and low-level systems where determinism, performance, and binary size are critical.

View File

@ -71,6 +71,82 @@ T exchange(T& object, const U& new_value)
Copies the new value to object and returns the old value.
Note: This is not an atomic operation.
## Integer comparison functions
Safe comparison of integers of different signedness. Unlike the built-in
comparison operators, negative signed integers always compare less than (and
never equal to) unsigned integers, so the result is never affected by
value-changing implicit conversions.
The arguments must be standard signed or unsigned integer types, including
`signed char` and `unsigned char`. `bool`, `char` and the extended character
types are not permitted.
When the STL is available and the compiler provides
`__cpp_lib_integer_comparison_functions` (C++20), the `std` versions are used.
Since: `20.49.0`
```cpp
template <typename T, typename U>
constexpr bool cmp_equal(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is equal to `u`.
---
```cpp
template <typename T, typename U>
constexpr bool cmp_not_equal(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is not equal to `u`.
---
```cpp
template <typename T, typename U>
constexpr bool cmp_less(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is less than `u`.
---
```cpp
template <typename T, typename U>
constexpr bool cmp_greater(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is greater than `u`.
---
```cpp
template <typename T, typename U>
constexpr bool cmp_less_equal(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is less than or equal to `u`.
---
```cpp
template <typename T, typename U>
constexpr bool cmp_greater_equal(T t, U u) noexcept
```
**Description**
Returns `true` if `t` is greater than or equal to `u`.
---
```cpp
template <typename R, typename T>
constexpr bool in_range(T t) noexcept
```
**Description**
Returns `true` if the value of `t` is in the range of values that can be
represented by `R`, that is, if `t` can be converted to `R` without loss of its
value.
## add_const
```cpp

View File

@ -40,6 +40,9 @@ SOFTWARE.
#include "static_assert.h"
#include "type_traits.h"
#include "private/tuple_element.h"
#include "private/tuple_size.h"
#include <stddef.h>
///\defgroup array array
@ -709,7 +712,7 @@ namespace etl
//*************************************************************************
/// Returns a const reference to the last element.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR const_reference back() const
ETL_NODISCARD ETL_CONSTEXPR const_reference back() const ETL_NOEXCEPT
{
return *data();
}
@ -1063,7 +1066,7 @@ namespace etl
///\param rhs The second array.
//*************************************************************************
template <typename T, const size_t SIZE>
void swap(etl::array<T, SIZE>& lhs, etl::array<T, SIZE>& rhs)
ETL_CONSTEXPR14 void swap(etl::array<T, SIZE>& lhs, etl::array<T, SIZE>& rhs) ETL_NOEXCEPT_FROM(ETL_OR_STD::swap(etl::declval<T&>(), etl::declval<T&>()))
{
lhs.swap(rhs);
}
@ -1100,7 +1103,7 @@ namespace etl
/// second, otherwise <b>false</b>
//*************************************************************************
template <typename T, size_t SIZE>
bool operator<(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
ETL_CONSTEXPR14 bool operator<(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
{
return etl::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
}
@ -1114,7 +1117,7 @@ namespace etl
///< b>false</b>
//*************************************************************************
template <typename T, size_t SIZE>
bool operator<=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
ETL_CONSTEXPR14 bool operator<=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
{
return !(lhs > rhs);
}
@ -1127,7 +1130,7 @@ namespace etl
/// the second, otherwise <b>false</b>
template <typename T, size_t SIZE>
//*************************************************************************
bool operator>(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
ETL_CONSTEXPR14 bool operator>(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
{
return (rhs < lhs);
}
@ -1141,7 +1144,7 @@ namespace etl
///< b>false</b>
//*************************************************************************
template <typename T, size_t SIZE>
bool operator>=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
ETL_CONSTEXPR14 bool operator>=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
{
return !(lhs < rhs);
}
@ -1155,7 +1158,7 @@ namespace etl
///\return A reference to the element
//*************************************************************************
template <size_t Index, typename T, size_t Size>
inline T& get(array<T, Size>& a)
ETL_NODISCARD ETL_CONSTEXPR14 T& get(array<T, Size>& a) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
return a[Index];
@ -1170,11 +1173,106 @@ namespace etl
///\return A const reference to the element
//*************************************************************************
template <size_t Index, typename T, size_t Size>
inline const T& get(const array<T, Size>& a)
ETL_NODISCARD ETL_CONSTEXPR14 const T& get(const array<T, Size>& a) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
return a[Index];
}
#if ETL_USING_CPP11
//*************************************************************************
/// Gets an rvalue reference to an element in the array.
///\tparam Index The index.
///\tparam T The type.
///\tparam Size The array size.
///\param a The array.
///\return An rvalue reference to the element
//*************************************************************************
template <size_t Index, typename T, size_t Size>
ETL_NODISCARD ETL_CONSTEXPR14 T&& get(array<T, Size>&& a) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
return static_cast<T&&>(a[Index]);
}
//*************************************************************************
/// Gets a const rvalue reference to an element in the array.
///\tparam Index The index.
///\tparam T The type.
///\tparam Size The array size.
///\param a The array.
///\return A const rvalue reference to the element
//*************************************************************************
template <size_t Index, typename T, size_t Size>
ETL_NODISCARD ETL_CONSTEXPR14 const T&& get(const array<T, Size>&& a) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
return static_cast<const T&&>(a[Index]);
}
//*************************************************************************
/// Gets the number of elements in an array.
///\tparam T The type.
///\tparam Size The array size.
//*************************************************************************
template <typename T, size_t Size>
struct tuple_size<etl::array<T, Size> > : etl::integral_constant<size_t, Size>
{
};
//*************************************************************************
/// Gets the type of the element at Index in an array.
///\tparam Index The index.
///\tparam T The type.
///\tparam Size The array size.
//*************************************************************************
template <size_t Index, typename T, size_t Size>
struct tuple_element<Index, etl::array<T, Size> >
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
using type = T;
};
#endif
} // namespace etl
#if ETL_USING_CPP11
namespace std
{
// libc++ already declares std::tuple_size / std::tuple_element in its inline
// namespace (std::__1), so re-declaring them here would make the name
// ambiguous. Detect libc++ via _LIBCPP_VERSION and skip the forward
// declarations in that case, even when not using the STL.
#if ETL_NOT_USING_STL && !defined(_LIBCPP_VERSION) \
&& !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000) && (ETL_COMPILER_FULL_VERSION < 210000)) \
&& defined(ETL_COMPILER_CLANG))
template <typename T>
struct tuple_size;
template <size_t Index, typename TType>
struct tuple_element;
#endif
//***************************************************************************
/// Specialisation of tuple_size to allow the use of C++ structured bindings.
//***************************************************************************
template <typename T, size_t Size>
struct tuple_size<etl::array<T, Size> > : etl::integral_constant<size_t, Size>
{
};
//***************************************************************************
/// Specialisation of tuple_element to allow the use of C++ structured
/// bindings.
//***************************************************************************
template <size_t Index, typename T, size_t Size>
struct tuple_element<Index, etl::array<T, Size> >
{
ETL_STATIC_ASSERT(Index < Size, "Index out of bounds");
using type = T;
};
} // namespace std
#endif
#endif

View File

@ -211,6 +211,7 @@ namespace etl
typedef T element_type;
typedef typename etl::remove_cv<T>::type value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
@ -788,6 +789,7 @@ namespace etl
typedef T element_type;
typedef typename etl::remove_cv<T>::type value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;

View File

@ -80,7 +80,7 @@ namespace etl
/// Constructor.
//*************************************************************************
string()
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->initialise();
}
@ -90,7 +90,7 @@ namespace etl
///\param other The other string.
//*************************************************************************
string(const etl::string<MAX_SIZE_>& other)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -100,7 +100,7 @@ namespace etl
///\param other The other istring.
//*************************************************************************
string(const etl::istring& other)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -112,7 +112,7 @@ namespace etl
///\param length The number of characters. Default = npos.
//*************************************************************************
string(const etl::istring& other, size_t position, size_t length = npos)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
@ -124,7 +124,7 @@ namespace etl
///\param text The initial text of the string.
//*************************************************************************
ETL_EXPLICIT_STRING_FROM_CHAR string(const value_type* text)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(text);
}
@ -135,7 +135,7 @@ namespace etl
///\param count The number of characters to copy.
//*************************************************************************
string(const value_type* text, size_t count)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(text, text + count);
}
@ -146,7 +146,7 @@ namespace etl
///\param value The value to fill the string with.
//*************************************************************************
string(size_type count, value_type c)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->initialise();
this->resize(count, c);
@ -160,7 +160,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
string(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(first, last);
}
@ -170,7 +170,7 @@ namespace etl
/// Construct from initializer_list.
//*************************************************************************
string(std::initializer_list<value_type> init)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(init.begin(), init.end());
}
@ -181,7 +181,7 @@ namespace etl
///\param view The string_view.
//*************************************************************************
explicit string(const etl::string_view& view)
: istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: istring(buffer, MAX_SIZE)
{
this->assign(view.begin(), view.end());
}

View File

@ -39,6 +39,7 @@ SOFTWARE.
#endif
#include "functional.h"
#include "invoke.h"
#include "nth_type.h"
#include "type_list.h"
#include "type_traits.h"
@ -934,6 +935,35 @@ namespace etl
return tuple<TTypes&&...>(etl::forward<TTypes>(args)...);
}
namespace private_tuple
{
//**********************************
// Helper for apply.
// Invokes the callable with the tuple elements expanded via the index sequence.
// Uses an unqualified 'get' so that argument-dependent lookup finds the
// appropriate overload for etl::tuple, etl::array, std::tuple, std::pair, etc.
//**********************************
template <typename TFunction, typename TTuple, size_t... Indices>
ETL_CONSTEXPR14 auto apply_impl(TFunction&& f, TTuple&& t, etl::index_sequence<Indices...>)
-> decltype(etl::invoke(etl::forward<TFunction>(f), get<Indices>(etl::forward<TTuple>(t))...))
{
return etl::invoke(etl::forward<TFunction>(f), get<Indices>(etl::forward<TTuple>(t))...);
}
} // namespace private_tuple
//***************************************************************************
/// Invokes the callable object 'f' with the elements of the tuple 't' as
/// arguments. Equivalent to std::apply.
//***************************************************************************
template <typename TFunction, typename TTuple>
ETL_CONSTEXPR14 auto apply(TFunction&& f, TTuple&& t)
-> decltype(private_tuple::apply_impl(etl::forward<TFunction>(f), etl::forward<TTuple>(t),
etl::make_index_sequence<etl::tuple_size<etl::remove_reference_t<TTuple>>::value>{}))
{
return private_tuple::apply_impl(etl::forward<TFunction>(f), etl::forward<TTuple>(t),
etl::make_index_sequence<etl::tuple_size<etl::remove_reference_t<TTuple>>::value>{});
}
namespace private_tuple
{
//**********************************

View File

@ -77,7 +77,7 @@ namespace etl
/// Constructor.
//*************************************************************************
u16string()
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->initialise();
}
@ -87,7 +87,7 @@ namespace etl
///\param other The other string.
//*************************************************************************
u16string(const etl::u16string<MAX_SIZE_>& other)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -97,7 +97,7 @@ namespace etl
///\param other The other iu16string.
//*************************************************************************
u16string(const etl::iu16string& other)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -109,7 +109,7 @@ namespace etl
///\param length The number of characters. Default = npos.
//*************************************************************************
u16string(const etl::iu16string& other, size_type position, size_type length = npos)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
@ -121,7 +121,7 @@ namespace etl
///\param text The initial text of the u16string.
//*************************************************************************
ETL_EXPLICIT_STRING_FROM_CHAR u16string(const value_type* text)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(text);
}
@ -132,7 +132,7 @@ namespace etl
///\param count The number of characters to copy.
//*************************************************************************
u16string(const value_type* text, size_type count)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(text, text + count);
}
@ -143,7 +143,7 @@ namespace etl
///\param value The value to fill the u16string with.
//*************************************************************************
u16string(size_type count, value_type c)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->initialise();
this->resize(count, c);
@ -157,7 +157,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
u16string(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(first, last);
}
@ -167,7 +167,7 @@ namespace etl
/// Construct from initializer_list.
//*************************************************************************
u16string(std::initializer_list<value_type> init)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(init.begin(), init.end());
}
@ -178,7 +178,7 @@ namespace etl
///\param view The string_view.
//*************************************************************************
explicit u16string(const etl::u16string_view& view)
: iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu16string(buffer, MAX_SIZE)
{
this->assign(view.begin(), view.end());
}

View File

@ -77,7 +77,7 @@ namespace etl
/// Constructor.
//*************************************************************************
u32string()
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->initialise();
}
@ -87,7 +87,7 @@ namespace etl
///\param other The other string.
//*************************************************************************
u32string(const etl::u32string<MAX_SIZE_>& other)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -97,7 +97,7 @@ namespace etl
///\param other The other iu32string.
//*************************************************************************
u32string(const etl::iu32string& other)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -109,7 +109,7 @@ namespace etl
///\param length The number of characters. Default = npos.
//*************************************************************************
u32string(const etl::iu32string& other, size_type position, size_type length = npos)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
@ -121,7 +121,7 @@ namespace etl
///\param text The initial text of the u32string.
//*************************************************************************
ETL_EXPLICIT_STRING_FROM_CHAR u32string(const value_type* text)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(text);
}
@ -132,7 +132,7 @@ namespace etl
///\param count The number of characters to copy.
//*************************************************************************
u32string(const value_type* text, size_type count)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(text, text + count);
}
@ -143,7 +143,7 @@ namespace etl
///\param value The value to fill the u32string with.
//*************************************************************************
u32string(size_type count, value_type c)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->initialise();
this->resize(count, c);
@ -157,7 +157,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
u32string(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(first, last);
}
@ -167,7 +167,7 @@ namespace etl
/// Construct from initializer_list.
//*************************************************************************
u32string(std::initializer_list<value_type> init)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(init.begin(), init.end());
}
@ -178,7 +178,7 @@ namespace etl
///\param view The string_view.
//*************************************************************************
explicit u32string(const etl::u32string_view& view)
: iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu32string(buffer, MAX_SIZE)
{
this->assign(view.begin(), view.end());
}

View File

@ -80,7 +80,7 @@ namespace etl
/// Constructor.
//*************************************************************************
u8string()
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->initialise();
}
@ -90,7 +90,7 @@ namespace etl
///\param other The other u8string.
//*************************************************************************
u8string(const etl::u8string<MAX_SIZE_>& other)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -100,7 +100,7 @@ namespace etl
///\param other The other iu8string.
//*************************************************************************
u8string(const etl::iu8string& other)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -112,7 +112,7 @@ namespace etl
///\param length The number of characters. Default = npos.
//*************************************************************************
u8string(const etl::iu8string& other, size_t position, size_t length = npos)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
@ -124,7 +124,7 @@ namespace etl
///\param text The initial text of the u8string.
//*************************************************************************
ETL_EXPLICIT_STRING_FROM_CHAR u8string(const value_type* text)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(text);
}
@ -135,7 +135,7 @@ namespace etl
///\param count The number of characters to copy.
//*************************************************************************
u8string(const value_type* text, size_t count)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(text, text + count);
}
@ -146,7 +146,7 @@ namespace etl
///\param value The value to fill the u8string with.
//*************************************************************************
u8string(size_type count, value_type c)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->initialise();
this->resize(count, c);
@ -160,7 +160,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
u8string(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(first, last);
}
@ -170,7 +170,7 @@ namespace etl
/// Construct from initializer_list.
//*************************************************************************
u8string(std::initializer_list<value_type> init)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(init.begin(), init.end());
}
@ -181,7 +181,7 @@ namespace etl
///\param view The string_view.
//*************************************************************************
explicit u8string(const etl::u8string_view& view)
: iu8string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iu8string(buffer, MAX_SIZE)
{
this->assign(view.begin(), view.end());
}

View File

@ -32,6 +32,7 @@ SOFTWARE.
#define ETL_UTILITY_INCLUDED
#include "platform.h"
#include "limits.h"
#include "type_traits.h"
#include "private/tuple_element.h"
@ -142,6 +143,173 @@ namespace etl
return static_cast<typename underlying_type<T>::type>(value);
}
#if ETL_USING_STL && ETL_USING_CPP20 && defined(__cpp_lib_integer_comparison_functions)
//***************************************************************************
// Safe integer comparison functions.
//***************************************************************************
using std::cmp_equal;
using std::cmp_greater;
using std::cmp_greater_equal;
using std::cmp_less;
using std::cmp_less_equal;
using std::cmp_not_equal;
using std::in_range;
#else
namespace private_utility
{
//***********************************
/// Determines whether T is one of the standard integer types permitted as
/// an argument to the safe integer comparison functions. The permitted
/// types are the signed and unsigned standard integer types, including
/// signed char and unsigned char. bool, char and the extended character
/// types are excluded, matching the C++ standard's constraints on
/// etl::cmp_* and etl::in_range.
//***********************************
template <typename T>
struct is_standard_integer : etl::false_type
{
};
template <>
struct is_standard_integer<signed char> : etl::true_type
{
};
template <>
struct is_standard_integer<short> : etl::true_type
{
};
template <>
struct is_standard_integer<int> : etl::true_type
{
};
template <>
struct is_standard_integer<long> : etl::true_type
{
};
template <>
struct is_standard_integer<long long> : etl::true_type
{
};
template <>
struct is_standard_integer<unsigned char> : etl::true_type
{
};
template <>
struct is_standard_integer<unsigned short> : etl::true_type
{
};
template <>
struct is_standard_integer<unsigned int> : etl::true_type
{
};
template <>
struct is_standard_integer<unsigned long> : etl::true_type
{
};
template <>
struct is_standard_integer<unsigned long long> : etl::true_type
{
};
template <typename T>
struct is_standard_integer<const T> : is_standard_integer<T>
{
};
template <typename T>
struct is_standard_integer<volatile T> : is_standard_integer<T>
{
};
template <typename T>
struct is_standard_integer<const volatile T> : is_standard_integer<T>
{
};
//***********************************
/// Enabled when both T and U are permitted comparison types.
//***********************************
template <typename T, typename U, typename TReturn = void>
struct enable_if_comparable : etl::enable_if<is_standard_integer<T>::value && is_standard_integer<U>::value, TReturn>
{
};
} // namespace private_utility
//***************************************************************************
/// Compares the values of two integers.
/// Unlike the built-in comparison operators, negative signed integers always
/// compare less than (and not equal to) unsigned integers.
/// The comparison is safe against value-changing implicit conversions.
/// https://en.cppreference.com/w/cpp/utility/intcmp
///\ingroup utility
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_equal(T t, U u) ETL_NOEXCEPT
{
return (etl::is_signed<T>::value == etl::is_signed<U>::value) ? (t == u)
: etl::is_signed<T>::value ? ((t >= T(0)) && (typename etl::make_unsigned<T>::type(t) == u))
: ((u >= U(0)) && (t == typename etl::make_unsigned<U>::type(u)));
}
//***************************************************************************
/// See @ref cmp_equal.
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_not_equal(T t, U u) ETL_NOEXCEPT
{
return !etl::cmp_equal(t, u);
}
//***************************************************************************
/// See @ref cmp_equal.
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_less(T t, U u) ETL_NOEXCEPT
{
return (etl::is_signed<T>::value == etl::is_signed<U>::value) ? (t < u)
: etl::is_signed<T>::value ? ((t < T(0)) || (typename etl::make_unsigned<T>::type(t) < u))
: ((u >= U(0)) && (t < typename etl::make_unsigned<U>::type(u)));
}
//***************************************************************************
/// See @ref cmp_equal.
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_greater(T t, U u) ETL_NOEXCEPT
{
return etl::cmp_less(u, t);
}
//***************************************************************************
/// See @ref cmp_equal.
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_less_equal(T t, U u) ETL_NOEXCEPT
{
return !etl::cmp_less(u, t);
}
//***************************************************************************
/// See @ref cmp_equal.
//***************************************************************************
template <typename T, typename U>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<T, U, bool>::type cmp_greater_equal(T t, U u) ETL_NOEXCEPT
{
return !etl::cmp_less(t, u);
}
//***************************************************************************
/// Returns whether the value of t is in the range of values that can be
/// represented by R, that is, whether t can be converted to R without loss
/// of its value.
/// https://en.cppreference.com/w/cpp/utility/in_range
///\ingroup utility
//***************************************************************************
template <typename R, typename T>
ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable<R, T, bool>::type in_range(T t) ETL_NOEXCEPT
{
return etl::cmp_greater_equal(t, etl::numeric_limits<R>::min()) && etl::cmp_less_equal(t, etl::numeric_limits<R>::max());
}
#endif
// We can't have std::swap and etl::swap templates coexisting in the unit
// tests as the compiler will be unable to decide which one to use, due to
// ADL.

View File

@ -77,7 +77,7 @@ namespace etl
/// Constructor.
//*************************************************************************
wstring()
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->initialise();
}
@ -87,7 +87,7 @@ namespace etl
///\param other The other string.
//*************************************************************************
wstring(const etl::wstring<MAX_SIZE_>& other)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -97,7 +97,7 @@ namespace etl
///\param other The other iwstring.
//*************************************************************************
wstring(const etl::iwstring& other)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(other);
}
@ -109,7 +109,7 @@ namespace etl
///\param length The number of characters. Default = npos.
//*************************************************************************
wstring(const etl::iwstring& other, size_type position, size_type length = npos)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
@ -121,7 +121,7 @@ namespace etl
///\param text The initial text of the wstring.
//*************************************************************************
ETL_EXPLICIT_STRING_FROM_CHAR wstring(const value_type* text)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(text);
}
@ -132,7 +132,7 @@ namespace etl
///\param count The number of characters to copy.
//*************************************************************************
wstring(const value_type* text, size_type count)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(text, text + count);
}
@ -143,7 +143,7 @@ namespace etl
///\param value The value to fill the wstring with.
//*************************************************************************
wstring(size_type count, value_type c)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->initialise();
this->resize(count, c);
@ -157,7 +157,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
wstring(TIterator first, TIterator last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(first, last);
}
@ -167,7 +167,7 @@ namespace etl
/// Construct from initializer_list.
//*************************************************************************
wstring(std::initializer_list<value_type> init)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(init.begin(), init.end());
}
@ -178,7 +178,7 @@ namespace etl
///\param view The string_view.
//*************************************************************************
explicit wstring(const etl::wstring_view& view)
: iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
: iwstring(buffer, MAX_SIZE)
{
this->assign(view.begin(), view.end());
}

View File

@ -35,6 +35,9 @@ SOFTWARE.
#include <algorithm>
#include <array>
#include <iterator>
#if ETL_USING_CPP11
#include <tuple>
#endif
#include <type_traits>
#include "etl/integral_limits.h"
@ -400,6 +403,96 @@ namespace
// int i = etl::get<11>(data2);
}
#if ETL_USING_CPP11
//*************************************************************************
TEST(test_get_rvalue)
{
Data data1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
const Data data2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int&& r0 = etl::get<3>(std::move(data1));
const int&& r1 = etl::get<3>(std::move(data2));
CHECK_EQUAL(3, r0);
CHECK_EQUAL(3, r1);
// The rvalue overloads must be selected and return rvalue references.
CHECK((std::is_same<int&&, decltype(etl::get<3>(std::move(data1)))>::value));
CHECK((std::is_same<const int&&, decltype(etl::get<3>(std::move(data2)))>::value));
// Moving out of an rvalue array element actually moves.
etl::array<Moveable, 2U> data3 = {Moveable(1), Moveable(2)};
Moveable moved(etl::get<0>(std::move(data3)));
CHECK_EQUAL(1, moved.value);
CHECK(!data3[0].valid);
}
#endif
//*************************************************************************
TEST(test_get_constexpr)
{
ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 int result = etl::get<3>(data);
CHECK_EQUAL(3, result);
}
#if ETL_USING_CPP11
//*************************************************************************
TEST(test_tuple_size)
{
CHECK_EQUAL(SIZE, (etl::tuple_size<Data>::value));
CHECK_EQUAL(SIZE, (std::tuple_size<Data>::value));
#if ETL_USING_CPP17
CHECK_EQUAL(SIZE, (etl::tuple_size_v<Data>));
CHECK_EQUAL(SIZE, (std::tuple_size_v<Data>));
#endif
}
//*************************************************************************
TEST(test_tuple_element)
{
CHECK_TRUE((std::is_same<int, etl::tuple_element_t<0, Data>>::value));
CHECK_TRUE((std::is_same<int, etl::tuple_element_t<SIZE - 1, Data>>::value));
CHECK_TRUE((std::is_same<int, std::tuple_element<0, Data>::type>::value));
CHECK_TRUE((std::is_same<int, std::tuple_element<SIZE - 1, Data>::type>::value));
}
#endif
#if ETL_USING_CPP17
//*************************************************************************
TEST(test_structured_bindings)
{
etl::array<int, 3> data = {1, 2, 3};
// Bind by reference and modify.
auto& [a, b, c] = data;
CHECK_EQUAL(1, a);
CHECK_EQUAL(2, b);
CHECK_EQUAL(3, c);
a = 10;
b = 20;
c = 30;
CHECK_EQUAL(10, data[0]);
CHECK_EQUAL(20, data[1]);
CHECK_EQUAL(30, data[2]);
// Bind by const reference.
const auto& [x, y, z] = data;
CHECK_EQUAL(10, x);
CHECK_EQUAL(20, y);
CHECK_EQUAL(30, z);
}
#endif
//*************************************************************************
TEST(test_assign)
{
@ -691,6 +784,16 @@ namespace
CHECK(!(greater < data));
}
//*************************************************************************
TEST(test_less_than_constexpr)
{
ETL_CONSTEXPR14 Data lesser = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9};
ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 bool result = (lesser < data);
CHECK(result);
}
//*************************************************************************
TEST(test_less_than_equal)
{
@ -703,6 +806,16 @@ namespace
CHECK(!(greater <= data));
}
//*************************************************************************
TEST(test_less_than_equal_constexpr)
{
ETL_CONSTEXPR14 Data lesser = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9};
ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 bool result = (lesser <= data);
CHECK(result);
}
//*************************************************************************
TEST(test_greater_than)
{
@ -715,6 +828,16 @@ namespace
CHECK(!(lesser > data));
}
//*************************************************************************
TEST(test_greater_than_constexpr)
{
ETL_CONSTEXPR14 Data greater = {0, 1, 2, 3, 5, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 bool result = (greater > data);
CHECK(result);
}
//*************************************************************************
TEST(test_greater_than_equal)
{
@ -727,6 +850,16 @@ namespace
CHECK(!(lesser >= data));
}
//*************************************************************************
TEST(test_greater_than_equal_constexpr)
{
ETL_CONSTEXPR14 Data greater = {0, 1, 2, 3, 5, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ETL_CONSTEXPR14 bool result = (greater >= data);
CHECK(result);
}
//*************************************************************************
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
TEST(test_array_template_deduction)

View File

@ -76,6 +76,32 @@ namespace
int i;
};
//*********************************
int apply_sum(int a, int b, int c)
{
return a + b + c;
}
//*********************************
struct Summer
{
int operator()(int a, int b) const
{
return a + b;
}
};
//*********************************
struct Accumulator
{
int total;
void add(int a, int b)
{
total = a + b;
}
};
SUITE(test_tuple)
{
//*************************************************************************
@ -930,5 +956,61 @@ namespace
CHECK_EQUAL(1, i);
CHECK_EQUAL(std::string("2"), d.value);
}
//*************************************************************************
TEST(test_apply_free_function)
{
etl::tuple<int, int, int> t(1, 2, 3);
CHECK_EQUAL(6, etl::apply(apply_sum, t));
}
//*************************************************************************
TEST(test_apply_function_object)
{
etl::tuple<int, int> t(10, 20);
CHECK_EQUAL(30, etl::apply(Summer(), t));
}
//*************************************************************************
#if ETL_USING_CPP11
TEST(test_apply_lambda)
{
etl::tuple<int, int, int> t(2, 3, 4);
int result = etl::apply([](int a, int b, int c) { return a * b * c; }, t);
CHECK_EQUAL(24, result);
}
#endif
//*************************************************************************
TEST(test_apply_member_function)
{
Accumulator acc = {0};
etl::apply(&Accumulator::add, etl::make_tuple(&acc, 5, 7));
CHECK_EQUAL(12, acc.total);
}
//*************************************************************************
TEST(test_apply_rvalue_tuple)
{
CHECK_EQUAL(6, etl::apply(apply_sum, etl::make_tuple(1, 2, 3)));
}
//*************************************************************************
#if ETL_USING_CPP11
TEST(test_apply_empty_tuple)
{
etl::tuple<> t;
int result = etl::apply([]() { return 42; }, t);
CHECK_EQUAL(42, result);
}
#endif
}
} // namespace

View File

@ -785,6 +785,161 @@ namespace
}
#endif
//*********************************
TEST(test_cmp_equal)
{
// Same signedness.
CHECK_TRUE(etl::cmp_equal(1, 1));
CHECK_FALSE(etl::cmp_equal(1, 2));
CHECK_TRUE(etl::cmp_equal(1U, 1U));
CHECK_FALSE(etl::cmp_equal(1U, 2U));
// Mixed signedness where the built-in operator would give the wrong result.
// -1 as unsigned would be a large value, so a naive (a == b) would be false anyway,
// but the classic trap is comparing a negative signed with an equal-bit-pattern unsigned.
CHECK_FALSE(etl::cmp_equal(-1, static_cast<unsigned int>(-1)));
CHECK_FALSE(etl::cmp_equal(static_cast<unsigned int>(-1), -1));
// Non-negative signed compared with unsigned.
CHECK_TRUE(etl::cmp_equal(5, 5U));
CHECK_TRUE(etl::cmp_equal(5U, 5));
CHECK_FALSE(etl::cmp_equal(-5, 5U));
CHECK_FALSE(etl::cmp_equal(5U, -5));
// Different widths.
CHECK_TRUE(etl::cmp_equal(int8_t(100), int64_t(100)));
CHECK_FALSE(etl::cmp_equal(int8_t(-1), uint64_t(0xFFFFFFFFFFFFFFFFULL)));
}
//*********************************
TEST(test_cmp_not_equal)
{
CHECK_FALSE(etl::cmp_not_equal(1, 1));
CHECK_TRUE(etl::cmp_not_equal(1, 2));
CHECK_TRUE(etl::cmp_not_equal(-1, static_cast<unsigned int>(-1)));
CHECK_FALSE(etl::cmp_not_equal(5, 5U));
CHECK_TRUE(etl::cmp_not_equal(-5, 5U));
}
//*********************************
TEST(test_cmp_less)
{
// Same signedness.
CHECK_TRUE(etl::cmp_less(1, 2));
CHECK_FALSE(etl::cmp_less(2, 1));
CHECK_FALSE(etl::cmp_less(1, 1));
CHECK_TRUE(etl::cmp_less(1U, 2U));
CHECK_FALSE(etl::cmp_less(2U, 1U));
// A negative signed value is always less than any unsigned value.
CHECK_TRUE(etl::cmp_less(-1, 0U));
CHECK_TRUE(etl::cmp_less(-1, static_cast<unsigned int>(-1)));
CHECK_FALSE(etl::cmp_less(static_cast<unsigned int>(-1), -1));
// Non-negative signed with unsigned.
CHECK_TRUE(etl::cmp_less(5, 6U));
CHECK_FALSE(etl::cmp_less(6, 5U));
CHECK_TRUE(etl::cmp_less(5U, 6));
CHECK_FALSE(etl::cmp_less(6U, 5));
// Large unsigned is not less than a small signed.
CHECK_FALSE(etl::cmp_less(0xFFFFFFFFU, 1));
CHECK_TRUE(etl::cmp_less(1, 0xFFFFFFFFU));
}
//*********************************
TEST(test_cmp_greater)
{
CHECK_TRUE(etl::cmp_greater(2, 1));
CHECK_FALSE(etl::cmp_greater(1, 2));
CHECK_FALSE(etl::cmp_greater(1, 1));
CHECK_FALSE(etl::cmp_greater(-1, 0U));
CHECK_TRUE(etl::cmp_greater(static_cast<unsigned int>(-1), -1));
CHECK_TRUE(etl::cmp_greater(0xFFFFFFFFU, 1));
CHECK_FALSE(etl::cmp_greater(1, 0xFFFFFFFFU));
}
//*********************************
TEST(test_cmp_less_equal)
{
CHECK_TRUE(etl::cmp_less_equal(1, 1));
CHECK_TRUE(etl::cmp_less_equal(1, 2));
CHECK_FALSE(etl::cmp_less_equal(2, 1));
CHECK_TRUE(etl::cmp_less_equal(-1, static_cast<unsigned int>(-1)));
CHECK_FALSE(etl::cmp_less_equal(static_cast<unsigned int>(-1), -1));
CHECK_TRUE(etl::cmp_less_equal(5U, 5));
CHECK_FALSE(etl::cmp_less_equal(6U, 5));
}
//*********************************
TEST(test_cmp_greater_equal)
{
CHECK_TRUE(etl::cmp_greater_equal(1, 1));
CHECK_TRUE(etl::cmp_greater_equal(2, 1));
CHECK_FALSE(etl::cmp_greater_equal(1, 2));
CHECK_FALSE(etl::cmp_greater_equal(-1, static_cast<unsigned int>(-1)));
CHECK_TRUE(etl::cmp_greater_equal(static_cast<unsigned int>(-1), -1));
CHECK_TRUE(etl::cmp_greater_equal(5, 5U));
CHECK_FALSE(etl::cmp_greater_equal(-5, 5U));
}
//*********************************
TEST(test_in_range)
{
// Signed target type.
CHECK_TRUE(etl::in_range<int8_t>(0));
CHECK_TRUE(etl::in_range<int8_t>(127));
CHECK_TRUE(etl::in_range<int8_t>(-128));
CHECK_FALSE(etl::in_range<int8_t>(128));
CHECK_FALSE(etl::in_range<int8_t>(-129));
CHECK_FALSE(etl::in_range<int8_t>(200));
// Unsigned target type.
CHECK_TRUE(etl::in_range<uint8_t>(0));
CHECK_TRUE(etl::in_range<uint8_t>(255));
CHECK_FALSE(etl::in_range<uint8_t>(256));
CHECK_FALSE(etl::in_range<uint8_t>(-1));
// Unsigned source that would be negative if reinterpreted as signed.
CHECK_FALSE(etl::in_range<int8_t>(static_cast<unsigned int>(-1)));
CHECK_TRUE(etl::in_range<uint32_t>(static_cast<unsigned int>(-1)));
// Wider target always contains a narrower value.
CHECK_TRUE(etl::in_range<int64_t>(int8_t(-1)));
CHECK_TRUE(etl::in_range<int64_t>(uint32_t(0xFFFFFFFFU)));
}
#if ETL_USING_CPP14
//*********************************
TEST(test_cmp_and_in_range_constexpr)
{
constexpr bool ce0 = etl::cmp_equal(1, 1);
constexpr bool ce1 = etl::cmp_not_equal(-1, static_cast<unsigned int>(-1));
constexpr bool ce2 = etl::cmp_less(-1, 0U);
constexpr bool ce3 = etl::cmp_greater(static_cast<unsigned int>(-1), -1);
constexpr bool ce4 = etl::cmp_less_equal(-1, static_cast<unsigned int>(-1));
constexpr bool ce5 = etl::cmp_greater_equal(static_cast<unsigned int>(-1), -1);
constexpr bool ce6 = etl::in_range<int8_t>(100);
constexpr bool ce7 = etl::in_range<int8_t>(200);
static_assert(ce0, "cmp_equal constexpr");
static_assert(ce1, "cmp_not_equal constexpr");
static_assert(ce2, "cmp_less constexpr");
static_assert(ce3, "cmp_greater constexpr");
static_assert(ce4, "cmp_less_equal constexpr");
static_assert(ce5, "cmp_greater_equal constexpr");
static_assert(ce6, "in_range true constexpr");
static_assert(!ce7, "in_range false constexpr");
CHECK_TRUE(ce0);
CHECK_TRUE(ce6);
CHECK_FALSE(ce7);
}
#endif
#if ETL_HAS_PACKED
//*********************************
TEST(test_packed)