Merge branch 'development' into fix-variant-review

This commit is contained in:
John Wellbelove 2026-03-27 08:46:29 +00:00 committed by GitHub
commit adcb7b341f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 37982 additions and 1082 deletions

View File

@ -0,0 +1,40 @@
# s390x Big-Endian Test Environment for ETL
# Uses QEMU user-mode emulation to run s390x binaries on x64 host
FROM debian:trixie
# Avoid prompts from apt
ENV DEBIAN_FRONTEND=noninteractive
# Install QEMU user-mode emulation and s390x cross-compilation tools
RUN dpkg --add-architecture s390x && \
apt-get update && apt-get install -y --no-install-recommends\
qemu-user-static \
qemu-user \
binfmt-support \
gcc-s390x-linux-gnu \
g++-s390x-linux-gnu \
cmake \
make \
ninja-build \
git \
wget \
file \
libc6:s390x \
libstdc++6:s390x \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /workspaces/etl
# Verify QEMU and cross-compilation setup
RUN echo "=== Host Architecture ===" && \
uname -m && \
echo "" && \
echo "=== s390x Cross Compiler ===" && \
s390x-linux-gnu-gcc --version && \
echo "" && \
echo "=== QEMU s390x ===" && \
qemu-s390x-static --version | head -n1
# Default command
CMD ["/bin/bash"]

View File

@ -0,0 +1,29 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
{
"name": "s390x Big Endian (Debian)",
"build": {
"dockerfile": "./Dockerfile",
"context": "."
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"ms-vscode.cmake-tools"
],
"settings": {
"cmake.sourceDirectory": "${workspaceFolder}/test",
"cmake.configureArgs": [
"-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/s390x/toolchain-s390x.cmake",
"-DBUILD_TESTS=ON",
"-DNO_STL=OFF",
"-DETL_CXX_STANDARD=17"
],
"cmake.buildDirectory": "${workspaceFolder}/build-s390x",
"cmake.generator": "Ninja"
}
}
},
"remoteUser": "root"
}

View File

@ -0,0 +1,21 @@
# CMake toolchain file for s390x cross-compilation
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR s390x)
# Specify the cross compiler
set(CMAKE_C_COMPILER s390x-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER s390x-linux-gnu-g++)
set(CMAKE_AR s390x-linux-gnu-ar)
set(CMAKE_RANLIB s390x-linux-gnu-ranlib)
set(CMAKE_STRIP s390x-linux-gnu-strip)
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# Set QEMU for running tests
set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-s390x-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries")

72
.github/workflows/coverage.yml vendored Normal file
View File

