Merge branch 'development' into big-endian-2

This commit is contained in:
John Wellbelove 2026-03-25 12:21:09 +00:00 committed by GitHub
commit 31f8b0c5bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 5345 additions and 701 deletions

38
.treefmt.toml Normal file
View File

@ -0,0 +1,38 @@
[global]
excludes = [
"**/Doxyfile",
"**/Makefile",
"*.*-format",
"*.S",
"*.cmm",
"*.css",
"*.dld",
"*.gdb",
"*.gif",
"*.gitignore",
"*.html",
"*.ini",
"*.josh",
"*.json",
"*.md",
"*.png",
"*.puml",
"*.py",
"*.rb",
"*.rst",
"*.s",
"*.sh",
"*.spec",
"*.toml",
"*.txt",
"*.yaml",
"*.yml",
"docker/**",
"scripts/clang-format-wrapper",
"include/etl/generators/**"
]
[formatter.cpp]
command = "scripts/clang-format-wrapper"
options = [ "-i", "--style=file" ]
includes = [ "*.c", "*.cc", "*.cpp", "*.h", "*.hh", "*.hpp" ]

View File

@ -6,6 +6,7 @@ Thanks for considering a contribution! Heres what you need to know before ope
- If you are fixing a bug, add a unit test that *fails* before the bug fix is implemented.
- Do not initiate a pull request until all of the units tests pass. See below for information on project files and test scripts.
- Branches should be based on the branch `master`. If `development` has pending updates, Ill rebase the PR against it before pulling..
- For formatting help, you can use clang-format, or the convenience wrapper treefmt. See also [docs/source-formatting.md](docs/source-formatting.md)
There is a project file for VS2022 for C++14, 17, 20, 23, and bash scripts that run the tests for C++11, 14, 17, 20, 23 under Linux with GCC and Clang.
There are syntax-only check bash scripts that cover C++03, 11, 14, 17, 20, 23 under Linux with GCC and Clang.

6
docs/_config.yml Normal file
View File

@ -0,0 +1,6 @@
plugins:
- jekyll-relative-links
relative_links:
enabled: true
include:
- manchester.md

7
docs/index.md Normal file
View File

@ -0,0 +1,7 @@
---
title: ETL documentation
---
## Pages
* [Manchester](manchester.md)

258
docs/manchester.md Normal file
View File

@ -0,0 +1,258 @@
---
title: Manchester encoding and decoding
---
Efficient Manchester encoding and decoding of data. The Manchester code represents a data bit as a sequence of a 'high' and a 'low' value. In software this translates to a conversion from one to two bits, or in a practical situation, from `n` bytes to `n*2` bytes.
## See also
[Manchester code](https://en.wikipedia.org/wiki/Manchester_code)
## Features
- Normal and inverted Manchester encoding
- Support for multiple encoding chunk sizes: 8-bit, 16-bit and 32-bit
- Span-based operations or chunk-based operations
- Constexpr functions for compile-time encoding/decoding (8-bit chunk size only)
- Validation of encoded data
## Algorithm background
To encode the value `0b11001100` we must first duplicate all bits to create the value `0b1111000011110000`. We then perform an XOR of this value with the constant `0b1010101010101010` (`0xAAAA`) to obtain the Manchester coded value of `0b1010010110100101`. We have now replaced each `1` bit with the sequence `10` and each `0` bit with the sequence `01`.
### 2. Bit duplication
Bit duplication is achieved with the following steps. This is also called binary interleaving. The example shows encoding of an 8-bit value.
| Step | High Byte | Low Byte | Operation |
|------|--------------------|--------------------|----------------------------|
| 0 | `_ _ _ _ _ _ _ _` | `A B C D E F G H` | input value (i) |
| 1 | `_ _ _ _ A B C D` | `_ _ _ _ E F G H` | `(i \| (i << 4)) & 0x0F0F` |
| 2 | `_ _ A B _ _ C D` | `_ _ E F _ _ G H` | `(i \| (i << 2)) & 0x3333` |
| 3 | `_ A _ B _ C _ D` | `_ E _ F _ G _ H` | `(i \| (i << 1)) & 0x5555` |
| 4 | `A A B B C C D D` | `E E F F G G H H` | `(i \| (i << 1))` |
This process can be easily extended to 16-bit or 32-bit values by adding additional steps to the bit duplication.
### 3. Manchester Decoding
Manchester decoding is done in a similar, but reversed way.
### 4. Error Detection
Error detection in Manchester coded data is done by comparing 2 neighboring bits. If they are
equal, then there is an error in the encoded input data.
Comparing all 8 bit pairs in a 16-bit word is done as follows.
| Step | Binary Value | Operation | Description |
|------|--------------|-------------------|-----------------------------------------------------------------------------------------------|
| 1 | `11011000` | Original | First bit pair (lsb, 00) is invalid. Last bit pair is also invalid. Other bit pairs are valid |
| 2 | `01101100` | Shift right by 1 | Shift the original value right by one bit |
| 3 | `10110100` | XOR | XOR the original with the shifted value |
| 4 | `01010101` | Mask with 0x55 | Apply mask to isolate bit pairs |
| 5 | `00010100` | Result | If result is not equal to 0x55, there was an error in the input |
## Analysis
Most traditional ways to Manchester encode data consist of a loop over all bits and a nested if-statement to check the value of the current bit. This approach does not scale well to increasing number of bits. The algorithm implemented here contains no conditional code and scales well. Doubling the number of processed bits per step (the chunk size) adds a single row to the bit duplication table. Because of the lack of loops and conditional code, this algorithm is likely to perform better than traditional ones on simple processors or when compiler optimization is disabled. On modern, powerful processors with caches and advanced optimization possibilities this algorithm may not show much benefit. In any case, the performance of the algorithm depends heavily on the processor type, compiler and compiler (optimization) settings.
## API Reference
### Classes
Classes `etl::manchester` and `etl::manchester_inverted` contain static functions for encoding, decoding and validity checking. It is not necessary to instantiate objects of these classes.
#### etl::manchester
```cpp
typedef manchester_base<private_manchester::manchester_type_normal> manchester;
```
Manchester encoder using normal encoding (no inversion).
#### etl::manchester_inverted
```cpp
typedef manchester_base<private_manchester::manchester_type_inverted> manchester_inverted;
```
Manchester encoder using inverted encoding.
### Encoding Functions
#### Encode single value
```cpp
template <typename TDecoded>
static ETL_CONSTEXPR14 typename encoded<TDecoded>::type encode(TDecoded decoded)
```
Encodes a single value using Manchester encoding.
**Parameters:**
- `decoded`: The value to encode (`uint8_t`, `uint16_t`, or `uint32_t`)
**Returns:**
- The Manchester encoded value (twice the bit width of input)
**Example:**
```cpp
uint16_t encoded = etl::manchester::encode(0x55);
```
#### Encode range
```cpp
template <typename TChunk = uint_least8_t>
static ETL_CONSTEXPR14 void encode(etl::span<const uint_least8_t> decoded,
etl::span<uint_least8_t> encoded)
```
Encodes a span of data using the specified chunk size.
**Parameters:**
- `decoded`: Source data to encode
- `encoded`: Destination for encoded data (must be twice the size of `decoded`)
**Template Parameters:**
- `TChunk`: Chunk size for encoding (`uint8_t`, `uint16_t` or `uint32_t`)
**Example:**
```cpp
std::array<uint8_t, 4> data = {0x12, 0x34, 0x56, 0x78};
std::array<uint8_t, 8> encoded_data1{};
std::array<uint8_t, 8> encoded_data2{};
// Encode with TChunk == uint8_t
etl::manchester::encode(data, encoded_data1);
// Encode with TChunk == uint32_t
etl::manchester::encode<uint32_t>(data, encoded_data2);
```
### Decoding Functions
#### Decode single value
```cpp
template <typename TEncoded>
static ETL_CONSTEXPR14 typename decoded<TEncoded>::type decode(TEncoded encoded)
```
Decodes a single Manchester encoded value.
**Parameters:**
- `encoded`: The encoded value to decode (`uint16_t`, `uint32_t`, or `uint64_t`)
**Returns:**
- The Manchester decoded value (half the bit width of input)
**Example:**
```cpp
uint8_t decoded = etl::manchester::decode(0x5A5A);
```
#### Decode range
```cpp
template <typename TChunk = typename private_manchester::encoded<uint_least8_t>::type>
static ETL_CONSTEXPR14 void decode(etl::span<const uint_least8_t> encoded,
etl::span<uint_least8_t> decoded)
```
Decodes a span of Manchester encoded data.
**Parameters:**
- `encoded`: Source data to decode
- `decoded`: Destination for decoded data (must be half the size of `encoded`)
**Template Parameters:**
- `TChunk`: Chunk type for decoding (`uint16_t`, `uint32_t`, or `uint64_t`)
**Example:**
```cpp
std::array<uint8_t, 8> encoded = {/* ... */};
std::array<uint8_t, 4> decoded1 {};
std::array<uint8_t, 4> decoded2 {};
// Decode with TChunk == uint16_t
etl::manchester::decode(encoded, decoded1);
// Decode with TChunk == uint64_t
etl::manchester::decode<uint64_t>(encoded, decoded2);
```
### Validation Functions
#### Single value
```cpp
template <typename TChunk>
static ETL_CONSTEXPR14 bool is_valid(TChunk encoded)
```
Validates that a single value contains valid Manchester encoded data.
**Parameters:**
- `encoded`: The encoded value to validate
**Returns:**
- `true` if the value contains valid Manchester encoded data, `false` otherwise
**Example:**
```cpp
bool valid = etl::manchester::is_valid(0x5A5A);
```
#### Range
```cpp
static ETL_CONSTEXPR14 bool is_valid(etl::span<const uint_least8_t> encoded)
```
Validates that a range contains valid Manchester encoded data.
**Parameters:**
- `encoded`: The range of encoded data to validate
**Returns:**
- `true` if all data is valid Manchester encoding, `false` otherwise
**Example:**
```cpp
std::array<uint8_t, 8> encoded_data = {/* ... */};
bool valid = etl::manchester::is_valid(encoded_data);
```
## Supported Types
### Input/chunk types for encoding
- `uint8_t``uint16_t` (if 8-bit types are supported)
- `uint16_t``uint32_t`
- `uint32_t``uint64_t` (if 64-bit types are supported)
### Input/chunk types for decoding
- `uint16_t``uint8_t` (if 8-bit types are supported)
- `uint32_t``uint16_t`
- `uint64_t``uint32_t` (if 64-bit types are supported)

99
docs/source-formatting.md Normal file
View File

@ -0,0 +1,99 @@
# Source Formatting
This project uses **clang-format** (version 18) to enforce a consistent coding style
for C and C++ source files. For convenience, **treefmt** is also configured as a
single-command wrapper that discovers and formats every file in the tree.
---
## clang-format
### Configuration file
The formatting rules live in [`.clang-format`](../.clang-format) at the repository
root. The style is based on **LLVM**.
See the `.clang-format` file itself for the complete list.
### Version requirement
clang-format **18** is required.
The helper script [`scripts/clang-format-wrapper`](../scripts/clang-format-wrapper)
automatically resolves the correct binary: it first looks for `clang-format-18` on
`PATH`, then falls back to `clang-format` and verifies that its major version is 18.
All other tooling in the repo calls this wrapper instead of `clang-format` directly.
### Running clang-format manually
Format every tracked source file in the repository:
```bash
git ls-files -z \
'*.c' '*.cc' '*.cpp' \
'*.h' '*.hh' '*.hpp' \
':(exclude)include/etl/generators/*' | xargs -0 scripts/clang-format-wrapper -i --verbose --style=file
```
You can also format individual files directly:
```bash
scripts/clang-format-wrapper -i --style=file path/to/file.cpp
```
---
## treefmt
[treefmt](https://treefmt.com) is a language-agnostic source-tree formatter.
It reads a single configuration file and dispatches each file to the appropriate
formatter. In this project, it delegates all C/C++ formatting to the same
`clang-format-wrapper` described above.
In comparison to calling clang-format directly, it brings a significant speedup.
### Configuration file
The configuration lives in [`.treefmt.toml`](../.treefmt.toml) at the repository root.
### Installing treefmt
treefmt is a standalone Go binary. Install it with any of:
```bash
# Using the official install script
curl -fsSL https://raw.githubusercontent.com/numtide/treefmt/main/install.sh | bash
# Or via Homebrew
brew install treefmt
# Or via Nix
nix profile install nixpkgs#treefmt2
```
See the [treefmt documentation](https://treefmt.com) for more options.
### Running treefmt
From the repository root:
```bash
# Format everything
treefmt
# Check formatting without modifying files (useful in CI)
treefmt --fail-on-change
```
---
## Excluded paths
`.treefmt.toml` excludes generated files under
`include/etl/generators/`. Do **not** format those files manually via clang-format or treefmt.
## Pre-commit
Before submitting a PR / contribution, run `treefmt --fail-on-change` to catch
unformatted code before merge.
Alternatively, a plain `treefmt` automatically fixes any issues.

View File

@ -34,16 +34,43 @@ SOFTWARE.
#include "platform.h"
#include "type_traits.h"
#include "integral_limits.h"
#include "error_handler.h"
namespace etl
{
namespace private_absolute
{
//*************************************************************************
// Non-constexpr function that is never called for valid inputs.
// If reached during constant evaluation, the compiler emits an error
// because it's not constexpr.
// At runtime, triggers the ETL assert handler.
//*************************************************************************
template <typename T>
inline T signed_min_error()
{
ETL_ASSERT_FAIL(ETL_ERROR_GENERIC("absolute value of minimum signed integer is undefined"));
return T(0);
}
}
//***************************************************************************
// For signed types.
//***************************************************************************
template <typename T>
ETL_NODISCARD
ETL_CONSTEXPR
typename etl::enable_if<etl::is_signed<T>::value, T>::type
ETL_CONSTEXPR
typename etl::enable_if<etl::is_signed<T>::value && etl::is_integral<T>::value, T>::type
absolute(T value)
{
return (value == etl::integral_limits<T>::min) ? etl::private_absolute::signed_min_error<T>()
: (value < T(0)) ? -value : value;
}
template <typename T>
ETL_NODISCARD
ETL_CONSTEXPR
typename etl::enable_if<etl::is_signed<T>::value && !etl::is_integral<T>::value, T>::type
absolute(T value) ETL_NOEXCEPT
{
return (value < T(0)) ? -value : value;

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ SOFTWARE.
#include <stddef.h>
///\defgroup array array
/// A replacement for std::array if you haven't got C++0x11.
/// A replacement for std::array if you haven't got C++11.
///\ingroup containers
namespace etl
@ -81,7 +81,7 @@ namespace etl
//***************************************************************************
///\ingroup array
/// A replacement for std::array if you haven't got C++0x11.
/// A replacement for std::array if you haven't got C++11.
//***************************************************************************
template <typename T, size_t SIZE_>
class array
@ -646,7 +646,7 @@ namespace etl
//***************************************************************************
///\ingroup array
/// A replacement for std::array if you haven't got C++0x11.
/// A replacement for std::array if you haven't got C++11.
/// Specialisation for zero sized array.
//***************************************************************************
template <typename T>
@ -1105,7 +1105,7 @@ namespace etl
#if ETL_USING_CPP17
template <typename... T>
array(T...) -> array<typename etl::common_type<T...>::type, sizeof...(T)>;
#endif
#endif
//*************************************************************************
/// Make

View File

@ -48,7 +48,9 @@ SOFTWARE.
#include "variant.h"
#include "visitor.h"
#if ETL_USING_FORMAT_FLOATING_POINT
#include <cmath>
#endif
#if ETL_USING_CPP11
@ -138,9 +140,11 @@ namespace etl
unsigned int,
long long int,
unsigned long long int,
#if ETL_USING_FORMAT_FLOATING_POINT
float,
double,
long double,
#endif
const char*,
etl::string_view,
const void*
@ -302,6 +306,7 @@ namespace etl
{
}
#if ETL_USING_FORMAT_FLOATING_POINT
basic_format_arg(const float v)
: data(v)
{
@ -316,6 +321,7 @@ namespace etl
: data(v)
{
}
#endif
basic_format_arg(const etl::string_view v)
: data(v)
@ -1039,6 +1045,7 @@ namespace etl
format_plain_num(it, value, spec, width);
}
#if ETL_USING_FORMAT_FLOATING_POINT
template<typename OutputIt, typename T>
void format_floating_default(OutputIt& it, T value, const format_spec_t& spec)
{
@ -1214,6 +1221,7 @@ namespace etl
private_format::format_sequence<OutputIt>(it, ".");
private_format::format_plain_num<OutputIt, unsigned long long int>(it, fractional_int, spec, fractional_decimals);
}
#endif
class dummy_assign_to
{
@ -1336,6 +1344,7 @@ namespace etl
size_t count;
};
#if ETL_USING_FORMAT_FLOATING_POINT
template<typename OutputIt, typename T>
void format_floating_g(OutputIt& it, T value, const format_spec_t& spec)
{
@ -1409,6 +1418,7 @@ namespace etl
}
}
}
#endif
template<class OutputIt>
struct format_visitor
@ -1490,6 +1500,7 @@ namespace etl
return it;
}
#if ETL_USING_FORMAT_FLOATING_POINT
template<typename OutputIt, typename Float>
typename format_context<OutputIt>::iterator format_aligned_floating(Float arg, format_context<OutputIt>& fmt_ctx)
{
@ -1534,6 +1545,7 @@ namespace etl
private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
return it;
}
#endif
template<typename OutputIt>
void format_string_view(OutputIt& it, etl::string_view arg, const format_spec_t& spec)
@ -2072,6 +2084,7 @@ namespace etl
}
};
#if ETL_USING_FORMAT_FLOATING_POINT
template<>
struct formatter<float>
{
@ -2119,6 +2132,7 @@ namespace etl
return private_format::format_aligned_floating<OutputIt, long double>(arg, fmt_ctx);
}
};
#endif
template<>
struct formatter<etl::string_view>

