mirror of
https://github.com/ETLCPP/etl.git
synced 2026-07-30 16:26:17 +08:00
Merge branch 'development' into fix-vector-const-cast
This commit is contained in:
commit
a03b267ce2
@ -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).
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||
|
||||
@ -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 type’s 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.
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
//**********************************
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user