@ -0,0 +1,72 @@
name: coverage
on:
push:
branches: [ master, pull-request/* ]
pull_request:
branches: [ master, pull-request/* ]
types: [opened, synchronize, reopened]
# Allow only one concurrent deployment to GitHub Pages
concurrency:
group: coverage-${{ github.ref }}
cancel-in-progress: true
# Grant GITHUB_TOKEN the minimum permissions needed at the workflow level
permissions:
contents: read
jobs:
coverage:
name: Generate Coverage Report
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y lcov llvm gcc g++ clang cmake
- name: Build, test, and collect coverage
run: |
cd test
./run-coverage.sh
- name: Upload coverage report artifact
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: test/build-coverage/coverage/
retention-days: 30
- name: Upload Pages artifact
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/upload-pages-artifact@v3
with:
path: test/build-coverage/coverage/
deploy-pages:
name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
needs: coverage
runs-on: ubuntu-22.04
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
# GitHub Repository settings
# -> Settings -> Pages
# -> Source: gh actions

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)

259
docs/manchester.md Normal file
View File

@ -0,0 +1,259 @@
---
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
- Validation of encoded data
- Chunked span I/O uses little-endian byte order for multi-byte chunks, independent of host platform endianness
## 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)

328
docs/ranges.md Normal file
View File

@ -0,0 +1,328 @@
# ETL C++17 Ranges Implementation
## Overview
The Embedded Template Library provides a C++17-compatible implementation of ranges, inspired by the C++20 ranges library. This implementation enables range-based algorithms and views for embedded and resource-constrained environments where full C++20 support may not be available.
## Features
- **Ranges**: Provides range types and iterator wrappers for composing operations over sequences.
- **Views**: Includes lightweight, composable views such as `filter_view`, `transform_view`, and `subrange`.
- **Algorithms**: Supports range-based algorithms compatible with ETL containers and standard containers.
- **Compatibility**: Designed for C++17, with minimal dependencies and no reliance on C++20 features.
## Getting Started
Include the main header in your project:
```cpp
#include <etl/ranges.h>
```
### Example Usage
#### Using Ranges
```cpp
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {6, 1, 3, 3, 2};
etl::ranges::sort(data);
etl::ranges::for_each(data, [](const int& i){etl::print(" {}", i);});
```
Output:
```text
1 2 3 3 6
```
#### Using Views
```cpp
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5};
auto even = [](int v) { return v % 2 == 0; };
auto filtered = etl::ranges::filter_view(data, even);
etl::ranges::for_each(filtered, [](const int& i){etl::print(" {}", i);});
```
Output:
```text
2 4
```
#### Transforming Elements
```cpp
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5};
auto squared = etl::ranges::transform_view(data, [](int v) { return v * v; });
etl::ranges::for_each(squared, [](const int& i){etl::print(" {}", i);});
```
Output:
```text
1 4 9 16 25
```
#### Composition
Views can be composed using the pipe (`|`) operator, allowing you to chain multiple transformations in a readable, left-to-right style:
```cpp
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
namespace views = etl::ranges::views;
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = data
| views::filter([](const int& v) { return v % 2 == 0; })
| views::transform([](const int& v) { return v * v; });
etl::ranges::for_each(result, [](const int& i){ etl::print(" {}", i); });
```
Output:
```text
4 16 36 64 100
```
This first filters the even numbers and then squares them. Each `|` passes the result of the previous stage as input to the next view adaptor.
## Supported Views
All views are in the `etl::ranges` namespace. Corresponding range adaptor objects are available in `etl::ranges::views`.
### Range Factories
| View | `views::` adaptor | Description |
|---|---|---|
| `empty_view<T>` | `views::empty<T>` | A view with no elements. |
| `single_view` | `views::single` | A view containing exactly one element. |
| `iota_view` | `views::iota` | A view of sequentially increasing values. |
| `repeat_view` | `views::repeat` | A view that repeats a value a given number of times. |
### Range Adaptors
| View | `views::` adaptor | Description |
|---|---|---|
| `ref_view` | `views::ref` | A non-owning view that wraps a reference to a range. |
| `owning_view` | `views::owning` | A view that takes ownership of a range via move. |
| — | `views::all` | Returns the range itself (if already a view), a `ref_view`, or an `owning_view`. |
| `filter_view` | `views::filter` | Filters elements based on a predicate. |
| `transform_view` | `views::transform` | Applies a transformation to each element. |
| `as_rvalue_view` | `views::as_rvalue` | Casts each element to an rvalue reference. |
| `as_const_view` | `views::as_const` | Provides a const view of the elements. |
| `cache_latest_view` | `views::cache_latest` | Caches the most recently accessed element (avoids recomputation). |
| `reverse_view` | `views::reverse` | Reverses the order of elements. |
| `drop_view` | `views::drop` | Skips the first *n* elements. |
| `drop_while_view` | `views::drop_while` | Skips leading elements while a predicate is true. |
| `take_view` | `views::take` | Takes the first *n* elements. |
| `take_while_view` | `views::take_while` | Takes leading elements while a predicate is true. |
| `join_view` | `views::join` | Flattens a range of ranges into a single range. |
| `join_with_view` | `views::join_with` | Flattens a range of ranges, inserting a delimiter between each. |
| `split_view` | `views::split` | Splits a range into subranges around a delimiter pattern. |
| `lazy_split_view` | `views::lazy_split` | Lazily splits a range by a pattern (inner ranges discovered on iteration). |
| — | `views::counted` | Creates a view of *n* elements starting from an iterator. |
| `concat_view` | `views::concat` | Concatenates multiple ranges into a single view. |
| `zip_view` | `views::zip` | Zips multiple ranges into a view of tuples (length of shortest range). |
| `zip_transform_view` | `views::zip_transform` | Zips multiple ranges and applies a function to each tuple of elements. |
| `common_view` | `views::common` | Adapts a view so that its iterator and sentinel types are the same. |
| `enumerate_view` | `views::enumerate` | Pairs each element with its index, producing tuples of (index, value). |
| `elements_view` | `views::elements` | Extracts the *N*-th element from each tuple-like value. |
| `keys_view` | `views::keys` | Alias for `elements_view` with *N*=0 (extracts first element of pairs/tuples). |
| `values_view` | `views::values` | Alias for `elements_view` with *N*=1 (extracts second element of pairs/tuples). |
| `adjacent_view` | `views::adjacent` | Produces a view of tuples of *N* adjacent elements (sliding window of tuples). |
| — | `views::pairwise` | Alias for `views::adjacent<2>`. |
| `adjacent_transform_view` | `views::adjacent_transform` | Applies a function to each group of *N* adjacent elements. |
| — | `views::pairwise_transform` | Alias for `views::adjacent_transform<2>`. |
| `chunk_view` | `views::chunk` | Splits a range into non-overlapping chunks of a given size. |
| `slide_view` | `views::slide` | Produces overlapping subranges (sliding windows) of a given size. |
| `chunk_by_view` | `views::chunk_by` | Splits a range into subranges between adjacent elements where a predicate is false. |
| `stride_view` | `views::stride` | Yields every *N*-th element from the underlying range. |
| `cartesian_product_view` | `views::cartesian_product` | Produces the Cartesian product of multiple ranges as a view of tuples. |
| `to_input_view` | `views::to_input` | Downgrades iterator category to input iterator while preserving elements and order. |
| `subrange` | — | Represents a sub-range defined by an iteratorsentinel pair. |
All views support range-based for-loop iteration and can be composed with the pipe (`|`) operator.
## Supported Algorithms
All algorithms are callable objects in the `etl::ranges` namespace. Each supports both an iterator-pair overload and a range overload (where applicable), and most accept optional projection and comparator arguments.
### Non-modifying Sequence Operations
| Algorithm | Description |
|---|---|
| `for_each` | Applies a function to each element in a range. |
| `for_each_n` | Applies a function to the first *n* elements. |
| `find` | Finds the first element equal to a value. |
| `find_if` | Finds the first element satisfying a predicate. |
| `find_if_not` | Finds the first element not satisfying a predicate. |
| `find_end` | Finds the last occurrence of a subsequence. |
| `find_first_of` | Finds the first element matching any in a second range. |
| `adjacent_find` | Finds the first pair of adjacent equal elements. |
| `count` | Counts elements equal to a value. |
| `count_if` | Counts elements satisfying a predicate. |
| `all_of` | Checks if all elements satisfy a predicate. |
| `any_of` | Checks if any element satisfies a predicate. |
| `none_of` | Checks if no elements satisfy a predicate. |
| `mismatch` | Finds the first position where two ranges differ. |
| `equal` | Checks if two ranges are equal. |
| `is_permutation` | Checks if one range is a permutation of another. |
| `search` | Searches for the first occurrence of a subsequence. |
| `search_n` | Searches for *n* consecutive copies of a value. |
| `starts_with` | Checks if a range starts with another range. |
| `ends_with` | Checks if a range ends with another range. |
| `lexicographical_compare` | Compares two ranges lexicographically. |
### Fold Operations
| Algorithm | Description |
|---|---|
| `fold_left` | Left-folds elements with a binary operation. |
| `fold_left_with_iter` | Left-folds, returning both the result and an iterator. |
| `fold_left_first` | Left-folds using the first element as the initial value. |
| `fold_left_first_with_iter` | Like `fold_left_first`, also returning an iterator. |
| `fold_right` | Right-folds elements with a binary operation. |
| `fold_right_last` | Right-folds using the last element as the initial value. |
### Modifying Sequence Operations
| Algorithm | Description |
|---|---|
| `copy` | Copies elements to a destination range. |
| `copy_n` | Copies *n* elements to a destination range. |
| `copy_if` | Copies elements satisfying a predicate. |
| `copy_backward` | Copies elements backwards to a destination range. |
| `move` | Moves elements to a destination range. |
| `move_backward` | Moves elements backwards to a destination range. |
| `swap_ranges` | Swaps elements between two ranges. |
| `replace` | Replaces elements equal to a value. |
| `replace_if` | Replaces elements satisfying a predicate. |
| `replace_copy` | Copies, replacing elements equal to a value. |
| `replace_copy_if` | Copies, replacing elements satisfying a predicate. |
| `remove` | Removes elements equal to a value. |
| `remove_if` | Removes elements satisfying a predicate. |
| `remove_copy` | Copies, omitting elements equal to a value. |
| `fill` | Fills a range with a value. |
| `fill_n` | Fills *n* elements with a value. |
| `generate` | Assigns each element the result of a generator function. |
| `generate_n` | Assigns *n* elements the result of a generator function. |
| `iota` | Fills a range with sequentially increasing values. |
| `unique` | Removes consecutive duplicate elements. |
| `unique_copy` | Copies, removing consecutive duplicates. |
| `transform` | Applies a transformation to each element. |
| `reverse` | Reverses the order of elements. |
| `reverse_copy` | Copies elements in reverse order. |
| `rotate` | Rotates elements in a range. |
| `rotate_copy` | Copies elements with rotation. |
| `shift_left` | Shifts elements to the left. |
| `shift_right` | Shifts elements to the right. |
| `shuffle` | Randomly reorders elements. |
| `sample` | Selects *n* random elements from a range. |
### Sorting Operations
| Algorithm | Description |
|---|---|
| `sort` | Sorts elements in a range. |
| `stable_sort` | Sorts elements preserving relative order of equivalent elements. |
| `partial_sort` | Partially sorts a range so that the first *n* elements are sorted. |
| `partial_sort_copy` | Copies and partially sorts elements. |
| `nth_element` | Partially sorts so that the *n*-th element is in its sorted position. |
| `is_sorted` | Checks if a range is sorted. |
| `is_sorted_until` | Finds the first unsorted element. |
### Partitioning Operations
| Algorithm | Description |
|---|---|
| `partition` | Partitions elements by a predicate. |
| `stable_partition` | Partitions elements, preserving relative order. |
| `is_partitioned` | Checks if a range is partitioned. |
| `partition_copy` | Copies elements into two ranges based on a predicate. |
| `partition_point` | Finds the partition point. |
### Binary Search (on sorted ranges)
| Algorithm | Description |
|---|---|
| `lower_bound` | Finds the first element not less than a value. |
| `upper_bound` | Finds the first element greater than a value. |
| `equal_range` | Returns the range of elements equal to a value. |
| `binary_search` | Checks if a sorted range contains a value. |
### Set Operations (on sorted ranges)
| Algorithm | Description |
|---|---|
| `includes` | Checks if one sorted range includes another. |
| `merge` | Merges two sorted ranges. |
| `inplace_merge` | Merges two consecutive sorted sub-ranges in place. |
| `set_union` | Computes the union of two sorted ranges. |
| `set_intersection` | Computes the intersection of two sorted ranges. |
| `set_difference` | Computes the difference of two sorted ranges. |
| `set_symmetric_difference` | Computes the symmetric difference of two sorted ranges. |
### Heap Operations
| Algorithm | Description |
|---|---|
| `make_heap` | Creates a heap from a range. |
| `push_heap` | Pushes an element onto a heap. |
| `pop_heap` | Pops the top element from a heap. |
| `sort_heap` | Sorts a heap into a sorted range. |
| `is_heap` | Checks if a range is a heap. |
| `is_heap_until` | Finds the first element that breaks the heap property. |
### Min/Max Operations
| Algorithm | Description |
|---|---|
| `min` | Returns the smaller of two values or the smallest in an initializer list. |
| `min_element` | Finds the smallest element in a range. |
| `max` | Returns the larger of two values or the largest in an initializer list. |
| `max_element` | Finds the largest element in a range. |
| `minmax` | Returns the smaller and larger of two values. |
| `minmax_element` | Finds both the smallest and largest elements in a range. |
| `clamp` | Clamps a value between a minimum and maximum. |
### Permutation Operations
| Algorithm | Description |
|---|---|
| `next_permutation` | Generates the next lexicographic permutation. |
| `prev_permutation` | Generates the previous lexicographic permutation. |
## Reference
For reference to the STD implementation, see also:
- Algorithms: https://en.cppreference.com/w/cpp/algorithm.html
- Ranges/Views: https://en.cppreference.com/w/cpp/ranges.html
## Limitations
- Not all C++20 range features are available due to limitation to C++17. Especially C++20 concepts are not used.
- Designed for ETL containers but can work with standard containers if compatible with ETL's iterator requirements.

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

@ -37,7 +37,6 @@ SOFTWARE.
#include "error_handler.h"
#include "exception.h"
#include "utility.h"
#include "algorithm.h"
#include <stdint.h>

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

@ -807,6 +807,13 @@ namespace etl
{
public:
ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
atomic()
: flag(0)
, value(T())
@ -827,13 +834,6 @@ namespace etl
return v;
}
T operator =(T v) volatile
{
store(v);
return v;
}
// Conversion operator
operator T () const
{
@ -844,26 +844,12 @@ namespace etl
return result;
}
operator T() volatile const
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Is lock free?
bool is_lock_free() const
{
return false;
}
bool is_lock_free() const volatile
{
return false;
}
// Store
void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -873,25 +859,6 @@ namespace etl
ETL_BUILTIN_UNLOCK;
}
void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
ETL_BUILTIN_LOCK;
value = v;
ETL_BUILTIN_UNLOCK;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
{
(void)order;
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const
{
@ -915,17 +882,6 @@ namespace etl
return result;
}
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
ETL_BUILTIN_LOCK;
T result = value;
value = v;
ETL_BUILTIN_UNLOCK;
return result;
}
// Compare exchange weak
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -947,26 +903,6 @@ namespace etl
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
bool result;
(void)order;
ETL_BUILTIN_LOCK;
if (memcmp(&value, &expected, sizeof(T)) == 0)
{
value = desired;
result = true;
}
else
{
result = false;
}
ETL_BUILTIN_UNLOCK;
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
(void)success;
@ -974,13 +910,6 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
(void)success;
(void)failure;
return compare_exchange_weak(expected, desired);
}
// Compare exchange strong
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -988,12 +917,6 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
(void)success;
@ -1001,15 +924,11 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
(void)success;
(void)failure;
return compare_exchange_weak(expected, desired);
}
private:
atomic& operator =(const atomic&) ETL_DELETE;
atomic& operator =(const atomic&) volatile ETL_DELETE;
mutable char flag;
mutable T value;
};
@ -1995,6 +1914,13 @@ namespace etl
{
public:
ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
atomic()
: flag(0)
, value(T())
@ -2015,13 +1941,6 @@ namespace etl
return v;
}
T operator =(T v) volatile
{
store(v);
return v;
}
// Conversion operator
operator T () const
{
@ -2032,26 +1951,12 @@ namespace etl
return result;
}
operator T() volatile const
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Is lock free?
bool is_lock_free() const
{
return false;
}
bool is_lock_free() const volatile
{
return false;
}
// Store
void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -2060,23 +1965,6 @@ namespace etl
ETL_BUILTIN_UNLOCK;
}
void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
ETL_BUILTIN_LOCK;
value = v;
ETL_BUILTIN_UNLOCK;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const
{
@ -2098,16 +1986,6 @@ namespace etl
return result;
}
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
ETL_BUILTIN_LOCK;
T result = value;
value = v;
ETL_BUILTIN_UNLOCK;
return result;
}
// Compare exchange weak
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -2128,58 +2006,27 @@ namespace etl
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
bool result;
ETL_BUILTIN_LOCK;
if (memcmp(&value, &expected, sizeof(T)) == 0)
{
value = desired;
result = true;
}
else
{
result = false;
}
ETL_BUILTIN_UNLOCK;
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
return compare_exchange_weak(expected, desired);
}
// Compare exchange strong
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
return compare_exchange_weak(expected, desired);
}
private:
atomic& operator =(const atomic&) ETL_DELETE;
atomic& operator =(const atomic&) volatile ETL_DELETE;
mutable char flag;
mutable T value;
};

View File

@ -41,6 +41,7 @@ SOFTWARE.
#include "initializer_list.h"
#include "type_traits.h"
#include "invoke.h"
#include "memory.h"
namespace etl
{

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>
@ -79,6 +79,17 @@ namespace etl
return *t;
}
#if ETL_USING_CPP11
// implementation without etl::invoke, which would add a circular dependency
template <typename... TArgs>
ETL_CONSTEXPR20 auto operator()(TArgs&&... args) const
noexcept(noexcept(etl::declval<T&>()(etl::declval<TArgs>()...)))
-> decltype(etl::declval<T&>()(etl::declval<TArgs>()...))
{
return get()(etl::forward<TArgs>(args)...);
}
#endif
private:
T* t;
@ -224,9 +235,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 +261,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 +287,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 +314,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 +340,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));
}
@ -646,7 +657,41 @@ namespace etl
return private_functional::const_mem_fn_impl<TReturnType, TClassType, TArgs...>(member_function);
}
#endif
#if ETL_USING_CPP14
struct identity
{
template<class T>
constexpr T&& operator()(T&& t) const noexcept
{
return etl::forward<T>(t);
}
};
#endif
#if ETL_USING_CPP17
namespace ranges
{
struct equal_to
{
template <typename T, typename U>
constexpr auto operator()(T&& t, U&& u) const -> decltype(static_cast<T&&>(t) == static_cast<U&&>(u))
{
return static_cast<T&&>(t) == static_cast<U&&>(u);
}
};
struct less
{
template <typename T, typename U>
constexpr auto operator()(T&& t, U&& u) const -> decltype(static_cast<T&&>(t) < static_cast<U&&>(u))
{
return static_cast<T&&>(t) < static_cast<U&&>(u);
}
};
}
#endif
}
#endif

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

@ -375,6 +375,7 @@ namespace etl
}
#include "private/diagnostic_pop.h"
#include "private/diagnostic_uninitialized_push.h"
//********************************************
template <typename TType>
bool add_new_message_type(etl::imessage&& msg)
@ -390,6 +391,7 @@ namespace etl
return false;
}
}
#include "private/diagnostic_pop.h"
typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
bool valid;

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
@ -1857,6 +1929,16 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
using is_move_constructible = std::is_move_constructible<T>;
//*********************************************
// is_copy_assignable
template <typename T>
using is_copy_assignable = std::is_copy_assignable<T>;
//*********************************************
// is_move_assignable
template <typename T>
using is_move_assignable = std::is_move_assignable<T>;
//*********************************************
// is_trivially_constructible
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
@ -1902,6 +1984,9 @@ typedef integral_constant<bool, true> true_type;
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
template <typename T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
template <typename T>
using is_trivially_copyable = etl::bool_constant<__is_trivially_copyable(T)>;
#else
template <typename T>
using is_trivially_copyable = etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>;
@ -1961,6 +2046,29 @@ typedef integral_constant<bool, true> true_type;
{
};
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
//*********************************************
// is_move_assignable
#if ETL_USING_CPP11
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type, T>
{
};
#endif
#if ETL_USING_CPP11
//*********************************************
// is_trivially_constructible
@ -2035,11 +2143,7 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_trivially_copyable
{
#if defined(ETL_COMPILER_GCC)
static ETL_CONSTANT bool value = __has_trivial_copy(T);
#else
static ETL_CONSTANT bool value = __is_trivially_copyable(T);
#endif
};
#elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)
@ -2110,6 +2214,32 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_move_constructible<T, false>;
//*********************************************
// is_copy_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_copy_assignable;
template <typename T>
struct is_copy_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_copy_assignable<T, false>;
//*********************************************
// is_move_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_move_assignable;
template <typename T>
struct is_move_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_move_assignable<T, false>;
//*********************************************
// is_trivially_constructible
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
@ -2185,14 +2315,18 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_assignable
template <typename T1, typename T2>
#if ETL_USING_BUILTIN_IS_ASSIGNABLE
struct is_assignable : public etl::bool_constant<__is_assignable(T1, T2)>
#else
struct is_assignable : public etl::bool_constant<(etl::is_arithmetic<T1>::value || etl::is_pointer<T1>::value) && (etl::is_arithmetic<T2>::value || etl::is_pointer<T2>::value)>
#endif
{
};
#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 {};
@ -2239,6 +2373,31 @@ typedef integral_constant<bool, true> true_type;
};
#endif
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
#if ETL_USING_CPP11
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
{
};
#endif
//*********************************************
// is_trivially_constructible
template <typename T>
@ -2270,7 +2429,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_trivially_copyable
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
struct is_trivially_copyable : public etl::bool_constant<__is_trivially_copyable(T)>
#else
struct is_trivially_copyable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
@ -2317,6 +2480,12 @@ typedef integral_constant<bool, true> true_type;
template<typename T>
inline constexpr bool is_move_constructible_v = etl::is_move_constructible<T>::value;
template<typename T>
inline constexpr bool is_copy_assignable_v = etl::is_copy_assignable<T>::value;
template<typename T>
inline constexpr bool is_move_assignable_v = etl::is_move_assignable<T>::value;
template <typename T>
inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible<T>::value;
@ -2371,7 +2540,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 +2885,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 +2978,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 +3203,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

@ -110,7 +110,7 @@ namespace etl
//****************************************************************************
/// Pointer to member object + object (or derived) reference
template <typename TFunction,
template <typename TFunction,
typename TObject,
typename = etl::enable_if_t<etl::is_member_object_pointer<etl::decay_t<TFunction>>::value &&
!etl::is_pointer<etl::decay_t<TObject>>::value &&
@ -121,11 +121,37 @@ namespace etl
return etl::forward<TObject>(obj).*f;
}
//****************************************************************************
/// reference_wrapper callable (unwrap and call directly)
template <typename TFunction,
typename... TArgs,
typename = etl::enable_if_t<etl::is_reference_wrapper<etl::decay_t<TFunction>>::value &&
!etl::is_member_pointer<etl::decay_t<decltype(etl::declval<TFunction>().get())>>::value>>
ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args)
-> decltype(f.get()(etl::forward<TArgs>(args)...))
{
return f.get()(etl::forward<TArgs>(args)...);
}
//****************************************************************************
/// reference_wrapper callable wrapping a member pointer (unwrap and re-invoke)
template <typename TFunction,
typename... TArgs,
typename = etl::enable_if_t<etl::is_reference_wrapper<etl::decay_t<TFunction>>::value &&
etl::is_member_pointer<etl::decay_t<decltype(etl::declval<TFunction>().get())>>::value>,
typename = void>
ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args)
-> decltype(etl::invoke(f.get(), etl::forward<TArgs>(args)...))
{
return etl::invoke(f.get(), etl::forward<TArgs>(args)...);
}
//****************************************************************************
/// General callable (function object / lambda / function pointer)
template <typename TFunction,
typename... TArgs,
typename = etl::enable_if_t<!etl::is_member_pointer<etl::decay_t<TFunction>>::value>>
typename = etl::enable_if_t<!etl::is_member_pointer<etl::decay_t<TFunction>>::value &&
!etl::is_reference_wrapper<etl::decay_t<TFunction>>::value>>
ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args)
-> decltype(etl::forward<TFunction>(f)(etl::forward<TArgs>(args)...))
{
@ -204,11 +230,30 @@ namespace etl
using invoke_result_impl_t = typename invoke_result_impl<TFunction, TArgs...>::type;
//*******************************************
// Map raw function type to pointer.
// Unwrap reference_wrapper<T> to its underlying type T&,
// forwarding to etl::unwrap_ref_decay for reference_wrapper detection.
template <typename TFunction, bool = etl::is_reference_wrapper<etl::decay_t<TFunction>>::value>
struct unwrap_ref_callable
{
using type = TFunction;
};
template <typename TFunction>
struct unwrap_ref_callable<TFunction, true>
{
using type = etl::unwrap_ref_decay_t<TFunction>;
};
template <typename TFunction>
using unwrap_ref_callable_t = typename unwrap_ref_callable<TFunction>::type;
//*******************************************
// Map raw function type to pointer, and unwrap reference_wrapper
// so that function_traits sees the actual callable type.
template <typename TFunction>
using effective_callable_t = etl::conditional_t<etl::is_function<etl::remove_reference_t<TFunction>>::value,
etl::add_pointer_t<etl::remove_reference_t<TFunction>>,
TFunction>;
unwrap_ref_callable_t<TFunction>>;
}
//****************************************************************************

View File

@ -34,6 +34,7 @@ SOFTWARE.
#include "platform.h"
#include "type_traits.h"
#include "utility.h"
#include "invoke.h"
#include "private/addressof.h"
#if ETL_USING_STL || defined(ETL_IN_UNIT_TEST)
@ -67,7 +68,7 @@ namespace etl
typedef typename TIterator::pointer pointer;
typedef typename TIterator::reference reference;
};
// For pointers.
template <typename T>
struct iterator_traits<T*, void>
@ -92,10 +93,19 @@ namespace etl
//***************************************************************************
// advance
template <typename TIterator, typename TDistance>
ETL_CONSTEXPR14 void advance_helper(TIterator& itr, TDistance n, ETL_OR_STD::input_iterator_tag)
{
while (n-- > 0)
{
++itr;
}
}
template <typename TIterator, typename TDistance>
ETL_CONSTEXPR14 void advance_helper(TIterator& itr, TDistance n, ETL_OR_STD::output_iterator_tag)
{
while (n--)
while (n-- > 0)
{
++itr;
}
@ -104,7 +114,7 @@ namespace etl
template <typename TIterator, typename TDistance>
ETL_CONSTEXPR14 void advance_helper(TIterator& itr, TDistance n, ETL_OR_STD::forward_iterator_tag)
{
while (n--)
while (n-- > 0)
{
++itr;
}
@ -606,7 +616,7 @@ namespace etl
ETL_CONSTEXPR14 back_insert_iterator& operator =(const typename TContainer::value_type& value)
{
container->push_back(value);
return (*this);
}
@ -617,7 +627,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 +665,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,7 +1221,767 @@ namespace etl
char(&array_size(T(&array)[Array_Size]))[Array_Size];
#define ETL_ARRAY_SIZE(a) sizeof(etl::array_size(a))
#if ETL_USING_CPP17
template<class T>
using iter_value_t = typename etl::iterator_traits<etl::remove_cvref_t<T>>::value_type;
template<class T>
using iter_reference_t = decltype(*etl::declval<T&>());
#if ETL_USING_CPP20
template<class T>
using iter_const_reference_t = typename etl::common_reference_t<const etl::iter_value_t<T>&&, etl::iter_reference_t<T>>;
#endif
template<class T>
using iter_difference_t = typename etl::iterator_traits<etl::remove_cvref_t<T>>::difference_type;
template<class I, class Proj>
using projected_value_t = etl::remove_cvref_t<etl::invoke_result_t<Proj&, etl::iter_reference_t<I>>>;
namespace ranges
{
namespace private_ranges
{
struct begin
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::begin(t);
}
};
struct end
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::end(t);
}
};
struct cbegin
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::cbegin(t);
}
};
struct cend
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::cend(t);
}
};
struct rbegin
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::rbegin(t);
}
};
struct rend
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::rend(t);
}
};
struct crbegin
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::crbegin(t);
}
};
struct crend
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::crend(t);
}
};
template<class T, class = void>
struct has_size_member : etl::false_type {};
template<class T>
struct has_size_member<T, etl::void_t<decltype(etl::declval<const T&>().size())>> : etl::true_type {};
template<class T, class = void>
struct has_empty_member : etl::false_type {};
template<class T>
struct has_empty_member<T, etl::void_t<decltype(etl::declval<const T&>().empty())>> : etl::true_type {};
struct distance
{
// Overload for common ranges (iterator == sentinel type)
template<typename I, typename = etl::enable_if_t<etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value>>
constexpr etl::iter_difference_t<I> operator()(I first, I last) const
{
if constexpr (etl::is_random_access_iterator_concept<I>::value)
{
return last - first;
}
else
{
etl::iter_difference_t<I> n = 0;
while (!(first == last))
{
++first;
++n;
}
return n;
}
}
// Overload for non-common ranges (iterator != sentinel type)
template<typename I, typename S, typename = etl::enable_if_t<
(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) &&
!etl::is_same<I, S>::value>>
constexpr etl::iter_difference_t<I> operator()(I first, S last) const
{
etl::iter_difference_t<I> n = 0;
while (!(first == last))
{
++first;
++n;
}
return n;
}
};
struct size
{
template<class T>
constexpr size_t operator()(T&& t) const
{
using U = etl::remove_cvref_t<T>;
if constexpr (has_size_member<U>::value)
{
return static_cast<size_t>(t.size());
}
else
{
using iter_type = decltype(ETL_OR_STD::begin(t));
static_assert(etl::is_forward_iterator_concept<iter_type>::value,
"ranges::size requires a sized range or at least a forward range; "
"single-pass input ranges are not supported");
return static_cast<size_t>(distance{}(ETL_OR_STD::begin(t), ETL_OR_STD::end(t)));
}
}
};
struct ssize
{
template<class T>
constexpr auto operator()(T&& t) const
{
using U = etl::remove_cvref_t<T>;
if constexpr (has_size_member<U>::value)
{
return static_cast<ptrdiff_t>(t.size());
}
else
{
using iter_type = decltype(ETL_OR_STD::begin(t));
static_assert(etl::is_forward_iterator_concept<iter_type>::value,
"ranges::ssize requires a sized range or at least a forward range; "
"single-pass input ranges are not supported");
return static_cast<ptrdiff_t>(distance{}(ETL_OR_STD::begin(t), ETL_OR_STD::end(t)));
}
}
};
struct empty
{
template<class T>
constexpr auto operator()(T&& t) const
{
using U = etl::remove_cvref_t<T>;
if constexpr (has_empty_member<U>::value)
{
return t.empty();
}
else
{
return ETL_OR_STD::cbegin(t) == ETL_OR_STD::cend(t);
}
}
};
struct data
{
template<class T>
constexpr auto operator()(T& t) const
{
return ETL_OR_STD::data(t);
}
};
struct cdata
{
template<class T>
constexpr etl::add_pointer_t<etl::add_const_t<etl::remove_pointer_t<decltype(ETL_OR_STD::data(etl::declval<T&>()))>>> operator()(T& t) const
{
return ETL_OR_STD::data(t);
}
};
}
inline constexpr private_ranges::begin begin;
inline constexpr private_ranges::end end;
inline constexpr private_ranges::cbegin cbegin;
inline constexpr private_ranges::cend cend;
inline constexpr private_ranges::rbegin rbegin;
inline constexpr private_ranges::rend rend;
inline constexpr private_ranges::crbegin crbegin;
inline constexpr private_ranges::crend crend;
inline constexpr private_ranges::size size;
inline constexpr private_ranges::ssize ssize;
inline constexpr private_ranges::empty empty;
inline constexpr private_ranges::data data;
inline constexpr private_ranges::cdata cdata;
inline constexpr private_ranges::distance distance;
//*************************************************************************
/// Range primitives.
//*************************************************************************
template<class T>
using iterator_t = decltype(etl::ranges::begin(etl::declval<T&>()));
template<class T>
using const_iterator_t = decltype(etl::ranges::cbegin(etl::declval<T&>()));
template<class T>
using sentinel_t = decltype(etl::ranges::end(etl::declval<T&>()));
template<class T>
using const_sentinel_t = decltype(etl::ranges::cend(etl::declval<T&>()));
template<class T>
using range_size_t = decltype(etl::ranges::size(etl::declval<T&>()));
template<class T>
using range_difference_t = etl::iter_difference_t<etl::ranges::iterator_t<T>>;
template<class T>
using range_value_t = etl::iter_value_t<etl::ranges::iterator_t<T>>;
template<class T>
using range_reference_t = etl::iter_reference_t<ranges::iterator_t<T>>;
struct advance_fn
{
template<typename I, typename = etl::enable_if_t<(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) && etl::is_integral<etl::iter_difference_t<I>>::value>>
constexpr void operator()(I& i, etl::iter_difference_t<I> n) const
{
if constexpr (etl::is_random_access_iterator_concept<I>::value)
{
i += n;
}
else
{
while (n > 0)
{
--n;
++i;
}
if constexpr (etl::is_bidirectional_iterator_concept<I>::value)
{
while (n < 0)
{
++n;
--i;
}
}
}
}
template<typename I, typename S, typename = etl::enable_if_t<(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) && !etl::is_integral<S>::value>>
constexpr void operator()(I& i, S bound) const
{
if constexpr (etl::is_assignable_v<I&, S>)
{
i = etl::move(bound);
}
else if constexpr (etl::is_same_v<S, I> && etl::is_random_access_iterator_concept<I>::value)
{
(*this)(i, bound - i);
}
else
{
while (!(i == bound))
{
++i;
}
}
}
template<typename I, typename S, typename = etl::enable_if_t<etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value>>
constexpr etl::iter_difference_t<I>
operator()(I& i, etl::iter_difference_t<I> n, S bound) const
{
if constexpr (etl::is_same_v<S, I> && etl::is_random_access_iterator_concept<I>::value)
{
const auto dist = bound - i;
if ((n >= 0 && dist >= 0 && n >= dist) ||
(n <= 0 && dist <= 0 && n <= dist))
{
(*this)(i, bound);
return n - dist;
}
(*this)(i, n);
return 0;
}
else
{
while (n > 0 && !(i == bound))
{
--n;
++i;
}
if constexpr (etl::is_bidirectional_iterator_concept<I>::value)
{
while (n < 0 && !(i == bound))
{
++n;
--i;
}
}
return n;
}
}
};
inline constexpr auto advance = advance_fn();
struct prev_fn
{
template<typename I, typename = etl::enable_if_t<etl::is_bidirectional_iterator_concept<I>::value>>
constexpr I operator()(I i) const
{
--i;
return i;
}
template<typename I, typename = etl::enable_if_t<etl::is_bidirectional_iterator_concept<I>::value>>
constexpr I operator()(I i, etl::iter_difference_t<I> n) const
{
ranges::advance(i, -n);
return i;
}
template<typename I, typename = etl::enable_if_t<etl::is_bidirectional_iterator_concept<I>::value>>
constexpr I operator()(I i, etl::iter_difference_t<I> n, I bound) const
{
ranges::advance(i, -n, bound);
return i;
}
};
inline constexpr auto prev = prev_fn();
struct next_fn
{
template<typename I, typename = etl::enable_if_t<etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value>>
constexpr I operator()(I i) const
{
++i;
return i;
}
template<typename I, typename = etl::enable_if_t<(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) && etl::is_integral<etl::iter_difference_t<I>>::value>>
constexpr I operator()(I i, etl::iter_difference_t<I> n) const
{
ranges::advance(i, n);
return i;
}
template<typename I, typename S, typename = etl::enable_if_t<(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) && !etl::is_integral<S>::value>>
constexpr I operator()(I i, S bound) const
{
ranges::advance(i, bound);
return i;
}
template<typename I, typename S, typename = etl::enable_if_t<(etl::is_input_iterator_concept<I>::value || etl::is_output_iterator_concept<I>::value) && !etl::is_integral<S>::value>>
constexpr I operator()(I i, etl::iter_difference_t<I> n, S bound) const
{
ranges::advance(i, n, bound);
return i;
}
};
inline constexpr auto next = next_fn();
}
struct unreachable_sentinel_t
{
};
inline constexpr unreachable_sentinel_t unreachable_sentinel{};
template<typename I>
constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept
{
return false;
}
template<typename I>
constexpr bool operator==(const I&, unreachable_sentinel_t) noexcept
{
return false;
}
template<typename I>
constexpr bool operator!=(unreachable_sentinel_t, const I& i) noexcept
{
return !(unreachable_sentinel_t{} == i);
}
template<typename I>
constexpr bool operator!=(const I& i, unreachable_sentinel_t) noexcept
{
return !(i == unreachable_sentinel_t{});
}
struct default_sentinel_t
{
};
inline constexpr default_sentinel_t default_sentinel{};
namespace private_iterator
{
template<typename T, typename = void>
struct has_arrow_operator : etl::false_type {};
template<typename T>
struct has_arrow_operator<T, etl::void_t<decltype(etl::declval<const T&>().operator->())>> : etl::true_type {};
//***********************************
/// Proxy that owns a copy of the dereferenced value so that operator->
/// can safely return a pointer to it. Used when the wrapped iterator
/// has no member operator-> and is not a raw pointer (i.e. *it may
/// yield a prvalue / proxy whose address would otherwise dangle).
//***********************************
template<typename TValue>
struct arrow_proxy
{
TValue stored;
constexpr arrow_proxy(TValue value) : stored(etl::move(value)) {}
constexpr const TValue* operator->() const noexcept { return etl::addressof(stored); }
};
}
template<class I>
class counted_iterator
{
template<class> friend class counted_iterator;
public:
using iterator_type = I;
using value_type = etl::iter_value_t<I>;
using difference_type = etl::iter_difference_t<I>;
using iterator_category = typename etl::iterator_traits<iterator_type>::iterator_category;
using pointer = typename etl::iterator_traits<iterator_type>::pointer;
using reference = typename etl::iterator_traits<iterator_type>::reference;
constexpr counted_iterator() = default;
constexpr counted_iterator(I x, etl::iter_difference_t<I> n): current(etl::move(x)), length(n)
{
}
template<class I2>
constexpr counted_iterator(const counted_iterator<I2>& other): current(other.current), length(other.length)
{
}
template<class I2>
constexpr counted_iterator& operator=(const counted_iterator<I2>& other)
{
current = other.current;
length = other.length;
return *this;
}
constexpr const I& base() const& noexcept
{
return current;
}
constexpr I base() &&
{
return etl::move(current);
}
constexpr etl::iter_difference_t<I> count() const noexcept
{
return length;
}
constexpr decltype(auto) operator*() const
{
return *current;
}
// operator-> for iterator types that provide a member operator->
template<typename J = I, etl::enable_if_t<
(etl::is_input_iterator_concept<J>::value || etl::is_output_iterator_concept<J>::value) &&
private_iterator::has_arrow_operator<J>::value, int> = 0>
constexpr auto operator->() const noexcept
{
return current.operator->();
}
// operator-> fallback for raw-pointer iterators (addressof is always safe)
template<typename J = I, etl::enable_if_t<
(etl::is_input_iterator_concept<J>::value || etl::is_output_iterator_concept<J>::value) &&
!private_iterator::has_arrow_operator<J>::value &&
etl::is_pointer<J>::value, int> = 0>
constexpr auto operator->() const noexcept
{
return current;
}
// operator-> fallback for class-type iterators without member operator->
// When *current yields an lvalue reference, just take its address.
template<typename J = I, etl::enable_if_t<
(etl::is_input_iterator_concept<J>::value || etl::is_output_iterator_concept<J>::value) &&
!private_iterator::has_arrow_operator<J>::value &&
!etl::is_pointer<J>::value &&
etl::is_lvalue_reference<decltype(*etl::declval<const J&>())>::value, int> = 0>
constexpr auto operator->() const noexcept
{
return etl::addressof(*current);
}
// operator-> fallback for class-type iterators without member operator->
// When *current yields a prvalue / proxy, use an owning proxy so the
// address remains valid.
template<typename J = I, etl::enable_if_t<
(etl::is_input_iterator_concept<J>::value || etl::is_output_iterator_concept<J>::value) &&
!private_iterator::has_arrow_operator<J>::value &&
!etl::is_pointer<J>::value &&
!etl::is_lvalue_reference<decltype(*etl::declval<const J&>())>::value, int> = 0>
constexpr auto operator->() const
{
return private_iterator::arrow_proxy<value_type>{*current};
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
constexpr decltype(auto) operator[](etl::iter_difference_t<I> n) const
{
return current[n];
}
constexpr counted_iterator& operator++()
{
++current;
--length;
return *this;
}
constexpr counted_iterator operator++(int)
{
counted_iterator tmp = *this;
current++;
length--;
return tmp;
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
constexpr counted_iterator& operator+=(etl::iter_difference_t<I> n)
{
current += n;
length -= n;
return *this;
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
constexpr counted_iterator operator+(etl::iter_difference_t<I> n) const
{
counted_iterator result{*this};
result += n;
return result;
}
constexpr counted_iterator& operator--()
{
--current;
++length;
return *this;
}
constexpr counted_iterator operator--(int)
{
counted_iterator tmp = *this;
current--;
length++;
return tmp;
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
constexpr counted_iterator& operator-=(etl::iter_difference_t<I> n)
{
current -= n;
length += n;
return *this;
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
constexpr counted_iterator operator-(etl::iter_difference_t<I> n) const
{
counted_iterator result{*this};
result -= n;
return result;
}
friend constexpr bool operator==(const counted_iterator& x, const counted_iterator& y)
{
return x.length == y.length;
}
friend constexpr bool operator==(const counted_iterator& x, etl::default_sentinel_t)
{
return x.count() == 0;
}
friend constexpr bool operator==(etl::default_sentinel_t, const counted_iterator& x)
{
return x.count() == 0;
}
friend constexpr bool operator!=(const counted_iterator& x, etl::default_sentinel_t)
{
return x.count() != 0;
}
friend constexpr bool operator!=(etl::default_sentinel_t, const counted_iterator& y)
{
return y.count() != 0;
}
template<typename J = I, etl::enable_if_t<etl::is_random_access_iterator<J>::value, int> = 0>
friend constexpr counted_iterator operator+(etl::iter_difference_t<I> n, const counted_iterator& x)
{
return counted_iterator(x.current + n, x.length - n);
}
friend constexpr etl::iter_difference_t<I> operator-(const counted_iterator& x, const counted_iterator& y)
{
return y.length - x.length;
}
friend constexpr etl::iter_difference_t<I> operator-(const counted_iterator& x, etl::default_sentinel_t)
{
return -x.length;
}
friend constexpr etl::iter_difference_t<I> operator-(etl::default_sentinel_t, const counted_iterator& y)
{
return y.length;
}
private:
I current{};
difference_type length{};
};
template<typename TIterator, typename = etl::enable_if_t<etl::is_base_of<etl::counted_iterator<typename TIterator::iterator_type>, TIterator>::value>>
constexpr typename etl::iterator_traits<TIterator>::difference_type distance(TIterator first, etl::default_sentinel_t)
{
return first.count();
}
#endif
#if ETL_USING_CPP14
template <class T, typename = void>
struct is_range: etl::false_type
{
};
template <class T>
struct is_range<T,
etl::void_t<decltype(ETL_OR_STD::begin(etl::declval<T&>())),
decltype(ETL_OR_STD::end(etl::declval<T&>()))>>: etl::true_type
{
};
#if ETL_USING_CPP17
template <typename T>
inline constexpr bool is_range_v = is_range<T>::value;
#endif
#endif
#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

@ -32,10 +32,8 @@ SOFTWARE.
#define ETL_MANCHESTER_INCLUDED
#include "platform.h"
#include "endianness.h"
#include "span.h"
#include "static_assert.h"
#include <cstring>
///\defgroup manchester manchester
/// Manchester encoding and decoding
@ -172,18 +170,37 @@ namespace etl
};
//*************************************************************************
/// Alias for memcpy. etl::mem_copy is not suitable for the Manchester
/// algorithm because all memory copies are between different types. This
/// alias is a way to respect ETL_USING_BUILTIN_MEMCPY while using the
/// memcpy function signature
/// Read a multi-byte value from a span in little-endian byte order.
///\tparam T The type to read.
///\param bytes The span to read from.
///\param index The starting index in the span.
///\return The value read from the span.
//*************************************************************************
inline void* memcpy(void* dest, const void* src, std::size_t count) ETL_NOEXCEPT
template <typename T>
static ETL_CONSTEXPR14 T read_little_endian(etl::span<const uint_least8_t> bytes, size_t index)
{
#if ETL_USING_BUILTIN_MEMCPY
return __builtin_memcpy(dest, src, count);
#else
return ::memcpy(dest, src, count);
#endif
T value = 0;
for (size_t j = 0; j < sizeof(T); ++j)
{
value |= static_cast<T>(bytes[index + j]) << (j * CHAR_BIT);
}
return value;
}
//*************************************************************************
/// Write a multi-byte value to a span in little-endian byte order.
///\tparam T The type to write.
///\param bytes The span to write to.
///\param index The starting index in the span.
///\param value The value to write.
//*************************************************************************
template <typename T>
static ETL_CONSTEXPR14 void write_little_endian(etl::span<uint_least8_t> bytes, size_t index, T value)
{
for (size_t j = 0; j < sizeof(T); ++j)
{
bytes[index + j] = static_cast<uint_least8_t>(value >> (j * CHAR_BIT));
}
}
} // namespace private_manchester
@ -297,44 +314,13 @@ namespace etl
#endif
//*************************************************************************
/// Encode a span of data with the selected chunk size.
///\param source The source data to encode.
///\param destination The destination buffer for encoded data.
///\tparam TChunk The chunk size for encoding (default: uint_least8_t).
//*************************************************************************
template <typename TChunk>
static typename etl::enable_if<!etl::is_same<TChunk, uint_least8_t>::value, void>::type
encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
{
typedef TChunk TDecoded;
typedef typename etl::private_manchester::encoded<TChunk>::type TEncoded;
ETL_ASSERT(encoded.size() >= decoded.size() * 2, ETL_ERROR(manchester_invalid_size));
ETL_ASSERT(decoded.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size));
size_t dest_index = 0;
size_t source_index = 0;
for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i)
{
TDecoded decoded_value = 0;
etl::private_manchester::memcpy(&decoded_value, &decoded[source_index], sizeof(TDecoded));
const TEncoded encoded_value = encode(decoded_value);
etl::private_manchester::memcpy(&encoded[dest_index], &encoded_value, sizeof(TEncoded));
source_index += sizeof(TDecoded);
dest_index += sizeof(TEncoded);
}
}
//*************************************************************************
/// Encode a span of data with the minimum chunk size. This version is
/// constexpr so that it can be used to encode data at compile time.
/// Encode a span of data with the specified chunk size.
///\param source The source data to encode.
///\param destination The destination buffer for encoded data.
///\tparam TChunk The chunk size for encoding (default: uint_least8_t).
//*************************************************************************
template <typename TChunk = uint_least8_t>
static ETL_CONSTEXPR14 typename etl::enable_if<etl::is_same<TChunk, uint_least8_t>::value, void>::type encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
static ETL_CONSTEXPR14 void encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
{
typedef TChunk TDecoded;
typedef typename etl::private_manchester::encoded<TChunk>::type TEncoded;
@ -346,17 +332,9 @@ namespace etl
size_t source_index = 0;
for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i)
{
const TEncoded encoded_value = encode(decoded[source_index]);
if (etl::endianness::value() == etl::endian::little)
{
encoded[dest_index] = static_cast<uint_least8_t>(encoded_value);
encoded[dest_index + 1] = static_cast<uint_least8_t>(encoded_value >> CHAR_BIT);
}
else
{
encoded[dest_index] = static_cast<uint_least8_t>(encoded_value >> CHAR_BIT);
encoded[dest_index + 1] = static_cast<uint_least8_t>(encoded_value);
}
const TDecoded decoded_value = private_manchester::read_little_endian<TDecoded>(decoded, source_index);
const TEncoded encoded_value = encode(decoded_value);
private_manchester::write_little_endian<TEncoded>(encoded, dest_index, encoded_value);
source_index += sizeof(TDecoded);
dest_index += sizeof(TEncoded);
@ -426,14 +404,13 @@ namespace etl
#endif
//*************************************************************************
/// Decode a span of data using specified chunk type.
/// Decode a span of data using the specified chunk type.
///\param source The source encoded data to decode.
///\param destination The destination buffer for decoded data.
///\tparam TChunk The chunk type for decoding.
///\tparam TChunk The chunk type for decoding (default: uint16_t).
//*************************************************************************
template <typename TChunk>
static typename etl::enable_if<!etl::is_same<TChunk, typename private_manchester::encoded<uint_least8_t>::type>::value, void>::type
decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> decoded)
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)
{
typedef typename private_manchester::decoded<TChunk>::type TDecoded;
typedef TChunk TEncoded;
@ -445,53 +422,15 @@ namespace etl
size_t source_index = 0;
for (size_t i = 0; i < encoded.size() / sizeof(TEncoded); ++i)
{
TChunk encoded_value = 0;
etl::private_manchester::memcpy(&encoded_value, &encoded[source_index], sizeof(TEncoded));
const TEncoded encoded_value = private_manchester::read_little_endian<TEncoded>(encoded, source_index);
const TDecoded decoded_value = decode(encoded_value);
etl::private_manchester::memcpy(&decoded[dest_index], &decoded_value, sizeof(TDecoded));
private_manchester::write_little_endian<TDecoded>(decoded, dest_index, decoded_value);
source_index += sizeof(TEncoded);
dest_index += sizeof(TDecoded);
}
}
//*************************************************************************
/// Decode a span of data using the smallest chunk type. This version is
/// constexpr so that it can be used to decode data at compile time.
///\param source The source encoded data to decode.
///\param destination The destination buffer for decoded data.
///\tparam TChunk The chunk type for decoding (default type).
//*************************************************************************
template <typename TChunk = typename private_manchester::encoded<uint_least8_t>::type>
static ETL_CONSTEXPR14 typename etl::enable_if<etl::is_same<TChunk, typename private_manchester::encoded<uint_least8_t>::type>::value, void>::type
decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> decoded)
{
typedef uint_least8_t TDecoded;
ETL_ASSERT(decoded.size() * 2 >= encoded.size(), ETL_ERROR(manchester_invalid_size));
ETL_ASSERT(encoded.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size));
size_t dest_index = 0;
size_t source_index = 0;
for (size_t i = 0; i < encoded.size() / sizeof(TChunk); ++i)
{
TChunk encoded_value{};
if (etl::endianness::value() == etl::endian::little)
{
encoded_value = static_cast<TChunk>((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]);
}
else
{
encoded_value = static_cast<TChunk>((encoded[source_index] << CHAR_BIT) | encoded[source_index + 1]);
}
decoded[dest_index] = decode<TChunk>(encoded_value);
source_index += sizeof(TChunk);
dest_index += sizeof(TDecoded);
}
}
//*************************************************************************
// Validation functions
//*************************************************************************
@ -521,15 +460,7 @@ namespace etl
for (size_t i = 0; i < encoded.size(); i += sizeof(uint16_t))
{
uint16_t chunk{};
if (etl::endianness::value() == etl::endian::little)
{
chunk = static_cast<uint16_t>((encoded[i + 1] << CHAR_BIT) | encoded[i]);
}
else
{
chunk = static_cast<uint16_t>((encoded[i] << CHAR_BIT) | encoded[i + 1]);
}
const uint16_t chunk = private_manchester::read_little_endian<uint16_t>(encoded, i);
if (!is_valid<uint16_t>(chunk))
{

View File

@ -322,6 +322,190 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Copies a range of objects to uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_copy
///\ingroup memory
//*****************************************************************************
struct uninitialized_copy_fn
{
template<class I, class S1, class O, class S2, typename = etl::enable_if_t<!etl::is_range_v<I>>>
ranges::uninitialized_copy_result<I, O>
operator()(I ifirst, S1 ilast, O ofirst, S2 olast) const
{
using value_type = typename etl::iterator_traits<O>::value_type;
O ofirst_original = ofirst;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; ifirst != ilast && ofirst != olast; ++ifirst, ++ofirst)
{
::new (static_cast<void*>(etl::to_address(ofirst)))
value_type(*ifirst);
}
return {etl::move(ifirst), etl::move(ofirst)};
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; ofirst_original != ofirst; ++ofirst_original)
{
etl::to_address(ofirst_original)->~value_type();
}
throw;
}
#endif
}
template<class IR, class OR, typename = etl::enable_if_t<etl::is_range_v<IR>>>
ranges::uninitialized_copy_result<ranges::borrowed_iterator_t<IR>, ranges::borrowed_iterator_t<OR>>
operator()(IR&& in_range, OR&& out_range) const
{
return (*this)(ranges::begin(in_range), ranges::end(in_range),
ranges::begin(out_range), ranges::end(out_range));
}
};
inline constexpr uninitialized_copy_fn uninitialized_copy {};
//*****************************************************************************
/// Copies N objects to uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_copy_n
///\ingroup memory
//*****************************************************************************
struct uninitialized_copy_n_fn
{
template<class I, class O, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
ranges::uninitialized_copy_n_result<I, O>
operator()(I ifirst, etl::iter_difference_t<I> n, O ofirst, S olast) const
{
using value_type = typename etl::iterator_traits<O>::value_type;
O ofirst_original = ofirst;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; n > 0 && ofirst != olast; ++ifirst, ++ofirst, --n)
{
::new (static_cast<void*>(etl::to_address(ofirst)))
value_type(*ifirst);
}
return {etl::move(ifirst), etl::move(ofirst)};
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; ofirst_original != ofirst; ++ofirst_original)
{
etl::to_address(ofirst_original)->~value_type();
}
throw;
}
#endif
}
};
inline constexpr uninitialized_copy_n_fn uninitialized_copy_n {};
//*****************************************************************************
/// Fills uninitialised memory range with a value.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_fill
///\ingroup memory
//*****************************************************************************
struct uninitialized_fill_fn
{
template<class I, class S, class T, typename = etl::enable_if_t<!etl::is_range_v<I>>>
I operator()(I first, S last, const T& value) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; current != last; ++current)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type(value);
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
template<class R, class T, typename = etl::enable_if_t<etl::is_range_v<R>>>
ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value) const
{
return (*this)(ranges::begin(r), ranges::end(r), value);
}
};
inline constexpr uninitialized_fill_fn uninitialized_fill {};
//*****************************************************************************
/// Fills uninitialised memory with N copies of a value.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_fill_n
///\ingroup memory
//*****************************************************************************
struct uninitialized_fill_n_fn
{
template<class I, class T>
I operator()(I first, etl::iter_difference_t<I> n, const T& value) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; n > 0; ++current, --n)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type(value);
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
};
inline constexpr uninitialized_fill_n_fn uninitialized_fill_n {};
}
#endif
#if ETL_USING_STL && ETL_USING_CPP11
//*****************************************************************************
/// Copies N objects to uninitialised memory.
@ -638,6 +822,102 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Moves a range of objects to uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_move
///\ingroup memory
//*****************************************************************************
struct uninitialized_move_fn
{
template<class I, class S1, class O, class S2, typename = etl::enable_if_t<!etl::is_range_v<I>>>
ranges::uninitialized_move_result<I, O>
operator()(I ifirst, S1 ilast, O ofirst, S2 olast) const
{
using value_type = typename etl::iterator_traits<O>::value_type;
O ofirst_original = ofirst;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; ifirst != ilast && ofirst != olast; ++ifirst, ++ofirst)
{
::new (static_cast<void*>(etl::to_address(ofirst)))
value_type(etl::move(*ifirst));
}
return {etl::move(ifirst), etl::move(ofirst)};
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; ofirst_original != ofirst; ++ofirst_original)
{
etl::to_address(ofirst_original)->~value_type();
}
throw;
}
#endif
}
template<class IR, class OR, typename = etl::enable_if_t<etl::is_range_v<IR>>>
ranges::uninitialized_move_result<ranges::borrowed_iterator_t<IR>, ranges::borrowed_iterator_t<OR>>
operator()(IR&& in_range, OR&& out_range) const
{
return (*this)(ranges::begin(in_range), ranges::end(in_range),
ranges::begin(out_range), ranges::end(out_range));
}
};
inline constexpr uninitialized_move_fn uninitialized_move {};
//*****************************************************************************
/// Moves N objects to uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_move_n
///\ingroup memory
//*****************************************************************************
struct uninitialized_move_n_fn
{
template<class I, class O, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
ranges::uninitialized_move_n_result<I, O>
operator()(I ifirst, etl::iter_difference_t<I> n, O ofirst, S olast) const
{
using value_type = typename etl::iterator_traits<O>::value_type;
O ofirst_original = ofirst;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; n > 0 && ofirst != olast; ++ifirst, ++ofirst, --n)
{
::new (static_cast<void*>(etl::to_address(ofirst)))
value_type(etl::move(*ifirst));
}
return {etl::move(ifirst), etl::move(ofirst)};
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; ofirst_original != ofirst; ++ofirst_original)
{
etl::to_address(ofirst_original)->~value_type();
}
throw;
}
#endif
}
};
inline constexpr uninitialized_move_n_fn uninitialized_move_n {};
}
#endif
#if ETL_USING_STL && ETL_USING_CPP17
//*****************************************************************************
/// Default initialises a range of objects to uninitialised memory.
@ -818,6 +1098,98 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Default constructs objects in uninitialised memory range.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_default_construct
///\ingroup memory
//*****************************************************************************
struct uninitialized_default_construct_fn
{
template<class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
I operator()(I first, S last) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; current != last; ++current)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type;
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
template<class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
ranges::borrowed_iterator_t<R> operator()(R&& r) const
{
return (*this)(ranges::begin(r), ranges::end(r));
}
};
inline constexpr uninitialized_default_construct_fn uninitialized_default_construct {};
//*****************************************************************************
/// Default constructs N objects in uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_default_construct_n
///\ingroup memory
//*****************************************************************************
struct uninitialized_default_construct_n_fn
{
template<class I>
I operator()(I first, etl::iter_difference_t<I> n) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; n > 0; ++current, --n)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type;
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
};
inline constexpr uninitialized_default_construct_n_fn uninitialized_default_construct_n {};
}
#endif
#if ETL_USING_STL && ETL_USING_CPP17
//*****************************************************************************
/// Default initialises a range of objects to uninitialised memory.
@ -951,6 +1323,98 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Value constructs objects in uninitialised memory range.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_value_construct
///\ingroup memory
//*****************************************************************************
struct uninitialized_value_construct_fn
{
template<class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
I operator()(I first, S last) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; current != last; ++current)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type();
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
template<class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
ranges::borrowed_iterator_t<R> operator()(R&& r) const
{
return (*this)(ranges::begin(r), ranges::end(r));
}
};
inline constexpr uninitialized_value_construct_fn uninitialized_value_construct {};
//*****************************************************************************
/// Value constructs N objects in uninitialised memory.
/// https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_value_construct_n
///\ingroup memory
//*****************************************************************************
struct uninitialized_value_construct_n_fn
{
template<class I>
I operator()(I first, etl::iter_difference_t<I> n) const
{
using value_type = typename etl::iterator_traits<I>::value_type;
I current = first;
#if ETL_USING_EXCEPTIONS
try
{
#endif
for (; n > 0; ++current, --n)
{
::new (static_cast<void*>(etl::to_address(current)))
value_type();
}
return current;
#if ETL_USING_EXCEPTIONS
}
catch (...)
{
for (; first != current; ++first)
{
etl::to_address(first)->~value_type();
}
throw;
}
#endif
}
};
inline constexpr uninitialized_value_construct_n_fn uninitialized_value_construct_n {};
}
#endif
#if ETL_USING_STL && ETL_USING_CPP20
//*****************************************************************************
/// Constructs an item at address p with value constructed from 'args'.
@ -996,6 +1460,26 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Constructs an item at address p with value constructed from 'args'.
/// https://en.cppreference.com/w/cpp/memory/ranges/construct_at
///\ingroup memory
//*****************************************************************************
struct construct_at_fn
{
template<class T, class... Args>
constexpr T* operator()(T* p, Args&&... args) const
{
return etl::construct_at(p, etl::forward<Args>(args)...);
}
};
inline constexpr construct_at_fn construct_at {};
}
#endif
#if ETL_USING_STL && ETL_USING_CPP20
//*****************************************************************************
/// Destroys an item at address p.
@ -1254,6 +1738,74 @@ namespace etl
}
#endif
#if ETL_USING_CPP17
namespace ranges {
//*****************************************************************************
/// Destroys an item at address p.
/// https://en.cppreference.com/w/cpp/memory/ranges/destroy_at
///\ingroup memory
//*****************************************************************************
struct destroy_at_fn
{
template<class T>
constexpr void operator()(T* p) const
{
etl::destroy_at(p);
}
};
inline constexpr destroy_at_fn destroy_at {};
//*****************************************************************************
/// Destroys a range of items.
/// https://en.cppreference.com/w/cpp/memory/ranges/destroy
///\ingroup memory
//*****************************************************************************
struct destroy_fn
{
template<class I, class S, typename = etl::enable_if_t<!etl::is_range_v<I>>>
I operator()(I first, S last) const
{
for (; first != last; ++first)
{
etl::destroy_at(etl::to_address(first));
}
return first;
}
template<class R, typename = etl::enable_if_t<etl::is_range_v<R>>>
ranges::borrowed_iterator_t<R> operator()(R&& r) const
{
return (*this)(ranges::begin(r), ranges::end(r));
}
};
inline constexpr destroy_fn destroy {};
//*****************************************************************************
/// Destroys a number of items.
/// https://en.cppreference.com/w/cpp/memory/ranges/destroy_n
///\ingroup memory
//*****************************************************************************
struct destroy_n_fn
{
template<class I>
I operator()(I first, etl::iter_difference_t<I> n) const
{
for (; n > 0; ++first, --n)
{
etl::destroy_at(etl::to_address(first));
}
return first;
}
};
inline constexpr destroy_n_fn destroy_n {};
}
#endif
//*****************************************************************************
/// Default deleter.
///\tparam T The pointed to type type.

View File

@ -363,6 +363,7 @@ namespace etl
}
#include "private/diagnostic_pop.h"
#include "private/diagnostic_uninitialized_push.h"
//********************************************
template <typename TType>
bool add_new_message_type(etl::imessage&& msg)
@ -378,6 +379,7 @@ namespace etl
return false;
}
}
#include "private/diagnostic_pop.h"
typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
bool valid;

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

@ -0,0 +1,412 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_RANGES_MINI_VARIANT_INCLUDED
#define ETL_RANGES_MINI_VARIANT_INCLUDED
#include "../platform.h"
#include "../error_handler.h"
#include "../utility.h"
#if ETL_USING_CPP17
namespace etl
{
namespace ranges
{
namespace private_ranges
{
//*********************************************************************
/// mini_variant
/// A minimal, self-contained variant used internally by ranges,
/// to prevent cyclic dependencies from algorithm.h and ranges.h.
//*********************************************************************
// Helper: get the I-th type from a parameter pack.
template<size_t I, typename... Ts>
struct type_at_index;
template<size_t I, typename Head, typename... Tail>
struct type_at_index<I, Head, Tail...> : type_at_index<I - 1, Tail...> {};
template<typename Head, typename... Tail>
struct type_at_index<0, Head, Tail...>
{
using type = Head;
};
template<size_t I, typename... Ts>
using type_at_index_t = typename type_at_index<I, Ts...>::type;
// Helper: maximum of sizeof... values
template<typename... Ts>
struct max_size;
template<typename T>
struct max_size<T>
{
static constexpr size_t value = sizeof(T);
};
template<typename T, typename... Ts>
struct max_size<T, Ts...>
{
static constexpr size_t value = (sizeof(T) > max_size<Ts...>::value) ? sizeof(T) : max_size<Ts...>::value;
};
// Helper: maximum of alignof... values
template<typename... Ts>
struct max_align;
template<typename T>
struct max_align<T>
{
static constexpr size_t value = alignof(T);
};
template<typename T, typename... Ts>
struct max_align<T, Ts...>
{
static constexpr size_t value = (alignof(T) > max_align<Ts...>::value) ? alignof(T) : max_align<Ts...>::value;
};
// Index value representing "no active alternative"
inline constexpr size_t mini_variant_npos = ~size_t(0);
// Detection trait: is a single type equality-comparable?
template<typename T, typename = void>
struct is_equality_comparable : etl::false_type {};
template<typename T>
struct is_equality_comparable<T, etl::void_t<decltype(etl::declval<const T&>() == etl::declval<const T&>())>>
: etl::true_type {};
// Conjunction: all types in the pack are equality-comparable
template<typename... Ts>
struct all_equality_comparable : etl::bool_constant<(is_equality_comparable<Ts>::value && ...)> {};
// Detection trait: is a single type nothrow-move-constructible?
template<typename T>
struct is_nothrow_move_constructible
{
private:
template<typename U>
static auto test(int) -> etl::bool_constant<noexcept(U(etl::declval<U&&>()))>;
template<typename>
static etl::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
// Conjunction: all types in the pack are nothrow-move-constructible
template<typename... Ts>
struct all_nothrow_move_constructible : etl::bool_constant<(is_nothrow_move_constructible<Ts>::value && ...)> {};
// Detection trait: is a single type nothrow-destructible?
template<typename T>
struct is_nothrow_destructible
{
private:
template<typename U>
static auto test(int) -> etl::bool_constant<noexcept(etl::declval<U&>().~U())>;
template<typename>
static etl::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
// Conjunction: all types in the pack are nothrow-destructible
template<typename... Ts>
struct all_nothrow_destructible : etl::bool_constant<(is_nothrow_destructible<Ts>::value && ...)> {};
template<typename... Ts>
class mini_variant
{
static_assert(sizeof...(Ts) > 0, "mini_variant requires at least one type");
static constexpr size_t storage_size = max_size<Ts...>::value;
static constexpr size_t storage_align = max_align<Ts...>::value;
alignas(storage_align) unsigned char _storage[storage_size];
size_t _index;
// ---- Destruction dispatch table ----
using destroy_fn = void(*)(void*);
template<size_t I>
static void destroy_impl(void* ptr)
{
using T = type_at_index_t<I, Ts...>;
static_cast<T*>(ptr)->~T();
}
template<size_t... Is>
static const destroy_fn* make_destroy_table(etl::index_sequence<Is...>)
{
static const destroy_fn table[] = { &destroy_impl<Is>... };
return table;
}
static const destroy_fn* destroy_table()
{
static const destroy_fn* t = make_destroy_table(etl::make_index_sequence<sizeof...(Ts)>{});
return t;
}
// ---- Copy dispatch table ----
using copy_fn = void(*)(void* /*dst*/, const void* /*src*/);
template<size_t I>
static void copy_impl(void* dst, const void* src)
{
using T = type_at_index_t<I, Ts...>;
::new (dst) T(*static_cast<const T*>(src));
}
template<size_t... Is>
static const copy_fn* make_copy_table(etl::index_sequence<Is...>)
{
static const copy_fn table[] = { &copy_impl<Is>... };
return table;
}
static const copy_fn* copy_table()
{
static const copy_fn* t = make_copy_table(etl::make_index_sequence<sizeof...(Ts)>{});
return t;
}
// ---- Move dispatch table ----
using move_fn = void(*)(void* /*dst*/, void* /*src*/);
template<size_t I>
static void move_impl(void* dst, void* src)
{
using T = type_at_index_t<I, Ts...>;
::new (dst) T(etl::move(*static_cast<T*>(src)));
}
template<size_t... Is>
static const move_fn* make_move_table(etl::index_sequence<Is...>)
{
static const move_fn table[] = { &move_impl<Is>... };
return table;
}
static const move_fn* move_table()
{
static const move_fn* t = make_move_table(etl::make_index_sequence<sizeof...(Ts)>{});
return t;
}
// ---- Equality dispatch table ----
using equal_fn = bool(*)(const void* /*lhs*/, const void* /*rhs*/);
template<size_t I>
static bool equal_impl(const void* lhs, const void* rhs)
{
using T = type_at_index_t<I, Ts...>;
return *static_cast<const T*>(lhs) == *static_cast<const T*>(rhs);
}
template<size_t... Is>
static const equal_fn* make_equal_table(etl::index_sequence<Is...>)
{
static const equal_fn table[] = { &equal_impl<Is>... };
return table;
}
static const equal_fn* equal_table()
{
static const equal_fn* t = make_equal_table(etl::make_index_sequence<sizeof...(Ts)>{});
return t;
}
void destroy_current()
{
if (_index != mini_variant_npos)
{
destroy_table()[_index](&_storage);
_index = mini_variant_npos;
}
}
public:
mini_variant() : _index{mini_variant_npos}
{
}
mini_variant(const mini_variant& other) : _index{mini_variant_npos}
{
if (other._index != mini_variant_npos)
{
copy_table()[other._index](&_storage, &other._storage);
_index = other._index;
}
}
mini_variant& operator=(const mini_variant& other)
{
if (this != &other)
{
destroy_current();
if (other._index != mini_variant_npos)
{
copy_table()[other._index](&_storage, &other._storage);
_index = other._index;
}
}
return *this;
}
mini_variant(mini_variant&& other) noexcept(all_nothrow_move_constructible<Ts...>::value && all_nothrow_destructible<Ts...>::value)
: _index{mini_variant_npos}
{
if (other._index != mini_variant_npos)
{
move_table()[other._index](&_storage, &other._storage);
_index = other._index;
other.destroy_current();
}
}
mini_variant& operator=(mini_variant&& other) noexcept(all_nothrow_move_constructible<Ts...>::value && all_nothrow_destructible<Ts...>::value)
{
if (this != &other)
{
destroy_current();
if (other._index != mini_variant_npos)
{
move_table()[other._index](&_storage, &other._storage);
_index = other._index;
other.destroy_current();
}
}
return *this;
}
~mini_variant() noexcept(all_nothrow_destructible<Ts...>::value)
{
destroy_current();
}
template<size_t I, typename... Args>
void emplace(Args&&... args)
{
static_assert(I < sizeof...(Ts), "Index out of range");
using T = type_at_index_t<I, Ts...>;
destroy_current();
::new (&_storage) T(etl::forward<Args>(args)...);
_index = I;
}
constexpr size_t index() const
{
return _index;
}
template<size_t I>
type_at_index_t<I, Ts...>& get_ref()
{
static_assert(I < sizeof...(Ts), "Index out of range");
ETL_ASSERT(_index == I, ETL_ERROR_GENERIC("mini_variant: bad index"));
using T = type_at_index_t<I, Ts...>;
return *reinterpret_cast<T*>(&_storage);
}
template<size_t I>
const type_at_index_t<I, Ts...>& get_ref() const
{
static_assert(I < sizeof...(Ts), "Index out of range");
ETL_ASSERT(_index == I, ETL_ERROR_GENERIC("mini_variant: bad index"));
using T = type_at_index_t<I, Ts...>;
return *reinterpret_cast<const T*>(&_storage);
}
template<bool B = all_equality_comparable<Ts...>::value, etl::enable_if_t<B, int> = 0>
friend bool operator==(const mini_variant& lhs, const mini_variant& rhs)
{
if (lhs._index != rhs._index)
{
return false;
}
if (lhs._index == mini_variant_npos)
{
return true;
}
return equal_table()[lhs._index](&lhs._storage, &rhs._storage);
}
template<bool B = all_equality_comparable<Ts...>::value, etl::enable_if_t<B, int> = 0>
friend bool operator!=(const mini_variant& lhs, const mini_variant& rhs)
{
return !(lhs == rhs);
}
};
} // namespace private_ranges
} // namespace ranges (temporarily close to define get<> in etl namespace)
template<size_t I, typename... Ts>
typename ranges::private_ranges::type_at_index_t<I, Ts...>&
get(ranges::private_ranges::mini_variant<Ts...>& v)
{
return v.template get_ref<I>();
}
template<size_t I, typename... Ts>
const typename ranges::private_ranges::type_at_index_t<I, Ts...>&
get(const ranges::private_ranges::mini_variant<Ts...>& v)
{
return v.template get_ref<I>();
}
template<size_t I, typename... Ts>
typename ranges::private_ranges::type_at_index_t<I, Ts...>&&
get(ranges::private_ranges::mini_variant<Ts...>&& v)
{
return etl::move(v.template get_ref<I>());
}
template<size_t I, typename... Ts>
const typename ranges::private_ranges::type_at_index_t<I, Ts...>&&
get(const ranges::private_ranges::mini_variant<Ts...>&& v)
{
return etl::move(v.template get_ref<I>());
}
} // namespace etl
#endif // ETL_USING_CPP17
#endif