View File

@ -62,6 +62,7 @@ SOFTWARE.
#include "largest.h"
#if ETL_USING_CPP11
#include "tuple.h"
#include "type_list.h"
#endif
#include <stdint.h>
@ -83,14 +84,14 @@ namespace etl
// For internal FSM use.
typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
template <typename, typename, etl::fsm_state_id_t, typename...>
class fsm_state;
#else
template <typename, typename, etl::fsm_state_id_t,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename>
class fsm_state;
#endif
@ -195,7 +196,7 @@ namespace etl
// Pass this whenever no state change is desired.
// The highest unsigned value of fsm_state_id_t.
static ETL_CONSTANT fsm_state_id_t No_State_Change = etl::integral_limits<fsm_state_id_t>::max;
// Pass this when this event also needs to be passed to the parent.
static ETL_CONSTANT fsm_state_id_t Pass_To_Parent = No_State_Change - 1U;
@ -213,15 +214,15 @@ namespace etl
ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
// Compile-time: TState::ID must equal its index in the type list (0..N-1)
template <size_t Id, typename...> struct check_ids : etl::true_type
template <size_t Id, typename...> struct check_ids : etl::true_type
{
};
template <size_t Id, typename TState0, typename... TRest>
struct check_ids<Id, TState0, TRest...>
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
{
};
};
//***************************************************************************
/// RAII detection mechanism to catch reentrant calls to methods that might
@ -250,11 +251,11 @@ namespace etl
{
is_locked = false;
}
private:
// Reference to the flag signifying a lock on the state machine.
bool& is_locked;
// Copy & move semantics disabled since this is a guard.
fsm_reentrancy_guard(fsm_reentrancy_guard const&) ETL_DELETE;
fsm_reentrancy_guard& operator= (fsm_reentrancy_guard const&) ETL_DELETE;
@ -272,7 +273,7 @@ namespace etl
/// A class to store FSM states.
//***************************************************************************
template <typename... TStates>
class fsm_state_pack
class fsm_state_pack
{
public:
@ -294,18 +295,18 @@ namespace etl
/// Gets a reference to the state.
//*********************************
template <typename TState>
TState& get()
{
return etl::get<TState>(storage);
TState& get()
{
return etl::get<TState>(storage);
}
//*********************************
/// Gets a const reference to the state.
//*********************************
template <typename TState>
const TState& get() const
{
return etl::get<TState>(storage);
const TState& get() const
{
return etl::get<TState>(storage);
}
private:
@ -341,14 +342,14 @@ namespace etl
using private_fsm::ifsm_state_helper<>::Pass_To_Parent;
using private_fsm::ifsm_state_helper<>::Self_Transition;
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
template <typename, typename, etl::fsm_state_id_t, typename...>
friend class fsm_state;
#else
template <typename, typename, etl::fsm_state_id_t,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename,
typename, typename, typename, typename>
friend class etl::fsm_state;
#endif
@ -560,7 +561,7 @@ namespace etl
{
etl::fsm_state_id_t next_state_id = p_state->process_event(message);
process_state_change(next_state_id);
process_state_change(next_state_id);
}
else
{
@ -691,7 +692,7 @@ namespace etl
p_state->on_exit_state();
next_state_id = p_state->on_enter_state();
}
if (have_changed_state(next_state_id))
{
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
@ -722,17 +723,249 @@ namespace etl
};
//*************************************************************************************************
// For C++17 and above.
// For C++11 and above.
//*************************************************************************************************
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
//***************************************************************************
// The definition for all types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
class fsm_state : public ifsm_state
{
private:
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
public:
using message_types = etl::type_list<TMessageTypes...>;
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
fsm_state()
: ifsm_state(STATE_ID)
{
}
protected:
~fsm_state()
{
}
TContext& get_fsm_context() const
{
return static_cast<TContext&>(ifsm_state::get_fsm_context());
}
private:
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
static_assert(Number_Of_Messages > 0, "Zero messages");
//**********************************************
// Checks that the message ids are contiguous.
//**********************************************
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
struct contiguous_impl;
template <size_t Index>
struct contiguous_impl<Index, true> : etl::true_type
{
};
template <size_t Index>
struct contiguous_impl<Index, false>
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
contiguous_impl<Index + 1U>::value>
{
};
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
using handler_ptr = etl::fsm_state_id_t (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
//********************************************
etl::fsm_state_id_t process_event(const etl::imessage& message)
{
const etl::message_id_t id = message.get_message_id();
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
const size_t index = get_dispatch_index_from_message_id(id);
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
{
const etl::fsm_state_id_t new_state_id = dispatch(message, index);
if (new_state_id != Pass_To_Parent)
{
return new_state_id;
}
}
}
#include "etl/private/diagnostic_array_bounds_push.h"
// If we get here, then we don't have a handler for this message type, so pass it to the parent if we have one, otherwise call on_event_unknown.
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
#include "etl/private/diagnostic_pop.h"
}
//**********************************************
// Call for a single message type
//**********************************************
template <typename TMessage>
static etl::fsm_state_id_t call_on_event(TDerived& derived, const imessage& msg)
{
return derived.on_event(static_cast<const TMessage&>(msg));
}
//**********************************************
// Get the handler for a single message type at the index in the sorted type_list.
// This will be called for each message type to generate the dispatch table.
//**********************************************
template <size_t Index>
static constexpr handler_ptr get_message_handler()
{
return &call_on_event<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
}
//**********************************************
// Generate the dispatch table at compile time.
// This will create an array of handler pointers, one for each message type.
//**********************************************
template <size_t... Indices>
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
{
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
}
//**********************************************
// Get the message id for a single message type at an index in the sorted type_list.
// This will be called for each message type to generate the message id table.
//**********************************************
template <size_t Index>
static constexpr etl::message_id_t get_message_id_from_index()
{
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
}
//**********************************************
// Generate the message id table at compile time.
// This will create an array of message ids, one for each message type.
//**********************************************
template <size_t... Indices>
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
{
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
}
//**********************************************
// Get the dispatch index for a message id.
// This will be used at runtime to find the handler for a message id.
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
// This will return Number_Of_Messages if the message id is not found.
//**********************************************
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
{
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
{
// The IDs are contiguous, so we can calculate the index directly.
return static_cast<size_t>(id - Message_Id_Start);
}
else
{
// The IDs are not contiguous, so we need to do a binary search.
size_t left = 0;
size_t right = Number_Of_Messages;
while (left < right)
{
size_t mid = (left + right) / 2;
if (message_id_table[mid] == id)
{
return mid;
}
else if (message_id_table[mid] < id)
{
left = mid + 1;
}
else
{
right = mid;
}
}
}
return Number_Of_Messages; // Not found
}
//**********************************************
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
//**********************************************
etl::fsm_state_id_t dispatch(const etl::imessage& msg, size_t index)
{
return message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
}
//**********************************************
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
//**********************************************
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
//**********************************************
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
//**********************************************
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
};
#if ETL_USING_CPP11 && !ETL_USING_CPP17
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table_t
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table;
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table_t
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table;
#endif
/// Definition of STATE_ID
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
//***************************************************************************
// The definition for no messages.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>
class fsm_state<TContext, TDerived, STATE_ID_> : public ifsm_state
{
private:
using message_id_sequence = etl::index_sequence<>;
public:
using message_types = etl::type_list<>;
using sorted_message_types = etl::type_list<>;
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
fsm_state()
@ -753,59 +986,24 @@ namespace etl
private:
//********************************************
struct result_t
{
bool was_handled;
etl::fsm_state_id_t state_id;
};
//********************************************
etl::fsm_state_id_t process_event(const etl::imessage& message)
{
etl::fsm_state_id_t new_state_id;
const bool was_handled = (process_event_type<TMessageTypes>(message, new_state_id) || ...);
if (!was_handled || (new_state_id == Pass_To_Parent))
{
new_state_id = (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
}
return new_state_id;
}
//********************************************
template <typename TMessage>
bool process_event_type(const etl::imessage& msg, etl::fsm_state_id_t& new_state_id)
{
if (TMessage::ID == msg.get_message_id())
{
new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const TMessage&>(msg));
return true;
}
else
{
return false;
}
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
}
};
/// Definition of STATE_ID
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
#else
//*************************************************************************************************
// For C++14 and below.
// For C++03 and below.
//*************************************************************************************************
//***************************************************************************
// The definition for all 16 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
class fsm_state : public ifsm_state
{
@ -864,10 +1062,10 @@ namespace etl
//***************************************************************************
// Specialisation for 15 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
typename T13, typename T14, typename T15>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> : public ifsm_state
{
@ -925,10 +1123,10 @@ namespace etl
//***************************************************************************
// Specialisation for 14 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
typename T13, typename T14>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> : public ifsm_state
{
@ -985,10 +1183,10 @@ namespace etl
//***************************************************************************
// Specialisation for 13 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
typename T13>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> : public ifsm_state
{
@ -1044,9 +1242,9 @@ namespace etl
//***************************************************************************
// Specialisation for 12 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> : public ifsm_state
{
@ -1101,9 +1299,9 @@ namespace etl
//***************************************************************************
// Specialisation for 11 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> : public ifsm_state
{
@ -1157,9 +1355,9 @@ namespace etl
//***************************************************************************
// Specialisation for 10 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> : public ifsm_state
{
@ -1212,9 +1410,9 @@ namespace etl
//***************************************************************************
// Specialisation for 9 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1266,8 +1464,8 @@ namespace etl
//***************************************************************************
// Specialisation for 8 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1318,8 +1516,8 @@ namespace etl
//***************************************************************************
// Specialisation for 7 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1369,8 +1567,8 @@ namespace etl
//***************************************************************************
// Specialisation for 6 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1419,8 +1617,8 @@ namespace etl
//***************************************************************************
// Specialisation for 5 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1468,7 +1666,7 @@ namespace etl
//***************************************************************************
// Specialisation for 4 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1515,7 +1713,7 @@ namespace etl
//***************************************************************************
// Specialisation for 3 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1561,7 +1759,7 @@ namespace etl
//***************************************************************************
// Specialisation for 2 message types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2>
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1606,7 +1804,7 @@ namespace etl
//***************************************************************************
// Specialisation for 1 message type.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1>
class fsm_state<TContext, TDerived, STATE_ID_, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
{
@ -1680,10 +1878,10 @@ namespace etl
}
};
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10, typename T11, typename T12,
typename T13, typename T14, typename T15, typename T16>
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::STATE_ID;
#endif

View File

@ -43,7 +43,7 @@ SOFTWARE.
namespace etl
{
//***************************************************************************
/// A definition of reference_wrapper for those that don't have C++ 0x11 support.
/// A definition of reference_wrapper for those that don't have C++11 support.
///\ingroup reference
//***************************************************************************
template <typename T>
@ -224,9 +224,9 @@ namespace etl
typedef int is_transparent;
template <typename T1, typename T2>
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs))
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(!(static_cast<T2&&>(rhs) < static_cast<T1&&>(lhs)))
{
return !(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs));
return !(static_cast<T2&&>(rhs) < static_cast<T1&&>(lhs));
}
};
#endif
@ -250,7 +250,7 @@ namespace etl
typedef int is_transparent;
template <typename T1, typename T2>
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs))
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T2&&>(rhs) < static_cast<T1&&>(lhs))
{
return static_cast<T2&&>(rhs) < static_cast<T1&&>(lhs);
}
@ -276,9 +276,9 @@ namespace etl
typedef int is_transparent;
template <typename T1, typename T2>
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs))
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(!(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs)))
{
return static_cast<T1&&>(rhs) < static_cast<T2&&>(lhs);
return !(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs));
}
};
#endif
@ -303,7 +303,7 @@ namespace etl
typedef int is_transparent;
template <typename T1, typename T2>
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs))
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) == static_cast<T2&&>(rhs))
{
return static_cast<T1&&>(lhs) == static_cast<T2&&>(rhs);
}
@ -329,7 +329,7 @@ namespace etl
typedef int is_transparent;
template <typename T1, typename T2>
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast<T1&&>(lhs) < static_cast<T2&&>(rhs))
constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(!(static_cast<T1&&>(lhs) == static_cast<T2&&>(rhs)))
{
return !(static_cast<T1&&>(lhs) == static_cast<T2&&>(rhs));
}