View File

@ -338,11 +338,11 @@ namespace etl
}
// Find the integral part of the floating point
T f_integral = floor(etl::absolute(value));
T f_integral = ::floor(etl::absolute(value));
uworkspace_t integral = static_cast<uworkspace_t>(f_integral);
// Find the fractional part of the floating point.
uworkspace_t fractional = static_cast<uworkspace_t>(round((etl::absolute(value) - f_integral) * multiplier));
uworkspace_t fractional = static_cast<uworkspace_t>(::round((etl::absolute(value) - f_integral) * multiplier));
// Check for a rounding carry to the integral.
if (fractional == multiplier)

View File

@ -30,7 +30,6 @@ SOFTWARE.
#include "../platform.h"
#include "../utility.h"
#include "../array.h"
#include "../largest.h"
#include "../exception.h"
#include "../type_traits.h"
@ -39,6 +38,7 @@ SOFTWARE.
#include "../alignment.h"
#include "../error_handler.h"
#include "../null_type.h"
#include "../parameter_type.h"
#include "../placement_new.h"
#include "../monostate.h"

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.
//*************************************************************************

5927
include/etl/ranges.h Normal file

File diff suppressed because it is too large Load Diff

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

@ -713,6 +713,7 @@ namespace etl
//***************************************************************************
/// get_token
//***************************************************************************
#include "private/diagnostic_uninitialized_push.h"
template <typename TInput, typename TStringView>
etl::optional<TStringView> get_token(const TInput& input, typename TInput::const_pointer delimiters, const etl::optional<TStringView>& last_view, bool ignore_empty_tokens)
{
@ -755,6 +756,7 @@ namespace etl
return etl::optional<TStringView>(view);
}
#include "private/diagnostic_pop.h"
//***************************************************************************
/// get_token_list