View File

@ -74,6 +74,7 @@ cog.outl("//********************************************************************
#include "largest.h"
#if ETL_USING_CPP11
#include "tuple.h"
#include "type_list.h"
#endif
#include <stdint.h>
@ -95,20 +96,20 @@ namespace etl
// For internal FSM use.
typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
template <typename, typename, etl::fsm_state_id_t, typename...>
class fsm_state;
#else
/*[[[cog
import cog
cog.outl("template <typename, typename, etl::fsm_state_id_t,")
cog.out(" ")
cog.out(" ")
for n in range(1, int(Handlers)):
cog.out("typename, ")
cog.out(" typename,")
if n % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename>")
cog.out(" ")
cog.outl(" typename>")
cog.outl("class fsm_state;")
]]]*/
/*[[[end]]]*/
@ -214,7 +215,7 @@ namespace etl
// Pass this whenever no state change is desired.
// The highest unsigned value of fsm_state_id_t.
static ETL_CONSTANT fsm_state_id_t No_State_Change = etl::integral_limits<fsm_state_id_t>::max;
// Pass this when this event also needs to be passed to the parent.
static ETL_CONSTANT fsm_state_id_t Pass_To_Parent = No_State_Change - 1U;
@ -232,15 +233,15 @@ namespace etl
ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
// Compile-time: TState::ID must equal its index in the type list (0..N-1)
template <size_t Id, typename...> struct check_ids : etl::true_type
template <size_t Id, typename...> struct check_ids : etl::true_type
{
};
template <size_t Id, typename TState0, typename... TRest>
struct check_ids<Id, TState0, TRest...>
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
{
};
};
//***************************************************************************
/// RAII detection mechanism to catch reentrant calls to methods that might
@ -269,11 +270,11 @@ namespace etl
{
is_locked = false;
}
private:
// Reference to the flag signifying a lock on the state machine.
bool& is_locked;
// Copy & move semantics disabled since this is a guard.
fsm_reentrancy_guard(fsm_reentrancy_guard const&) ETL_DELETE;
fsm_reentrancy_guard& operator= (fsm_reentrancy_guard const&) ETL_DELETE;
@ -291,7 +292,7 @@ namespace etl
/// A class to store FSM states.
//***************************************************************************
template <typename... TStates>
class fsm_state_pack
class fsm_state_pack
{
public:
@ -313,18 +314,18 @@ namespace etl
/// Gets a reference to the state.
//*********************************
template <typename TState>
TState& get()
{
return etl::get<TState>(storage);
TState& get()
{
return etl::get<TState>(storage);
}
//*********************************
/// Gets a const reference to the state.
//*********************************
template <typename TState>
const TState& get() const
{
return etl::get<TState>(storage);
const TState& get() const
{
return etl::get<TState>(storage);
}
private:
@ -360,20 +361,20 @@ namespace etl
using private_fsm::ifsm_state_helper<>::Pass_To_Parent;
using private_fsm::ifsm_state_helper<>::Self_Transition;
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
template <typename, typename, etl::fsm_state_id_t, typename...>
friend class fsm_state;
#else
/*[[[cog
import cog
cog.outl(" template <typename, typename, etl::fsm_state_id_t,")
cog.out(" ")
cog.out(" ")
for n in range(1, int(Handlers)):
cog.out("typename, ")
cog.out(" typename,")
if n % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename>")
cog.out(" ")
cog.outl(" typename>")
]]]*/
/*[[[end]]]*/
friend class etl::fsm_state;
@ -586,7 +587,7 @@ namespace etl
{
etl::fsm_state_id_t next_state_id = p_state->process_event(message);
process_state_change(next_state_id);
process_state_change(next_state_id);
}
else
{
@ -717,7 +718,7 @@ namespace etl
p_state->on_exit_state();
next_state_id = p_state->on_enter_state();
}
if (have_changed_state(next_state_id))
{
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
@ -748,17 +749,249 @@ namespace etl
};
//*************************************************************************************************
// For C++17 and above.
// For C++11 and above.
//*************************************************************************************************
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
//***************************************************************************
// The definition for all types.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
class fsm_state : public ifsm_state
{
private:
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
public:
using message_types = etl::type_list<TMessageTypes...>;
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
fsm_state()
: ifsm_state(STATE_ID)
{
}
protected:
~fsm_state()
{
}
TContext& get_fsm_context() const
{
return static_cast<TContext&>(ifsm_state::get_fsm_context());
}
private:
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
static_assert(Number_Of_Messages > 0, "Zero messages");
//**********************************************
// Checks that the message ids are contiguous.
//**********************************************
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
struct contiguous_impl;
template <size_t Index>
struct contiguous_impl<Index, true> : etl::true_type
{
};
template <size_t Index>
struct contiguous_impl<Index, false>
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
contiguous_impl<Index + 1U>::value>
{
};
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
using handler_ptr = etl::fsm_state_id_t (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
//********************************************
etl::fsm_state_id_t process_event(const etl::imessage& message)
{
const etl::message_id_t id = message.get_message_id();
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
const size_t index = get_dispatch_index_from_message_id(id);
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
{
const etl::fsm_state_id_t new_state_id = dispatch(message, index);
if (new_state_id != Pass_To_Parent)
{
return new_state_id;
}
}
}
#include "etl/private/diagnostic_array_bounds_push.h"
// If we get here, then we don't have a handler for this message type, so pass it to the parent if we have one, otherwise call on_event_unknown.
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
#include "etl/private/diagnostic_pop.h"
}
//**********************************************
// Call for a single message type
//**********************************************
template <typename TMessage>
static etl::fsm_state_id_t call_on_event(TDerived& derived, const imessage& msg)
{
return derived.on_event(static_cast<const TMessage&>(msg));
}
//**********************************************
// Get the handler for a single message type at the index in the sorted type_list.
// This will be called for each message type to generate the dispatch table.
//**********************************************
template <size_t Index>
static constexpr handler_ptr get_message_handler()
{
return &call_on_event<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
}
//**********************************************
// Generate the dispatch table at compile time.
// This will create an array of handler pointers, one for each message type.
//**********************************************
template <size_t... Indices>
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
{
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
}
//**********************************************
// Get the message id for a single message type at an index in the sorted type_list.
// This will be called for each message type to generate the message id table.
//**********************************************
template <size_t Index>
static constexpr etl::message_id_t get_message_id_from_index()
{
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
}
//**********************************************
// Generate the message id table at compile time.
// This will create an array of message ids, one for each message type.
//**********************************************
template <size_t... Indices>
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
{
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
}
//**********************************************
// Get the dispatch index for a message id.
// This will be used at runtime to find the handler for a message id.
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
// This will return Number_Of_Messages if the message id is not found.
//**********************************************
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
{
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
{
// The IDs are contiguous, so we can calculate the index directly.
return static_cast<size_t>(id - Message_Id_Start);
}
else
{
// The IDs are not contiguous, so we need to do a binary search.
size_t left = 0;
size_t right = Number_Of_Messages;
while (left < right)
{
size_t mid = (left + right) / 2;
if (message_id_table[mid] == id)
{
return mid;
}
else if (message_id_table[mid] < id)
{
left = mid + 1;
}
else
{
right = mid;
}
}
}
return Number_Of_Messages; // Not found
}
//**********************************************
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
//**********************************************
etl::fsm_state_id_t dispatch(const etl::imessage& msg, size_t index)
{
return message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
}
//**********************************************
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
//**********************************************
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
//**********************************************
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
//**********************************************
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
};
#if ETL_USING_CPP11 && !ETL_USING_CPP17
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table_t
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table;
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table_t
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table;
#endif
/// Definition of STATE_ID
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
//***************************************************************************
// The definition for no messages.
//***************************************************************************
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>
class fsm_state<TContext, TDerived, STATE_ID_> : public ifsm_state
{
private:
using message_id_sequence = etl::index_sequence<>;
public:
using message_types = etl::type_list<>;
using sorted_message_types = etl::type_list<>;
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
fsm_state()
@ -779,51 +1012,16 @@ namespace etl
private:
//********************************************
struct result_t
{
bool was_handled;
etl::fsm_state_id_t state_id;
};
//********************************************
etl::fsm_state_id_t process_event(const etl::imessage& message)
{
etl::fsm_state_id_t new_state_id;
const bool was_handled = (process_event_type<TMessageTypes>(message, new_state_id) || ...);
if (!was_handled || (new_state_id == Pass_To_Parent))
{
new_state_id = (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
}
return new_state_id;
}
//********************************************
template <typename TMessage>
bool process_event_type(const etl::imessage& msg, etl::fsm_state_id_t& new_state_id)
{
if (TMessage::ID == msg.get_message_id())
{
new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const TMessage&>(msg));
return true;
}
else
{
return false;
}
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
}
};
/// Definition of STATE_ID
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
#else
//*************************************************************************************************
// For C++14 and below.
// For C++03 and below.
//*************************************************************************************************
/*[[[cog
import cog
@ -833,14 +1031,14 @@ namespace etl
cog.outl("//***************************************************************************")
cog.outl("// The definition for all %s message types." % Handlers)
cog.outl("//***************************************************************************")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
cog.out(" ")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
cog.out(" ")
for n in range(1, int(Handlers)):
cog.out("typename T%s = void, " % n)
cog.out(" typename T%s = void," % n)
if n % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename T%s = void>" % Handlers)
cog.out(" ")
cog.outl(" typename T%s = void>" % Handlers)
cog.outl("class fsm_state : public ifsm_state")
cog.outl("{")
cog.outl("public:")
@ -896,26 +1094,26 @@ namespace etl
else:
cog.outl("// Specialisation for %d message types." % n)
cog.outl("//***************************************************************************")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
cog.out(" ")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
cog.out(" ")
for t in range(1, n):
cog.out("typename T%d, " % t)
cog.out(" typename T%d," % t)
if t % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename T%d>" % n)
cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
cog.out(" ")
cog.outl(" typename T%d>" % n)
cog.out("class fsm_state<TContext, TDerived, STATE_ID_,")
for t in range(1, n + 1):
cog.out("T%d, " % t)
cog.out(" T%d," % t)
if t % 16 == 0:
cog.outl("")
cog.out(" ")
for t in range(n + 1, int(Handlers)):
cog.out("void, ")
cog.out(" void,")
if t % 16 == 0:
cog.outl("")
cog.out(" ")
cog.outl("void> : public ifsm_state")
cog.outl(" void> : public ifsm_state")
cog.outl("{")
cog.outl("public:")
cog.outl("")
@ -966,13 +1164,13 @@ namespace etl
cog.outl("// Specialisation for 0 message types.")
cog.outl("//***************************************************************************")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>")
cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
cog.out("class fsm_state<TContext, TDerived, STATE_ID_,")
for t in range(1, int(Handlers)):
cog.out("void, ")
cog.out(" void,")
if t % 16 == 0:
cog.outl("")
cog.out(" ")
cog.outl("void> : public ifsm_state")
cog.outl(" void> : public ifsm_state")
cog.outl("{")
cog.outl("public:")
cog.outl("")
@ -1002,18 +1200,18 @@ namespace etl
cog.outl("};")
cog.outl("")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
cog.out(" ")
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
cog.out(" ")
for n in range(1, int(Handlers)):
cog.out("typename T%s, " % n)
cog.out(" typename T%s," % n)
if n % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename T%s>" % Handlers)
cog.out("ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, ")
cog.out(" ")
cog.outl(" typename T%s>" % Handlers)
cog.out("ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_,")
for n in range(1, int(Handlers)):
cog.out("T%s, " % n)
cog.outl("T%s>::STATE_ID;" % Handlers)
cog.out(" T%s," % n)
cog.outl(" T%s>::STATE_ID;" % Handlers)
]]]*/
/*[[[end]]]*/
#endif

View File

@ -525,33 +525,31 @@ namespace etl
//***********************************************
void receive(const etl::imessage& msg) ETL_OVERRIDE
{
etl::message_id_t id = msg.get_message_id();
size_t index = Number_Of_Messages;
const etl::message_id_t id = msg.get_message_id();
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
index = get_dispatch_index_from_message_id(id);
const size_t index = get_dispatch_index_from_message_id(id);
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
{
dispatch(msg, index);
return;
}
}
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
if (has_successor())
{
dispatch(msg, index);
get_successor().receive(msg);
}
else
{
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
if (has_successor())
{
get_successor().receive(msg);
}
else
{
#include "etl/private/diagnostic_array_bounds_push.h"
static_cast<TDerived*>(this)->on_receive_unknown(msg);
static_cast<TDerived*>(this)->on_receive_unknown(msg);
#include "etl/private/diagnostic_pop.h"
}
}
}
@ -601,29 +599,17 @@ namespace etl
//***********************************************
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
{
size_t index = Number_Of_Messages;
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
index = get_dispatch_index_from_message_id(id);
const size_t index = get_dispatch_index_from_message_id(id);
if (index < Number_Of_Messages)
{
return true;
}
}
if (index < Number_Of_Messages)
{
return true;
}
else
{
if (has_successor())
{
return get_successor().accepts(id);
}
else
{
return false;
}
}
return has_successor() ? get_successor().accepts(id) : false;
}
//********************************************

View File

@ -765,11 +765,11 @@ namespace etl
///\ingroup type_traits
/// Implemented by checking if type is convertible to an integer through static_cast
namespace private_type_traits
namespace private_type_traits
{
// Base case
template <typename T, typename = int>
struct is_convertible_to_int
struct is_convertible_to_int
: false_type
{
};
@ -778,7 +778,7 @@ namespace etl
// 2nd template argument of base case defaults to int to ensure that this partial specialization is always tried first
template <typename T>
struct is_convertible_to_int<T, decltype(static_cast<int>(declval<T>()))>
: true_type
: true_type
{
};
}
@ -788,7 +788,7 @@ namespace etl
: integral_constant<bool, private_type_traits::is_convertible_to_int<T>::value &&
!is_class<T>::value &&
!is_arithmetic<T>::value &&
!is_reference<T>::value>
!is_reference<T>::value>
{
};
@ -872,6 +872,42 @@ namespace etl
public:
static ETL_CONSTANT bool value = decltype(test<TFrom>(0))::value;
};
#else
namespace private_type_traits
{
typedef char yes;
struct no { char dummy[2]; };
template <typename TFrom, typename TTo>
struct is_convertible_impl
{
static yes test(TTo);
static no test(...);
static TFrom make();
static const bool value = (sizeof(test(make())) == sizeof(yes));
};
template <typename TTo>
struct is_convertible_impl<void, TTo>
{
static const bool value = false;
};
template <typename TFrom>
struct is_convertible_impl<TFrom, void>
{
static const bool value = false;
};
template <>
struct is_convertible_impl<void, void>
{
static const bool value = true;
};
}
template <typename TFrom, typename TTo>
struct is_convertible : etl::bool_constant<private_type_traits::is_convertible_impl<TFrom, TTo>::value> {};
#endif
#if ETL_USING_CPP17
@ -1420,6 +1456,42 @@ typedef integral_constant<bool, true> true_type;
public:
static ETL_CONSTANT bool value = decltype(test<TFrom>(0))::value;
};
#else
namespace private_type_traits
{
typedef char yes;
struct no { char dummy[2]; };
template <typename TFrom, typename TTo>
struct is_convertible_impl
{
static yes test(TTo);
static no test(...);
static TFrom make();
static const bool value = (sizeof(test(make())) == sizeof(yes));
};
template <typename TTo>
struct is_convertible_impl<void, TTo>
{
static const bool value = false;
};
template <typename TFrom>
struct is_convertible_impl<TFrom, void>
{
static const bool value = false;
};
template <>
struct is_convertible_impl<void, void>
{
static const bool value = true;
};
}
template <typename TFrom, typename TTo>
struct is_convertible : etl::bool_constant<private_type_traits::is_convertible_impl<TFrom, TTo>::value> {};
#endif
#if ETL_USING_CPP17
@ -1556,17 +1628,17 @@ typedef integral_constant<bool, true> true_type;
cog.outl("/// Template to determine if a type is one of a specified list.")
cog.outl("///\\ingroup types")
cog.outl("template <typename T,")
cog.out(" ")
cog.out("typename T1, ")
cog.out(" ")
cog.out(" typename T1,")
for n in range(2, int(IsOneOf)):
cog.out("typename T%s = void, " % n)
cog.out(" typename T%s = void," % n)
if n % 4 == 0:
cog.outl("")
cog.out(" ")
cog.outl("typename T%s = void>" % IsOneOf)
cog.out(" ")
cog.outl(" typename T%s = void>" % IsOneOf)
cog.outl("struct is_one_of")
cog.outl("{")
cog.outl(" static const bool value = ")
cog.outl(" static const bool value =")
for n in range(1, int(IsOneOf)):
cog.outl(" etl::is_same<T, T%s>::value ||" % n)
cog.outl(" etl::is_same<T, T%s>::value;" % IsOneOf)
@ -1647,7 +1719,7 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
/// Get the Nth base of a recursively inherited type.
/// Requires that the class has defined 'base_type'.
//***************************************************************************
//***************************************************************************
// Recursive definition of the type.
template <size_t Index, typename TType>
struct nth_base
@ -2192,7 +2264,7 @@ typedef integral_constant<bool, true> true_type;
#if ETL_USING_CPP11
//***************************************************************************
/// is_constructible
namespace private_type_traits
namespace private_type_traits
{
template <class, class T, class... TArgs>
struct is_constructible_ : etl::false_type {};
@ -2371,7 +2443,7 @@ typedef integral_constant<bool, true> true_type;
};
template <typename T1, typename T2, typename = void>
struct common_type_2_impl
struct common_type_2_impl
: decay_conditional_result<const T1&, const T2&>
{
};
@ -2716,7 +2788,7 @@ typedef integral_constant<bool, true> true_type;
struct is_member_pointer_helper<T TObject::*> : etl::true_type {};
}
template<typename T>
template<typename T>
struct is_member_pointer : private_type_traits::is_member_pointer_helper<typename etl::remove_cv<T>::type> {};
#if ETL_USING_CPP17
@ -2809,10 +2881,10 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
namespace private_type_traits
{
template<typename>
template<typename>
struct is_member_object_pointer_helper : public etl::false_type {};
template<typename T, typename TObject>
template<typename T, typename TObject>
struct is_member_object_pointer_helper<T TObject::*> : public etl::negation<etl::is_function<T>> {};
}
@ -3034,6 +3106,60 @@ typedef integral_constant<bool, true> true_type;
};
#endif
#if ETL_USING_CPP11
template <typename, typename = void>
struct has_size : etl::false_type {};
template <typename T>
struct has_size<T, void_t<decltype(etl::declval<T>().size())> >
: etl::true_type {};
#else
template <typename T>
struct has_size
{
private:
typedef char yes;
struct no { char dummy[2]; };
template <typename U>
static yes test_size(char (*)[sizeof(&U::size)]);
template <typename U>
static no test_size(...);
public:
static const bool value = (sizeof(test_size<T>(0)) == sizeof(yes));
};
#endif
#if ETL_USING_CPP11
template <typename, typename = void>
struct has_data : etl::false_type {};
template <typename T>
struct has_data<T, void_t<decltype(etl::declval<T>().data())> >
: etl::true_type {};
#else
template <typename T>
struct has_data
{
private:
typedef char yes;
struct no { char dummy[2]; };
template <typename U>
static yes test_data(char (*)[sizeof(&U::data)]);
template <typename U>
static no test_data(...);
public:
static const bool value = (sizeof(test_data<T>(0)) == sizeof(yes));
};
#endif
}
// Helper macros