View File

@ -276,7 +276,7 @@ namespace etl
/// Implicit conversion
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
tuple(tuple<UHead, UTail...>& other)
@ -290,7 +290,7 @@ namespace etl
/// Explicit conversion
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
!etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
explicit tuple(tuple<UHead, UTail...>& other)
@ -304,7 +304,7 @@ namespace etl
/// Implicit conversion
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
tuple(const tuple<UHead, UTail...>& other)
@ -318,7 +318,7 @@ namespace etl
/// Explicit conversion
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
!etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
explicit tuple(const tuple<UHead, UTail...>& other)
@ -332,7 +332,7 @@ namespace etl
/// Implicit conversion
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
tuple(tuple<UHead, UTail...>&& other)
@ -399,7 +399,7 @@ namespace etl
//*********************************
template <typename UHead, typename... UTail, etl::enable_if_t<!is_tuple<etl::remove_reference_t<UHead>>::value &&
(number_of_types<THead, TTail...>() == number_of_types<UHead, UTail...>()) &&
(number_of_types<THead, TTail...>() >= 1U) &&
(number_of_types<THead, TTail...>() >= 1U) &&
etl::is_convertible<UHead, THead>::value, int> = 0>
ETL_CONSTEXPR14
tuple(UHead&& head, UTail&&... tail) ETL_NOEXCEPT
@ -428,8 +428,8 @@ namespace etl
/// Implicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
etl ::is_convertible<U1, THead>::value &&
etl ::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
etl::is_convertible<U1, THead>::value &&
etl::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
ETL_CONSTEXPR14
tuple(ETL_OR_STD::pair<U1, U2>& p) ETL_NOEXCEPT
: base_type(p.second)
@ -442,8 +442,8 @@ namespace etl
/// Explicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
(!etl ::is_convertible<U1, THead>::value ||
!etl ::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
(!etl::is_convertible<U1, THead>::value ||
!etl::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
ETL_CONSTEXPR14
explicit tuple(ETL_OR_STD::pair<U1, U2>& p) ETL_NOEXCEPT
: base_type(p.second)
@ -456,8 +456,8 @@ namespace etl
/// Implicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
etl ::is_convertible<U1, THead>::value &&
etl ::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
etl::is_convertible<U1, THead>::value &&
etl::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
ETL_CONSTEXPR14
tuple(const ETL_OR_STD::pair<U1, U2>& p) ETL_NOEXCEPT
: base_type(p.second)
@ -470,8 +470,8 @@ namespace etl
/// Explicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
(!etl ::is_convertible<U1, THead>::value ||
!etl ::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
(!etl::is_convertible<U1, THead>::value ||
!etl::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
ETL_CONSTEXPR14
explicit tuple(const ETL_OR_STD::pair<U1, U2>& p) ETL_NOEXCEPT
: base_type(p.second)
@ -484,8 +484,8 @@ namespace etl
/// Implicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
etl ::is_convertible<U1, THead>::value &&
etl ::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
etl::is_convertible<U1, THead>::value &&
etl::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
ETL_CONSTEXPR14
tuple(ETL_OR_STD::pair<U1, U2>&& p) ETL_NOEXCEPT
: base_type(etl::forward<U2>(p.second))
@ -498,8 +498,8 @@ namespace etl
/// Explicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
(!etl ::is_convertible<U1, THead>::value ||
!etl ::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
(!etl::is_convertible<U1, THead>::value ||
!etl::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
ETL_CONSTEXPR14
explicit tuple(ETL_OR_STD::pair<U1, U2>&& p) ETL_NOEXCEPT
: base_type(etl::forward<U2>(p.second))
@ -512,12 +512,12 @@ namespace etl
/// Implicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
etl ::is_convertible<U1, THead>::value &&
etl ::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
etl::is_convertible<U1, THead>::value &&
etl::is_convertible<U2, typename base_type::value_type>::value, int> = 0>
ETL_CONSTEXPR14
tuple(const ETL_OR_STD::pair<U1, U2>&& p) ETL_NOEXCEPT
: base_type(etl::forward<U2>(p.second))
, value(etl::forward<U1>(p.first))
: base_type(etl::forward<const U2>(p.second))
, value(etl::forward<const U1>(p.first))
{
}
@ -526,12 +526,12 @@ namespace etl
/// Explicit conversion.
//*********************************
template <typename U1, typename U2, etl::enable_if_t<number_of_types<THead, TTail...>() == 2U &&
(!etl ::is_convertible<U1, THead>::value ||
!etl ::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
(!etl::is_convertible<U1, THead>::value ||
!etl::is_convertible<U2, typename base_type::value_type>::value), int> = 0>
ETL_CONSTEXPR14
explicit tuple(const ETL_OR_STD::pair<U1, U2>&& p) ETL_NOEXCEPT
: base_type(p.second)
, value(p.first)
: base_type(etl::forward<const U2>(p.second))
, value(etl::forward<const U1>(p.first))
{
}
@ -605,8 +605,8 @@ namespace etl
ETL_CONSTEXPR14
tuple& operator =(const ETL_OR_STD::pair<U1, U2>&& p)
{
get_value() = p.first;
get_base().get_value() = p.second;
get_value() = etl::forward<const U1>(p.first);
get_base().get_value() = etl::forward<const U2>(p.second);
return *this;
}
@ -763,7 +763,7 @@ namespace etl
//***************************************************************************
/// Extracts the element at Index from the tuple.
/// Index must be an integer value in sizeof...(TTypes)).
/// Index must be an integer value in [0, sizeof...(TTypes)).
/// Returns a reference.
//***************************************************************************
template <size_t Index, typename... TTypes>
@ -782,7 +782,7 @@ namespace etl
//***************************************************************************
/// Extracts the element at Index from the tuple.
/// Index must be an integer value in [?0?, sizeof...(TTypes)).
/// Index must be an integer value in [0, sizeof...(TTypes)).
/// Returns a const reference.
//***************************************************************************
template <size_t Index, typename... TTypes>
@ -801,7 +801,7 @@ namespace etl
//***************************************************************************
/// Extracts the element at Index from the tuple.
/// Index must be an integer value in [?0?, sizeof...(TTypes)).
/// Index must be an integer value in [0, sizeof...(TTypes)).
/// Returns an rvalue reference.
//***************************************************************************
template <size_t Index, typename... TTypes>
@ -820,7 +820,7 @@ namespace etl
//***************************************************************************
/// Extracts the element at Index from the tuple.
/// Index must be an integer value in [?0?, sizeof...(TTypes)).
/// Index must be an integer value in [0, sizeof...(TTypes)).
/// Returns a const rvalue reference.
//***************************************************************************
template <size_t Index, typename... TTypes>
@ -1017,17 +1017,17 @@ namespace etl
ETL_NODISCARD
ETL_CONSTEXPR14
auto tuple_cat(Tuple1&& t1, Tuple2&& t2, Tuples&&... ts)
-> decltype(private_tuple::tuple_cat_impl(etl::forward<Tuple1>(t1),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple1>>::value>{},
etl::forward<Tuple2>(t2),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple2>>::value>{}))
-> decltype(tuple_cat(private_tuple::tuple_cat_impl(etl::forward<Tuple1>(t1),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple1>>::value>{},
etl::forward<Tuple2>(t2),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple2>>::value>{}),
etl::forward<Tuples>(ts)...))
{
auto concatenated = private_tuple::tuple_cat_impl(etl::forward<Tuple1>(t1),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple1>>::value>{},
etl::forward<Tuple2>(t2),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple2>>::value>{});
return tuple_cat(etl::move(concatenated), etl::forward<Tuples>(ts)...);
return tuple_cat(private_tuple::tuple_cat_impl(etl::forward<Tuple1>(t1),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple1>>::value>{},
etl::forward<Tuple2>(t2),
etl::make_index_sequence<etl::tuple_size<etl::decay_t<Tuple2>>::value>{}),
etl::forward<Tuples>(ts)...);
}
#if ETL_USING_STL
@ -1317,7 +1317,7 @@ namespace std
template <size_t Index, typename... Types>
struct tuple_element<Index, etl::tuple<Types...>>
{
using type = typename etl::nth_type_t<Index, Types...>;
using type = etl::nth_type_t<Index, Types...>;
};
}

View File

@ -31,7 +31,6 @@ SOFTWARE.
#include "platform.h"
#include "algorithm.h"
#include "index_of_type.h"
#include "integral_limits.h"
#include "static_assert.h"

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
@ -1850,6 +1922,16 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
using is_move_constructible = std::is_move_constructible<T>;
//*********************************************
// is_copy_assignable
template <typename T>
using is_copy_assignable = std::is_copy_assignable<T>;
//*********************************************
// is_move_assignable
template <typename T>
using is_move_assignable = std::is_move_assignable<T>;
//*********************************************
// is_trivially_constructible
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
@ -1895,6 +1977,9 @@ typedef integral_constant<bool, true> true_type;
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
template <typename T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
template <typename T>
using is_trivially_copyable = etl::bool_constant<__is_trivially_copyable(T)>;
#else
template <typename T>
using is_trivially_copyable = etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>;
@ -1954,6 +2039,29 @@ typedef integral_constant<bool, true> true_type;
{
};
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
//*********************************************
// is_move_assignable
#if ETL_USING_CPP11
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type, T>
{
};
#endif
#if ETL_USING_CPP11
//*********************************************
// is_trivially_constructible
@ -2028,11 +2136,7 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_trivially_copyable
{
#if defined(ETL_COMPILER_GCC)
static ETL_CONSTANT bool value = __has_trivial_copy(T);
#else
static ETL_CONSTANT bool value = __is_trivially_copyable(T);
#endif
};
#elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)
@ -2103,6 +2207,32 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_move_constructible<T, false>;
//*********************************************
// is_copy_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_copy_assignable;
template <typename T>
struct is_copy_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_copy_assignable<T, false>;
//*********************************************
// is_move_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_move_assignable;
template <typename T>
struct is_move_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_move_assignable<T, false>;
//*********************************************
// is_trivially_constructible
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
@ -2178,14 +2308,18 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_assignable
template <typename T1, typename T2>
#if ETL_USING_BUILTIN_IS_ASSIGNABLE
struct is_assignable : public etl::bool_constant<__is_assignable(T1, T2)>
#else
struct is_assignable : public etl::bool_constant<(etl::is_arithmetic<T1>::value || etl::is_pointer<T1>::value) && (etl::is_arithmetic<T2>::value || etl::is_pointer<T2>::value)>
#endif
{
};
#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 {};
@ -2232,6 +2366,31 @@ typedef integral_constant<bool, true> true_type;
};
#endif
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
#if ETL_USING_CPP11
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
{
};
#endif
//*********************************************
// is_trivially_constructible
template <typename T>
@ -2263,7 +2422,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_trivially_copyable
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
struct is_trivially_copyable : public etl::bool_constant<__is_trivially_copyable(T)>
#else
struct is_trivially_copyable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
@ -2310,6 +2473,12 @@ typedef integral_constant<bool, true> true_type;
template<typename T>
inline constexpr bool is_move_constructible_v = etl::is_move_constructible<T>::value;
template<typename T>
inline constexpr bool is_copy_assignable_v = etl::is_copy_assignable<T>::value;
template<typename T>
inline constexpr bool is_move_assignable_v = etl::is_move_assignable<T>::value;
template <typename T>
inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible<T>::value;
@ -2364,7 +2533,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 +2878,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 +2971,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 +3196,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
@ -274,6 +282,7 @@ add_executable(etl_tests
test_queue_spsc_locked.cpp
test_queue_spsc_locked_small.cpp
test_random.cpp
test_ranges.cpp
test_ratio.cpp
test_reference_flat_map.cpp
test_reference_flat_multimap.cpp
@ -286,6 +295,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
@ -371,6 +381,10 @@ target_compile_definitions(etl_tests PRIVATE -DETL_DEBUG)
option(ETL_NO_STL "No STL" OFF)
set(EXTRA_COMPILE_OPTIONS "" CACHE STRING "Additional compiler options")
set(EXTRA_LINK_OPTIONS "" CACHE STRING "Additional linker options")
set(EXTRA_LINK_LIBS "" CACHE STRING "Additional libraries to link")
if (ETL_CXX_STANDARD MATCHES "98")
message(STATUS "Compiling for C++98")
set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98)
@ -468,7 +482,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-Wnull-dereference
-Wextra-semi
-g
${EXTRA_COMPILE_OPTIONS}
)
target_link_options(etl_tests PRIVATE ${EXTRA_LINK_OPTIONS})
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@ -487,7 +503,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-Wextra-semi-stmt
-Wc++11-extra-semi
-g
${EXTRA_COMPILE_OPTIONS}
)
target_link_options(etl_tests PRIVATE ${EXTRA_LINK_OPTIONS})
endif ()
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
@ -513,13 +531,13 @@ target_include_directories(etl_tests
${PROJECT_SOURCE_DIR}/../include)
add_subdirectory(UnitTest++)
target_link_libraries(etl_tests PRIVATE UnitTestpp)
target_link_libraries(etl_tests PRIVATE UnitTestpp ${EXTRA_LINK_LIBS})
enable_testing()
# Enable the 'make test' CMake target using the executable defined above
add_test(etl_unit_tests etl_tests)
add_test(NAME etl_unit_tests COMMAND etl_tests)
# Since ctest will only show you the results of the single executable
# define a target that will output all of the failing or passing tests
# as they appear from UnitTest++
add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose)

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)
{

81
test/run-coverage.sh Executable file
View File

@ -0,0 +1,81 @@
#!/bin/bash
#
# run-coverage.sh [gcc|clang]
#
# defaults:
# compiler: clang
#
set -e
export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc)
# Choose gcc or clang via cmdline
if [ "$1" = "gcc" ] ; then
COMPILER=gcc
else
# default
COMPILER=clang
fi
if [ "$COMPILER" = "gcc" ]; then
C_COMPILER=gcc
CXX_COMPILER=g++
GCOV="$(command -v gcov)" || { echo "gcov not found in PATH"; exit 1; }
GCOV_ADD=""
EXTRA_LINK_OPTIONS=""
EXTRA_LINK_LIBS="gcov"
elif [ "$COMPILER" = "clang" ]; then
C_COMPILER=clang
CXX_COMPILER=clang++
GCOV="$(command -v llvm-cov)" || { echo "llvm-cov not found in PATH"; exit 1; }
GCOV_ADD="--gcov-tool gcov"
EXTRA_LINK_OPTIONS="--coverage"
EXTRA_LINK_LIBS=""
else
echo "Unsupported compiler: $COMPILER"
exit 1
fi
BUILD=build-coverage
rm -rf -- "${BUILD:?}"
mkdir -p "$BUILD"
cd "$BUILD" || exit 1
touch total.info
for CXXSTD in 11 14 17 20 23; do
for NOSTL in OFF ON; do
rm -rf CMakeFiles
cmake -DEXTRA_COMPILE_OPTIONS="--coverage" \
-DEXTRA_LINK_OPTIONS="$EXTRA_LINK_OPTIONS" \
-DEXTRA_LINK_LIBS="$EXTRA_LINK_LIBS" \
-DCMAKE_C_COMPILER=$C_COMPILER \
-DCMAKE_CXX_COMPILER=$CXX_COMPILER \
-DNO_STL=$NOSTL \
-DETL_USE_TYPE_TRAITS_BUILTINS=OFF \
-DETL_USER_DEFINED_TYPE_TRAITS=OFF \
-DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \
-DETL_OPTIMISATION=-O0 \
-DETL_CXX_STANDARD=$CXXSTD \
-DETL_ENABLE_SANITIZER=Off \
-DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF \
-DETL_USE_BUILTIN_MEM_FUNCTIONS=ON ..
cmake --build .
./etl_tests
lcov --gcov-tool "$GCOV" $GCOV_ADD --capture --directory CMakeFiles/etl_tests.dir \
--rc "geninfo_unexecuted_blocks=1" --output-file coverage.info --include '*/include/etl/*' --rc "lcov_branch_coverage=1" \
--ignore-errors inconsistent \
--ignore-errors mismatch
lcov -a total.info -a coverage.info -o total.info --rc "lcov_branch_coverage=1" \
--ignore-errors inconsistent \
--ignore-errors corrupt \
--ignore-errors empty
done
done
genhtml total.info --output-directory coverage --rc "genhtml_branch_coverage=1" --branch-coverage -t $COMPILER \
--ignore-errors inconsistent
cd ..

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

File diff suppressed because it is too large Load Diff

View File

@ -711,6 +711,130 @@ namespace
CHECK_EQUAL(compare.load(), test.load());
}
//*************************************************************************
TEST(test_atomic_non_scalar_trivially_copyable_struct)
{
struct Data
{
int x;
int y;
bool operator ==(const Data& other) const
{
return (x == other.x) && (y == other.y);
}
};
// Default construction
etl::atomic<Data> test;
Data d1 = { 1, 2 };
Data d2 = { 3, 4 };
Data d3 = { 5, 6 };
// Store and load
test.store(d1);
Data loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Assignment operator
test = d2;
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Conversion operator
test.store(d1);
Data converted = static_cast<Data>(test);
CHECK_EQUAL(d1.x, converted.x);
CHECK_EQUAL(d1.y, converted.y);
// Exchange
test.store(d1);
Data old_val = test.exchange(d2);
CHECK_EQUAL(d1.x, old_val.x);
CHECK_EQUAL(d1.y, old_val.y);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Compare exchange weak - pass (expected matches)
test.store(d1);
Data expected = d1;
bool result = test.compare_exchange_weak(expected, d3);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Compare exchange weak - fail (expected does not match)
test.store(d1);
expected = d2;
result = test.compare_exchange_weak(expected, d3);
CHECK_FALSE(result);
loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Compare exchange weak with two memory order args - pass
test.store(d1);
expected = d1;
result = test.compare_exchange_weak(expected, d2, etl::memory_order_seq_cst, etl::memory_order_seq_cst);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Compare exchange strong - pass (expected matches)
test.store(d1);
expected = d1;
result = test.compare_exchange_strong(expected, d3);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Compare exchange strong - fail (expected does not match)
test.store(d1);
expected = d2;
result = test.compare_exchange_strong(expected, d3);
CHECK_FALSE(result);
loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Compare exchange strong with two memory order args - pass
test.store(d1);
expected = d1;
result = test.compare_exchange_strong(expected, d2, etl::memory_order_seq_cst, etl::memory_order_seq_cst);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Explicit memory order on store/load
test.store(d3, etl::memory_order_release);
loaded = test.load(etl::memory_order_acquire);
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Exchange with explicit memory order
test.store(d1);
old_val = test.exchange(d2, etl::memory_order_acq_rel);
CHECK_EQUAL(d1.x, old_val.x);
CHECK_EQUAL(d1.y, old_val.y);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Value construction
etl::atomic<Data> test2(d1);
loaded = test2.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
}
//*************************************************************************
#if REALTIME_TEST

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

@ -35,6 +35,8 @@ SOFTWARE.
#include "etl/crc8_nrsc5.h"
#include <etl/endianness.h>
//*****************************************************************************
// The results for these tests were created from https://crccalc.com/
//*****************************************************************************
@ -115,7 +117,15 @@ namespace
TEST(test_crc8_nrsc5_4_add_range_endian)
{
std::vector<uint8_t> data1 = { 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U };
std::vector<uint32_t> data2 = { 0x04030201UL, 0x08070605UL };
std::vector<uint32_t> data2;
if (etl::endianness::value() == etl::endian::little)
{
data2 = { 0x04030201UL, 0x08070605UL };
}
else
{
data2 = { 0x01020304UL, 0x05060708UL };
}
std::vector<uint8_t> data3 = { 0x08U, 0x07U, 0x06U, 0x05U, 0x04U, 0x03U, 0x02U, 0x01U };
uint8_t crc1 = etl::crc8_nrsc5_t4(data1.begin(), data1.end());
@ -198,7 +208,15 @@ namespace
TEST(test_crc8_nrsc5_16_add_range_endian)
{
std::vector<uint8_t> data1 = { 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U };
std::vector<uint32_t> data2 = { 0x04030201UL, 0x08070605UL };
std::vector<uint32_t> data2;
if (etl::endianness::value() == etl::endian::little)
{
data2 = { 0x04030201UL, 0x08070605UL };
}
else
{
data2 = { 0x01020304UL, 0x05060708UL };
}
std::vector<uint8_t> data3 = { 0x08U, 0x07U, 0x06U, 0x05U, 0x04U, 0x03U, 0x02U, 0x01U };
uint8_t crc1 = etl::crc8_nrsc5_t16(data1.begin(), data1.end());
@ -281,7 +299,15 @@ namespace
TEST(test_crc8_nrsc5_256_add_range_endian)
{
std::vector<uint8_t> data1 = { 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U };
std::vector<uint32_t> data2 = { 0x04030201UL, 0x08070605UL };
std::vector<uint32_t> data2;
if (etl::endianness::value() == etl::endian::little)
{
data2 = { 0x04030201UL, 0x08070605UL };
}
else
{
data2 = { 0x01020304UL, 0x05060708UL };
}
std::vector<uint8_t> data3 = { 0x08U, 0x07U, 0x06U, 0x05U, 0x04U, 0x03U, 0x02U, 0x01U };
uint8_t crc1 = etl::crc8_nrsc5(data1.begin(), data1.end());

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
}
//*************************************************************************
@ -204,6 +274,43 @@ namespace
CHECK_EQUAL(1, ra);
}
#if ETL_USING_CPP11
//*************************************************************************
TEST(test_reference_wrapper_call_operator_no_args)
{
struct functor
{
int operator()() const { return 42; }
};
functor f;
etl::reference_wrapper<functor> rw(f);
CHECK_EQUAL(42, rw());
}
//*************************************************************************
TEST(test_reference_wrapper_call_operator_with_args)
{
struct adder
{
int operator()(int a, int b) const { return a + b; }
};
adder f;
etl::reference_wrapper<adder> rw(f);
CHECK_EQUAL(7, rw(3, 4));
}
//*************************************************************************
TEST(test_reference_wrapper_call_operator_function_pointer)
{
int (*fn)(int, int) = [](int a, int b) { return a * b; };
etl::reference_wrapper<int(*)(int, int)> rw(fn);
CHECK_EQUAL(12, rw(3, 4));
}
#endif
//*************************************************************************
TEST(test_plus)
{
@ -379,5 +486,96 @@ namespace
result = f3(mft, "Arg1", " : Arg2");
CHECK_EQUAL("Function3_Const: Arg1 : Arg2", result);
}
#if ETL_USING_CPP14
//*************************************************************************
TEST(test_identity)
{
etl::identity i;
std::string s{"abc"};
CHECK_EQUAL(s, i(s));
CHECK_EQUAL(&s, &i(s));
CHECK_EQUAL(&s, i(&s));
}
#endif
#if ETL_USING_CPP17
//*************************************************************************
TEST(test_ranges_equal_to_same_type)
{
etl::ranges::equal_to eq;
CHECK(eq(1, 1));
CHECK(!eq(1, 2));
CHECK(!eq(2, 1));
}
//*************************************************************************
TEST(test_ranges_equal_to_mixed_types)
{
etl::ranges::equal_to eq;
// int vs long
CHECK(eq(1, 1L));
CHECK(!eq(1, 2L));
CHECK(eq(2L, 2));
// int vs short
CHECK(eq(42, short(42)));
CHECK(!eq(42, short(43)));
}
//*************************************************************************
TEST(test_ranges_equal_to_constexpr)
{
constexpr etl::ranges::equal_to eq{};
constexpr bool result_equal = eq(5, 5);
constexpr bool result_not_equal = eq(5, 6);
CHECK(result_equal);
CHECK(!result_not_equal);
}
//*************************************************************************
TEST(test_ranges_less_same_type)
{
etl::ranges::less lt;
CHECK(lt(1, 2));
CHECK(!lt(2, 1));
CHECK(!lt(1, 1));
}
//*************************************************************************
TEST(test_ranges_less_mixed_types)
{
etl::ranges::less lt;
// int vs long
CHECK(lt(1, 2L));
CHECK(!lt(2, 1L));
CHECK(!lt(1, 1L));
CHECK(lt(1L, 2));
// int vs short
CHECK(lt(42, short(43)));
CHECK(!lt(42, short(42)));
CHECK(!lt(43, short(42)));
}
//*************************************************************************
TEST(test_ranges_less_constexpr)
{
constexpr etl::ranges::less lt{};
constexpr bool result_less = lt(5, 6);
constexpr bool result_not_less = lt(6, 5);
constexpr bool result_equal = lt(5, 5);
CHECK(result_less);
CHECK(!result_not_less);
CHECK(!result_equal);
}
#endif
}
}