View File

@ -67,7 +67,7 @@ namespace etl
typedef typename TIterator::pointer pointer;
typedef typename TIterator::reference reference;
};
// For pointers.
template <typename T>
struct iterator_traits<T*, void>
@ -606,7 +606,7 @@ namespace etl
ETL_CONSTEXPR14 back_insert_iterator& operator =(const typename TContainer::value_type& value)
{
container->push_back(value);
return (*this);
}
@ -617,7 +617,7 @@ namespace etl
ETL_CONSTEXPR14 back_insert_iterator& operator =(typename TContainer::value_type&& value)
{
container->push_back(etl::move(value));
return (*this);
}
#endif // ETL_USING_CPP11
@ -655,8 +655,8 @@ namespace etl
/// Creates a back_insert_iterator from a container.
//***************************************************************************
template <typename TContainer>
ETL_NODISCARD
ETL_CONSTEXPR14
ETL_NODISCARD
ETL_CONSTEXPR14
etl::back_insert_iterator<TContainer> back_inserter(TContainer& container)
{
return etl::back_insert_iterator<TContainer>(container);
@ -1211,6 +1211,48 @@ namespace etl
char(&array_size(T(&array)[Array_Size]))[Array_Size];
#define ETL_ARRAY_SIZE(a) sizeof(etl::array_size(a))
#if ETL_NOT_USING_STL || ETL_CPP17_NOT_SUPPORTED
//**************************************************************************
/// Returns a pointer to the block of memory containing the elements of the range.
///\ingroup container
//**************************************************************************
template<typename TContainer>
ETL_CONSTEXPR typename TContainer::pointer data(TContainer& container)
{
return container.data();
}
//**************************************************************************
/// Returns a const_pointer to the block of memory containing the elements of the range.
///\ingroup container
//**************************************************************************
template<typename TContainer>
ETL_CONSTEXPR typename TContainer::const_pointer data(const TContainer& container)
{
return container.data();
}
///**************************************************************************
/// Returns a pointer to the block of memory containing the elements of the range.
///\ingroup container
///**************************************************************************
template<typename TValue, size_t Array_Size>
ETL_CONSTEXPR TValue* data(TValue(&a)[Array_Size])
{
return a;
}
///**************************************************************************
/// Returns a const pointer to the block of memory containing the elements of the range.
///\ingroup container
///**************************************************************************
template<typename TValue, size_t Array_Size>
ETL_CONSTEXPR const TValue* data(const TValue(&a)[Array_Size])
{
return a;
}
#endif
}
#endif

View File

@ -513,33 +513,31 @@ namespace etl
//***********************************************
void receive(const etl::imessage& msg) ETL_OVERRIDE
{
etl::message_id_t id = msg.get_message_id();
size_t index = Number_Of_Messages;
const etl::message_id_t id = msg.get_message_id();
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
index = get_dispatch_index_from_message_id(id);
const size_t index = get_dispatch_index_from_message_id(id);
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
{
dispatch(msg, index);
return;
}
}
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
if (index < Number_Of_Messages)
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
if (has_successor())
{
dispatch(msg, index);
get_successor().receive(msg);
}
else
{
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
if (has_successor())
{
get_successor().receive(msg);
}
else
{
#include "etl/private/diagnostic_array_bounds_push.h"
static_cast<TDerived*>(this)->on_receive_unknown(msg);
static_cast<TDerived*>(this)->on_receive_unknown(msg);
#include "etl/private/diagnostic_pop.h"
}
}
}
@ -589,29 +587,17 @@ namespace etl
//***********************************************
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
{
size_t index = Number_Of_Messages;
// The IDs are sorted, so an ID less than the first is not handled by this router.
if (id >= Message_Id_Start)
{
index = get_dispatch_index_from_message_id(id);
const size_t index = get_dispatch_index_from_message_id(id);
if (index < Number_Of_Messages)
{
return true;
}
}
if (index < Number_Of_Messages)
{
return true;
}
else
{
if (has_successor())
{
return get_successor().accepts(id);
}
else
{
return false;
}
}
return has_successor() ? get_successor().accepts(id) : false;
}
//********************************************

View File

@ -47,7 +47,7 @@ namespace etl
{
//***************************************************************************
/// iota
/// Reverse engineered version of std::iota for non C++ 0x11 compilers.
/// Reverse engineered version of std::iota for non C++11 compilers.
/// Fills a range of elements with sequentially increasing values starting with <b>value</b>.
///\param first An iterator to the first position to fill.
///\param last An iterator to the last + 1 position.

View File

@ -169,21 +169,19 @@ namespace etl
}
//***************************************************************************
/// Constructor from value type.
/// Converting constructor from value type.
/// Constructs T in-place from U&&, without requiring T to be
/// copy/move constructible.
//***************************************************************************
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value &&
!etl::is_same<typename etl::decay<U>::type, optional_impl>::value, int>::type = 0>
ETL_CONSTEXPR20_STL
optional_impl(const T& value_)
optional_impl(U&& value_)
{
storage.construct(value_);
}
//***************************************************************************
/// Constructor from value type.
//***************************************************************************
ETL_CONSTEXPR20_STL
optional_impl(T&& value_)
{
storage.construct(etl::move(value_));
storage.construct(etl::forward<U>(value_));
}
//***************************************************************************
@ -280,23 +278,24 @@ namespace etl
//***************************************************************************
/// Assignment operator from value type.
//***************************************************************************
#if ETL_USING_CPP11
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, optional_impl>::value, int>::type = 0>
ETL_CONSTEXPR20_STL
optional_impl& operator =(U&& value_)
{
storage.construct(etl::forward<U>(value_));
return *this;
}
#else
ETL_CONSTEXPR20_STL
optional_impl& operator =(const T& value_)
{
storage.construct(value_);
return *this;
}
#if ETL_USING_CPP11
//***************************************************************************
/// Assignment operator from value type.
//***************************************************************************
ETL_CONSTEXPR20_STL
optional_impl& operator =(T&& value_)
{
storage.construct(etl::move(value_));
return *this;
}
#endif
@ -1442,22 +1441,36 @@ namespace etl
#if ETL_USING_CPP11
//***************************************************************************
/// Construct from value type.
/// Converting constructor from value type.
/// Constructs T in-place from U&&, without requiring T to be
/// copy/move constructible.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value &&
etl::is_pod<typename etl::remove_cv<T>::type>::value, int>::type = 0>
ETL_CONSTEXPR14
optional(const T& value_)
: impl_t(value_)
optional(U&& value_)
: impl_t(etl::forward<U>(value_))
{
}
//***************************************************************************
/// Construct from value type.
/// Converting constructor from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value &&
!etl::is_pod<typename etl::remove_cv<T>::type>::value, int>::type = 0>
ETL_CONSTEXPR20_STL
optional(const T& value_)
: impl_t(value_)
optional(U&& value_)
: impl_t(etl::forward<U>(value_))
{
}
#else
@ -1470,29 +1483,6 @@ namespace etl
}
#endif
#if ETL_USING_CPP11
//***************************************************************************
/// Move construct from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
ETL_CONSTEXPR14
optional(T&& value_)
: impl_t(etl::move(value_))
{
}
//***************************************************************************
/// Move construct from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
ETL_CONSTEXPR20_STL
optional(T&& value_)
: impl_t(etl::move(value_))
{
}
#endif
#if ETL_USING_CPP11
//***************************************************************************
/// Emplace construct from arguments.
@ -1641,25 +1631,35 @@ namespace etl
#if ETL_USING_CPP11
//***************************************************************************
/// Assignment operator from value type.
/// Converting assignment operator from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value &&
etl::is_pod<typename etl::remove_cv<T>::type>::value, int>::type = 0>
ETL_CONSTEXPR14
optional& operator =(const T& value_)
optional& operator =(U&& value_)
{
impl_t::operator=(value_);
impl_t::operator=(etl::forward<U>(value_));
return *this;
}
//***************************************************************************
/// Assignment operator from value type.
/// Converting assignment operator from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
template <typename U,
typename etl::enable_if<
etl::is_constructible<T, U&&>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value &&
!etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value &&
!etl::is_pod<typename etl::remove_cv<T>::type>::value, int>::type = 0>
ETL_CONSTEXPR20_STL
optional& operator =(const T& value_)
optional& operator =(U&& value_)
{
impl_t::operator=(value_);
impl_t::operator=(etl::forward<U>(value_));
return *this;
}
@ -1675,32 +1675,6 @@ namespace etl
}
#endif
#if ETL_USING_CPP11
//***************************************************************************
/// Move assignment operator from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
ETL_CONSTEXPR14
optional& operator =(T&& value_)
{
impl_t::operator=(etl::move(value_));
return *this;
}
//***************************************************************************
/// Move assignment operator from value type.
//***************************************************************************
template <typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
ETL_CONSTEXPR20_STL
optional& operator =(T&& value_)
{
impl_t::operator=(etl::move(value_));
return *this;
}
#endif
//***************************************************************************
/// Returns an iterator to the beginning of the optional.
//***************************************************************************

View File