View File

@ -481,4 +481,153 @@ SUITE(test_invoke)
CHECK_EQUAL(1, etl::invoke(&RR::f, etl::move(rr)));
CHECK_EQUAL(2, etl::invoke(&RR::g, rr));
}
//*************************************************************************
// Tests for reference_wrapper as callable (first argument)
//*************************************************************************
//*************************************************************************
TEST(test_reference_wrapper_free_function)
{
// reference_wrapper wrapping a function (decays to function pointer)
auto ref_fn = etl::ref(free_add);
CHECK_EQUAL(3, etl::invoke(ref_fn, 1, 2));
}
//*************************************************************************
TEST(test_reference_wrapper_functor)
{
Functor functor(10);
auto ref_functor = etl::ref(functor);
CHECK_EQUAL(12, etl::invoke(ref_functor, 2));
}
//*************************************************************************
TEST(test_reference_wrapper_const_functor)
{
const ConstFunctor functor(10);
auto ref_functor = etl::cref(functor);
CHECK_EQUAL(12, etl::invoke(ref_functor, 2));
}
//*************************************************************************
TEST(test_reference_wrapper_lambda)
{
int capture_value = 5;
auto lambda = [capture_value](int a) { return a + capture_value; };
auto ref_lambda = etl::ref(lambda);
CHECK_EQUAL(6, etl::invoke(ref_lambda, 1));
}
//*************************************************************************
TEST(test_reference_wrapper_nothrow_functor)
{
NoThrowFunctor nothrow_functor;
auto ref_functor = etl::ref(nothrow_functor);
CHECK_EQUAL(12, etl::invoke(ref_functor, 10));
}
//*************************************************************************
TEST(test_reference_wrapper_throwing_functor)
{
ThrowingFunctor throwing_functor;
auto ref_functor = etl::ref(throwing_functor);
CHECK_THROW(etl::invoke(ref_functor, 10), int);
}
//*************************************************************************
TEST(test_reference_wrapper_member_function_pointer)
{
// reference_wrapper wrapping a pointer-to-member-function
auto pmf = &Base::add;
auto ref_pmf = etl::ref(pmf);
Base base(10);
CHECK_EQUAL(11, etl::invoke(ref_pmf, base, 1));
CHECK_EQUAL(12, etl::invoke(ref_pmf, &base, 2));
}
//*************************************************************************
TEST(test_reference_wrapper_const_member_function_pointer)
{
auto pmf = &Base::add_const;
auto ref_pmf = etl::ref(pmf);
const Base const_base(20);
CHECK_EQUAL(24, etl::invoke(ref_pmf, const_base, 3));
CHECK_EQUAL(25, etl::invoke(ref_pmf, &const_base, 4));
}
//*************************************************************************
TEST(test_reference_wrapper_member_object_pointer)
{
// reference_wrapper wrapping a pointer-to-member-data
auto pmd = &MemberObj::i;
auto ref_pmd = etl::ref(pmd);
MemberObj obj(42);
CHECK_EQUAL(42, etl::invoke(ref_pmd, obj));
CHECK_EQUAL(42, etl::invoke(ref_pmd, &obj));
}
//*************************************************************************
TEST(test_reference_wrapper_derived_member_function)
{
// reference_wrapper wrapping member pointer, invoked on derived class
auto pmf = &Base::add;
auto ref_pmf = etl::ref(pmf);
Derived derived(10);
CHECK_EQUAL(11, etl::invoke(ref_pmf, derived, 1));
CHECK_EQUAL(12, etl::invoke(ref_pmf, &derived, 2));
}
#if ETL_USING_CPP14
//*************************************************************************
TEST(test_reference_wrapper_identity)
{
// This is the case that triggered the original compile error:
// reference_wrapper<etl::identity> as a callable
etl::identity id;
auto ref_id = etl::ref(id);
CHECK_EQUAL(42, etl::invoke(ref_id, 42));
CHECK_EQUAL(7, etl::invoke(ref_id, 7));
}
#endif
//*************************************************************************
TEST(test_reference_wrapper_with_reference_wrapper_arg)
{
// reference_wrapper as both callable and second argument (member pointer case)
auto pmf = &Base::add;
auto ref_pmf = etl::ref(pmf);
Base base(10);
auto ref_base = etl::ref(base);
CHECK_EQUAL(11, etl::invoke(ref_pmf, ref_base, 1));
}
//*************************************************************************
TEST(test_reference_wrapper_member_object_with_reference_wrapper_arg)
{
auto pmd = &MemberObj::i;
auto ref_pmd = etl::ref(pmd);
MemberObj obj(99);
auto ref_obj = etl::ref(obj);
CHECK_EQUAL(99, etl::invoke(ref_pmd, ref_obj));
}
}

View File

@ -32,6 +32,7 @@ SOFTWARE.
#include <list>
#include <queue>
#include <algorithm>
#include <vector>
#include "etl/iterator.h"
@ -70,6 +71,40 @@ namespace
typedef int* pointer;
typedef const int* const_pointer;
// A sentinel type for non_random_iterator, used to test the
// advance(i, n, bound) overload where I != S (different types).
template <typename T>
struct non_random_sentinel
{
non_random_sentinel() : ptr(nullptr) {}
non_random_sentinel(T* v) : ptr(v) {}
T* ptr;
};
template <typename T>
bool operator==(const non_random_iterator<T>& lhs, const non_random_sentinel<T>& rhs)
{
return lhs.ptr == rhs.ptr;
}
template <typename T>
bool operator!=(const non_random_iterator<T>& lhs, const non_random_sentinel<T>& rhs)
{
return lhs.ptr != rhs.ptr;
}
template <typename T>
bool operator==(const non_random_sentinel<T>& lhs, const non_random_iterator<T>& rhs)
{
return rhs == lhs;
}
template <typename T>
bool operator!=(const non_random_sentinel<T>& lhs, const non_random_iterator<T>& rhs)
{
return rhs != lhs;
}
const size_t SIZE = 10UL;
int dataA[SIZE] = { 2, 1, 4, 3, 6, 5, 8, 7, 10, 9 };
@ -580,5 +615,780 @@ namespace
// CHECK_EQUAL(expected.size(), output.size());
// CHECK(std::equal(output.begin(), output.end(), expected.begin()));
//}
#if ETL_USING_CPP17
//*************************************************************************
TEST(test_counted_iterator)
{
std::vector<int> v{1, 2, 3, 4};
etl::counted_iterator<std::vector<int>::iterator> ci0{};
CHECK_EQUAL(0, ci0.count());
etl::counted_iterator ci1{v.begin(), 3};
etl::counted_iterator ci2{v.begin(), 4};
CHECK_EQUAL(3, ci1.count());
CHECK_NOT_EQUAL(ci1.count(), ci2.count());
CHECK(!(ci1 == ci2));
ci2 = ci1;
CHECK_EQUAL(ci1.count(), ci2.count());
CHECK(ci1 == ci2);
CHECK(ci1.base() == v.begin());
CHECK(ci1.count() == 3);
ci1++;
CHECK(ci1.count() == 2);
++ci1;
CHECK(ci1.count() == 1);
ci1--;
CHECK(ci1.count() == 2);
--ci1;
CHECK(ci1.count() == 3);
ci1 += 2;
CHECK(ci1.count() == 1);
ci1 -= 2;
CHECK(ci1.count() == 3);
CHECK_EQUAL(ci1[0], 1);
CHECK_EQUAL(ci1[1], 2);
CHECK_EQUAL(ci1[2], 3);
auto ci3 = ci1 + 3;
CHECK(ci1.count() == 3);
CHECK_EQUAL(ci3.count(), 0);
auto ci4 = ci3 - 3;
CHECK(ci1.count() == 3);
CHECK_EQUAL(ci3.count(), 0);
CHECK(ci4.count() == 3);
}
//*************************************************************************
// etl::ranges::advance(i, n) with random access iterator
//*************************************************************************
TEST(ranges_advance_n_random_access_forward)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
etl::ranges::advance(itr, 4);
CHECK_EQUAL(4, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_random_access_backward)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[7];
etl::ranges::advance(itr, -3);
CHECK_EQUAL(4, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_random_access_zero)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
etl::ranges::advance(itr, 0);
CHECK_EQUAL(5, *itr);
}
//*************************************************************************
// etl::ranges::advance(i, n) with bidirectional (non-random) iterator
//*************************************************************************
TEST(ranges_advance_n_bidirectional_forward)
{
std::list<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto itr = data.begin();
etl::ranges::advance(itr, 4);
CHECK_EQUAL(4, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_bidirectional_backward)
{
std::list<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto itr = data.end();
etl::ranges::advance(itr, -3);
CHECK_EQUAL(7, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_bidirectional_zero)
{
std::list<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto itr = data.begin();
etl::ranges::advance(itr, 5);
etl::ranges::advance(itr, 0);
CHECK_EQUAL(5, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_non_random_iterator_forward)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
etl::ranges::advance(itr, 6);
CHECK_EQUAL(6, *itr);
}
//*************************************************************************
TEST(ranges_advance_n_non_random_iterator_backward)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[8]);
etl::ranges::advance(itr, -3);
CHECK_EQUAL(5, *itr);
}
//*************************************************************************
// etl::ranges::advance(i, bound) — advance to sentinel
//*************************************************************************
TEST(ranges_advance_to_bound_random_access)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[7];
etl::ranges::advance(itr, bound);
CHECK_EQUAL(7, *itr);
CHECK(itr == bound);
}
//*************************************************************************
TEST(ranges_advance_to_bound_bidirectional)
{
std::list<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto itr = data.begin();
auto bound = data.end();
etl::ranges::advance(itr, bound);
CHECK(itr == bound);
}
//*************************************************************************
TEST(ranges_advance_to_bound_non_random)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_iterator<int> bound(&data[5]);
etl::ranges::advance(itr, bound);
CHECK_EQUAL(5, *itr);
}
//*************************************************************************
TEST(ranges_advance_to_bound_already_at_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[3];
int* bound = &data[3];
etl::ranges::advance(itr, bound);
CHECK(itr == bound);
CHECK_EQUAL(3, *itr);
}
//*************************************************************************
// etl::ranges::advance(i, n, bound) — advance with bound, returns remainder
//*************************************************************************
TEST(ranges_advance_n_bound_random_access_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[9];
auto remaining = etl::ranges::advance(itr, 4, bound);
CHECK_EQUAL(4, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_random_access_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[3];
auto remaining = etl::ranges::advance(itr, 7, bound);
CHECK(itr == bound);
CHECK_EQUAL(3, *itr);
CHECK_EQUAL(4, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_random_access_exact_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[5];
auto remaining = etl::ranges::advance(itr, 5, bound);
CHECK(itr == bound);
CHECK_EQUAL(5, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_random_access_backward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[9];
int* bound = &data[0];
auto remaining = etl::ranges::advance(itr, -4, bound);
CHECK_EQUAL(5, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_random_access_backward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[2];
auto remaining = etl::ranges::advance(itr, -7, bound);
CHECK(itr == bound);
CHECK_EQUAL(2, *itr);
CHECK_EQUAL(-4, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_non_random_forward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_sentinel<int> bound(&data[9]);
auto remaining = etl::ranges::advance(itr, 4, bound);
CHECK_EQUAL(4, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_non_random_forward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_sentinel<int> bound(&data[3]);
auto remaining = etl::ranges::advance(itr, 7, bound);
CHECK_EQUAL(3, *itr);
CHECK_EQUAL(4, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_non_random_backward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[9]);
non_random_sentinel<int> bound(&data[0]);
auto remaining = etl::ranges::advance(itr, -3, bound);
CHECK_EQUAL(6, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_non_random_backward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[3]);
non_random_sentinel<int> bound(&data[1]);
auto remaining = etl::ranges::advance(itr, -7, bound);
CHECK_EQUAL(1, *itr);
CHECK_EQUAL(-5, remaining);
}
//*************************************************************************
TEST(ranges_advance_n_bound_zero_steps)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[8];
auto remaining = etl::ranges::advance(itr, 0, bound);
CHECK_EQUAL(5, *itr);
CHECK_EQUAL(0, remaining);
}
//*************************************************************************
// etl::ranges::prev(i) with random access iterator
//*************************************************************************
TEST(ranges_prev_random_access)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* result = etl::ranges::prev(itr);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(5, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i) with bidirectional (non-random) iterator
//*************************************************************************
TEST(ranges_prev_non_random)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[5]);
non_random_iterator<int> result = etl::ranges::prev(itr);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(5, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i, n) with random access iterator — positive n
//*************************************************************************
TEST(ranges_prev_n_random_access_positive)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[7];
int* result = etl::ranges::prev(itr, 3);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(7, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i, n) with random access iterator — zero n
//*************************************************************************
TEST(ranges_prev_n_random_access_zero)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* result = etl::ranges::prev(itr, 0);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::prev(i, n) with random access iterator — negative n (moves forward)
//*************************************************************************
TEST(ranges_prev_n_random_access_negative)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[3];
int* result = etl::ranges::prev(itr, -2);
CHECK_EQUAL(5, *result);
CHECK_EQUAL(3, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i, n) with bidirectional (non-random) iterator — positive n
//*************************************************************************
TEST(ranges_prev_n_non_random_positive)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[7]);
non_random_iterator<int> result = etl::ranges::prev(itr, 4);
CHECK_EQUAL(3, *result);
CHECK_EQUAL(7, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i, n) with bidirectional (non-random) iterator — zero n
//*************************************************************************
TEST(ranges_prev_n_non_random_zero)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[5]);
non_random_iterator<int> result = etl::ranges::prev(itr, 0);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::prev(i, n) with bidirectional (non-random) iterator — negative n (moves forward)
//*************************************************************************
TEST(ranges_prev_n_non_random_negative)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[3]);
non_random_iterator<int> result = etl::ranges::prev(itr, -2);
CHECK_EQUAL(5, *result);
CHECK_EQUAL(3, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::prev(i, n, bound) with random access iterator — not reaching bound
//*************************************************************************
TEST(ranges_prev_n_bound_random_access_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[8];
int* bound = &data[2];
int* result = etl::ranges::prev(itr, 4, bound);
CHECK_EQUAL(4, *result);
}
//*************************************************************************
// etl::ranges::prev(i, n, bound) with random access iterator — reaching bound
//*************************************************************************
TEST(ranges_prev_n_bound_random_access_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[3];
int* result = etl::ranges::prev(itr, 7, bound);
CHECK_EQUAL(3, *result);
CHECK(result == bound);
}
//*************************************************************************
// etl::ranges::prev(i, n, bound) with random access iterator — zero steps
//*************************************************************************
TEST(ranges_prev_n_bound_random_access_zero_steps)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[2];
int* result = etl::ranges::prev(itr, 0, bound);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::prev(i, n, bound) with bidirectional (non-random) iterator — not reaching bound
//*************************************************************************
TEST(ranges_prev_n_bound_non_random_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[8]);
non_random_iterator<int> bound(&data[2]);
non_random_iterator<int> result = etl::ranges::prev(itr, 3, bound);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::prev(i, n, bound) with bidirectional (non-random) iterator — reaching bound
//*************************************************************************
TEST(ranges_prev_n_bound_non_random_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[5]);
non_random_iterator<int> bound(&data[3]);
non_random_iterator<int> result = etl::ranges::prev(itr, 7, bound);
CHECK_EQUAL(3, *result);
CHECK(result.ptr == bound.ptr);
}
//*************************************************************************
// etl::ranges::next(i) with random access iterator
//*************************************************************************
TEST(ranges_next_random_access)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* result = etl::ranges::next(itr);
CHECK_EQUAL(6, *result);
CHECK_EQUAL(5, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i) with bidirectional (non-random) iterator
//*************************************************************************
TEST(ranges_next_non_random)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[5]);
non_random_iterator<int> result = etl::ranges::next(itr);
CHECK_EQUAL(6, *result);
CHECK_EQUAL(5, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, n) with random access iterator — positive n
//*************************************************************************
TEST(ranges_next_n_random_access_positive)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[2];
int* result = etl::ranges::next(itr, 5);
CHECK_EQUAL(7, *result);
CHECK_EQUAL(2, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, n) with random access iterator — zero n
//*************************************************************************
TEST(ranges_next_n_random_access_zero)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* result = etl::ranges::next(itr, 0);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::next(i, n) with random access iterator — negative n (moves backward)
//*************************************************************************
TEST(ranges_next_n_random_access_negative)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[7];
int* result = etl::ranges::next(itr, -3);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(7, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, n) with bidirectional (non-random) iterator — positive n
//*************************************************************************
TEST(ranges_next_n_non_random_positive)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[1]);
non_random_iterator<int> result = etl::ranges::next(itr, 4);
CHECK_EQUAL(5, *result);
CHECK_EQUAL(1, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, n) with bidirectional (non-random) iterator — zero n
//*************************************************************************
TEST(ranges_next_n_non_random_zero)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[5]);
non_random_iterator<int> result = etl::ranges::next(itr, 0);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::next(i, n) with bidirectional (non-random) iterator — negative n (moves backward)
//*************************************************************************
TEST(ranges_next_n_non_random_negative)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[7]);
non_random_iterator<int> result = etl::ranges::next(itr, -3);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(7, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, bound) with random access iterator
//*************************************************************************
TEST(ranges_next_bound_random_access)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[7];
int* result = etl::ranges::next(itr, bound);
CHECK_EQUAL(7, *result);
CHECK(result == bound);
CHECK_EQUAL(0, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, bound) with non-random iterator
//*************************************************************************
TEST(ranges_next_bound_non_random)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_sentinel<int> bound(&data[5]);
non_random_iterator<int> result = etl::ranges::next(itr, bound);
CHECK_EQUAL(5, *result);
CHECK_EQUAL(0, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, bound) already at bound
//*************************************************************************
TEST(ranges_next_bound_already_at_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[4];
int* bound = &data[4];
int* result = etl::ranges::next(itr, bound);
CHECK(result == bound);
CHECK_EQUAL(4, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — not reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_random_access_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[9];
int* result = etl::ranges::next(itr, 4, bound);
CHECK_EQUAL(4, *result);
CHECK_EQUAL(0, *itr); // original unchanged
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_random_access_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[3];
int* result = etl::ranges::next(itr, 7, bound);
CHECK(result == bound);
CHECK_EQUAL(3, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — exact bound
//*************************************************************************
TEST(ranges_next_n_bound_random_access_exact_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[0];
int* bound = &data[5];
int* result = etl::ranges::next(itr, 5, bound);
CHECK(result == bound);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — backward not reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_random_access_backward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[9];
int* bound = &data[0];
int* result = etl::ranges::next(itr, -4, bound);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — backward reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_random_access_backward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[2];
int* result = etl::ranges::next(itr, -7, bound);
CHECK(result == bound);
CHECK_EQUAL(2, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with random access iterator — zero steps
//*************************************************************************
TEST(ranges_next_n_bound_random_access_zero_steps)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* itr = &data[5];
int* bound = &data[8];
int* result = etl::ranges::next(itr, 0, bound);
CHECK_EQUAL(5, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with non-random iterator — forward not reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_non_random_forward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_sentinel<int> bound(&data[9]);
non_random_iterator<int> result = etl::ranges::next(itr, 4, bound);
CHECK_EQUAL(4, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with non-random iterator — forward reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_non_random_forward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[0]);
non_random_sentinel<int> bound(&data[3]);
non_random_iterator<int> result = etl::ranges::next(itr, 7, bound);
CHECK_EQUAL(3, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with non-random iterator — backward not reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_non_random_backward_not_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[9]);
non_random_sentinel<int> bound(&data[0]);
non_random_iterator<int> result = etl::ranges::next(itr, -3, bound);
CHECK_EQUAL(6, *result);
}
//*************************************************************************
// etl::ranges::next(i, n, bound) with non-random iterator — backward reaching bound
//*************************************************************************
TEST(ranges_next_n_bound_non_random_backward_reaching_bound)
{
int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
non_random_iterator<int> itr(&data[3]);
non_random_sentinel<int> bound(&data[1]);
non_random_iterator<int> result = etl::ranges::next(itr, -7, bound);
CHECK_EQUAL(1, *result);
}
TEST(test_is_range)
{
std::vector<int> vec;
int arr[3]{};
int i{};
static_assert(etl::is_range_v<decltype(vec)> == true, "Expected range");
static_assert(etl::is_range_v<decltype(arr)> == true, "Expected range");
static_assert(etl::is_range_v<decltype(i)> == false, "Expected non range");
}
#endif
}
}

View File

@ -71,12 +71,26 @@ SUITE(test_manchester)
}
#if ETL_USING_CPP14
constexpr etl::array<uint8_t, 8> manchester_encoded(etl::span<const uint_least8_t> decoded)
constexpr etl::array<uint8_t, 8> manchester_encoded_uint8(etl::span<const uint_least8_t> decoded)
{
etl::array<uint8_t, 8> encoded{0, 0, 0, 0, 0, 0, 0, 0};
etl::manchester::encode(decoded, encoded);
return encoded;
}
constexpr etl::array<uint8_t, 8> manchester_encoded_uint16(etl::span<const uint_least8_t> decoded)
{
etl::array<uint8_t, 8> encoded{0, 0, 0, 0, 0, 0, 0, 0};
etl::manchester::encode<uint16_t>(decoded, encoded);
return encoded;
}
constexpr etl::array<uint8_t, 8> manchester_encoded_uint32(etl::span<const uint_least8_t> decoded)
{
etl::array<uint8_t, 8> encoded{0, 0, 0, 0, 0, 0, 0, 0};
etl::manchester::encode<uint32_t>(decoded, encoded);
return encoded;
}
#endif
TEST(encode_span)
@ -105,18 +119,41 @@ SUITE(test_manchester)
CHECK_TRUE(encoded0 == encoded1);
CHECK_TRUE(encoded0 == encoded2);
CHECK_TRUE(encoded0 == encoded3);
}
#if ETL_USING_CPP14
static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed");
static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed");
#endif
TEST(encode_span_constexpr)
{
constexpr etl::array<const uint8_t, 4> decoded{0x00, 0xFF, 0x01, 0x80};
static_assert(manchester_encoded_uint8(decoded)[0] == 0xAA, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[1] == 0xAA, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[2] == 0x55, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[3] == 0x55, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[4] == 0xA9, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[5] == 0xAA, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[6] == 0xAA, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint8(decoded)[7] == 0x6A, "Compile time encoding with uint8_t failed");
static_assert(manchester_encoded_uint16(decoded)[0] == 0xAA, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[1] == 0xAA, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[2] == 0x55, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[3] == 0x55, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[4] == 0xA9, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[5] == 0xAA, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[6] == 0xAA, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint16(decoded)[7] == 0x6A, "Compile time encoding with uint16_t failed");
static_assert(manchester_encoded_uint32(decoded)[0] == 0xAA, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[1] == 0xAA, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[2] == 0x55, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[3] == 0x55, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[4] == 0xA9, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[5] == 0xAA, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[6] == 0xAA, "Compile time encoding with uint32_t failed");
static_assert(manchester_encoded_uint32(decoded)[7] == 0x6A, "Compile time encoding with uint32_t failed");
}
#endif
TEST(encode_span_inverted)
{
@ -233,12 +270,26 @@ SUITE(test_manchester)
}
#if ETL_USING_CPP14
constexpr etl::array<uint8_t, 4> manchester_decoded(etl::span<const uint_least8_t> encoded)
constexpr etl::array<uint8_t, 4> manchester_decoded_uint16(etl::span<const uint_least8_t> encoded)
{
etl::array<uint8_t, 4> decoded{0, 0, 0, 0};
etl::manchester::decode(encoded, decoded);
return decoded;
}
constexpr etl::array<uint8_t, 4> manchester_decoded_uint32(etl::span<const uint_least8_t> encoded)
{
etl::array<uint8_t, 4> decoded{0, 0, 0, 0};
etl::manchester::decode<uint32_t>(encoded, decoded);
return decoded;
}
constexpr etl::array<uint8_t, 4> manchester_decoded_uint64(etl::span<const uint_least8_t> encoded)
{
etl::array<uint8_t, 4> decoded{0, 0, 0, 0};
etl::manchester::decode<uint64_t>(encoded, decoded);
return decoded;
}
#endif
TEST(decode_span)
@ -260,18 +311,33 @@ SUITE(test_manchester)
CHECK_EQUAL(0x01, decoded0[2]);
CHECK_EQUAL(0x80, decoded0[3]);
#if ETL_USING_CPP14
static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed");
static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed");
static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed");
static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed");
#endif
CHECK_TRUE(decoded0 == decoded1);
CHECK_TRUE(decoded0 == decoded2);
CHECK_TRUE(decoded0 == decoded3);
}
#if ETL_USING_CPP14
TEST(decode_span_constexpr)
{
constexpr etl::array<const uint8_t, 8> encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAA, 0x6A};
static_assert(manchester_decoded_uint16(encoded)[0] == 0x00, "Compile time decoding with uint16_t failed");
static_assert(manchester_decoded_uint16(encoded)[1] == 0xFF, "Compile time decoding with uint16_t failed");
static_assert(manchester_decoded_uint16(encoded)[2] == 0x01, "Compile time decoding with uint16_t failed");
static_assert(manchester_decoded_uint16(encoded)[3] == 0x80, "Compile time decoding with uint16_t failed");
static_assert(manchester_decoded_uint32(encoded)[0] == 0x00, "Compile time decoding with uint32_t failed");
static_assert(manchester_decoded_uint32(encoded)[1] == 0xFF, "Compile time decoding with uint32_t failed");
static_assert(manchester_decoded_uint32(encoded)[2] == 0x01, "Compile time decoding with uint32_t failed");
static_assert(manchester_decoded_uint32(encoded)[3] == 0x80, "Compile time decoding with uint32_t failed");
static_assert(manchester_decoded_uint64(encoded)[0] == 0x00, "Compile time decoding with uint64_t failed");
static_assert(manchester_decoded_uint64(encoded)[1] == 0xFF, "Compile time decoding with uint64_t failed");
static_assert(manchester_decoded_uint64(encoded)[2] == 0x01, "Compile time decoding with uint64_t failed");
static_assert(manchester_decoded_uint64(encoded)[3] == 0x80, "Compile time decoding with uint64_t failed");
}
#endif
TEST(decode_span_inverted)
{
etl::array<const uint8_t, 8> encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0x55, 0x95};

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));