@ -154,6 +154,16 @@ SOFTWARE.
#define ETL_NOT_USING_WIDE_CHARACTERS 0
#endif
//*************************************
// Helper macro for ETL_FORMAT_NO_FLOATING_POINT.
#if defined(ETL_FORMAT_NO_FLOATING_POINT)
#define ETL_USING_FORMAT_FLOATING_POINT 0
#define ETL_NOT_USING_FORMAT_FLOATING_POINT 1
#else
#define ETL_USING_FORMAT_FLOATING_POINT 1
#define ETL_NOT_USING_FORMAT_FLOATING_POINT 0
#endif
//*************************************
// Figure out things about the compiler, if haven't already done so in etl_profile.h
#include "profiles/determine_compiler_version.h"
@ -372,11 +382,13 @@ SOFTWARE.
#if ETL_USING_EXCEPTIONS
#define ETL_NOEXCEPT noexcept
#define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__)
#define ETL_NOEXCEPT_IF(b) noexcept((b))
#define ETL_NOEXCEPT_FROM(x) noexcept(noexcept(x))
#else
#define ETL_NOEXCEPT
#define ETL_NOEXCEPT_EXPR(...)
#define ETL_NOEXCEPT_FROM(x)
#define ETL_NOEXCEPT_IF(b)
#define ETL_NOEXCEPT_FROM(x)
#endif
#else
#define ETL_CONSTEXPR
@ -389,7 +401,8 @@ SOFTWARE.
#define ETL_NORETURN
#define ETL_NOEXCEPT
#define ETL_NOEXCEPT_EXPR(...)
#define ETL_NOEXCEPT_FROM(x)
#define ETL_NOEXCEPT_IF(b)
#define ETL_NOEXCEPT_FROM(x)
#define ETL_MOVE(x) x
#define ETL_ENUM_CLASS(name) enum name
#define ETL_ENUM_CLASS_TYPE(name, type) enum name
@ -402,7 +415,7 @@ SOFTWARE.
#if ETL_USING_CPP14
#define ETL_CONSTEXPR14 constexpr
#if !defined(ETL_IN_UNIT_TEST)
#if !defined(ETL_IN_UNIT_TEST)
#define ETL_DEPRECATED [[deprecated]]
#define ETL_DEPRECATED_REASON(reason) [[deprecated(reason)]]
#else
@ -448,7 +461,13 @@ SOFTWARE.
#define ETL_UNLIKELY
#define ETL_CONSTEXPR20
#define ETL_CONSTEVAL
#define ETL_CONSTINIT
#if ETL_USING_CLANG_COMPILER && ETL_COMPILER_FULL_VERSION >= 40000
#define ETL_CONSTINIT __attribute__((require_constant_initialization))
#elif ETL_USING_GCC_COMPILER && ETL_COMPILER_FULL_VERSION >= 100000
#define ETL_CONSTINIT __constinit
#else
#define ETL_CONSTINIT
#endif
#define ETL_NO_UNIQUE_ADDRESS
#define ETL_EXPLICIT_EXPR(...) explicit
#endif
@ -601,7 +620,7 @@ SOFTWARE.
#elif defined(ETL_COMPILER_MICROSOFT)
#define ETL_PACKED_CLASS(class_type) __pragma(pack(push, 1)) class class_type
#define ETL_PACKED_STRUCT(struct_type) __pragma(pack(push, 1)) struct struct_type
#define ETL_PACKED
#define ETL_PACKED
#define ETL_END_PACKED __pragma(pack(pop))
#define ETL_HAS_PACKED 1
#else
@ -651,7 +670,8 @@ namespace etl
static ETL_CONSTANT bool using_exceptions = (ETL_USING_EXCEPTIONS == 1);
static ETL_CONSTANT bool using_libc_wchar_h = (ETL_USING_LIBC_WCHAR_H == 1);
static ETL_CONSTANT bool using_std_exception = (ETL_USING_STD_EXCEPTION == 1);
static ETL_CONSTANT bool using_format_floating_point = (ETL_USING_FORMAT_FLOATING_POINT == 1);
// Has...
static ETL_CONSTANT bool has_initializer_list = (ETL_HAS_INITIALIZER_LIST == 1);
static ETL_CONSTANT bool has_8bit_types = (ETL_USING_8BIT_TYPES == 1);

View File

@ -33,7 +33,11 @@ SOFTWARE.
#endif
#if !defined(ETL_CHRONO_SYSTEM_CLOCK_DURATION)
#define ETL_CHRONO_SYSTEM_CLOCK_DURATION etl::chrono::nanoseconds
#if (INT_MAX >= INT32_MAX)
#define ETL_CHRONO_SYSTEM_CLOCK_DURATION etl::chrono::nanoseconds
#else
#define ETL_CHRONO_SYSTEM_CLOCK_DURATION etl::chrono::milliseconds
#endif
#endif
#if !defined(ETL_CHRONO_SYSTEM_CLOCK_IS_STEADY)
@ -41,7 +45,11 @@ SOFTWARE.
#endif
#if !defined(ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION)
#define ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION etl::chrono::nanoseconds
#if (INT_MAX >= INT32_MAX)
#define ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION etl::chrono::nanoseconds
#else
#define ETL_CHRONO_HIGH_RESOLUTION_CLOCK_DURATION etl::chrono::milliseconds
#endif
#endif
#if !defined(ETL_CHRONO_HIGH_RESOLUTION_CLOCK_IS_STEADY)
@ -49,7 +57,11 @@ SOFTWARE.
#endif
#if !defined(ETL_CHRONO_STEADY_CLOCK_DURATION)
#define ETL_CHRONO_STEADY_CLOCK_DURATION etl::chrono::nanoseconds
#if (INT_MAX >= INT32_MAX)
#define ETL_CHRONO_STEADY_CLOCK_DURATION etl::chrono::nanoseconds
#else
#define ETL_CHRONO_STEADY_CLOCK_DURATION etl::chrono::milliseconds
#endif
#endif
extern "C" ETL_CHRONO_SYSTEM_CLOCK_DURATION::rep etl_get_system_clock();

View File

@ -315,13 +315,17 @@ namespace etl
/// Duration types
//***********************************************************************
#if (ETL_USING_64BIT_TYPES)
#if (INT_MAX >= INT32_MAX)
using nanoseconds = etl::chrono::duration<int64_t, etl::nano>;
using microseconds = etl::chrono::duration<int64_t, etl::micro>;
#endif
using milliseconds = etl::chrono::duration<int64_t, etl::milli>;
using seconds = etl::chrono::duration<int64_t, etl::ratio<1U>>;
#else
#if (INT_MAX >= INT32_MAX)
using nanoseconds = etl::chrono::duration<int32_t, etl::nano>;
using microseconds = etl::chrono::duration<int32_t, etl::micro>;
#endif
using milliseconds = etl::chrono::duration<int32_t, etl::milli>;
using seconds = etl::chrono::duration<int32_t, etl::ratio<1U>>;
#endif
@ -811,6 +815,7 @@ namespace etl
return etl::chrono::duration<double, milli>(s);
}
#if (INT_MAX >= INT32_MAX)
//***********************************************************************
/// Literal for microseconds duration
//***********************************************************************
@ -848,7 +853,7 @@ namespace etl
}
//***********************************************************************
/// Literal for floating point microseconds duration
/// Literal for floating point nanoseconds duration
//***********************************************************************
#if ETL_USING_VERBOSE_CHRONO_LITERALS
inline ETL_CONSTEXPR14 etl::chrono::duration<double, nano> operator ""_nanoseconds(long double s) ETL_NOEXCEPT
@ -858,6 +863,7 @@ namespace etl
{
return etl::chrono::duration<double, nano>(s);
}
#endif
}
}
}

View File

@ -454,7 +454,7 @@ namespace etl
}
//*************************************************************************
/// Removes the oldest value from the back of the queue.
/// Removes the oldest value from the front of the queue.
/// Does nothing if the queue is already empty.
/// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty.
//*************************************************************************

View File