File diff suppressed because it is too large Load Diff

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
}
}

5516
test/test_ranges.cpp Normal file

File diff suppressed because it is too large Load Diff

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

@ -35,6 +35,7 @@ SOFTWARE.
#include <string>
#include <array>
#include <type_traits>
namespace
{
@ -486,6 +487,56 @@ namespace
CHECK_EQUAL(std::string("2"), d.value);
}
//*************************************************************************
TEST(test_construct_from_rvalue_pair_implicit_conversion)
{
ETL_OR_STD::pair<int, Data> p(1, Data("2"));
etl::tuple<int, Data> tp(etl::move(p));
int i = etl::get<0>(tp);
Data d = etl::get<1>(tp);
CHECK_EQUAL(1, i);
CHECK_EQUAL(std::string("2"), d.value);
}
//*************************************************************************
TEST(test_construct_from_rvalue_pair_explicit_conversion)
{
ETL_OR_STD::pair<From, From> p(From(1), From(2));
etl::tuple<To, To> tp(etl::move(p));
CHECK_EQUAL(1, etl::get<0>(tp).i);
CHECK_EQUAL(2, etl::get<1>(tp).i);
}
//*************************************************************************
TEST(test_construct_from_const_rvalue_pair_implicit_conversion)
{
const ETL_OR_STD::pair<int, Data> p(1, Data("2"));
etl::tuple<int, Data> tp(etl::move(p));
int i = etl::get<0>(tp);
Data d = etl::get<1>(tp);
CHECK_EQUAL(1, i);
CHECK_EQUAL(std::string("2"), d.value);
}
//*************************************************************************
TEST(test_construct_from_const_rvalue_pair_explicit_conversion)
{
const ETL_OR_STD::pair<From, From> p(From(1), From(2));
etl::tuple<To, To> tp(etl::move(p));
CHECK_EQUAL(1, etl::get<0>(tp).i);
CHECK_EQUAL(2, etl::get<1>(tp).i);
}
//*************************************************************************
ETL_NODISCARD bool Get()
{
@ -553,7 +604,7 @@ namespace
}
//*************************************************************************
TEST(test_tuple_cat)
TEST(test_tuple_cat_2)
{
etl::tuple<int, double> tp1{1, 2.3};
etl::tuple<int, Data> tp2{4, Data("Data", 5)};
@ -566,6 +617,46 @@ namespace
CHECK_EQUAL(etl::get<3>(tp3), etl::get<1>(tp2));
}
//*************************************************************************
TEST(test_tuple_cat_3)
{
etl::tuple<int, double> tp1{1, 2.3};
etl::tuple<int, Data> tp2{4, Data("Data", 5)};
etl::tuple<bool, int> tp3{true, 5};
auto tp4 = etl::tuple_cat(tp1, tp2, tp3);
static_assert(std::is_same<decltype(tp4), etl::tuple<int, double, int, Data, bool, int>>::value, "tp4 type mismatch");
CHECK_EQUAL(etl::get<0>(tp4), etl::get<0>(tp1));
CHECK_EQUAL(etl::get<1>(tp4), etl::get<1>(tp1));
CHECK_EQUAL(etl::get<2>(tp4), etl::get<0>(tp2));
CHECK_EQUAL(etl::get<3>(tp4), etl::get<1>(tp2));
CHECK_EQUAL(etl::get<4>(tp4), etl::get<0>(tp3));
CHECK_EQUAL(etl::get<5>(tp4), etl::get<1>(tp3));
}
//*************************************************************************
TEST(test_tuple_cat_4)
{
etl::tuple<int, double> tp1{1, 2.3};
etl::tuple<int, Data> tp2{4, Data("Data", 5)};
etl::tuple<bool, int> tp3{true, 5};
etl::tuple<double, int, bool> tp4{1.01, 6, false};
auto tp5 = etl::tuple_cat(tp1, tp2, tp3, tp4);
static_assert(std::is_same<decltype(tp5), etl::tuple<int, double, int, Data, bool, int, double, int, bool>>::value, "tp5 type mismatch");
CHECK_EQUAL(etl::get<0>(tp5), etl::get<0>(tp1));
CHECK_EQUAL(etl::get<1>(tp5), etl::get<1>(tp1));
CHECK_EQUAL(etl::get<2>(tp5), etl::get<0>(tp2));
CHECK_EQUAL(etl::get<3>(tp5), etl::get<1>(tp2));
CHECK_EQUAL(etl::get<4>(tp5), etl::get<0>(tp3));
CHECK_EQUAL(etl::get<5>(tp5), etl::get<1>(tp3));
CHECK_EQUAL(etl::get<6>(tp5), etl::get<0>(tp4));
CHECK_EQUAL(etl::get<7>(tp5), etl::get<1>(tp4));
CHECK_EQUAL(etl::get<8>(tp5), etl::get<2>(tp4));
}
//*************************************************************************
TEST(test_forward_as_tuple)
{
@ -831,7 +922,7 @@ namespace
etl::tuple<int, Data> tp(0, Data(""));
tp = static_cast<const ETL_OR_STD::pair<int, Data>&&>(p);
tp = etl::move(p);
int i = etl::get<0>(tp);
Data d = etl::get<1>(tp);

View File

@ -210,6 +210,8 @@ using etl::is_assignable;
using etl::is_constructible;
using etl::is_copy_constructible;
using etl::is_move_constructible;
using etl::is_copy_assignable;
using etl::is_move_assignable;
//*************************
template <>
@ -227,6 +229,16 @@ struct etl::is_move_constructible<Copyable> : public etl::false_type
{
};
template <>
struct etl::is_copy_assignable<Copyable> : public etl::true_type
{
};
template <>
struct etl::is_move_assignable<Copyable> : public etl::true_type
{
};
//*************************
template <>
struct etl::is_assignable<Moveable, Moveable> : public etl::true_type
@ -243,6 +255,16 @@ struct etl::is_move_constructible<Moveable> : public etl::true_type
{
};
template <>
struct etl::is_copy_assignable<Moveable> : public etl::false_type
{
};
template <>
struct etl::is_move_assignable<Moveable> : public etl::true_type
{
};
//*************************
template <>
struct etl::is_assignable<MoveableCopyable, MoveableCopyable> : public etl::true_type
@ -258,6 +280,16 @@ template <>
struct etl::is_move_constructible<MoveableCopyable> : public etl::true_type
{
};
template <>
struct etl::is_copy_assignable<MoveableCopyable> : public etl::true_type
{
};
template <>
struct etl::is_move_assignable<MoveableCopyable> : public etl::true_type
{
};
#endif
namespace
@ -1296,6 +1328,34 @@ namespace
#endif
}
//*************************************************************************
TEST(test_is_copy_assignable)
{
#if ETL_USING_CPP17
CHECK((etl::is_copy_assignable_v<Copyable>) == (std::is_copy_assignable_v<Copyable>));
CHECK((etl::is_copy_assignable_v<Moveable>) == (std::is_copy_assignable_v<Moveable>));
CHECK((etl::is_copy_assignable_v<MoveableCopyable>) == (std::is_copy_assignable_v<MoveableCopyable>));
#else
CHECK((etl::is_copy_assignable<Copyable>::value) == (std::is_copy_assignable<Copyable>::value));
CHECK((etl::is_copy_assignable<Moveable>::value) == (std::is_copy_assignable<Moveable>::value));
CHECK((etl::is_copy_assignable<MoveableCopyable>::value) == (std::is_copy_assignable<MoveableCopyable>::value));
#endif
}
//*************************************************************************
TEST(test_is_move_assignable)
{
#if ETL_USING_CPP17
CHECK((etl::is_move_assignable_v<Copyable>) == (std::is_move_assignable_v<Copyable>));
CHECK((etl::is_move_assignable_v<Moveable>) == (std::is_move_assignable_v<Moveable>));
CHECK((etl::is_move_assignable_v<MoveableCopyable>) == (std::is_move_assignable_v<MoveableCopyable>));
#else
CHECK((etl::is_move_assignable<Copyable>::value) == (std::is_move_assignable<Copyable>::value));
CHECK((etl::is_move_assignable<Moveable>::value) == (std::is_move_assignable<Moveable>::value));
CHECK((etl::is_move_assignable<MoveableCopyable>::value) == (std::is_move_assignable<MoveableCopyable>::value));
#endif
}
//*************************************************************************
TEST(test_is_trivially_constructible)
{

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

@ -513,6 +513,7 @@ namespace
}
//*************************************************************************
#include "etl/private/diagnostic_uninitialized_push.h"
TEST_FIXTURE(SetupFixture, test_front)
{
Compare_Data compare_data(initial_data.begin(), initial_data.end());
@ -523,8 +524,10 @@ namespace
Data emptyData;
CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds);
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
#include "etl/private/diagnostic_uninitialized_push.h"
TEST_FIXTURE(SetupFixture, test_front_const)
{
const Compare_Data compare_data(initial_data.begin(), initial_data.end());
@ -535,6 +538,7 @@ namespace
const Data emptyData;
CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds);
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_back)
@ -998,6 +1002,7 @@ namespace
}
//*************************************************************************
#include "etl/private/diagnostic_uninitialized_push.h"
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds)
{
const int INITIAL_VALUE = 0;
@ -1007,6 +1012,7 @@ namespace
CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE);, etl::vector_out_of_bounds);
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess)
@ -1062,6 +1068,7 @@ namespace
}
//*************************************************************************
#include "etl/private/diagnostic_uninitialized_push.h"
TEST_FIXTURE(SetupFixture, test_insert_position_range_out_of_bounds)
{
Data data;
@ -1069,6 +1076,7 @@ namespace
CHECK_THROW(data.insert(data2.end(), insert_data.cbegin(), insert_data.cend());, etl::vector_out_of_bounds);
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_range_excess)

View File

@ -1022,6 +1022,7 @@ namespace
}
//*************************************************************************
#include "etl/private/diagnostic_array_bounds_push.h"
TEST(test_emplace_out_of_range_before_begin)
{
DataNDC data;
@ -1032,6 +1033,7 @@ namespace
CHECK_THROW(data.emplace(it, INITIAL_VALUE), etl::vector_out_of_bounds);
}
#include "etl/private/diagnostic_pop.h"
//*************************************************************************
#include "etl/private/diagnostic_array_bounds_push.h"

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" />
@ -3641,6 +3642,7 @@
<ClInclude Include="..\..\include\etl\private\crc_parameters.h" />
<ClInclude Include="..\..\include\etl\private\delegate_cpp03.h" />
<ClInclude Include="..\..\include\etl\private\delegate_cpp11.h" />
<ClInclude Include="..\..\include\etl\private\ranges_mini_variant.h" />
<ClInclude Include="..\..\include\etl\private\to_string_helper.h" />
<ClInclude Include="..\..\include\etl\private\variant_legacy.h" />
<ClInclude Include="..\..\include\etl\private\variant_variadic.h" />
@ -3812,6 +3814,7 @@
<ClInclude Include="..\..\include\etl\queue.h" />
<ClInclude Include="..\..\include\etl\radix.h" />
<ClInclude Include="..\..\include\etl\random.h" />
<ClInclude Include="..\..\include\etl\ranges.h" />
<ClInclude Include="..\..\include\etl\reference_flat_map.h" />
<ClInclude Include="..\..\include\etl\reference_flat_multimap.h" />
<ClInclude Include="..\..\include\etl\reference_flat_multiset.h" />
@ -10362,6 +10365,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" />
@ -11345,6 +11349,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\test_ranges.cpp" />
<ClCompile Include="..\test_reference_flat_map.cpp" />
<ClCompile Include="..\test_reference_flat_multimap.cpp" />
<ClCompile Include="..\test_reference_flat_multiset.cpp" />

View File

@ -2381,6 +2381,9 @@
<ClCompile Include="..\test_random.cpp">
<Filter>Tests\Maths</Filter>
</ClCompile>
<ClCompile Include="..\test_ranges.cpp">
<Filter>Tests\Misc</Filter>
</ClCompile>
<ClCompile Include="..\test_error_handler.cpp">
<Filter>Tests\Errors</Filter>
</ClCompile>

View File

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