@ -47,6 +47,12 @@ SOFTWARE.
#include "array.h"
#include "byte.h"
#include "static_assert.h"
#include "container.h"
#include "private/tuple_size.h"
#if ETL_USING_STL && ETL_USING_CPP20
#include <span>
#endif
#include "private/dynamic_extent.h"
@ -72,7 +78,28 @@ namespace etl
//***************************************************************************
// Tag to indicate a class is a span.
//***************************************************************************
class span_tag {};
// Forward declaration for trait
template <typename T, size_t Extent>
class span;
namespace private_span
{
template <typename T>
struct is_span_helper : etl::false_type {};
template <typename T, size_t Extent>
struct is_span_helper<etl::span<T, Extent> > : etl::true_type {};
}
template <typename T>
struct is_span
: private_span::is_span_helper<typename etl::remove_cvref<T>::type> {};
#if ETL_USING_CPP17
template <typename T>
inline constexpr bool is_span_v = is_span<T>::value;
#endif
//***************************************************************************
///\ingroup span
@ -130,6 +157,12 @@ namespace etl
}
};
//***************************************************************************
///\ingroup span
/// Tag to indicate a class is a span.
/// Deprecated, use is_span trait instead.
class span_tag {};
//***************************************************************************
/// Span - Fixed Extent
//***************************************************************************
@ -141,13 +174,13 @@ namespace etl
typedef T element_type;
typedef typename etl::remove_cv<T>::type value_type;
typedef size_t size_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef T* iterator;
typedef const T* const_iterator;
typedef T* iterator;
typedef const T* const_iterator;
typedef ETL_OR_STD::reverse_iterator<iterator> reverse_iterator;
typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;
@ -157,72 +190,92 @@ namespace etl
static ETL_CONSTANT size_t extent = Extent;
//*************************************************************************
/// Construct from iterators + size
/// Default constructor
/// Enabled only for zero extent, creates an empty span.
//*************************************************************************
template <typename TIterator, typename TSize>
ETL_CONSTEXPR explicit span(const TIterator begin_, const TSize /*size_*/) ETL_NOEXCEPT
#if ETL_USING_CPP11
template <size_t E = Extent, typename = typename etl::enable_if<E == 0, void>::type>
ETL_CONSTEXPR span() ETL_NOEXCEPT
: pbegin(ETL_NULLPTR)
{
}
#else
ETL_CONSTEXPR span() ETL_NOEXCEPT
: pbegin(ETL_NULLPTR)
{
ETL_STATIC_ASSERT(Extent == 0, "Default constructor only available for zero extent");
}
#endif
//*************************************************************************
/// Construct from iterator + size
//*************************************************************************
template <typename TIterator>
explicit ETL_CONSTEXPR14 span(const TIterator begin_, const size_t size_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
: pbegin(etl::to_address(begin_))
{
ETL_ASSERT(size_ == Extent, ETL_ERROR(span_size_mismatch));
(void)size_;
}
//*************************************************************************
/// Construct from iterators
//*************************************************************************
template <typename TIterator>
ETL_CONSTEXPR explicit span(const TIterator begin_, const TIterator /*end_*/) ETL_NOEXCEPT
template <typename TIteratorBegin, typename TIteratorEnd>
ETL_CONSTEXPR14 span(const TIteratorBegin begin_, const TIteratorEnd end_,
typename etl::enable_if<!etl::is_integral<TIteratorEnd>::value, void>::type* = 0) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
: pbegin(etl::to_address(begin_))
{
ETL_ASSERT(etl::distance(begin_, end_) == Extent, ETL_ERROR(span_size_mismatch));
(void)end_;
}
//*************************************************************************
/// Construct from C array
//*************************************************************************
#if ETL_USING_CPP11
template<size_t Array_Size, typename = typename etl::enable_if<(Array_Size == Extent), void>::type>
ETL_CONSTEXPR span(element_type(&begin_)[Array_Size]) ETL_NOEXCEPT
: pbegin(begin_)
{
}
#else
//*************************************************************************
/// Construct from C array
//*************************************************************************
template<size_t Array_Size>
ETL_CONSTEXPR span(element_type(&begin_)[Array_Size], typename etl::enable_if<(Array_Size == Extent), void>::type* = 0) ETL_NOEXCEPT
ETL_CONSTEXPR span(typename etl::type_identity<element_type>::type(&begin_)[Array_Size], typename etl::enable_if<(Array_Size == Extent), void>::type* = 0) ETL_NOEXCEPT
: pbegin(begin_)
{
}
#endif
#if ETL_USING_CPP11
//*************************************************************************
/// Construct from a container or other type that supports
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer, typename = typename etl::enable_if<!etl::is_base_of<span_tag, etl::remove_reference_t<TContainer>>::value &&
!etl::is_std_array<etl::remove_reference_t<TContainer>>::value &&
!etl::is_etl_array<etl::remove_reference_t<TContainer>>::value &&
!etl::is_pointer<etl::remove_reference_t<TContainer>>::value &&
!etl::is_array<etl::remove_reference_t<TContainer>>::value &&
etl::is_same<etl::remove_cv_t<T>, etl::remove_cv_t<typename etl::remove_reference_t<TContainer>::value_type>>::value, void>::type>
ETL_CONSTEXPR span(TContainer&& a) ETL_NOEXCEPT
: pbegin(a.data())
{
}
template <typename TContainer>
ETL_CONSTEXPR14 span(TContainer&& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
etl::is_lvalue_reference<TContainer&&>::value &&
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_convertible<decltype(etl::declval<typename etl::remove_reference<TContainer>::type&>().data()), pointer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
: pbegin(a.data())
{
ETL_ASSERT(a.size() == Extent, ETL_ERROR(span_size_mismatch));
}
#else
//*************************************************************************
/// Construct from a container or other type that supports
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer>
span(TContainer& a, typename etl::enable_if<!etl::is_base_of<span_tag, typename etl::remove_reference<TContainer>::type>::value &&
span(TContainer& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0)
: pbegin(a.data())
{
ETL_ASSERT(a.size() == Extent, ETL_ERROR(span_size_mismatch));
}
//*************************************************************************
@ -230,17 +283,69 @@ namespace etl
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer>
span(const TContainer& a, typename etl::enable_if<!etl::is_base_of<span_tag, typename etl::remove_reference<TContainer>::type>::value &&
span(const TContainer& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value&&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0)
: pbegin(a.data())
{
ETL_ASSERT(a.size() == Extent, ETL_ERROR(span_size_mismatch));
}
#endif
//*************************************************************************
/// Constructor from etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(etl::array<U, Size>& other, typename etl::enable_if<(Size == Extent) &&
etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
//*************************************************************************
/// Constructor from const etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const etl::array<U, Size>& other, typename etl::enable_if<(Size == Extent) &&
etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
#if ETL_USING_CPP11
template <typename U, size_t Size>
span(etl::array<U, Size>&&) = delete;
#endif
#if ETL_USING_STL && ETL_USING_CPP11
//*************************************************************************
/// Constructor from std array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(std::array<U, Size>& other, typename etl::enable_if<(Size == Extent) &&
etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
//*************************************************************************
/// Constructor from const std array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const std::array<U, Size>& other, typename etl::enable_if<(Size == Extent) &&
etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
template <typename U, size_t Size>
span(std::array<U, Size>&&) = delete;
#endif
//*************************************************************************
/// Copy constructor
//*************************************************************************
@ -254,7 +359,7 @@ namespace etl
/// From fixed extent span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const etl::span<U, Size>& other, typename etl::enable_if<Size == Extent, void>::type* = 0) ETL_NOEXCEPT
ETL_CONSTEXPR span(const etl::span<U, Size>& other, typename etl::enable_if<(Size == Extent) && (Size != etl::dynamic_extent), void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
@ -264,50 +369,37 @@ namespace etl
/// From dynamic extent span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR14 span(const etl::span<U, Size>& other, typename etl::enable_if<Size == etl::dynamic_extent, void>::type* = 0)
ETL_CONSTEXPR14 explicit span(const etl::span<U, Size>& other, typename etl::enable_if<(Size == etl::dynamic_extent), void>::type* = 0)
: pbegin(other.data())
{
ETL_ASSERT(other.size() == Extent, ETL_ERROR(span_size_mismatch));
}
#if ETL_USING_STL && ETL_USING_CPP11
#if ETL_USING_STL && ETL_USING_CPP20
//*************************************************************************
/// Constructor from std array.
/// Copy constructor
/// From fixed extent std::span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(std::array<U, Size>& other, typename etl::enable_if<Size == Extent, void>::type* = 0) ETL_NOEXCEPT
ETL_CONSTEXPR span(const std::span<U, Size>& other, typename etl::enable_if<(Size == Extent) &&
etl::is_convertible<U(*)[], T(*)[]>::value, int>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
//*************************************************************************
/// Constructor from const std array.
/// Copy constructor
/// From dynamic extent std::span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const std::array<U, Size>& other, typename etl::enable_if<Size == Extent && etl::is_const<T>::value, void>::type* = 0) ETL_NOEXCEPT
ETL_CONSTEXPR14 span(const std::span<U, Size>& other, typename etl::enable_if<(Size == etl::dynamic_extent &&
etl::is_convertible<U(*)[], T(*)[]>::value), int>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
ETL_ASSERT(other.size() == Extent, ETL_ERROR(span_size_mismatch));
}
#endif
//*************************************************************************
/// Constructor from etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(etl::array<U, Size>& other, typename etl::enable_if<Size == Extent, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
//*************************************************************************
/// Constructor from const etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const etl::array<U, Size>& other, typename etl::enable_if<Size == Extent && etl::is_const<T>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
{
}
//*************************************************************************
/// Returns a reference to the first element.
//*************************************************************************
@ -455,7 +547,7 @@ namespace etl
{
pbegin = other.pbegin;
return *this;
}
}
//*************************************************************************
/// Returns a reference to the value at index 'i'.
@ -506,13 +598,13 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view over the first count elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> first(size_t count) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> first(size_t count) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return count <= size() ? etl::span<element_type, etl::dynamic_extent>(pbegin, pbegin + count) : throw(ETL_ERROR(span_out_of_range));
#else
ETL_ASSERT_CHECK_EXTRA(count <= size(), ETL_ERROR(span_out_of_range));
return etl::span<element_type, etl::dynamic_extent>(pbegin, pbegin + count);
#endif
}
@ -532,11 +624,11 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view over the last count elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> last(size_t count) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> last(size_t count) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return count <= size() ?
etl::span<element_type, etl::dynamic_extent>((pbegin + Extent) - count, (pbegin + Extent)) :
return count <= size() ?
etl::span<element_type, etl::dynamic_extent>((pbegin + Extent) - count, (pbegin + Extent)) :
throw(ETL_ERROR(span_out_of_range));
#else
ETL_ASSERT_CHECK_EXTRA(count <= size(), ETL_ERROR(span_out_of_range));
@ -589,7 +681,7 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view from 'offset' over the next 'count' elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> subspan(size_t offset, size_t count = etl::dynamic_extent) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> subspan(size_t offset, size_t count = etl::dynamic_extent) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return (offset <= size()) && (count != etl::dynamic_extent ? count <= (size() - offset) : true) ?
@ -636,7 +728,7 @@ namespace etl
/// Span - Dynamic Extent
//***************************************************************************
template <typename T>
class span<T, etl::dynamic_extent> : public span_tag
class span<T, etl::dynamic_extent> : public span_tag
{
public:
@ -668,10 +760,10 @@ namespace etl
}
//*************************************************************************
/// Construct from pointer + size
/// Construct from iterator + size
//*************************************************************************
template <typename TIterator, typename TSize>
ETL_CONSTEXPR span(const TIterator begin_, const TSize size_) ETL_NOEXCEPT
template <typename TIterator>
ETL_CONSTEXPR span(const TIterator begin_, size_t size_) ETL_NOEXCEPT
: pbegin(etl::to_address(begin_))
, pend(etl::to_address(begin_) + size_)
{
@ -680,8 +772,9 @@ namespace etl
//*************************************************************************
/// Construct from iterators
//*************************************************************************
template <typename TIterator>
ETL_CONSTEXPR span(const TIterator begin_, const TIterator end_) ETL_NOEXCEPT
template <typename TIteratorBegin, typename TIteratorEnd>
ETL_CONSTEXPR span(const TIteratorBegin begin_, const TIteratorEnd end_,
typename etl::enable_if<!etl::is_integral<TIteratorEnd>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(etl::to_address(begin_))
, pend(etl::to_address(begin_) + etl::distance(begin_, end_))
{
@ -702,11 +795,17 @@ namespace etl
/// Construct from a container or other type that supports
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer, typename = typename etl::enable_if<!etl::is_base_of<span_tag, etl::remove_reference_t<TContainer>>::value &&
!etl::is_pointer<etl::remove_reference_t<TContainer>>::value &&
!etl::is_array<etl::remove_reference_t<TContainer>>::value &&
etl::is_same<etl::remove_cv_t<T>, etl::remove_cv_t<typename etl::remove_reference_t<TContainer>::value_type>>::value, void>::type>
ETL_CONSTEXPR span(TContainer&& a) ETL_NOEXCEPT
template <typename TContainer>
ETL_CONSTEXPR span(TContainer&& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
etl::is_lvalue_reference<TContainer&&>::value &&
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_convertible<decltype(etl::declval<typename etl::remove_reference<TContainer>::type&>().data()), pointer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(a.data())
, pend(a.data() + a.size())
{
@ -717,10 +816,14 @@ namespace etl
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer>
ETL_CONSTEXPR span(TContainer& a, typename etl::enable_if<!etl::is_base_of<span_tag, typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
span(TContainer& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(a.data())
, pend(a.data() + a.size())
{
@ -731,16 +834,92 @@ namespace etl
/// data() and size() member functions.
//*************************************************************************
template <typename TContainer>
ETL_CONSTEXPR span(const TContainer& a, typename etl::enable_if<!etl::is_base_of<span_tag, typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
span(const TContainer& a, typename etl::enable_if<!etl::is_span<TContainer>::value &&
!etl::is_std_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_etl_array<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_pointer<typename etl::remove_reference<TContainer>::type>::value &&
!etl::is_array<TContainer>::value &&
has_size<TContainer>::value &&
has_data<TContainer>::value &&
etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename etl::remove_reference<TContainer>::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(a.data())
, pend(a.data() + a.size())
{
}
#endif
#if ETL_USING_STL && ETL_USING_CPP20
//*************************************************************************
/// Constructor from std span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(std::span<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, int>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
, pend(other.data() + other.size())
{
}
//*************************************************************************
/// Constructor from const std span.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const std::span<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, int>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data())
, pend(other.data() + other.size())
{
}
#endif
//*************************************************************************
/// Constructor from etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(etl::array<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data()),
pend(other.data() + Size)
{
}
//*************************************************************************
/// Constructor from const etl array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const etl::array<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data()),
pend(other.data() + Size)
{
}
#if ETL_USING_CPP11
template <typename U, size_t Size>
span(etl::array<U, Size>&&) = delete;
#endif
#if ETL_USING_STL && ETL_USING_CPP11
//*************************************************************************
/// Constructor from std array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(std::array<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data()),
pend(other.data() + Size)
{
}
//*************************************************************************
/// Constructor from const std array.
//*************************************************************************
template <typename U, size_t Size>
ETL_CONSTEXPR span(const std::array<U, Size>& other, typename etl::enable_if<etl::is_convertible<U(*)[], T(*)[]>::value, void>::type* = 0) ETL_NOEXCEPT
: pbegin(other.data()),
pend(other.data() + Size)
{
}
template <typename U, size_t Size>
span(std::array<U, Size>&&) = delete;
#endif
//*************************************************************************
/// Copy constructor
//*************************************************************************
@ -763,7 +942,7 @@ namespace etl
//*************************************************************************
/// Returns a reference to the first element.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR reference front() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR reference front() const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return size() > 0 ? *pbegin : throw(ETL_ERROR(span_out_of_range));
@ -777,7 +956,7 @@ namespace etl
//*************************************************************************
/// Returns a reference to the last element.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR reference back() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR reference back() const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return size() > 0 ? *(pend - 1) : throw(ETL_ERROR(span_out_of_range));
@ -889,7 +1068,7 @@ namespace etl
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT
{
return (pend - pbegin);
return static_cast<size_t>(pend - pbegin);
}
//*************************************************************************
@ -897,7 +1076,7 @@ namespace etl
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR size_t size_bytes() const ETL_NOEXCEPT
{
return sizeof(element_type) * (pend - pbegin);
return sizeof(element_type) * static_cast<size_t>(pend - pbegin);
}
//*************************************************************************
@ -956,7 +1135,7 @@ namespace etl
/// Obtains a span that is a view over the first COUNT elements of this span.
//*************************************************************************
template <size_t COUNT>
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, COUNT> first() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, COUNT> first() const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return COUNT <= size() ? etl::span<element_type, COUNT>(pbegin, pbegin + COUNT) : throw(ETL_ERROR(span_out_of_range));
@ -970,7 +1149,7 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view over the first count elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> first(size_t count) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> first(size_t count) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return count <= size() ? etl::span<element_type, etl::dynamic_extent>(pbegin, pbegin + count) : throw(ETL_ERROR(span_out_of_range));
@ -985,7 +1164,7 @@ namespace etl
/// Obtains a span that is a view over the last COUNT elements of this span.
//*************************************************************************
template <size_t COUNT>
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, COUNT> last() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, COUNT> last() const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return COUNT <= size() ? etl::span<element_type, COUNT>(pend - COUNT, pend) : throw(ETL_ERROR(span_out_of_range));
@ -999,7 +1178,7 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view over the last count elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> last(size_t count) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> last(size_t count) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return count <= size() ? etl::span<element_type, etl::dynamic_extent>(pend - count, pend) : throw(ETL_ERROR(span_out_of_range));
@ -1016,7 +1195,7 @@ namespace etl
//*************************************************************************
template <size_t OFFSET, size_t COUNT = etl::dynamic_extent>
ETL_NODISCARD ETL_CONSTEXPR
etl::span<element_type, COUNT != etl::dynamic_extent ? COUNT : etl::dynamic_extent> subspan() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
etl::span<element_type, COUNT != etl::dynamic_extent ? COUNT : etl::dynamic_extent> subspan() const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
return (OFFSET <= size()) && (COUNT != etl::dynamic_extent ? COUNT <= (size() - OFFSET) : true) ?
@ -1055,7 +1234,7 @@ namespace etl
//*************************************************************************
/// Obtains a span that is a view from 'offset' over the next 'count' elements of this span.
//*************************************************************************
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<element_type, etl::dynamic_extent> subspan(size_t offset, size_t count = etl::dynamic_extent) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<element_type, etl::dynamic_extent> subspan(size_t offset, size_t count = etl::dynamic_extent) const ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_EXTRA)
{
ETL_ASSERT_CHECK_EXTRA(offset <= size(), ETL_ERROR(span_out_of_range));
ETL_ASSERT_CHECK_EXTRA(count != etl::dynamic_extent ? count <= (size() - offset) : true, ETL_ERROR(span_out_of_range));
@ -1083,7 +1262,7 @@ namespace etl
ETL_ASSERT(etl::is_aligned<etl::alignment_of<TNew>::value>(pbegin), ETL_ERROR(span_alignment_exception));
return etl::span<TNew, etl::dynamic_extent>(reinterpret_cast<TNew*>(pbegin),
(pend - pbegin) * sizeof(element_type) / sizeof(TNew));
static_cast<size_t>(pend - pbegin) * sizeof(element_type) / sizeof(TNew));
}
//*************************************************************************
@ -1161,7 +1340,7 @@ namespace etl
/// Compare two spans for equality.
//*************************************************************************
template <typename T1, size_t N1, typename T2, size_t N2>
ETL_NODISCARD
ETL_NODISCARD
ETL_CONSTEXPR
typename etl::enable_if<etl::is_same<typename etl::remove_cv<T1>::type, typename etl::remove_cv<T2>::type>::value, bool>::type
operator ==(const etl::span<T1, N1>& lhs, const etl::span<T2, N2>& rhs) ETL_NOEXCEPT
@ -1255,7 +1434,7 @@ namespace etl
template<typename T>
span(etl::ivector<T>&)
-> span<T>;
template<typename T>
span(const etl::ivector<T>&)
-> span<const T>;
@ -1269,7 +1448,7 @@ namespace etl
span(const std::array<T, Size>&)
->span<const T, Size>;
#endif
#endif
#endif
//*************************************************************************
/// Hash function.
@ -1290,7 +1469,7 @@ namespace etl
/// Obtains a view to the byte representation of the elements of the span s.
//*************************************************************************
template <class T, size_t Size>
span<const byte, (Size == etl::dynamic_extent) ? (etl::dynamic_extent) : (Size * sizeof(T))>
span<const byte, (Size == etl::dynamic_extent) ? (etl::dynamic_extent) : (Size * sizeof(T))>
as_bytes(span<T, Size> s) ETL_NOEXCEPT
{
return span<const byte, (Size == etl::dynamic_extent) ? (etl::dynamic_extent) : (Size * sizeof(T))>(reinterpret_cast<const byte*>(s.data()), s.size_bytes());
@ -1300,7 +1479,7 @@ namespace etl
/// Obtains a view to the byte representation of the elements of the span s.
//*************************************************************************
template <class T, size_t Size>
span<byte, (Size == etl::dynamic_extent) ? (etl::dynamic_extent) : (Size * sizeof(T))>
span<byte, (Size == etl::dynamic_extent) ? (etl::dynamic_extent) : (Size * sizeof(T))>
as_writable_bytes(span<T, Size> s) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(!etl::is_const<T>::value, "span<T> must be of non-const type");

View File

@ -753,11 +753,11 @@ namespace etl
///\ingroup type_traits
/// Implemented by checking if type is convertible to an integer through static_cast
namespace private_type_traits
namespace private_type_traits
{
// Base case
template <typename T, typename = int>
struct is_convertible_to_int
struct is_convertible_to_int
: false_type
{
};
@ -766,7 +766,7 @@ namespace etl
// 2nd template argument of base case defaults to int to ensure that this partial specialization is always tried first
template <typename T>
struct is_convertible_to_int<T, decltype(static_cast<int>(declval<T>()))>
: true_type
: true_type
{
};
}
@ -776,7 +776,7 @@ namespace etl
: integral_constant<bool, private_type_traits::is_convertible_to_int<T>::value &&
!is_class<T>::value &&
!is_arithmetic<T>::value &&
!is_reference<T>::value>
!is_reference<T>::value>
{
};
@ -860,6 +860,42 @@ namespace etl
public:
static ETL_CONSTANT bool value = decltype(test<TFrom>(0))::value;
};
#else
namespace private_type_traits
{
typedef char yes;
struct no { char dummy[2]; };
template <typename TFrom, typename TTo>
struct is_convertible_impl
{
static yes test(TTo);
static no test(...);
static TFrom make();
static const bool value = (sizeof(test(make())) == sizeof(yes));
};
template <typename TTo>
struct is_convertible_impl<void, TTo>
{
static const bool value = false;
};
template <typename TFrom>
struct is_convertible_impl<TFrom, void>
{
static const bool value = false;
};
template <>
struct is_convertible_impl<void, void>
{
static const bool value = true;
};
}
template <typename TFrom, typename TTo>
struct is_convertible : etl::bool_constant<private_type_traits::is_convertible_impl<TFrom, TTo>::value> {};
#endif
#if ETL_USING_CPP17
@ -1408,6 +1444,42 @@ typedef integral_constant<bool, true> true_type;
public:
static ETL_CONSTANT bool value = decltype(test<TFrom>(0))::value;
};
#else
namespace private_type_traits
{
typedef char yes;
struct no { char dummy[2]; };
template <typename TFrom, typename TTo>
struct is_convertible_impl
{
static yes test(TTo);
static no test(...);
static TFrom make();
static const bool value = (sizeof(test(make())) == sizeof(yes));
};
template <typename TTo>
struct is_convertible_impl<void, TTo>
{
static const bool value = false;
};
template <typename TFrom>
struct is_convertible_impl<TFrom, void>
{
static const bool value = false;
};
template <>
struct is_convertible_impl<void, void>
{
static const bool value = true;
};
}
template <typename TFrom, typename TTo>
struct is_convertible : etl::bool_constant<private_type_traits::is_convertible_impl<TFrom, TTo>::value> {};
#endif
#if ETL_USING_CPP17
@ -1542,13 +1614,13 @@ typedef integral_constant<bool, true> true_type;
/// Template to determine if a type is one of a specified list.
///\ingroup types
template <typename T,
typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
struct is_one_of
{
static const bool value =
static const bool value =
etl::is_same<T, T1>::value ||
etl::is_same<T, T2>::value ||
etl::is_same<T, T3>::value ||
@ -1640,7 +1712,7 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
/// Get the Nth base of a recursively inherited type.
/// Requires that the class has defined 'base_type'.
//***************************************************************************
//***************************************************************************
// Recursive definition of the type.
template <size_t Index, typename TType>
struct nth_base
@ -2185,7 +2257,7 @@ typedef integral_constant<bool, true> true_type;
#if ETL_USING_CPP11
//***************************************************************************
/// is_constructible
namespace private_type_traits
namespace private_type_traits
{
template <class, class T, class... TArgs>
struct is_constructible_ : etl::false_type {};
@ -2364,7 +2436,7 @@ typedef integral_constant<bool, true> true_type;
};
template <typename T1, typename T2, typename = void>
struct common_type_2_impl
struct common_type_2_impl
: decay_conditional_result<const T1&, const T2&>
{
};
@ -2709,7 +2781,7 @@ typedef integral_constant<bool, true> true_type;
struct is_member_pointer_helper<T TObject::*> : etl::true_type {};
}
template<typename T>
template<typename T>
struct is_member_pointer : private_type_traits::is_member_pointer_helper<typename etl::remove_cv<T>::type> {};
#if ETL_USING_CPP17
@ -2802,10 +2874,10 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
namespace private_type_traits
{
template<typename>
template<typename>
struct is_member_object_pointer_helper : public etl::false_type {};
template<typename T, typename TObject>
template<typename T, typename TObject>
struct is_member_object_pointer_helper<T TObject::*> : public etl::negation<etl::is_function<T>> {};
}
@ -3027,6 +3099,60 @@ typedef integral_constant<bool, true> true_type;
};
#endif
#if ETL_USING_CPP11
template <typename, typename = void>
struct has_size : etl::false_type {};
template <typename T>
struct has_size<T, void_t<decltype(etl::declval<T>().size())> >
: etl::true_type {};
#else
template <typename T>
struct has_size
{
private:
typedef char yes;
struct no { char dummy[2]; };
template <typename U>
static yes test_size(char (*)[sizeof(&U::size)]);
template <typename U>
static no test_size(...);
public:
static const bool value = (sizeof(test_size<T>(0)) == sizeof(yes));
};
#endif
#if ETL_USING_CPP11
template <typename, typename = void>
struct has_data : etl::false_type {};
template <typename T>
struct has_data<T, void_t<decltype(etl::declval<T>().data())> >
: etl::true_type {};
#else
template <typename T>
struct has_data
{
private:
typedef char yes;
struct no { char dummy[2]; };
template <typename U>
static yes test_data(char (*)[sizeof(&U::data)]);
template <typename U>
static no test_data(...);
public:
static const bool value = (sizeof(test_data<T>(0)) == sizeof(yes));
};
#endif
}
// Helper macros

View File

@ -345,8 +345,8 @@ namespace etl
{
memcpy(store, &value, Size_);
#if ETL_HAS_CONSTEXPR_ENDIANESS
if ETL_IF_CONSTEXPR(Endian_ == etl::endianness::value())
#if ETL_HAS_CONSTEXPR_ENDIANNESS
if ETL_IF_CONSTEXPR(Endian_ != etl::endianness::value())
#else
if (Endian_ != etl::endianness::value())
#endif
@ -361,8 +361,8 @@ namespace etl
{
memcpy(&value, store, Size_);
#if ETL_HAS_CONSTEXPR_ENDIANESS
if ETL_IF_CONSTEXPR(Endian == etl::endianness::value())
#if ETL_HAS_CONSTEXPR_ENDIANNESS
if ETL_IF_CONSTEXPR(Endian_ != etl::endianness::value())
#else
if (Endian_ != etl::endianness::value())
#endif
@ -402,8 +402,8 @@ namespace etl
{
memcpy(store, &value, Size_);
#if ETL_HAS_CONSTEXPR_ENDIANESS
if ETL_IF_CONSTEXPR(Endian_ == etl::endianness::value())
#if ETL_HAS_CONSTEXPR_ENDIANNESS
if ETL_IF_CONSTEXPR(Endian_ != etl::endianness::value())
#else
if (Endian_ != etl::endianness::value())
#endif
@ -418,14 +418,14 @@ namespace etl
{
memcpy(&value, store, Size_);
#if ETL_HAS_CONSTEXPR_ENDIANESS
if ETL_IF_CONSTEXPR(Endian == etl::endianness::value())
#if ETL_HAS_CONSTEXPR_ENDIANNESS
if ETL_IF_CONSTEXPR(Endian_ != etl::endianness::value())
#else
if (Endian_ != etl::endianness::value())
if (Endian_ != etl::endianness::value())
#endif
{
etl::reverse(reinterpret_cast<pointer>(&value), reinterpret_cast<pointer>(&value) + Size_);
}
{
etl::reverse(reinterpret_cast<pointer>(&value), reinterpret_cast<pointer>(&value) + Size_);
}
}
//*******************************

48
scripts/clang-format-wrapper Executable file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env python3
from shutil import which
import re
import subprocess
import sys
def get_correct_clang_format():
path = which("clang-format-18")
if path:
return path
if which("clang-format") is None:
raise Exception("no clang-format found")
result = subprocess.run(
["clang-format", "--version"], capture_output=True, text=True, check=True
)
match = re.search(r"\b(\d+\.\d+\.\d+)\b", result.stdout)
if not match:
raise Exception(
f"could not determine clang-format version from: {result.stdout.strip()}"
)
version = match.group(1)
if version.split(".")[0] != "18":
raise Exception(f"clang-format version 18 required. Found {version}")
return "clang-format"
def main():
clang_format = get_correct_clang_format()
try:
completed = subprocess.run([clang_format] + sys.argv[1:])
except FileNotFoundError:
print(f"error: clang-format not found at '{clang_format}'", file=sys.stderr)
sys.exit(1)
except PermissionError:
print(f"error: permission denied when running '{clang_format}'", file=sys.stderr)
sys.exit(1)
except OSError as exc:
print(f"error: failed to run '{clang_format}': {exc}", file=sys.stderr)
sys.exit(1)
sys.exit(completed.returncode)
if __name__ == "__main__":
main()

View File

@ -129,6 +129,29 @@ def update_library_properties(filename):
f.write(line)
f.write('\n')
#------------------------------------------------------------------------------
def update_zephyr_module():
print('')
print('Updating zephyr/module.yml')
zephyr_module = os.path.join(etl_dir, 'zephyr', 'module.yml')
with open(zephyr_module, 'r') as f:
text = f.read().splitlines()
search_purl = 'pkg:github/ETLCPP/etl@'
for i in range(len(text)):
if search_purl in text[i]:
idx = text[i].find(search_purl)
text[i] = text[i][:idx] + search_purl + full_version
print(text[i])
with open(zephyr_module, 'w') as f:
for line in text:
f.write(line)
f.write('\n')
#------------------------------------------------------------------------------
def update_versions():
print('')
@ -149,6 +172,8 @@ def update_versions():
update_library_properties(os.path.join(etl_dir, 'library.properties'))
update_zephyr_module()
#------------------------------------------------------------------------------
if __name__ == "__main__":
update_versions()

View File

@ -86,6 +86,7 @@ add_executable(etl_tests
test_closure.cpp
test_closure_constexpr.cpp
test_compare.cpp
test_concepts.cpp
test_constant.cpp
test_const_map.cpp
test_const_map_constexpr.cpp
@ -172,6 +173,7 @@ add_executable(etl_tests
test_endian.cpp
test_enum_type.cpp
test_error_handler.cpp
test_etl_assert.cpp
test_etl_traits.cpp
test_exception.cpp
test_expected.cpp
@ -183,6 +185,7 @@ add_executable(etl_tests
test_flat_multiset.cpp
test_flat_set.cpp
test_fnv_1.cpp
test_format.cpp
test_format_spec.cpp
test_forward_list.cpp
test_forward_list_shared_pool.cpp
@ -194,10 +197,12 @@ add_executable(etl_tests
test_hash.cpp
test_hfsm.cpp
test_hfsm_recurse_to_inner_state_on_start.cpp
test_hfsm_transition_on_enter.cpp
test_histogram.cpp
test_index_of_type.cpp
test_indirect_vector.cpp
test_indirect_vector_external_buffer.cpp
test_inplace_function.cpp
test_instance_count.cpp
test_integral_limits.cpp
test_intrusive_forward_list.cpp
@ -206,7 +211,9 @@ add_executable(etl_tests
test_intrusive_queue.cpp
test_intrusive_stack.cpp
test_invert.cpp
test_invoke.cpp
test_io_port.cpp
test_is_invocable.cpp
test_iterator.cpp
test_jenkins.cpp
test_largest.cpp
@ -259,6 +266,7 @@ add_executable(etl_tests
test_pool.cpp
test_pool_external_buffer.cpp
test_priority_queue.cpp
test_print.cpp
test_pseudo_moving_average.cpp
test_quantize.cpp
test_queue.cpp
@ -286,6 +294,7 @@ add_executable(etl_tests
test_scaled_rounding.cpp
test_set.cpp
test_shared_message.cpp
test_signal.cpp
test_singleton.cpp
test_singleton_base.cpp
test_smallest.cpp

View File

@ -113,6 +113,12 @@ struct non_random_iterator : public etl::iterator<ETL_OR_STD::bidirectional_iter
T* ptr;
};
template <typename T>
bool operator ==(const non_random_iterator<T>& lhs, const non_random_iterator<T>& rhs)
{
return lhs.ptr == rhs.ptr;
}
template <typename T>
bool operator !=(const non_random_iterator<T>& lhs, const non_random_iterator<T>& rhs)
{

0
test/run-syntax-checks.sh Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@ SOFTWARE.
#include "etl/container.h"
#include <list>
#include <vector>
#if ETL_NOT_USING_STL
@ -145,6 +146,34 @@ namespace
size_t compiletime_size = sizeof(etl::array_size(data));
CHECK_EQUAL(SIZE, compiletime_size);
}
//*************************************************************************
TEST(test_stl_style_container_data)
{
const size_t SIZE = 10UL;
std::vector<int> data(SIZE);
const std::vector<int> cdata(SIZE);
int* pdata = ETL_OR_STD17::data(data);
const int* pcdata = ETL_OR_STD17::data(cdata);
CHECK(data.data() == pdata);
CHECK(cdata.data() == pcdata);
}
//*************************************************************************
TEST(test_c_array_data)
{
const size_t SIZE = 10UL;
int data[SIZE];
const int cdata[SIZE] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* pdata = ETL_OR_STD17::data(data);
const int* pcdata = ETL_OR_STD17::data(cdata);
CHECK(&data[0] == pdata);
CHECK(&cdata[0] == pcdata);
}
}
}

View File

@ -34,6 +34,8 @@ SOFTWARE.
#include "etl/error_handler.h"
#include "etl/exception.h"
#include <cstring>
namespace
{
class TestException1 : public etl::exception

View File

@ -197,6 +197,7 @@ namespace
CHECK_EQUAL("-6759414", test_format(s, "{}", static_cast<int32_t>(-6759414)));
}
#if ETL_USING_FORMAT_FLOATING_POINT
//*************************************************************************
TEST(test_format_float)
{
@ -266,6 +267,7 @@ namespace
CHECK_EQUAL("0x1.92a738p-5", test_format(s, "{:a}", 0.0000015f));
CHECK_EQUAL("0x1.6345785d8ap+e", test_format(s, "{:a}", 100000000000000000.l));
}
#endif
//*************************************************************************
TEST(test_format_char_array)

View File

@ -515,7 +515,7 @@ namespace
//*************************************************************************
TEST(test_fsm_emergency_stop)
{
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
motorControl.reset();
motorControl.ClearStatistics();
@ -758,7 +758,7 @@ namespace
CHECK_EQUAL(StateId::Running, int(motorControl.get_state().get_state_id()));
auto id2 = motorControl.transition_to(StateId::Idle);
// Now in Locked state.
CHECK_EQUAL(StateId::Locked, int(id2));
CHECK_EQUAL(StateId::Locked, int(motorControl.get_state_id()));

View File

@ -85,6 +85,24 @@ namespace
mutable std::string result;
};
#if ETL_USING_CPP11
// Lightweight type used to verify transparent heterogeneous comparison.
// Only operator<(int, Wrapper) is defined; operator<(Wrapper, int) is
// intentionally absent. less_equal<void> is implemented as
// !(rhs < lhs), so less_equal<void>{}(Wrapper, int) needs
// operator<(int, Wrapper) which IS provided.
struct Wrapper
{
int value;
constexpr explicit Wrapper(int v) : value(v) {}
};
// int < Wrapper -- defined
constexpr bool operator<(int lhs, const Wrapper& rhs) { return lhs < rhs.value; }
// Wrapper < int -- intentionally NOT defined
#endif
SUITE(test_functional)
{
//*************************************************************************
@ -101,6 +119,32 @@ namespace
CHECK((compare<etl::less_equal<int>>(1, 2)));
CHECK(!(compare<etl::less_equal<int>>(2, 1)));
CHECK((compare<etl::less_equal<int>>(1, 1)));
#if ETL_USING_CPP11
CHECK((compare<etl::less_equal<void>>(1, 2)));
CHECK(!(compare<etl::less_equal<void>>(2, 1)));
CHECK((compare<etl::less_equal<void>>(1, 1)));
#endif
}
//*************************************************************************
TEST(test_less_equal_void_heterogeneous)
{
#if ETL_USING_CPP11
// less_equal<void>{}(lhs, rhs) is !(rhs < lhs).
// With only operator<(int, Wrapper) defined, we can call
// less_equal<void>{}(Wrapper, int) because the implementation
// evaluates !(int < Wrapper).
// Wrapper(1) <= 2 → !(2 < Wrapper(1)) → !(2 < 1) → !false → true
CHECK((etl::less_equal<void>{}(Wrapper(1), 2)));
// Wrapper(2) <= 1 → !(1 < Wrapper(2)) → !(1 < 2) → !true → false
CHECK(!(etl::less_equal<void>{}(Wrapper(2), 1)));
// Wrapper(3) <= 3 → !(3 < Wrapper(3)) → !(3 < 3) → !false → true
CHECK((etl::less_equal<void>{}(Wrapper(3), 3)));
#endif
}
//*************************************************************************
@ -117,6 +161,32 @@ namespace
CHECK(!(compare<etl::greater_equal<int>>(1, 2)));
CHECK((compare<etl::greater_equal<int>>(2, 1)));
CHECK((compare<etl::greater_equal<int>>(1, 1)));
#if ETL_USING_CPP11
CHECK(!(compare<etl::greater_equal<void>>(1, 2)));
CHECK((compare<etl::greater_equal<void>>(2, 1)));
CHECK((compare<etl::greater_equal<void>>(1, 1)));
#endif
}
//*************************************************************************
TEST(test_greater_equal_void_heterogeneous)
{
#if ETL_USING_CPP11
// greater_equal<void>{}(lhs, rhs) is !(lhs < rhs).
// With only operator<(int, Wrapper) defined, we can call
// greater_equal<void>{}(int, Wrapper) because the implementation
// evaluates !(int < Wrapper).
// 2 >= Wrapper(1) → !(2 < Wrapper(1)) → !(2 < 1) → !false → true
CHECK((etl::greater_equal<void>{}(2, Wrapper(1))));
// 1 >= Wrapper(2) → !(1 < Wrapper(2)) → !(1 < 2) → !true → false
CHECK(!(etl::greater_equal<void>{}(1, Wrapper(2))));
// 3 >= Wrapper(3) → !(3 < Wrapper(3)) → !(3 < 3) → !false → true
CHECK((etl::greater_equal<void>{}(3, Wrapper(3))));
#endif
}
//*************************************************************************

View File

@ -574,12 +574,11 @@ namespace
constexpr uint16_t absolute1 = etl::absolute(int16_t(0));
constexpr uint16_t absolute2 = etl::absolute(int16_t(32767));
constexpr uint16_t absolute3 = etl::absolute(int16_t(-32767));
constexpr uint16_t absolute4 = etl::absolute(int16_t(-32768));
//constexpr uint16_t absolute4 = etl::absolute(int16_t(-32768)); // Compile error
CHECK_EQUAL(uint16_t(0), absolute1);
CHECK_EQUAL(uint16_t(32767), absolute2);
CHECK_EQUAL(uint16_t(32767), absolute3);
CHECK_EQUAL(uint16_t(32768), absolute4);
constexpr uint16_t absolute5 = etl::absolute(uint16_t(0));
constexpr uint16_t absolute6 = etl::absolute(uint16_t(65535));

View File

@ -1118,5 +1118,46 @@ namespace
CHECK_EQUAL(42, *opt);
}
//*************************************************************************
// GitHub issue #146: etl::optional doesn't compile with deleted copy constructor
//*************************************************************************
#if ETL_USING_CPP11
struct Issue146_NonCopyable
{
Issue146_NonCopyable(int some) : _some(some) {}
Issue146_NonCopyable(const Issue146_NonCopyable&) = delete;
Issue146_NonCopyable(Issue146_NonCopyable&&) = delete;
Issue146_NonCopyable& operator=(const Issue146_NonCopyable&) = delete;
int _some;
};
struct Issue146_Container
{
Issue146_Container(int a_val) : a(a_val) {}
Issue146_Container() : a(etl::nullopt) {}
etl::optional<Issue146_NonCopyable> a;
};
TEST(test_optional_issue_146_deleted_copy_ctor)
{
// etl::optional<T> should compile when T has deleted copy/move constructors,
// as long as T is constructible from the given arguments.
Issue146_Container with_value(42);
Issue146_Container without_value;
CHECK_TRUE(with_value.a.has_value());
CHECK_EQUAL(42, with_value.a->_some);
CHECK_FALSE(without_value.a.has_value());
// in_place construction should also work
etl::optional<Issue146_NonCopyable> opt(etl::in_place_t{}, 99);
CHECK_TRUE(opt.has_value());
CHECK_EQUAL(99, opt->_some);
}
#endif
}
}

View File

@ -1627,5 +1627,23 @@ namespace
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
TEST(test_not_constructible_from_rvalue_container)
{
#if ETL_USING_CPP17
CHECK(!(etl::is_constructible_v<View, StlVData&&>));
CHECK(!(etl::is_constructible_v<CView, StlVData&&>));
CHECK(!(etl::is_constructible_v<View, EtlData&&>));
CHECK(!(etl::is_constructible_v<View, StlData&&>));
#else
CHECK(!(etl::is_constructible<View, StlVData&&>::value));
CHECK(!(etl::is_constructible<CView, StlVData&&>::value));
CHECK(!(etl::is_constructible<View, EtlData&&>::value));
CHECK(!(etl::is_constructible<View, StlData&&>::value));
#endif
}
}
}

View File

@ -496,13 +496,19 @@ namespace
//*************************************************************************
TEST(test_empty)
{
View view1(etldata.begin(), etldata.begin());
CHECK(!view1.empty());
EView view2(etldata.begin(), etldata.begin());
CHECK(view2.empty());
}
//*************************************************************************
TEST(test_construction_from_mismatched_size)
{
CHECK_THROW((View(etldata.begin(), etldata.begin())), etl::span_size_mismatch);
CHECK_THROW((View(etldata.begin(), 1)), etl::span_size_mismatch);
CHECK_THROW((View(etldata.begin(), etldata.size() - 1)), etl::span_size_mismatch);
CHECK_THROW((View(etldata.begin(), etldata.size() + 1)), etl::span_size_mismatch);
}
//*************************************************************************
TEST(test_size)
{
@ -664,7 +670,7 @@ namespace
CHECK_EQUAL(sub1.size(), cspan1.extent);
CHECK_EQUAL(sub1.size(), cspan1.size());
auto span2 = view.subspan<2>();
auto span2 = view.subspan<2>();
isEqual = std::equal(sub2.begin(), sub2.end(), span2.begin());
CHECK(isEqual);
CHECK_EQUAL(span2.size(), span2.extent);
@ -804,7 +810,7 @@ namespace
//*************************************************************************
#include "etl/private/diagnostic_unused_function_push.h"
struct C_issue_482 {};
void f_issue_482(etl::span<char>)
@ -1220,7 +1226,7 @@ namespace
etl::span<int, 5> span2(span1);
//etl::span<int, 10> span3(span1); // This line should fail to compile.
}
//*************************************************************************
TEST(test_reinterpret_as)
{
@ -1306,5 +1312,23 @@ namespace
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
TEST(test_not_constructible_from_rvalue_container)
{
#if ETL_USING_CPP17
CHECK(!(etl::is_constructible_v<View, StlVData&&>));
CHECK(!(etl::is_constructible_v<CView, StlVData&&>));
CHECK(!(etl::is_constructible_v<View, EtlData&&>));
CHECK(!(etl::is_constructible_v<View, StlData&&>));
#else
CHECK(!(etl::is_constructible<View, StlVData&&>::value));
CHECK(!(etl::is_constructible<CView, StlVData&&>::value));
CHECK(!(etl::is_constructible<View, EtlData&&>::value));
CHECK(!(etl::is_constructible<View, StlData&&>::value));
#endif
}
}
}

View File

@ -1030,6 +1030,98 @@ namespace
CHECK_EQUAL(0x12, bev0);
CHECK_EQUAL(0x34, bev1);
}
#if ETL_HAS_CONSTEXPR_ENDIANNESS
//*************************************************************************
TEST(test_constexpr_endianness_integral_round_trip)
{
// Store a known value in LE, BE, and host-order unaligned types.
const uint32_t value = 0x12345678U;
etl::le_uint32_t le_v(value);
etl::be_uint32_t be_v(value);
etl::host_uint32_t host_v(value);
// All must read back the original value.
CHECK_EQUAL(value, uint32_t(le_v));
CHECK_EQUAL(value, uint32_t(be_v));
CHECK_EQUAL(value, uint32_t(host_v));
// Verify the storage byte order is correct.
// LE stores LSB first: 0x78, 0x56, 0x34, 0x12
CHECK_EQUAL(0x78, int(le_v[0]));
CHECK_EQUAL(0x56, int(le_v[1]));
CHECK_EQUAL(0x34, int(le_v[2]));
CHECK_EQUAL(0x12, int(le_v[3]));
// BE stores MSB first: 0x12, 0x34, 0x56, 0x78
CHECK_EQUAL(0x12, int(be_v[0]));
CHECK_EQUAL(0x34, int(be_v[1]));
CHECK_EQUAL(0x56, int(be_v[2]));
CHECK_EQUAL(0x78, int(be_v[3]));
// Host-order must match one of the above depending on the platform.
if (etl::endianness::value() == etl::endian::little)
{
CHECK_EQUAL(0x78, int(host_v[0]));
CHECK_EQUAL(0x56, int(host_v[1]));
CHECK_EQUAL(0x34, int(host_v[2]));
CHECK_EQUAL(0x12, int(host_v[3]));
}
else
{
CHECK_EQUAL(0x12, int(host_v[0]));
CHECK_EQUAL(0x34, int(host_v[1]));
CHECK_EQUAL(0x56, int(host_v[2]));
CHECK_EQUAL(0x78, int(host_v[3]));
}
}
//*************************************************************************
TEST(test_constexpr_endianness_float_round_trip)
{
// Store a known float value in LE, BE, and host-order unaligned types.
const float value = 3.1415927f;
etl::le_float_t le_v(value);
etl::be_float_t be_v(value);
etl::host_float_t host_v(value);
// All must read back the original value.
CHECK_CLOSE(value, float(le_v), 0.0001f);
CHECK_CLOSE(value, float(be_v), 0.0001f);
CHECK_CLOSE(value, float(host_v), 0.0001f);
// LE and BE storage bytes must be the reverse of each other.
CHECK_EQUAL(int(le_v[0]), int(be_v[3]));
CHECK_EQUAL(int(le_v[1]), int(be_v[2]));
CHECK_EQUAL(int(le_v[2]), int(be_v[1]));
CHECK_EQUAL(int(le_v[3]), int(be_v[0]));
}
//*************************************************************************
TEST(test_constexpr_endianness_cross_endian_copy)
{
// Verify that converting between LE <-> BE via host works correctly.
const uint16_t value = 0xABCDU;
etl::le_uint16_t le_v(value);
etl::be_uint16_t be_v(value);
etl::host_uint16_t host_from_le(le_v);
etl::host_uint16_t host_from_be(be_v);
CHECK_EQUAL(value, uint16_t(host_from_le));
CHECK_EQUAL(value, uint16_t(host_from_be));
// Round-trip: host -> le -> read back
etl::le_uint16_t le_from_host(host_from_le);
CHECK_EQUAL(value, uint16_t(le_from_host));
// Round-trip: host -> be -> read back
etl::be_uint16_t be_from_host(host_from_be);
CHECK_EQUAL(value, uint16_t(be_from_host));
}
#endif
}
}

View File

@ -3552,6 +3552,7 @@
<ClInclude Include="..\..\include\etl\monostate.h" />
<ClInclude Include="..\..\include\etl\not_null.h" />
<ClInclude Include="..\..\include\etl\poly_span.h" />
<ClInclude Include="..\..\include\etl\print.h" />
<ClInclude Include="..\..\include\etl\private\bitset_legacy.h" />
<ClInclude Include="..\..\include\etl\private\bitset_new.h" />
<ClInclude Include="..\..\include\etl\private\chrono\day.h" />
@ -10362,6 +10363,7 @@
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
<ClCompile Include="..\test_poly_span_dynamic_extent.cpp" />
<ClCompile Include="..\test_poly_span_fixed_extent.cpp" />
<ClCompile Include="..\test_print.cpp" />
<ClCompile Include="..\test_pseudo_moving_average.cpp" />
<ClCompile Include="..\test_delegate.cpp" />
<ClCompile Include="..\test_delegate_cpp03.cpp" />

View File

@ -2,3 +2,6 @@ name: etl
build:
cmake: zephyr
kconfig: zephyr/Kconfig
security:
external-references:
- pkg:github/ETLCPP/etl@20.46.2