Merge branch 'development' into jhe/semaphores

This commit is contained in:
John Wellbelove 2026-08-31 20:32:11 +02:00 committed by GitHub
commit 6f0c02c397
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 5735 additions and 412 deletions

View File

@ -5,7 +5,7 @@
"build": {
"dockerfile": "../Dockerfile",
"args": {
"BASE_IMAGE_NAME": "silkeh/clang:18-bullseye",
"BASE_IMAGE_NAME": "silkeh/clang:18",
"DEBIAN_SNAPSHOT": "none"
},
"context": "../context"

View File

@ -5,7 +5,7 @@
"build": {
"dockerfile": "../Dockerfile",
"args": {
"BASE_IMAGE_NAME": "silkeh/clang:19-bullseye",
"BASE_IMAGE_NAME": "silkeh/clang:19",
"DEBIAN_SNAPSHOT": "none"
},
"context": "../context"

View File

@ -5,7 +5,7 @@
"build": {
"dockerfile": "../Dockerfile",
"args": {
"BASE_IMAGE_NAME": "silkeh/clang:20-bullseye",
"BASE_IMAGE_NAME": "silkeh/clang:20",
"DEBIAN_SNAPSHOT": "none"
},
"context": "../context"

View File

@ -5,7 +5,7 @@
"build": {
"dockerfile": "../Dockerfile",
"args": {
"BASE_IMAGE_NAME": "silkeh/clang:21-bullseye",
"BASE_IMAGE_NAME": "silkeh/clang:21",
"DEBIAN_SNAPSHOT": "none"
},
"context": "../context"

View File

@ -44,7 +44,7 @@ jobs:
- uses: actions/checkout@v6.0.3
- name: Build
run: bazel build //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL
run: bazel build //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL --//:etl_profile=//:no_profile
- name: Run tests
run: bazel test //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL --test_output=all
run: bazel test //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL --//:etl_profile=//:no_profile --test_output=all

View File

@ -50,7 +50,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -79,7 +78,6 @@ jobs:
export CXX=clang++
export CXXFLAGS="-stdlib=libc++"
export LDFLAGS="-stdlib=libc++"
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -101,7 +99,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -50,7 +50,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -79,7 +78,6 @@ jobs:
export CXX=clang++
export CXXFLAGS="-stdlib=libc++"
export LDFLAGS="-stdlib=libc++"
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -101,7 +99,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -50,7 +50,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -79,7 +78,6 @@ jobs:
export CXX=clang++
export CXXFLAGS="-stdlib=libc++"
export LDFLAGS="-stdlib=libc++"
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -101,7 +99,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -62,7 +62,6 @@ jobs:
export CXX=clang++-17
export CXXFLAGS="-stdlib=libc++"
export LDFLAGS="-stdlib=libc++"
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
clang-17 --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -91,7 +90,6 @@ jobs:
run: |
export CC=clang-17
export CXX=clang++-17
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
clang-17 --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -120,7 +118,6 @@ jobs:
run: |
export CC=clang-17
export CXX=clang++-17
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./
clang-17 --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -149,7 +146,6 @@ jobs:
run: |
export CC=clang-17
export CXX=clang++-17
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./
clang-17 --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -171,7 +167,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -193,7 +188,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -215,7 +209,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -237,7 +230,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -57,12 +57,19 @@ jobs:
export CXX=clang++
export CXXFLAGS="-stdlib=libc++"
export LDFLAGS="-stdlib=libc++"
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
- name: Run tests
# The system libc++/libc++abi are not built with ASan. Exception objects
# (e.g. std::runtime_error's reference counted string) are allocated with
# operator new inside libc++.so, but released with free() inside
# libc++abi.so, which AddressSanitizer reports as an alloc-dealloc-mismatch.
# This is a libc++ packaging issue, not an ETL defect, so the check is
# disabled for this job only.
env:
ASAN_OPTIONS: alloc_dealloc_mismatch=0
run: ./test/etl_tests -v
build-clang-cpp23-linux-no-stl:
@ -79,8 +86,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -101,8 +107,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -123,8 +128,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -145,8 +149,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -167,8 +170,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -189,8 +191,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -211,8 +212,7 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 -DETL_ENABLE_SANITIZER=ON ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -55,7 +55,6 @@ jobs:
export CXX=clang++ && \
export CXXFLAGS=-stdlib=libc++ && \
export LDFLAGS=-stdlib=libc++ && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \
clang --version && \
make -j \$(getconf _NPROCESSORS_ONLN) && \
@ -77,7 +76,6 @@ jobs:
cd /workspaces/etl && \
export CC=clang && \
export CXX=clang++ && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \
clang --version && \
make -j \$(getconf _NPROCESSORS_ONLN) && \
@ -99,7 +97,6 @@ jobs:
cd /workspaces/etl && \
export CC=clang && \
export CXX=clang++ && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \
clang --version && \
make -j \$(getconf _NPROCESSORS_ONLN) && \
@ -121,7 +118,6 @@ jobs:
cd /workspaces/etl && \
export CC=clang && \
export CXX=clang++ && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \
clang --version && \
make -j \$(getconf _NPROCESSORS_ONLN) && \
@ -143,7 +139,6 @@ jobs:
cd /workspaces/etl && \
export CC=clang && \
export CXX=clang++ && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \
clang --version && \
make -j \$(getconf _NPROCESSORS_ONLN) && \
@ -163,7 +158,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -185,7 +179,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -207,7 +200,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"
@ -229,7 +221,6 @@ jobs:
run: |
export CC=clang
export CXX=clang++
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./
clang --version
make -j "$(getconf _NPROCESSORS_ONLN)"

View File

@ -49,7 +49,6 @@ jobs:
- name: Build
run: |
git fetch
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./
@ -72,7 +71,6 @@ jobs:
- name: Build
run: |
git fetch
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./

View File

@ -48,7 +48,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./
@ -70,7 +69,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./

View File

@ -48,7 +48,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./
@ -70,7 +69,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./

View File

@ -48,7 +48,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
@ -70,7 +69,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
@ -92,7 +90,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./
@ -114,7 +111,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc
export CXX=g++
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./

View File

@ -48,7 +48,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc-14
export CXX=g++-14
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
@ -70,7 +69,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc-14
export CXX=g++-14
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
@ -92,7 +90,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc-14
export CXX=g++-14
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./
@ -114,7 +111,6 @@ jobs:
- name: Build
run: |
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0
export CC=gcc-14
export CXX=g++-14
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./

View File

@ -50,7 +50,6 @@ jobs:
run: |
docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\
cd /workspaces/etl && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
export CC=gcc && \
export CXX=g++ && \
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \
@ -72,7 +71,6 @@ jobs:
run: |
docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\
cd /workspaces/etl && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
export CC=gcc && \
export CXX=g++ && \
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \
@ -94,7 +92,6 @@ jobs:
run: |
docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\
cd /workspaces/etl && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
export CC=gcc && \
export CXX=g++ && \
cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \
@ -116,7 +113,6 @@ jobs:
run: |
docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\
cd /workspaces/etl && \
export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \
export CC=gcc && \
export CXX=g++ && \
cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \

View File

@ -20,14 +20,23 @@ package(default_visibility = ["//visibility:public"])
# strip_include_prefix = ".",
# )
#
# The default is empty, so ETL's built-in defaults are used unless overridden.
# The default of this label_flag is incompatible. This makes sure that the consumer
# explicitly sets a profile, even if it is the `no_profile` defined below.
label_flag(
name = "etl_profile",
build_setting_default = ":no_profile",
build_setting_default = ":incompatible_profile",
)
cc_library(name = "no_profile")
cc_library(
name = "incompatible_profile",
target_compatible_with = [
"@platforms//:incompatible",
],
)
cc_library(
name = "etl",
hdrs = glob(["include/**/*.h"]),

View File

@ -38,13 +38,23 @@ Defines data as an array of 'int', of length '10', containing the supplied data.
**C++11 and above**
```cpp
template <typename T, typename... TValues>
constexpr auto make_array(TValues&&... values) -> etl::array<T, sizeof...(TValues)>
template <typename T = void, typename... TValues>
constexpr auto make_array(TValues&&... values) -> etl::array</*element-type*/, sizeof...(TValues)>
```
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design). An empty
array requires the element type to be supplied explicitly, e.g.
`etl::make_array<int>()`; a call with neither an element type nor arguments
is ill-formed, as there is nothing to deduce the element type from.
### Example
```cpp
auto data = etl::make_array<int>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Deduced element type: etl::array<int, 10>.
auto data = etl::make_array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::array<char, 10>. Each argument is converted.
auto chars = etl::make_array<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types

View File

@ -65,15 +65,20 @@ Defines data as an `forward_list` of int, of length 10, containing the supplied
## Make template
**C++11 and above**
```cpp
template <typename... T>
constexpr auto make_forward_list(T&&... t) -> etl::forward_list<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto make_forward_list(TValues&&... values) -> etl::forward_list</*element-type*/, sizeof...(TValues)>
```
The element type is deduced as the common type of the arguments.
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design).
### Example
```cpp
// Deduced element type: etl::forward_list<int, 10>.
auto data = etl::make_forward_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::forward_list<char, 10>. Each argument is converted.
auto chars = etl::make_forward_list<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types

View File

@ -8,7 +8,7 @@ weight: 4
Similar to: `std::forward_list`
{{< /callout >}}
An intrusive forward list.https://www.messenger.com/t/837634551/
An intrusive forward list.
```cpp
template <typename TValue, typename TLink>

View File

@ -69,15 +69,20 @@ Defines data as an list of `int`, of length `10`, containing the supplied data.
## Make template
**C++11 and above**
```cpp
template <typename... T>
constexpr auto make_list(T&&... t) -> etl::list<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto make_list(TValues&&... values) -> etl::list</*element-type*/, sizeof...(TValues)>
```
The element type is deduced as the common type of the arguments.
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design).
### Example
```cpp
// Deduced element type: etl::list<int, 10>.
auto data = etl::make_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::list<char, 10>. Each argument is converted.
auto chars = etl::make_list<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types

View File

@ -239,7 +239,7 @@ The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
```cpp
pair<iterator, bool> emplace((const value_type& value))
pair<iterator, bool> emplace(const value_type& value)
pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
```
**Description**

View File

@ -239,7 +239,7 @@ The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
```cpp
pair<iterator, bool> emplace((const value_type& value))
pair<iterator, bool> emplace(const value_type& value)
pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
```
**Description**

View File

@ -69,11 +69,19 @@ const_reverse_iterator reverse_iterator<const_iterator>
```cpp
circular_buffer<typename T, size_t SIZE>();
circular_buffer<typename T, size_t SIZE>(size_t initial_size);
circular_buffer<typename T, size_t SIZE>(size_t initial_size, const_reference value);
circular_buffer<typename T, size_t SIZE>(const etl::circular_buffer<typename T, size_t SIZE>& other);
circular_buffer<typename T, size_t SIZE>(etl::circular_buffer<typename T, size_t SIZE>&& other);
```
The `initial_size` constructor fills the buffer with default-constructed values.
The `initial_size` and `value` constructor fills the buffer with copies of `value`.
If `initial_size` exceeds `SIZE`, the buffer is filled to its capacity.
---
```cpp
@ -81,6 +89,10 @@ circular_buffer_ext(void* buffer, size_t max_size)
circular_buffer_ext(size_t max_size) 20.32.1
circular_buffer_ext(size_t initial_size, void* buffer, size_t max_size)
circular_buffer_ext(size_t initial_size, const_reference value, void* buffer, size_t max_size)
template <typename TIterator>
circular_buffer_ext(TIterator first, const TIterator& last, void* buffer, size_t max_size)
@ -89,6 +101,10 @@ circular_buffer_ext(std::initializer_list<T> init, void* buffer, size_t max_size
circular_buffer_ext(const circular_buffer_ext& other, void* buffer, size_t max_size)
```
The `initial_size` constructor fills the buffer with default-constructed values.
The `initial_size` and `value` constructor fills the buffer with copies of `value`.
If `initial_size` exceeds `max_size`, the buffer is filled to its capacity. The external storage must contain at least `max_size + 1` elements.
## Status
```cpp
@ -225,6 +241,26 @@ Returns the remaining available capacity in the `circular_buffer`.
## Modifiers
```cpp
void assign(iterator first, const iterator& last)
void assign(const_iterator first, const const_iterator& last)
template <typename TIterator>
void assign(TIterator first, const TIterator& last)
```
**Description**
Replaces the contents of the circular buffer with the elements in the range `[first, last)`. If the range exceeds the capacity, only the last `capacity()` elements are retained. The range may refer to the circular buffer being assigned.
---
```cpp
void assign(size_type n, const_reference value)
```
**Description**
Replaces the contents of the circular buffer with `n` copies of `value`. If `n` exceeds the capacity, the buffer is filled to its capacity. `value` may refer to an element in the circular buffer being assigned.
---
```cpp
void set_buffer(void* buffer)
```

View File

@ -34,13 +34,20 @@ Defines data as an `deque` of `int`, of length `10`, containing the supplied dat
## Make template
**C++11 and above**
```cpp
template <typename T, typename... TValues>
constexpr auto make_deque(TValues&&... values) -> etl::deque<T, sizeof...(TValues)>
template <typename T = void, typename... TValues>
constexpr auto make_deque(TValues&&... values) -> etl::deque</*element-type*/, sizeof...(TValues)>
```
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design).
### Example
```cpp
auto data = etl::make_deque<int>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Deduced element type: etl::deque<int, 10>.
auto data = etl::make_deque(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::deque<char, 10>. Each argument is converted.
auto chars = etl::make_deque<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types

View File

@ -333,4 +333,4 @@ operator >=
## Technical stuff
The const set is implemented as a sorted array key/value pairs.
The const set is implemented as a sorted array of values.

View File

@ -333,4 +333,4 @@ operator >=
## Technical stuff
The const set is implemented as a sorted array key/value pairs.
The const set is implemented as a sorted array of values.

View File

@ -235,55 +235,60 @@ The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
```cpp
pair<iterator, bool> emplace((const_reference value))
pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
pair<iterator, bool> emplace(const_reference value)
```
**Description**
Inserts key/value pairs into the set by constructing directly into storage.
Inserts a value into the set by constructing directly into storage.
The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
**C++03**
The emplace functions differ from that of std::set in that, due to C++03 not supporting 'perfect forwarding'.
The emplace functions differ from that of std::multiset in that, due to C++03 not supporting 'perfect forwarding'.
```cpp
pair<iterator, bool> emplace()
```
**Description**
Emplaces a default constructed value into the set.
```cpp
template <typename T1>
pair<iterator, bool> emplace(const key_type& key, const T1& value1)
pair<iterator, bool> emplace(const T1& value1)
```
**Description**
Emplaces a value constructed from `key` and 1 argument into the set.
Emplaces a value constructed from 1 argument into the set.
```cpp
template <typename T1, typename T2>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2)
pair<iterator, bool> emplace(const T1& value1, const T2& value2)
```
**Description**
Emplaces a value constructed from `key` and 2 arguments into the set.
Emplaces a value constructed from 2 arguments into the set.
```cpp
template <typename T1, typename T2, typename T3>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2, const T3& value3)
pair<iterator, bool> emplace(const T1& value1, const T2& value2, const T3& value3)
```
**Description**
Emplaces a value constructed from `key` and 3 arguments into the set.
Emplaces a value constructed from 3 arguments into the set.
```cpp
template <typename T1, typename T2, typename T3, typename T4>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
pair<iterator, bool> emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
```
**Description**
Emplaces a value constructed from `key` and 4 arguments into the set.
Emplaces a value constructed from 4 arguments into the set.
---
**C++11**
```cpp
template <typename ... Args>
pair<iterator, bool> emplace(const key_type& key, Args&& ... args)
pair<iterator, bool> emplace(Args&& ... args)
```
**Description**
Emplaces a value constructed from the `key` and arguments into the set.
Emplaces a value constructed from the arguments into the set.
---
@ -493,9 +498,9 @@ operator !=
## Technical stuff
Flat maps are usually implemented internally as a sorted vector of key/value pairs. Whilst this makes searching fast, it can have a detrimental effect when items are inserted into a container that stores complex, non-trivial keys or values.
Flat sets are usually implemented internally as a sorted vector of values. Whilst this makes searching fast, it can have a detrimental effect when items are inserted into a container that stores complex, non-trivial values.
As inserting requires that all of the items to the right of the insert position must be shifted this can become an expensive operation for larger containers.
To improve insertion performance ETL flat maps are implemented as vectors of pointers to key/value pairs, sorted by key value. An insertion will involve a copy of a range of pointers; an operation that can be very fast.
To improve insertion performance ETL flat sets are implemented as vectors of pointers to values, sorted by value. An insertion will involve a copy of a range of pointers; an operation that can be very fast.
The downside is that access to an item via an iterator will involve one indirection and the overhead of the container will be one pointer per item. A normal flat set implementation does not have this overhead.

View File

@ -235,11 +235,10 @@ The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
```cpp
pair<iterator, bool> emplace((const_reference value))
pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
pair<iterator, bool> emplace(const_reference value)
```
**Description**
Inserts key/value pairs into the set by constructing directly into storage.
Inserts a value into the set by constructing directly into storage.
The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
---
@ -248,39 +247,48 @@ The return type is either `std::pair` (default) or `etl::pair` (`ETL_NO_STL`)
The emplace functions differ from that of `std::set` due to C++03 not supporting 'perfect forwarding'.
```cpp
template <typename T1>
pair<iterator, bool> emplace(const key_type& key, const T1& value1)
pair<iterator, bool> emplace()
```
**Description**
Emplaces a value constructed from `key` and 1 argument into the set.
Emplaces a default constructed value into the set.
---
```cpp
template <typename T1>
pair<iterator, bool> emplace(const T1& value1)
```
**Description**
Emplaces a value constructed from 1 argument into the set.
---
```cpp
template <typename T1, typename T2>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2)
pair<iterator, bool> emplace(const T1& value1, const T2& value2)
```
**Description**
Emplaces a value constructed from `key` and 2 arguments into the set.
Emplaces a value constructed from 2 arguments into the set.
---
```cpp
template <typename T1, typename T2, typename T3>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2, const T3& value3)
pair<iterator, bool> emplace(const T1& value1, const T2& value2, const T3& value3)
```
**Description**
Emplaces a value constructed from `key` and 3 arguments into the set.
Emplaces a value constructed from 3 arguments into the set.
---
```cpp
template <typename T1, typename T2, typename T3, typename T4>
pair<iterator, bool> emplace(const key_type& key, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
pair<iterator, bool> emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
```
**Description**
Emplaces a value constructed from `key` and 4 arguments into the set.
Emplaces a value constructed from 4 arguments into the set.
---
@ -288,10 +296,10 @@ Emplaces a value constructed from `key` and 4 arguments into the set.
```cpp
template <typename ... Args>
pair<iterator, bool> emplace(const key_type& key, Args&& ... args)
pair<iterator, bool> emplace(Args&& ... args)
```
**Description**
Emplaces a value constructed from the `key` and arguments into the set.
Emplaces a value constructed from the arguments into the set.
---
@ -509,9 +517,9 @@ operator !=
## Technical stuff
Flat maps are usually implemented internally as a sorted vector of key/value pairs. Whilst this makes searching fast, it can have a detrimental effect when items are inserted into a container that stores complex, non-trivial keys or values.
Flat sets are usually implemented internally as a sorted vector of values. Whilst this makes searching fast, it can have a detrimental effect when items are inserted into a container that stores complex, non-trivial values.
As inserting requires that all of the items to the right of the insert position must be shifted this can become an expensive operation for larger containers.
To improve insertion performance ETL flat maps are implemented as vectors of pointers to key/value pairs, sorted by key value. An insertion will involve a copy of a range of pointers; an operation that can be very fast.
To improve insertion performance ETL flat sets are implemented as vectors of pointers to values, sorted by value. An insertion will involve a copy of a range of pointers; an operation that can be very fast.
The downside is that access to an item via an iterator will involve one indirection and the overhead of the container will be one pointer per item. A normal flat set implementation does not have this overhead.

View File

@ -42,6 +42,26 @@ etl::indirect_vector data{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
```
Defines data as an `indirect_vector` of `int`, of length `10`, containing the supplied data.
## Make template
**C++11 and above**
```cpp
template <typename T = void, typename... TValues>
constexpr auto make_indirect_vector(TValues&&... values)
-> etl::indirect_vector</*element-type*/, sizeof...(TValues)>
```
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design).
### Example
```cpp
// Deduced element type: etl::indirect_vector<int, 10>.
auto data = etl::make_indirect_vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::indirect_vector<char, 10>. Each argument is converted.
auto chars = etl::make_indirect_vector<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types
```cpp

View File

@ -54,6 +54,25 @@ etl::vector data{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Defines data as an vector of int, of length 10, containing the supplied data.
## Make template
**C++11 and above**
```cpp
template <typename T = void, typename... TValues>
constexpr auto make_vector(TValues&&... values) -> etl::vector</*element-type*/, sizeof...(TValues)>
```
The element type is `T` when supplied, otherwise the decayed common type of
the arguments (the Library Fundamentals TS `make_array` design).
### Example
```cpp
// Deduced element type: etl::vector<int, 10>.
auto data = etl::make_vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Explicit element type: etl::vector<char, 10>. Each argument is converted.
auto chars = etl::make_vector<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```
## Member types
```cpp

View File

@ -133,6 +133,8 @@ ETL_CONSTEXPR17 typename std::iterator_traits<TIterator>::difference_type
distance(TIterator first, TIterator last)
```
See [Ranges](../../ranges/ranges) for the `etl::ranges` range access primitives, including `etl::ranges::distance`.
## iterator
A base class provided to simplify definitions of the required types for iterators.
https://en.cppreference.com/w/cpp/iterator/iterator

View File

@ -119,6 +119,63 @@ Output:
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.
## Range Access and Primitives
These are declared in the `etl::ranges` namespace in `iterator.h`, which is included by `ranges.h`.
### Range access
Function objects, equivalent to their `std::ranges` counterparts.
| Name | Description |
|---|---|
| `begin`, `end` | The iterator to the first element, and the sentinel. |
| `cbegin`, `cend` | The const iterator to the first element, and the const sentinel. |
| `rbegin`, `rend` | The reverse iterator to the last element in forward order, and the past-the-end reverse iterator. |
| `crbegin`, `crend` | The const reverse iterator to the last element in forward order, and the const past-the-end reverse iterator. |
| `size` | The number of elements, as a `size_t`. |
| `ssize` | The number of elements, as a `ptrdiff_t`. |
| `empty` | Whether the range has no elements. |
| `data`, `cdata` | A pointer to the first element. |
| `distance` | The number of elements between two iterators, or in a range. |
| `advance` | Advances an iterator by a given distance and/or to a bound. |
| `next`, `prev` | An iterator advanced forwards or backwards by a given distance and/or to a bound. |
`size` and `ssize` use the range's `size()` member if it has one; otherwise they count the elements by traversing the range, which requires at least a forward range.
#### distance
```cpp
// Iterator and sentinel of the same type.
template <typename I>
constexpr etl::iter_difference_t<I> distance(I first, I last)
// Iterator and sentinel of different types.
template <typename I, typename S>
constexpr etl::iter_difference_t<I> distance(I first, S last)
// Range.
template <typename R>
constexpr etl::iter_difference_t<etl::ranges::iterator_t<R>> distance(R&& r)
```
The range overload uses the range's `size()` member if it has one; otherwise it counts the elements by traversing from `begin()` to `end()`.
### Range primitives
Alias templates that give the associated types of a range.
| Name | Description |
|---|---|
| `iterator_t<R>` | The iterator type. |
| `const_iterator_t<R>` | The const iterator type. |
| `sentinel_t<R>` | The sentinel type. |
| `const_sentinel_t<R>` | The const sentinel type. |
| `range_size_t<R>` | The size type. |
| `range_difference_t<R>` | The difference type. |
| `range_value_t<R>` | The element value type. |
| `range_reference_t<R>` | The element reference type. |
## Supported Views
All views are in the `etl::ranges` namespace. Corresponding range adaptor objects are available in `etl::ranges::views`.

View File

@ -327,7 +327,7 @@ Inequality test for etl::to_arithmetic_result
```cpp
template <typename T, typename U>
ETL_CONSTEXPR14 bool operator !=(const T& lhs,
const etl::to_arithmetic_result<T>& rhs)
const etl::to_arithmetic_result<U>& rhs)
```
Inequality test for etl::to_arithmetic_result

View File

@ -32,6 +32,28 @@ Not all traits have been defined as some rely on compiler intrinsics that are no
`is_compound`
`is_array`
`is_pointer`
`is_null_pointer`
`is_scalar`
`is_union`
`is_empty`
`is_polymorphic`
`is_abstract`
`is_final`
`is_aggregate`
`is_trivial`
`is_standard_layout`
`is_layout_compatible`
`is_pointer_interconvertible_base_of`
`is_destructible`
`is_nothrow_destructible`
`has_virtual_destructor`
`has_unique_object_representations`
`is_bounded_array`
`is_unbounded_array`
`is_swappable`
`is_swappable_with`
`is_nothrow_swappable`
`is_nothrow_swappable_with`
`is_reference`
`is_base_of`
`make_signed`
@ -52,6 +74,7 @@ Not all traits have been defined as some rely on compiler intrinsics that are no
`declvar` `20.28.0`
`common_type`
`is_enum` `20.30.0`
`is_scoped_enum` `20.50.0`
`underlying_type` `20.42.0`
&emsp;Unless the ETL is set to use builtins, the user must specialise the template for their enumerations.
@ -67,8 +90,12 @@ The following will be defined according to the C++ standard and user defined mac
`is_move_constructible`
`is_trivially_constructible`
`is_trivially_copy_constructible`
`is_trivially_default_constructible`
`is_trivially_move_constructible`
`is_trivially_destructible`
`is_trivially_assignable`
`is_trivially_copy_assignable`
`is_trivially_move_assignable`
`is_trivially_copyable`
## Scenario 1
@ -476,3 +503,499 @@ template <typename T>
inline constexpr bool is_object_pointer_v = etl::is_object_pointer<T>::value;
```
C++17
## is_pod
From: `20.49.0`
```cpp
template <typename T>
struct is_pod
```
Checks if `T` is a POD (Plain Old Data) type.
The result is found in the member `value`.
&emsp;When using the STL, this is defined as `is_standard_layout<T> && is_trivially_default_constructible<T> && is_trivially_copyable<T>`.
&emsp;When not using the STL, this is conservatively defined as `is_fundamental<T> || is_pointer<T>`.
```cpp
template <typename T>
inline constexpr bool is_pod_v = etl::is_pod<T>::value;
```
C++17
## is_standard_layout
From: `20.49.0`
```cpp
template <typename T>
struct is_standard_layout
```
Checks if `T` is a standard-layout type.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_standard_layout_v = etl::is_standard_layout<T>::value;
```
C++17
## is_trivial
From: `20.49.0`
```cpp
template <typename T>
struct is_trivial
```
Checks if `T` is a trivial type; i.e. it is trivially copyable and has one or more
default constructors, all of which are trivial.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_trivial_v = etl::is_trivial<T>::value;
```
C++17
**Note:** When not using the STL, this trait requires compiler support (the `__is_trivial` intrinsic).
If that is not available then the trait is not defined, as there is no portable way of
determining whether a type is trivial.
## is_bounded_array
From: `20.49.0`
```cpp
template <typename T>
struct is_bounded_array
```
Checks if `T` is an array type of known bound.
`T[N]` returns `true`, `T[]` and all other types return `false`.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_bounded_array_v = etl::is_bounded_array<T>::value;
```
C++17
## is_unbounded_array
From: `20.49.0`
```cpp
template <typename T>
struct is_unbounded_array
```
Checks if `T` is an array type of unknown bound.
`T[]` returns `true`, `T[N]` and all other types return `false`.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_unbounded_array_v = etl::is_unbounded_array<T>::value;
```
C++17
## is_destructible
From: `20.49.0`
```cpp
template <typename T>
struct is_destructible
```
Checks if `T` is a destructible type; that is, an object type whose destructor is not deleted and is accessible, a reference type, or an array of a destructible type.
Incomplete types, `void`, function types and arrays of unknown bound are not destructible.
The result is found in the member `value`.
&emsp;When not using the STL, the trait is detected by checking whether `declval<T&>().~T()` is a valid expression.
&emsp;Requires either compiler support or C++11. When neither is available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_destructible_v = etl::is_destructible<T>::value;
```
C++17
## is_nothrow_destructible
From: `20.49.0`
```cpp
template <typename T>
struct is_nothrow_destructible
```
Checks if `T` is a destructible type whose destructor is known not to throw.
Types that are not destructible are not nothrow destructible.
The result is found in the member `value`.
&emsp;When not using the STL, the trait is detected by checking `noexcept(declval<T&>().~T())` for destructible types.
&emsp;Requires either compiler support or C++11. When neither is available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_nothrow_destructible_v = etl::is_nothrow_destructible<T>::value;
```
C++17
## is_swappable
From: `20.49.0`
```cpp
template <typename T>
struct is_swappable
```
Checks if `T` is a referenceable type and lvalues of type `T` can be swapped by an unqualified call to `swap`.
The result is found in the member `value`.
&emsp;When using the STL and C++17, this is defined as `std::is_swappable<T>`.
&emsp;Otherwise the trait checks whether `swap(declval<T&>(), declval<T&>())` is a valid expression, where the `swap` considered is `etl::swap`, `std::swap` if it is available, and any `swap` found by argument dependent lookup.
&emsp;Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined.
&emsp;Note that when using the STL with C++11 or C++14, the accuracy of this trait depends on `std::swap` being constrained by the standard library implementation. Standard libraries that only constrain `std::swap` from C++17 will cause this trait to report `true` for types that cannot actually be swapped.
```cpp
template <typename T>
inline constexpr bool is_swappable_v = etl::is_swappable<T>::value;
```
C++17
## is_swappable_with
From: `20.49.0`
```cpp
template <typename T, typename U>
struct is_swappable_with
```
Checks if expressions of type `T` and `U` can be swapped by unqualified calls to `swap`, in both directions.
The result is found in the member `value`.
&emsp;When using the STL and C++17, this is defined as `std::is_swappable_with<T, U>`.
&emsp;Otherwise the trait checks whether both `swap(declval<T>(), declval<U>())` and `swap(declval<U>(), declval<T>())` are valid expressions, where the `swap` considered is `etl::swap`, `std::swap` if it is available, and any `swap` found by argument dependent lookup.
&emsp;Note that, unlike `is_swappable`, no references are added to `T` and `U`, so the value categories of the arguments are those of `T` and `U`. `is_swappable_with<int, int>::value` is `false`, whereas `is_swappable_with<int&, int&>::value` is `true`.
&emsp;Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined.
&emsp;Note that when using the STL with C++11 or C++14, the accuracy of this trait depends on `std::swap` being constrained by the standard library implementation. Standard libraries that only constrain `std::swap` from C++17 will cause this trait to report `true` for types that cannot actually be swapped.
```cpp
template <typename T, typename U>
inline constexpr bool is_swappable_with_v = etl::is_swappable_with<T, U>::value;
```
C++17
## is_nothrow_swappable
From: `20.49.0`
```cpp
template <typename T>
struct is_nothrow_swappable
```
Checks if `T` is a referenceable type and lvalues of type `T` can be swapped by an unqualified call to `swap`, and that the swap cannot throw.
The result is found in the member `value`.
&emsp;When using the STL and C++17, this is defined as `std::is_nothrow_swappable<T>`.
&emsp;Otherwise the trait checks that `etl::is_swappable<T>::value` is `true` and that `swap(declval<T&>(), declval<T&>())` is `noexcept`.
&emsp;Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined.
&emsp;Note that when neither the STL nor the type traits builtins are available, `etl::is_nothrow_move_constructible` and `etl::is_nothrow_move_assignable` are conservatively `false` for class types, so `etl::swap` is not `noexcept` for them and this trait is conservatively `false` too.
```cpp
template <typename T>
inline constexpr bool is_nothrow_swappable_v = etl::is_nothrow_swappable<T>::value;
```
C++17
## is_nothrow_swappable_with
From: `20.49.0`
```cpp
template <typename T, typename U>
struct is_nothrow_swappable_with
```
Checks if expressions of type `T` and `U` can be swapped by unqualified calls to `swap`, in both directions, and that neither swap can throw.
The result is found in the member `value`.
&emsp;When using the STL and C++17, this is defined as `std::is_nothrow_swappable_with<T, U>`.
&emsp;Otherwise the trait checks that `etl::is_swappable_with<T, U>::value` is `true` and that both `swap(declval<T>(), declval<U>())` and `swap(declval<U>(), declval<T>())` are `noexcept`.
&emsp;Note that, as for `is_swappable_with`, no references are added to `T` and `U`, so the value categories of the arguments are those of `T` and `U`. `is_nothrow_swappable_with<int, int>::value` is `false`, whereas `is_nothrow_swappable_with<int&, int&>::value` is `true`.
&emsp;Requires C++11. Without it there is no way of detecting the validity of an expression, so this trait is not defined.
&emsp;Note that when neither the STL nor the type traits builtins are available, `etl::is_nothrow_move_constructible` and `etl::is_nothrow_move_assignable` are conservatively `false` for class types, so `etl::swap` is not `noexcept` for them and this trait is conservatively `false` too.
```cpp
template <typename T, typename U>
inline constexpr bool is_nothrow_swappable_with_v = etl::is_nothrow_swappable_with<T, U>::value;
```
C++17
## is_union
From: `20.49.0`
```cpp
template <typename T>
struct is_union
```
Checks if `T` is a union type.
The result is found in the member `value`.
&emsp;When the compiler does not provide the required intrinsic, this trait conservatively reports `false` for every type.
```cpp
template <typename T>
inline constexpr bool is_union_v = etl::is_union<T>::value;
```
C++17
## is_empty
From: `20.49.0`
```cpp
template <typename T>
struct is_empty
```
Checks if `T` is an empty class type; that is, a non-union class type with no non-static data members other than zero-sized bit-fields, no virtual functions, no virtual base classes and no non-empty base classes.
The result is found in the member `value`.
&emsp;Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_empty_v = etl::is_empty<T>::value;
```
C++17
## is_polymorphic
From: `20.49.0`
```cpp
template <typename T>
struct is_polymorphic
```
Checks if `T` is a polymorphic class type; that is, a class that declares or inherits at least one virtual function.
The result is found in the member `value`.
&emsp;Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_polymorphic_v = etl::is_polymorphic<T>::value;
```
C++17
## is_abstract
From: `20.49.0`
```cpp
template <typename T>
struct is_abstract
```
Checks if `T` is an abstract class type; that is, a class that declares or inherits at least one pure virtual function.
The result is found in the member `value`.
&emsp;Requires compiler support. When the compiler does not provide the required intrinsic, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_abstract_v = etl::is_abstract<T>::value;
```
C++17
## is_final
From: `20.49.0`
```cpp
template <typename T>
struct is_final
```
Checks if `T` is a class or union type marked `final`, optionally cv-qualified.
The result is found in the member `value`.
&emsp;When using the STL, this requires C++14 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_final_v = etl::is_final<T>::value;
```
C++17
## is_aggregate
From: `20.49.0`
```cpp
template <typename T>
struct is_aggregate
```
Checks if `T` is an aggregate type, optionally cv-qualified.
An aggregate is an array type or a class type that has no user-declared or inherited constructors, no private or protected non-static data members, no virtual functions and no virtual, private or protected base classes.
The result is found in the member `value`.
&emsp;When using the STL, this requires C++17 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool is_aggregate_v = etl::is_aggregate<T>::value;
```
C++17
## has_virtual_destructor
From: `20.49.0`
```cpp
template <typename T>
struct has_virtual_destructor
```
Checks if `T` is a class type with a virtual destructor, optionally cv-qualified.
The result is found in the member `value`.
&emsp;When not using the STL, this requires compiler support. When it is not available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool has_virtual_destructor_v = etl::has_virtual_destructor<T>::value;
```
C++17
## has_unique_object_representations
From: `20.49.0`
```cpp
template <typename T>
struct has_unique_object_representations
```
Checks if `T` is trivially copyable and any two objects of type `T` with the same value have the same object representation; that is, the type has no padding bits and no two distinct object representations compare equal.
Arrays and cv-qualifiers are ignored; the trait is applied to `etl::remove_all_extents<typename etl::remove_cv<T>::type>::type`.
The result is found in the member `value`.
&emsp;When using the STL, this requires C++17 or above. Otherwise it requires compiler support. When neither is available, this trait is not defined.
```cpp
template <typename T>
inline constexpr bool has_unique_object_representations_v = etl::has_unique_object_representations<T>::value;
```
C++17
## is_null_pointer
From: `20.49.0`
```cpp
template <typename T>
struct is_null_pointer
```
Checks if `T` is `etl::nullptr_t`, optionally cv-qualified.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_null_pointer_v = etl::is_null_pointer<T>::value;
```
C++17
## is_scalar
From: `20.49.0`
```cpp
template <typename T>
struct is_scalar
```
Checks if `T` is a scalar type; that is, an arithmetic, enumeration, pointer, pointer to member or `etl::nullptr_t` type, optionally cv-qualified.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_scalar_v = etl::is_scalar<T>::value;
```
C++17
## is_scoped_enum
From: `20.50.0`
```cpp
template <typename T>
struct is_scoped_enum
```
Checks if `T` is a scoped enumeration type; that is, an enumeration type that is not implicitly convertible to an integer.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_scoped_enum_v = etl::is_scoped_enum<T>::value;
```
C++17
## is_trivially_default_constructible
From: `20.50.0`
```cpp
template <typename T>
struct is_trivially_default_constructible
```
Checks if `T` is default constructible and the default construction is trivial.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_trivially_default_constructible_v = etl::is_trivially_default_constructible<T>::value;
```
C++17
## is_trivially_move_constructible
From: `20.50.0`
```cpp
template <typename T>
struct is_trivially_move_constructible
```
Checks if `T` is move constructible and the move construction is trivial.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_trivially_move_constructible_v = etl::is_trivially_move_constructible<T>::value;
```
C++17
## is_trivially_move_assignable
From: `20.50.0`
```cpp
template <typename T>
struct is_trivially_move_assignable
```
Checks if `T` is move assignable and the move assignment is trivial.
The result is found in the member `value`.
```cpp
template <typename T>
inline constexpr bool is_trivially_move_assignable_v = etl::is_trivially_move_assignable<T>::value;
```
C++17
## is_trivially_assignable
```cpp
template <typename T1, typename T2>
struct is_trivially_assignable
```
Checks if an expression of type `T2` can be assigned to an lvalue expression of type `T1`, and that the assignment is trivial.
The result is found in the member `value`.
&emsp;See Scenarios 1 to 4 above for how this trait is defined when the STL or the compiler built-ins are unavailable.
```cpp
template <typename T1, typename T2>
inline constexpr bool is_trivially_assignable_v = etl::is_trivially_assignable<T1, T2>::value;
```
C++17
## is_layout_compatible
From: `20.50.0`
```cpp
template <typename T, typename U>
struct is_layout_compatible
```
Checks if `T` and `U` are layout-compatible types.
The result is found in the member `value`.
&emsp;When using the STL with C++20 or above, this is defined as `std::is_layout_compatible<T, U>`.
&emsp;Otherwise it requires compiler support (the `__is_layout_compatible` intrinsic). When neither is available, this trait is not defined, as there is no portable way of determining layout compatibility.
```cpp
template <typename T, typename U>
inline constexpr bool is_layout_compatible_v = etl::is_layout_compatible<T, U>::value;
```
C++17
## is_pointer_interconvertible_base_of
From: `20.50.0`
```cpp
template <typename TBase, typename TDerived>
struct is_pointer_interconvertible_base_of
```
Checks if `TBase` is a pointer-interconvertible base class of `TDerived`; that is, every object of type `TDerived` has its `TBase` base class subobject at the same address as the complete object.
The result is found in the member `value`.
&emsp;When using the STL with C++20 or above, this is defined as `std::is_pointer_interconvertible_base_of<TBase, TDerived>`.
&emsp;Otherwise it requires compiler support (the `__is_pointer_interconvertible_base_of` intrinsic). When neither is available, this trait is not defined, as there is no portable way of determining pointer interconvertibility.
&emsp;Note that, as required by the standard, the program is ill-formed if `TDerived` is a complete non-union class type and `TBase` is an incomplete class type. The trait cannot be used to probe possibly-incomplete types.
```cpp
template <typename TBase, typename TDerived>
inline constexpr bool is_pointer_interconvertible_base_of_v = etl::is_pointer_interconvertible_base_of<TBase, TDerived>::value;
```
C++17

View File

@ -192,13 +192,13 @@ Swap with another etl::unexpected
```cpp
template <typename TValue, typename TError>
class expected
```cpp
```
Specialisation for void value type.
```cpp
template <typename TError>
class expected<void, TError>
```cpp
```
### Types
@ -421,6 +421,7 @@ value_type& value() const
Get the value.
Undefined if has_value() returns false.
Not valid for void specialisation.
Before: C++11
---
@ -536,13 +537,46 @@ Before: C++11
---
```cpp
template <typename G>
ETL_NODISCARD
ETL_CONSTEXPR14
error_type error_or(G&& default_error) const&
```
**Description**
Returns default_error if has_value() returns true; otherwise returns the stored error.
Since: C++11
---
```cpp
template <typename G>
ETL_NODISCARD
ETL_CONSTEXPR14
error_type error_or(G&& default_error)&&
```
**Description**
Returns default_error if has_value() returns true; otherwise returns the stored error.
Since: C++11
---
```cpp
template <typename G>
error_type error_or(const G& default_error) const
```
**Description**
Returns default_error if has_value() returns true; otherwise returns the stored error.
Before: C++11
---
```cpp
template <typename... TArgs>
ETL_CONSTEXPR14 value_type& emplace(TArgs&&... args) ETL_NOEXCEPT
```
**Description**
Returns the error if has_value() returns false.
Undefined if has_value() returns true.
Create from arguments.
Since: C++11
---
@ -574,15 +608,411 @@ Const class member access operator.
---
```cpp
value_type& operator *()
value_type& operator *() &
```
**Description**
**Description**
Dereference operator.
---
```cpp
const value_type& operator *() const
const value_type& operator *() const&
```
**Description**
**Description**
Dereference operator.
---
```cpp
value_type&& operator *() &&
```
**Description**
Dereference operator.
Since: C++11
---
```cpp
const value_type&& operator *() const&&
```
**Description**
Dereference operator.
Since: C++11
---
```cpp
ETL_NODISCARD
ETL_CONSTEXPR14
value_type* begin() ETL_NOEXCEPT
```
**Description**
Returns a pointer to the value if has_value() returns true, otherwise returns nullptr.
Allows expected to be used as a range of 0 or 1 elements. Not valid for void specialisation.
---
```cpp
ETL_NODISCARD
ETL_CONSTEXPR14
const value_type* begin() const ETL_NOEXCEPT
```
**Description**
Returns a pointer to the value if has_value() returns true, otherwise returns nullptr. Not valid for void specialisation.
---
```cpp
ETL_NODISCARD
ETL_CONSTEXPR14
value_type* end() ETL_NOEXCEPT
```
**Description**
Returns a pointer past the value if has_value() returns true, otherwise returns nullptr. Not valid for void specialisation.
---
```cpp
ETL_NODISCARD
ETL_CONSTEXPR14
const value_type* end() const ETL_NOEXCEPT
```
**Description**
Returns a pointer past the value if has_value() returns true, otherwise returns nullptr. Not valid for void specialisation.
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TValue&>::type>::type>
auto transform(F&& f) & -> expected<U, TError>
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto transform(F&& f) & -> expected<U, TError>
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TValue&>::type>::type>
auto transform(F&& f) const& -> expected<U, TError>
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto transform(F&& f) const& -> expected<U, TError>
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TValue&&>::type>::type>
auto transform(F&& f) && -> expected<U, TError>
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto transform(F&& f) && -> expected<U, TError>
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TValue&&>::type>::type>
auto transform(F&& f) const&& -> expected<U, TError>
```
**Description**
If has_value() returns true, it invokes f and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto transform(F&& f) const&& -> expected<U, TError>
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result wrapped in an expected object; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TValue&>::type>::type>
auto and_then(F&& f) & -> U
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>
auto and_then(F&& f) & -> U
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TValue&>::type>::type>
auto and_then(F&& f) const& -> U
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto and_then(F&& f) const& -> U
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TValue&&>::type>::type>
auto and_then(F&& f) && -> U
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto and_then(F&& f) && -> U
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TValue&&>::type>::type>
auto and_then(F&& f) const&& -> U
```
**Description**
If has_value() returns true, it invokes f on the value and returns the result; otherwise it returns an expected object that contains error(). For void specialisation see below.
Since: C++11
---
```cpp
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void>::type>::type>
auto and_then(F&& f) const&& -> U
```
**Description**
For void specialisation.
If has_value() returns true, it invokes f and returns the result; otherwise it returns an expected object that contains error().
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&>::type>::type>
auto or_else(F&& f) & -> U
```
**Description**
If has_value() returns true, it returns an expected object that contains value(); otherwise it invokes f on error() and returns the result. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&>::type>::type>
auto or_else(F&& f) & -> U
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&>::type>::type>
auto or_else(F&& f) const& -> U
```
**Description**
If has_value() returns true, it returns an expected object that contains value(); otherwise it invokes f on error() and returns the result. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&>::type>::type>
auto or_else(F&& f) const& -> U
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&&>::type>::type>
auto or_else(F&& f) && -> U
```
**Description**
If has_value() returns true, it returns an expected object that contains value(); otherwise it invokes f on error() and returns the result. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&&>::type>::type>
auto or_else(F&& f) && -> U
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&&>::type>::type>
auto or_else(F&& f) const&& -> U
```
**Description**
If has_value() returns true, it returns an expected object that contains value(); otherwise it invokes f on error() and returns the result. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&&>::type>::type>
auto or_else(F&& f) const&& -> U
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&>::type>::type>
auto transform_error(F&& f) & -> expected<TValue, U>
```
**Description**
If has_value() returns true, it returns an expected that contains value(); otherwise it invokes f on error() and returns the result wrapped in an expected object. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&>::type>::type>
auto transform_error(F&& f) & -> expected<TValue, U>
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result wrapped in an expected object.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&>::type>::type>
auto transform_error(F&& f) const& -> expected<TValue, U>
```
**Description**
If has_value() returns true, it returns an expected that contains value(); otherwise it invokes f on error() and returns the result wrapped in an expected object. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&>::type>::type>
auto transform_error(F&& f) const& -> expected<TValue, U>
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result wrapped in an expected object.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&&>::type>::type>
auto transform_error(F&& f) && -> expected<TValue, U>
```
**Description**
If has_value() returns true, it returns an expected that contains value(); otherwise it invokes f on error() and returns the result wrapped in an expected object. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, TError&&>::type>::type>
auto transform_error(F&& f) && -> expected<TValue, U>
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result wrapped in an expected object.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&&>::type>::type>
auto transform_error(F&& f) const&& -> expected<TValue, U>
```
**Description**
If has_value() returns true, it returns an expected that contains value(); otherwise it invokes f on error() and returns the result wrapped in an expected object. For void specialisation see below.
Since: C++11
---
```cpp
template <typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&&>::type>::type>
auto transform_error(F&& f) const&& -> expected<TValue, U>
```
**Description**
For void specialisation.
If has_value() returns true, it returns a default constructed expected object of the appropriate type; otherwise it invokes f on error() and returns the result wrapped in an expected object.
Since: C++11

View File

@ -222,6 +222,64 @@ bool has_value() const
Checks whether *this is in a valid state, i.e. whether the contained value is initialised.
Returns `true` if valid, otherwise `false`.
## Monadic operations
C++11 and above.
Each operation is supplied as four reference qualified overloads (`&`, `const&`, `&&`, `const&&`),
so that the contained value is passed to the supplied callable with the value category of `*this`.
```cpp
template <typename F>
etl::optional<U> transform(F&& f)
```
**Description**
If `*this` contains a value, returns an `etl::optional<U>` containing the result of invoking `f`
with the contained value, otherwise returns an empty `etl::optional<U>`.
`U` is the result type of `f`, with any reference and cv qualification removed.
### Note
Unlike `std::optional::transform`, which only removes cv qualification, a callable returning a
reference is accepted, and the referenced value is copied into the resulting optional.
---
```cpp
template <typename F>
U and_then(F&& f)
```
**Description**
If `*this` contains a value, returns the result of invoking `f` with the contained value,
otherwise returns an empty `U`.
`U` is the result type of `f`, with any reference and cv qualification removed, and must be an
`etl::optional`. The overload takes no part in overload resolution otherwise.
---
```cpp
template <typename F>
U or_else(F&& f)
```
**Description**
If `*this` contains a value, returns a copy of `*this`, otherwise returns the result of invoking
`f` with no arguments.
`U` is the result type of `f`, with any reference and cv qualification removed, and must be an
`etl::optional` whose `value_type` is `T`. The overload takes no part in overload resolution
otherwise.
### Example
```cpp
etl::optional<int> opt = 6;
etl::optional<double> result = opt.and_then([](int i) { return i > 0 ? etl::optional<int>(i * 2) : etl::optional<int>(); })
.or_else([]() { return etl::optional<int>(1); })
.transform([](int i) { return double(i) / 2.0; });
// result contains 6.0
```
## Non-member functions
```cpp
@ -269,3 +327,15 @@ operator >=
```
**Description**
`true` if the contents of the lhs are lexicographically greater than or equal to the contents of the rhs, otherwise `false`.
---
```cpp
template <typename T>
struct etl::is_optional;
template <typename T>
inline constexpr bool etl::is_optional_v; // C++17 and above
```
**Description**
`true` if `T` is an `etl::optional`, otherwise `false`. Any cv qualification on `T` is ignored.

View File

@ -1052,17 +1052,18 @@ namespace etl
//*************************************************************************
/// Make
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
template <typename T, typename... TValues>
constexpr auto make_array(TValues&&... values) ETL_NOEXCEPT -> etl::array<T, sizeof...(TValues)>
#if ETL_USING_CPP11
template <typename T = void, typename... TValues>
constexpr auto make_array(TValues&&... values) -> etl::array<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
// Forward each argument as its own deduced type, then convert explicitly to T.
// Forwarding as T (the old behaviour) made the call ill-formed for any const-qualified
// lvalue of type T: forward<T> requires a non-const T&, and a T&& cannot bind to a
// reference-related const lvalue. The explicit conversion also keeps narrowing
// initialisers (e.g. make_array<char>(0, 1)) working, which plain forwarding into the
// braced initialiser list would reject.
return {static_cast<T>(etl::forward<TValues>(values))...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards arguments that already have the element type and
// converts the rest with static_cast, so const-qualified lvalues,
// narrowing initialisers such as make_array<char>(0, 1) and non-movable
// element types all work.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -900,6 +900,53 @@ namespace etl
return pbuffer[(out + index) % buffer_size];
}
//*************************************************************************
/// Assigns an iterator range to the circular buffer.
//*************************************************************************
void assign(iterator first, const iterator& last)
{
assign_range(first, last);
}
//*************************************************************************
/// Assigns a const iterator range to the circular buffer.
//*************************************************************************
void assign(const_iterator first, const const_iterator& last)
{
assign_range(first, last);
}
//*************************************************************************
/// Assigns a range to the circular buffer.
//*************************************************************************
template <typename TIterator>
typename etl::enable_if<!etl::is_integral<TIterator>::value, void>::type assign(TIterator first, const TIterator& last)
{
clear();
push(first, last);
}
//*************************************************************************
/// Assigns 'n' copies of a value to the circular buffer.
//*************************************************************************
void assign(size_type n, const_reference value)
{
if (n == 0U)
{
clear();
return;
}
const T value_copy(value);
clear();
while (n-- != 0U)
{
push(value_copy);
}
}
//*************************************************************************
/// push.
/// Adds an item to the buffer.
@ -1036,6 +1083,43 @@ namespace etl
protected:
//*************************************************************************
/// Assigns a circular buffer iterator range.
//*************************************************************************
template <typename TIterator>
void assign_range(TIterator first, const TIterator& last)
{
const bool is_self_range = (&first.container() == this) && (&last.container() == this);
if (!is_self_range)
{
clear();
push(first, last);
}
else
{
const size_type first_index = static_cast<size_type>(first.get_index());
const size_type last_index = static_cast<size_type>(last.get_index());
while (out != first_index)
{
pop();
}
while (in != last_index)
{
if (in == 0U)
{
in = buffer_size;
}
--in;
pbuffer[in].~T();
ETL_DECREMENT_DEBUG_COUNT;
}
}
}
//*************************************************************************
/// Protected constructor.
//*************************************************************************
@ -1127,6 +1211,24 @@ namespace etl
{
}
//*************************************************************************
/// Constructor, with size.
//*************************************************************************
explicit circular_buffer(size_t initial_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
this->assign(initial_size, T());
}
//*************************************************************************
/// Constructor, from initial size and value.
//*************************************************************************
circular_buffer(size_t initial_size, typename etl::icircular_buffer<T>::const_reference value)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
this->assign(initial_size, value);
}
//*************************************************************************
/// Constructor.
/// Constructs a buffer from an iterator range.
@ -1274,6 +1376,24 @@ namespace etl
{
}
//*************************************************************************
/// Constructor, with size.
//*************************************************************************
explicit circular_buffer_ext(size_t initial_size, void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
this->assign(initial_size, T());
}
//*************************************************************************
/// Constructor, from initial size and value.
//*************************************************************************
circular_buffer_ext(size_t initial_size, typename etl::icircular_buffer<T>::const_reference value, void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
this->assign(initial_size, value);
}
//*************************************************************************
/// Constructor.
/// Constructs a buffer from an iterator range.

View File

@ -449,7 +449,6 @@ namespace etl
//*************************************************************************
/// Constructor
//*************************************************************************
template <typename... TElements>
ETL_CONSTEXPR14 explicit iconst_map(const value_type* element_list_, size_type size_, size_type max_elements_) ETL_NOEXCEPT
: element_list(element_list_)
, element_list_end{element_list_ + size_}

View File

@ -398,7 +398,6 @@ namespace etl
//*************************************************************************
/// Constructor
//*************************************************************************
template <typename... TElements>
ETL_CONSTEXPR14 explicit iconst_multimap(const value_type* element_list_, size_type size_, size_type max_elements_) ETL_NOEXCEPT
: element_list(element_list_)
, element_list_end{element_list_ + size_}

View File

@ -354,7 +354,6 @@ namespace etl
//*************************************************************************
/// Constructor
//*************************************************************************
template <typename... TElements>
ETL_CONSTEXPR14 explicit iconst_multiset(const value_type* element_list_, size_type size_, size_type max_elements_) ETL_NOEXCEPT
: element_list(element_list_)
, element_list_end{element_list_ + size_}

View File

@ -345,7 +345,6 @@ namespace etl
//*************************************************************************
/// Constructor
//*************************************************************************
template <typename... TElements>
ETL_CONSTEXPR14 explicit iconst_set(const value_type* element_list_, size_type size_, size_type max_elements_) ETL_NOEXCEPT
: element_list(element_list_)
, element_list_end{element_list_ + size_}

View File

@ -348,16 +348,7 @@ namespace etl
}
//***************************************************
reference operator[](size_t i)
{
iterator result(*this);
result += i;
return *result;
}
//***************************************************
const_reference operator[](size_t i) const
reference operator[](difference_type i) const
{
iterator result(*this);
result += i;
@ -607,10 +598,10 @@ namespace etl
}
//***************************************************
const_reference operator[](size_t i) const
const_reference operator[](difference_type i) const
{
const_iterator result(*this);
result += static_cast<difference_type>(i);
result += i;
return *result;
}
@ -2532,16 +2523,17 @@ namespace etl
/// Make
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
template <typename T, typename... TValues>
constexpr auto make_deque(TValues&&... values) -> etl::deque<T, sizeof...(TValues)>
template <typename T = void, typename... TValues>
constexpr auto make_deque(TValues&&... values) -> etl::deque<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
// Forward each argument as its own deduced type, then convert explicitly to T.
// Forwarding as T (the old behaviour) made the call ill-formed for any const-qualified
// lvalue of type T: forward<T> requires a non-const T&, and a T&& cannot bind to a
// reference-related const lvalue. The explicit conversion also keeps narrowing
// initialisers (e.g. make_deque<char>(0, 1)) working, which plain forwarding into the
// braced initialiser list would reject.
return {static_cast<T>(etl::forward<TValues>(values))...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards arguments that already have the element type and
// converts the rest with static_cast, so const-qualified lvalues,
// narrowing initialisers such as make_deque<char>(0, 1) and non-movable
// element types all work.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -1435,6 +1435,11 @@ namespace etl
return lhs.error() == rhs.error();
}
#include "private/diagnostic_uninitialized_push.h"
//*******************************************
// The error is only read when the expected does not have a value, in which
// case it is always fully constructed. GCC can emit a false positive
// -Wmaybe-uninitialized when these are inlined at high optimisation levels.
//*******************************************
template <typename TError, typename TError2>
ETL_CONSTEXPR14 bool operator==(const etl::expected<void, TError>& lhs, const etl::expected<void, TError2>& rhs)
@ -1460,6 +1465,7 @@ namespace etl
}
return lhs.error() == rhs.error();
}
#include "private/diagnostic_pop.h"
//*******************************************
template <typename TError, typename TError2>

View File

@ -321,7 +321,6 @@ namespace etl
//*************************************************************************
/// Emplaces a value to the set.
//*************************************************************************
template <typename T1>
ETL_OR_STD::pair<iterator, bool> emplace(const_reference value)
{
return insert(value);

View File

@ -1516,7 +1516,7 @@ namespace etl
}
// for integers
template <typename OutputIt, typename T, bool skip_last_zeros = false>
template <typename OutputIt, typename T>
void format_num(OutputIt& it, T value, const format_spec_t& spec)
{
size_t width = 0;

View File

@ -1793,10 +1793,14 @@ namespace etl
/// Make
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
template <typename... T>
constexpr auto make_forward_list(T&&... t) -> etl::forward_list<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto make_forward_list(TValues&&... values) -> etl::forward_list<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
return {etl::forward<T>(t)...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards same-type arguments and static_casts the rest.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -1551,10 +1551,15 @@ namespace etl
/// Make
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
template <typename... T>
constexpr auto make_indirect_vector(T&&... t) -> etl::indirect_vector<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto
make_indirect_vector(TValues&&... values) -> etl::indirect_vector<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
return {etl::forward<T>(t)...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards same-type arguments and static_casts the rest.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -1126,8 +1126,13 @@ namespace etl
{
}
#include "private/diagnostic_uninitialized_push.h"
//*************************************************************************
// clone_from
//
// GCC can emit a false positive -Wmaybe-uninitialized for the source
// storage when this is inlined into a copy constructor at high
// optimisation levels. The source object is always fully constructed.
//*************************************************************************
template <size_t Other_Object_Size, size_t Other_Object_Alignment>
void clone_from(const etl::inplace_function<TReturn(TArgs...), Other_Object_Size, Other_Object_Alignment>& other)
@ -1139,6 +1144,7 @@ namespace etl
vtable->copy(&other.storage, &storage);
}
}
#include "private/diagnostic_pop.h"
//*************************************************************************
// move_from

View File

@ -39,6 +39,8 @@ SOFTWARE.
#if ETL_USING_CPP11
#include "private/diagnostic_array_bounds_push.h"
namespace etl
{
//****************************************************************************
@ -387,5 +389,7 @@ namespace etl
#endif
} // namespace etl
#include "private/diagnostic_pop.h"
#endif // ETL_USING_CPP11
#endif // ETL_INVOKE_INCLUDED

View File

@ -1656,6 +1656,22 @@ namespace etl
}
return n;
}
// Overload for ranges
template <typename R, typename I = decltype(ETL_OR_STD::begin(etl::declval<R&>()))>
constexpr etl::iter_difference_t<I> operator()(R&& r) const
{
using U = etl::remove_cvref_t<R>;
if constexpr (has_size_member<U>::value)
{
return static_cast<etl::iter_difference_t<I>>(r.size());
}
else
{
return (*this)(ETL_OR_STD::begin(r), ETL_OR_STD::end(r));
}
}
};
struct size

View File

@ -2218,10 +2218,14 @@ namespace etl
/// Make
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
template <typename... T>
constexpr auto make_list(T&&... t) -> etl::list<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto make_list(TValues&&... values) -> etl::list<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
return {etl::forward<T>(t)...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards same-type arguments and static_casts the rest.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -305,6 +305,7 @@ namespace etl
(add_new_message_type<TMessageTypes>(etl::move(msg)) || ...);
}
#include "private/diagnostic_array_bounds_push.h"
#include "private/diagnostic_uninitialized_push.h"
//********************************************
/// Only enabled for types that are in the typelist.
@ -318,6 +319,9 @@ namespace etl
}
#include "private/diagnostic_pop.h"
#include "private/diagnostic_pop.h"
#include "private/diagnostic_array_bounds_push.h"
#include "private/diagnostic_uninitialized_push.h"
//********************************************
template <typename TType>
@ -336,6 +340,9 @@ namespace etl
}
#include "private/diagnostic_pop.h"
#include "private/diagnostic_pop.h"
#include "private/diagnostic_array_bounds_push.h"
#include "private/diagnostic_uninitialized_push.h"
//********************************************
template <typename TType>
@ -352,6 +359,8 @@ namespace etl
return false;
}
}
#include "private/diagnostic_pop.h"
#include "private/diagnostic_pop.h"
typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;

View File

@ -31,8 +31,26 @@ SOFTWARE.
#include "../platform.h"
#include "FreeRTOS.h"
#include <semphr.h>
#if defined(__has_include) // Compiler supports __has_include
#if __has_include(<FreeRTOS.h>) && __has_include(<semphr.h>) // Standard FreeRTOS include layout
#include <FreeRTOS.h>
#include <semphr.h>
#elif __has_include(<freertos/FreeRTOS.h>) && __has_include(<freertos/semphr.h>) // ESP-IDF style include layout
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#else // Neither include layout found
#error "FreeRTOS.h and semphr.h not found. Please include path to FreeRTOS in your project settings"
#endif
#else
#include <FreeRTOS.h>
#include <semphr.h>
#endif
namespace etl
{

View File

@ -35,6 +35,7 @@ SOFTWARE.
#include "error_handler.h"
#include "exception.h"
#include "memory.h"
#include "nullptr.h"
#include "type_traits.h"
namespace etl
@ -95,7 +96,16 @@ namespace etl
ETL_CONSTEXPR14 explicit not_null(underlying_type ptr_)
: ptr(ptr_)
{
ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
if (etl::is_constant_evaluated())
{
// ETL_IS_FOLDED_NULL keeps the compile time rejection of null working
// when the undefined behaviour sanitizer instruments the comparison.
ETL_ASSERT(!ETL_IS_FOLDED_NULL(ptr_), ETL_ERROR(not_null_contains_null));
}
else
{
ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
}
}
//*********************************
@ -112,7 +122,14 @@ namespace etl
//*********************************
ETL_CONSTEXPR14 not_null& operator=(underlying_type rhs)
{
ETL_ASSERT_OR_RETURN_VALUE(rhs != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this);
if (etl::is_constant_evaluated())
{
ETL_ASSERT_OR_RETURN_VALUE(!ETL_IS_FOLDED_NULL(rhs), ETL_ERROR(not_null_contains_null), *this);
}
else
{
ETL_ASSERT_OR_RETURN_VALUE(rhs != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this);
}
ptr = rhs;

View File

@ -78,4 +78,26 @@ namespace etl
#endif
} // namespace etl
//*****************************************************************************
/// True when the compiler can fold the comparison at compile time and it yields
/// null.
///
/// Normally the comparison folds for any pointer that is a constant expression,
/// so this is equivalent to a plain null check. Under GCC's undefined behaviour
/// sanitizer, however, the comparison is instrumented and only folds for a null
/// pointer constant, not for the address of an object or function.
/// __builtin_constant_p filters out the latter, which would otherwise make the
/// enclosing expression non-constant and reject perfectly valid code.
///
/// Only meaningful during constant evaluation. At run time
/// __builtin_constant_p is false for any pointer that is not a compile time
/// constant, so this reports false for a genuine null pointer. Callers must
/// use a plain comparison against ETL_NULLPTR on the run time path.
//*****************************************************************************
#if ETL_USING_BUILTIN_CONSTANT_P
#define ETL_IS_FOLDED_NULL(p) (__builtin_constant_p((p) == ETL_NULLPTR) && ((p) == ETL_NULLPTR))
#else
#define ETL_IS_FOLDED_NULL(p) ((p) == ETL_NULLPTR)
#endif
#endif

View File

@ -36,6 +36,7 @@ SOFTWARE.
#include "error_handler.h"
#include "exception.h"
#include "initializer_list.h"
#include "invoke.h"
#include "memory.h"
#include "placement_new.h"
#include "type_traits.h"
@ -49,6 +50,41 @@ namespace etl
template <typename T>
class optional;
//*****************************************************************************
/// Determines if a type is an etl::optional.
/// Ignores any cv qualification on the type being tested.
///\ingroup utilities
//*****************************************************************************
template <typename T>
struct is_optional : etl::false_type
{
};
template <typename T>
struct is_optional<optional<T> > : etl::true_type
{
};
template <typename T>
struct is_optional<const optional<T> > : etl::true_type
{
};
template <typename T>
struct is_optional<volatile optional<T> > : etl::true_type
{
};
template <typename T>
struct is_optional<const volatile optional<T> > : etl::true_type
{
};
#if ETL_USING_CPP17
template <typename T>
inline constexpr bool is_optional_v = etl::is_optional<T>::value;
#endif
//*****************************************************************************
/// A null option type.
///\ingroup utilities
@ -174,10 +210,9 @@ namespace etl
/// 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>
template <typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value
&& !etl::is_same<etl::decay_t<U>, optional_impl>::value,
int> = 0>
ETL_CONSTEXPR20_STL optional_impl(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
{
storage.construct(etl::forward<U>(value_));
@ -276,9 +311,7 @@ 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>
template <typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, optional_impl>::value, int> = 0>
ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
{
storage.construct(etl::forward<U>(value_));
@ -511,8 +544,7 @@ namespace etl
//*******************************************
/// Emplaces a value from initializer_list and arbitrary constructor arguments.
//*******************************************
template <typename U, typename... Args,
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<U>&, Args...>::value, int>::type = 0 >
template <typename U, typename... Args, etl::enable_if_t< etl::is_constructible<T, std::initializer_list<U>&, Args...>::value, int> = 0 >
ETL_CONSTEXPR20_STL T& emplace(std::initializer_list<U> ilist, Args&&... args)
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<U>&, Args...>::value))
{
@ -671,6 +703,11 @@ namespace etl
}
#endif
#include "private/diagnostic_uninitialized_push.h"
//*******************************
// GCC may warn that 'valid' is used uninitialised when the storage of a
// nested optional is inspected through an inlined destructor chain.
// The flag is always initialised by the constructors, so this is a false positive.
//*******************************
ETL_CONSTEXPR20_STL
void destroy()
@ -681,6 +718,7 @@ namespace etl
valid = false;
}
}
#include "private/diagnostic_pop.h"
//*******************************
union union_type
@ -1217,8 +1255,8 @@ namespace etl
};
} // namespace private_optional
#define ETL_OPTIONAL_ENABLE_CPP14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CPP20_STL typename etl::enable_if< !etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CPP14 etl::enable_if_t< etl::is_pod<typename etl::remove_cv<U>::type>::value, int> = 0
#define ETL_OPTIONAL_ENABLE_CPP20_STL etl::enable_if_t< !etl::is_pod<typename etl::remove_cv<U>::type>::value, int> = 0
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 \
ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<T>::type>::value, bool>::type
@ -1319,12 +1357,10 @@ namespace etl
/// 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::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>
template < typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
&& !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && etl::is_pod<etl::remove_cvref_t<T>>::value,
int> = 0>
ETL_CONSTEXPR14 optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
: impl_t(etl::forward<U>(value_))
{
@ -1334,11 +1370,10 @@ namespace etl
/// Converting constructor from value type.
//***************************************************************************
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::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
&& !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value && !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value
&& !etl::is_pod<etl::remove_cvref_t<T>>::value,
int> = 0>
ETL_CONSTEXPR20_STL optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
: impl_t(etl::forward<U>(value_))
{
@ -1446,11 +1481,9 @@ namespace etl
//***************************************************************************
/// Converting assignment operator from value type.
//***************************************************************************
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>
template < typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && etl::is_pod<etl::remove_cvref_t<T>>::value,
int> = 0>
ETL_CONSTEXPR14 optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
{
impl_t::operator=(etl::forward<U>(value_));
@ -1462,10 +1495,9 @@ namespace etl
/// Converting assignment operator from value type.
//***************************************************************************
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::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && !etl::is_pod<etl::remove_cvref_t<T>>::value,
int> = 0>
ETL_CONSTEXPR20_STL optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
{
impl_t::operator=(etl::forward<U>(value_));
@ -1519,6 +1551,124 @@ namespace etl
{
return this->has_value() ? this->operator->() + 1 : ETL_NULLPTR;
}
#if ETL_USING_CPP11
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, T&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
auto transform(F&& f) & -> etl::optional<U>
{
return transform_impl<F, optional&, U, T&>(etl::forward<F>(f), *this);
}
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, const T&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
auto transform(F&& f) const& -> etl::optional<U>
{
return transform_impl<F, const optional&, U, const T&>(etl::forward<F>(f), *this);
}
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, T&&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
auto transform(F&& f) && -> etl::optional<U>
{
return transform_impl<F, optional&&, U, T&&>(etl::forward<F>(f), etl::move(*this));
}
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, const T&&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
auto transform(F&& f) const&& -> etl::optional<U>
{
return transform_impl<F, const optional&&, U, const T&&>(etl::forward<F>(f), etl::move(*this));
}
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, T&>>>
auto and_then(F&& f) & -> U
{
return and_then_impl<F, optional&, U, T&>(etl::forward<F>(f), *this);
}
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, const T&>>>
auto and_then(F&& f) const& -> U
{
return and_then_impl<F, const optional&, U, const T&>(etl::forward<F>(f), *this);
}
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, T&&>>>
auto and_then(F&& f) && -> U
{
return and_then_impl<F, optional&&, U, T&&>(etl::forward<F>(f), etl::move(*this));
}
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, const T&&>>>
auto and_then(F&& f) const&& -> U
{
return and_then_impl<F, const optional&&, U, const T&&>(etl::forward<F>(f), etl::move(*this));
}
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F>>>
auto or_else(F&& f) & -> U
{
return or_else_impl<F, optional&, U>(etl::forward<F>(f), *this);
}
template < typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F>>>
auto or_else(F&& f) const& -> U
{
return or_else_impl<F, const optional&, U>(etl::forward<F>(f), *this);
}
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F>>>
auto or_else(F&& f) && -> U
{
return or_else_impl<F, optional&&, U>(etl::forward<F>(f), etl::move(*this));
}
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F>>>
auto or_else(F&& f) const&& -> U
{
return or_else_impl<F, const optional&&, U>(etl::forward<F>(f), etl::move(*this));
}
private:
template < typename F, typename TOpt, typename TRet, typename TValueRef, typename = etl::enable_if_t<!etl::is_void<TRet>::value>>
auto transform_impl(F&& f, TOpt&& opt) const -> etl::optional<TRet>
{
if (opt.has_value())
{
return etl::optional<TRet>(etl::invoke(etl::forward<F>(f), etl::forward<TValueRef>(*opt)));
}
else
{
return etl::optional<TRet>();
}
}
template < typename F, typename TOpt, typename TRet, typename TValueRef,
typename = etl::enable_if_t<!etl::is_void<TRet>::value && etl::is_optional<TRet>::value>>
auto and_then_impl(F&& f, TOpt&& opt) const -> TRet
{
if (opt.has_value())
{
return etl::invoke(etl::forward<F>(f), etl::forward<TValueRef>(*opt));
}
else
{
return TRet();
}
}
template <
typename F, typename TOpt, typename TRet,
typename = etl::enable_if_t< !etl::is_void<TRet>::value && etl::is_optional<TRet>::value && etl::is_same<typename TRet::value_type, T>::value>>
auto or_else_impl(F&& f, TOpt&& opt) const -> TRet
{
if (opt.has_value())
{
return TRet(etl::forward<TOpt>(opt));
}
else
{
return etl::invoke(etl::forward<F>(f));
}
}
#endif
};
#include "private/diagnostic_uninitialized_push.h"
@ -2132,17 +2282,17 @@ namespace etl
/// This overload participates in overload resolution only if
/// `etl::is_constructible_v<T, Args...>` is true.
//***************************************************************************
template <typename T, typename... Args, //
typename etl::enable_if< etl::is_constructible<T, Args...>::value, int>::type = 0, //
template <typename T, typename... Args, //
etl::enable_if_t< etl::is_constructible<T, Args...>::value, int> = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
ETL_CONSTEXPR14 etl::optional<T> make_optional(Args&&... args) //
ETL_CONSTEXPR14 etl::optional<T> make_optional(Args&&... args) //
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
{
return etl::optional<T>(etl::in_place_t{}, etl::forward<Args>(args)...);
}
template <typename T, typename... Args, //
typename etl::enable_if< etl::is_constructible<T, Args...>::value, int>::type = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
template <typename T, typename... Args, //
etl::enable_if_t< etl::is_constructible<T, Args...>::value, int> = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(Args&&... args) //
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
{
@ -2156,17 +2306,17 @@ namespace etl
/// This overload participates in overload resolution only if
/// `etl::is_constructible_v<T, std::initializer_list<U>&, Args...>` is true.
//***************************************************************************
template <typename T, typename TL, typename... Args, //
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int>::type = 0, //
template <typename T, typename TL, typename... Args, //
etl::enable_if_t< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int> = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
ETL_CONSTEXPR14 etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
{
return etl::optional<T>(etl::in_place_t{}, ilist, etl::forward<Args>(args)...);
}
template <typename T, typename TL, typename... Args, //
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int>::type = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
template <typename T, typename TL, typename... Args, //
etl::enable_if_t< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int> = 0, //
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
{

View File

@ -77,6 +77,7 @@ namespace etl
typedef ptrdiff_t difference_type;
typedef TBase* pointer;
typedef TBase& reference;
typedef const TBase& const_reference;
typedef ETL_OR_STD::random_access_iterator_tag iterator_category;
//*****************************************
@ -114,6 +115,15 @@ namespace etl
return ptr;
}
//***************************************************
reference operator[](difference_type i) const
{
iterator result(*this);
result += i;
return *result;
}
//*****************************************
iterator& operator++()
{

View File

@ -492,7 +492,7 @@ namespace etl
//*************************************************************************
/// Assignment
//*************************************************************************
delegate& operator=(const delegate& rhs) = default;
ETL_CONSTEXPR14 delegate& operator=(const delegate& rhs) = default;
//*************************************************************************
/// Create from Lambda or Functor.

View File

@ -94,6 +94,15 @@ namespace etl
template <size_t Index, typename THead, typename... TRest>
struct variant_operations<Index, THead, TRest...>
{
#include "diagnostic_uninitialized_push.h"
//*************************************************************************
// destroy
//
// GCC can emit a false positive -Wmaybe-uninitialized when this is inlined
// into a variant destructor at high optimisation levels, as it cannot
// prove that the branch for an inactive alternative is never taken.
// The alternative identified by type_id is always fully constructed.
//*************************************************************************
static void destroy(char* data, size_t type_id)
{
if (type_id == Index)
@ -105,6 +114,7 @@ namespace etl
variant_operations<Index + 1, TRest...>::destroy(data, type_id);
}
}
#include "diagnostic_pop.h"
static void copy(char* dst, const char* src, size_t type_id)
{
@ -156,6 +166,14 @@ namespace etl
private:
#include "diagnostic_uninitialized_push.h"
//*************************************************************************
// The *_impl functions below read the alternative identified by type_id,
// which is always fully constructed. GCC can emit a false positive
// -Wmaybe-uninitialized when these are inlined at high optimisation
// levels, as it cannot prove that the branch for an inactive alternative
// is never taken.
//*************************************************************************
static void copy_impl(char* dst, const char* src, etl::true_type)
{
::new (dst) THead(*reinterpret_cast<const THead*>(src));
@ -183,6 +201,7 @@ namespace etl
}
static void move_assign_impl(char*, const char*, etl::false_type) {}
#include "diagnostic_pop.h"
};
//*******************************************
@ -555,113 +574,94 @@ namespace etl
}
};
//***************************************************************************
/// variant_base specialisation for trivially destructible types.
/// Uses variadic_union storage. Destructor is trivial (defaulted), making
/// the variant a literal type eligible for constexpr / ROM placement.
/// No operation function pointer is needed since destroy/copy/move are
/// all handled without indirection for trivially destructible types.
//***************************************************************************
//*******************************************
/// Trait: are all types trivially copyable?
//*******************************************
template <typename... TTypes>
struct variant_base<true, TTypes...>
struct are_all_trivially_copyable : etl::conjunction<etl::is_trivially_copyable<TTypes>...>
{
};
//***************************************************************************
/// Storage and copy/move operations used by the trivially destructible
/// variant_base specialisation.
/// The general case defines the copy and move operations in terms of the
/// operations of the currently active alternative.
//***************************************************************************
template <bool IsAllTriviallyCopyable, typename... TTypes>
struct variant_trivially_destructible_base
{
variadic_union<TTypes...> data;
size_t type_id;
constexpr variant_base() noexcept
constexpr variant_trivially_destructible_base() noexcept
: data()
, type_id(variant_npos)
{
}
constexpr variant_base(size_t id) noexcept
constexpr variant_trivially_destructible_base(size_t id) noexcept
: data()
, type_id(id)
{
}
template <size_t Index, typename T>
constexpr variant_base(etl::in_place_index_t<Index>, T&& value,
size_t id) noexcept(etl::is_nothrow_constructible<etl::nth_type_t<Index, TTypes...>, T>::value)
constexpr variant_trivially_destructible_base(etl::in_place_index_t<Index>, T&& value,
size_t id) noexcept(etl::is_nothrow_constructible<etl::nth_type_t<Index, TTypes...>, T>::value)
: data(etl::in_place_index_t<Index>{}, etl::forward<T>(value))
, type_id(id)
{
}
variant_base(const variant_base& other) noexcept(etl::conjunction<etl::is_nothrow_copy_constructible<TTypes>...>::value)
variant_trivially_destructible_base(const variant_trivially_destructible_base& other) noexcept(
etl::conjunction<etl::is_nothrow_copy_constructible<TTypes>...>::value)
: data()
, type_id(other.type_id)
{
copy_construct_from(other, is_all_trivially_copyable{});
copy_construct_from(other);
}
variant_base(variant_base&& other) noexcept(etl::conjunction<etl::is_nothrow_move_constructible<TTypes>...>::value)
variant_trivially_destructible_base(variant_trivially_destructible_base&& other) noexcept(
etl::conjunction<etl::is_nothrow_move_constructible<TTypes>...>::value)
: data()
, type_id(other.type_id)
{
move_construct_from(other, is_all_trivially_copyable{});
move_construct_from(other);
}
variant_base& operator=(const variant_base& other) noexcept(etl::conjunction<etl::is_nothrow_copy_constructible<TTypes>...>::value
&& etl::conjunction<etl::is_nothrow_copy_assignable<TTypes>...>::value)
variant_trivially_destructible_base&
operator=(const variant_trivially_destructible_base& other) noexcept(etl::conjunction<etl::is_nothrow_copy_constructible<TTypes>...>::value
&& etl::conjunction<etl::is_nothrow_copy_assignable<TTypes>...>::value)
{
if (this != &other)
{
copy_assign_from(other, is_all_trivially_copyable{});
copy_assign_from(other);
}
return *this;
}
variant_base& operator=(variant_base&& other) noexcept(etl::conjunction<etl::is_nothrow_move_constructible<TTypes>...>::value
&& etl::conjunction<etl::is_nothrow_move_assignable<TTypes>...>::value)
variant_trivially_destructible_base&
operator=(variant_trivially_destructible_base&& other) noexcept(etl::conjunction<etl::is_nothrow_move_constructible<TTypes>...>::value
&& etl::conjunction<etl::is_nothrow_move_assignable<TTypes>...>::value)
{
if (this != &other)
{
move_assign_from(other, is_all_trivially_copyable{});
move_assign_from(other);
}
return *this;
}
~variant_base() = default;
~variant_trivially_destructible_base() = default;
private:
// All alternatives trivially copyable => a raw-byte copy correctly
// reproduces both copy and move construction.
typedef etl::integral_constant<bool, etl::conjunction<etl::is_trivially_copyable<TTypes>...>::value> is_all_trivially_copyable;
//*******************************************
// Trivially copyable fast path: raw-byte copy.
// Dispatch to the active alternative's own copy/move operations.
// The active union member shares its address with the union, so the
// raw-pointer dispatch places the new object in the correct storage.
//*******************************************
void copy_construct_from(const variant_base& other, etl::true_type) noexcept
{
memcpy(static_cast<void*>(&data), static_cast<const void*>(&other.data), sizeof(data));
}
void move_construct_from(const variant_base& other, etl::true_type) noexcept
{
memcpy(static_cast<void*>(&data), static_cast<const void*>(&other.data), sizeof(data));
}
void copy_assign_from(const variant_base& other, etl::true_type) noexcept
{
type_id = other.type_id;
memcpy(static_cast<void*>(&data), static_cast<const void*>(&other.data), sizeof(data));
}
void move_assign_from(const variant_base& other, etl::true_type) noexcept
{
type_id = other.type_id;
memcpy(static_cast<void*>(&data), static_cast<const void*>(&other.data), sizeof(data));
}
//*******************************************
// Non-trivial path: dispatch to the active alternative's own
// copy/move constructor. The active union member shares its address
// with the union, so the raw-pointer dispatch places the new object
// in the correct storage.
//*******************************************
void copy_construct_from(const variant_base& other, etl::false_type)
void copy_construct_from(const variant_trivially_destructible_base& other)
{
if (other.type_id != variant_npos)
{
@ -669,7 +669,7 @@ namespace etl
}
}
void move_construct_from(variant_base& other, etl::false_type)
void move_construct_from(variant_trivially_destructible_base& other)
{
if (other.type_id != variant_npos)
{
@ -677,7 +677,7 @@ namespace etl
}
}
void copy_assign_from(const variant_base& other, etl::false_type)
void copy_assign_from(const variant_trivially_destructible_base& other)
{
if ((type_id != variant_npos) && (type_id == other.type_id))
{
@ -698,7 +698,7 @@ namespace etl
}
}
void move_assign_from(variant_base& other, etl::false_type)
void move_assign_from(variant_trivially_destructible_base& other)
{
if ((type_id != variant_npos) && (type_id == other.type_id))
{
@ -720,6 +720,76 @@ namespace etl
}
};
//***************************************************************************
/// Specialisation for when all of the types are trivially copyable.
/// All of the copy and move operations are defaulted, so that they are
/// trivial and the variant itself is trivially copyable. See P0602R4.
//***************************************************************************
template <typename... TTypes>
struct variant_trivially_destructible_base<true, TTypes...>
{
variadic_union<TTypes...> data;
size_t type_id;
constexpr variant_trivially_destructible_base() noexcept
: data()
, type_id(variant_npos)
{
}
constexpr variant_trivially_destructible_base(size_t id) noexcept
: data()
, type_id(id)
{
}
template <size_t Index, typename T>
constexpr variant_trivially_destructible_base(etl::in_place_index_t<Index>, T&& value,
size_t id) noexcept(etl::is_nothrow_constructible<etl::nth_type_t<Index, TTypes...>, T>::value)
: data(etl::in_place_index_t<Index>{}, etl::forward<T>(value))
, type_id(id)
{
}
variant_trivially_destructible_base(const variant_trivially_destructible_base&) = default;
variant_trivially_destructible_base(variant_trivially_destructible_base&&) = default;
variant_trivially_destructible_base& operator=(const variant_trivially_destructible_base&) = default;
variant_trivially_destructible_base& operator=(variant_trivially_destructible_base&&) = default;
~variant_trivially_destructible_base() = default;
};
//***************************************************************************
/// variant_base specialisation for trivially destructible types.
/// Uses variadic_union storage. Destructor is trivial (defaulted), making
/// the variant a literal type eligible for constexpr / ROM placement.
/// No operation function pointer is needed since destroy/copy/move are
/// all handled without indirection for trivially destructible types.
/// The copy and move operations are inherited so that they are trivial
/// when every alternative is trivially copyable.
//***************************************************************************
template <typename... TTypes>
struct variant_base<true, TTypes...> : public variant_trivially_destructible_base<are_all_trivially_copyable<TTypes...>::value, TTypes...>
{
typedef variant_trivially_destructible_base<are_all_trivially_copyable<TTypes...>::value, TTypes...> base_t;
constexpr variant_base() noexcept
: base_t()
{
}
constexpr variant_base(size_t id) noexcept
: base_t(id)
{
}
template <size_t Index, typename T>
constexpr variant_base(etl::in_place_index_t<Index>, T&& value,
size_t id) noexcept(etl::is_nothrow_constructible<etl::nth_type_t<Index, TTypes...>, T>::value)
: base_t(etl::in_place_index_t<Index>{}, etl::forward<T>(value), id)
{
}
};
//*******************************************
/// Trait: are all types copy constructible?
//*******************************************

View File

@ -53,14 +53,74 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT)
#define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIAL)
#define ETL_USING_BUILTIN_IS_TRIVIAL 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE)
#define ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
#define ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_UNION)
#define ETL_USING_BUILTIN_IS_UNION 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_EMPTY)
#define ETL_USING_BUILTIN_IS_EMPTY 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC)
#define ETL_USING_BUILTIN_IS_POLYMORPHIC 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_ABSTRACT)
#define ETL_USING_BUILTIN_IS_ABSTRACT 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_FINAL)
#define ETL_USING_BUILTIN_IS_FINAL 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_AGGREGATE)
#define ETL_USING_BUILTIN_IS_AGGREGATE 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS)
#define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 1
#endif
@ -120,14 +180,74 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE (__has_builtin(__has_trivial_constructor) || __has_builtin(__is_trivially_constructible))
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE __has_builtin(__is_trivially_assignable)
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE (__has_builtin(__has_trivial_destructor) || __has_builtin(__is_trivially_destructible))
#endif
#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_DESTRUCTIBLE __has_builtin(__is_destructible)
#endif
#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE __has_builtin(__is_nothrow_destructible)
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE (__has_builtin(__has_trivial_copy) || __has_builtin(__is_trivially_copyable))
#endif
#if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT)
#define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT __has_builtin(__is_standard_layout)
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIAL)
#define ETL_USING_BUILTIN_IS_TRIVIAL __has_builtin(__is_trivial)
#endif
#if !defined(ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE)
#define ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE __has_builtin(__is_layout_compatible)
#endif
#if !defined(ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
#define ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF __has_builtin(__is_pointer_interconvertible_base_of)
#endif
#if !defined(ETL_USING_BUILTIN_IS_UNION)
#define ETL_USING_BUILTIN_IS_UNION __has_builtin(__is_union)
#endif
#if !defined(ETL_USING_BUILTIN_IS_EMPTY)
#define ETL_USING_BUILTIN_IS_EMPTY __has_builtin(__is_empty)
#endif
#if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC)
#define ETL_USING_BUILTIN_IS_POLYMORPHIC __has_builtin(__is_polymorphic)
#endif
#if !defined(ETL_USING_BUILTIN_IS_ABSTRACT)
#define ETL_USING_BUILTIN_IS_ABSTRACT __has_builtin(__is_abstract)
#endif
#if !defined(ETL_USING_BUILTIN_IS_FINAL)
#define ETL_USING_BUILTIN_IS_FINAL __has_builtin(__is_final)
#endif
#if !defined(ETL_USING_BUILTIN_IS_AGGREGATE)
#define ETL_USING_BUILTIN_IS_AGGREGATE __has_builtin(__is_aggregate)
#endif
#if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR __has_builtin(__has_virtual_destructor)
#endif
#if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS)
#define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS __has_builtin(__has_unique_object_representations)
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE __has_builtin(__underlying_type)
#endif
@ -136,6 +256,10 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED __has_builtin(__builtin_is_constant_evaluated)
#endif
#if !defined(ETL_USING_BUILTIN_CONSTANT_P)
#define ETL_USING_BUILTIN_CONSTANT_P __has_builtin(__builtin_constant_p)
#endif
#if !defined(ETL_USING_BUILTIN_BIT_CAST)
#define ETL_USING_BUILTIN_BIT_CAST __has_builtin(__builtin_bit_cast)
#endif
@ -183,6 +307,50 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT)
#define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIAL)
#define ETL_USING_BUILTIN_IS_TRIVIAL 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_UNION)
#define ETL_USING_BUILTIN_IS_UNION 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_EMPTY)
#define ETL_USING_BUILTIN_IS_EMPTY 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC)
#define ETL_USING_BUILTIN_IS_POLYMORPHIC 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_ABSTRACT)
#define ETL_USING_BUILTIN_IS_ABSTRACT 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_FINAL)
#define ETL_USING_BUILTIN_IS_FINAL 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_AGGREGATE)
#define ETL_USING_BUILTIN_IS_AGGREGATE 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS)
#define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
#endif
// MSVC has supported __builtin_bit_cast since VS2019 16.6. __has_builtin is not
// used for Microsoft (see above) to avoid a VS2022 intellisense issue, so the
// intrinsic is enabled here directly for the no-STL configuration.
@ -212,14 +380,74 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_NOTHROW_DESTRUCTIBLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_STANDARD_LAYOUT)
#define ETL_USING_BUILTIN_IS_STANDARD_LAYOUT 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIAL)
#define ETL_USING_BUILTIN_IS_TRIVIAL 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE)
#define ETL_USING_BUILTIN_IS_LAYOUT_COMPATIBLE 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
#define ETL_USING_BUILTIN_IS_POINTER_INTERCONVERTIBLE_BASE_OF 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_UNION)
#define ETL_USING_BUILTIN_IS_UNION 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_EMPTY)
#define ETL_USING_BUILTIN_IS_EMPTY 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_POLYMORPHIC)
#define ETL_USING_BUILTIN_IS_POLYMORPHIC 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_ABSTRACT)
#define ETL_USING_BUILTIN_IS_ABSTRACT 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_FINAL)
#define ETL_USING_BUILTIN_IS_FINAL 0
#endif
#if !defined(ETL_USING_BUILTIN_IS_AGGREGATE)
#define ETL_USING_BUILTIN_IS_AGGREGATE 0
#endif
#if !defined(ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_VIRTUAL_DESTRUCTOR 0
#endif
#if !defined(ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS)
#define ETL_USING_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 0
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 0
#endif
@ -260,6 +488,16 @@ SOFTWARE.
#define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE 0
#endif
// __builtin_constant_p predates __has_builtin on GCC and Clang, so enable it for
// those compilers when __has_builtin was not available to detect it.
#if !defined(ETL_USING_BUILTIN_CONSTANT_P) && (defined(__GNUC__) || defined(__clang__))
#define ETL_USING_BUILTIN_CONSTANT_P 1
#endif
#if !defined(ETL_USING_BUILTIN_CONSTANT_P)
#define ETL_USING_BUILTIN_CONSTANT_P 0
#endif
#if !defined(ETL_USING_BUILTIN_BIT_CAST)
#define ETL_USING_BUILTIN_BIT_CAST 0
#endif
@ -282,10 +520,12 @@ namespace etl
static ETL_CONSTANT bool using_builtin_is_nothrow_constructible = (ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE == 1);
static ETL_CONSTANT bool using_builtin_is_nothrow_assignable = (ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE == 1);
static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1);
static ETL_CONSTANT bool using_builtin_is_trivially_assignable = (ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE == 1);
static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1);
static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1);
static ETL_CONSTANT bool using_builtin_underlying_type = (ETL_USING_BUILTIN_UNDERLYING_TYPE == 1);
static ETL_CONSTANT bool using_builtin_is_constant_evaluated = (ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED == 1);
static ETL_CONSTANT bool using_builtin_constant_p = (ETL_USING_BUILTIN_CONSTANT_P == 1);
static ETL_CONSTANT bool using_builtin_memcpy = (ETL_USING_BUILTIN_MEMCPY == 1);
static ETL_CONSTANT bool using_builtin_memmove = (ETL_USING_BUILTIN_MEMMOVE == 1);
static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1);

View File

@ -384,7 +384,7 @@ namespace etl
//*************************************************************************
/// For a delegate slot type.
//*************************************************************************
template <typename TSlotType, typename... TArgs>
template <typename TSlotType>
static typename etl::enable_if_t<etl::is_delegate<TSlotType>::value, bool> slot_is_valid(const TSlotType& s) ETL_NOEXCEPT
{
return s.is_valid();
@ -393,7 +393,7 @@ namespace etl
//*************************************************************************
/// For a non-delegate slot type.
//*************************************************************************
template <typename TSlotType, typename... TArgs>
template <typename TSlotType>
static typename etl::enable_if_t<!etl::is_delegate<TSlotType>::value, bool> slot_is_valid(const TSlotType&) ETL_NOEXCEPT
{
return true;

View File

@ -425,18 +425,28 @@ namespace etl
//*************************************************************************
/// Shrinks the view by moving its start forward.
/// When n >= size(), the view is set to empty.
//*************************************************************************
ETL_CONSTEXPR14 void remove_prefix(size_type n) ETL_NOEXCEPT
ETL_CONSTEXPR14 void remove_prefix(size_type n)
{
mbegin += n;
ETL_ASSERT(n <= size(), ETL_ERROR(string_view_bounds));
if (n < size())
mbegin += n;
else
mbegin = mend;
}
//*************************************************************************
/// Shrinks the view by moving its end backward.
/// When n >= size(), the view is set to empty.
//*************************************************************************
ETL_CONSTEXPR14 void remove_suffix(size_type n) ETL_NOEXCEPT
ETL_CONSTEXPR14 void remove_suffix(size_type n)
{
mend -= n;
ETL_ASSERT(n <= size(), ETL_ERROR(string_view_bounds));
if (n < size())
mend -= n;
else
mend = mbegin;
}
//*************************************************************************

View File

@ -713,7 +713,9 @@ namespace etl
const uvalue_t uvalue = static_cast<uvalue_t>(accumulator_result.value());
// Convert from the accumulator type to the desired type.
result = (is_negative ? static_cast<TValue>(static_cast<TValue>(0) - static_cast<TValue>(uvalue)) : etl::bit_cast<TValue>(uvalue));
// The negation is performed on the unsigned type to avoid signed overflow
// when the value is the most negative value for the type.
result = (is_negative ? etl::bit_cast<TValue>(static_cast<uvalue_t>(static_cast<uvalue_t>(0) - uvalue)) : etl::bit_cast<TValue>(uvalue));
}
}
}
@ -908,7 +910,7 @@ ETL_CONSTEXPR14 bool operator==(const etl::to_arithmetic_result<T>& lhs, const e
}
else
{
return (lhs.status() == rhs.status());
return (lhs.error() == rhs.error());
}
}
@ -952,7 +954,7 @@ ETL_CONSTEXPR14 bool operator!=(const etl::to_arithmetic_result<T>& lhs, const U
/// Inequality test for etl::to_arithmetic_result
//***************************************************************************
template <typename T, typename U>
ETL_CONSTEXPR14 bool operator!=(const T& lhs, const etl::to_arithmetic_result<T>& rhs)
ETL_CONSTEXPR14 bool operator!=(const T& lhs, const etl::to_arithmetic_result<U>& rhs)
{
return !(lhs == rhs);
}

File diff suppressed because it is too large Load Diff

View File

@ -340,7 +340,31 @@ namespace etl
// We can't have std::swap and etl::swap templates coexisting in the unit
// tests as the compiler will be unable to decide which one to use, due to
// ADL.
// These are declared in type_traits.h, so that etl::is_swappable can find
// them, and defined here.
#if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)
#if ETL_USING_CPP11
//***************************************************************************
// swap
template <typename T>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_move_constructible<T>::value && etl::is_move_assignable<T>::value>::type swap(T& a, T& b)
ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible<T>::value&& etl::is_nothrow_move_assignable<T>::value)
{
T temp(ETL_MOVE(a));
a = ETL_MOVE(b);
b = ETL_MOVE(temp);
}
template <typename T, size_t Size>
ETL_CONSTEXPR14 typename etl::enable_if<private_type_traits::is_swappable_helper<T>::value>::type swap(T (&a)[Size], T (&b)[Size])
ETL_NOEXCEPT_IF(private_type_traits::is_nothrow_swappable_helper<T>::value)
{
for (size_t i = 0UL; i < Size; ++i)
{
swap(a[i], b[i]);
}
}
#else
//***************************************************************************
// swap
template <typename T>
@ -351,7 +375,7 @@ namespace etl
b = ETL_MOVE(temp);
}
template < class T, size_t Size >
template <typename T, size_t Size>
ETL_CONSTEXPR14 void swap(T (&a)[Size], T (&b)[Size]) ETL_NOEXCEPT
{
for (size_t i = 0UL; i < Size; ++i)
@ -359,6 +383,7 @@ namespace etl
swap(a[i], b[i]);
}
}
#endif
#endif
//***************************************************************************

View File

@ -1999,10 +1999,14 @@ namespace etl
/// Make
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
template <typename... T>
constexpr auto make_vector(T&&... t) -> etl::vector<typename etl::common_type_t<T...>, sizeof...(T)>
template <typename T = void, typename... TValues>
constexpr auto make_vector(TValues&&... values) -> etl::vector<etl::private_make::element_type_t<T, TValues...>, sizeof...(TValues)>
{
return {etl::forward<T>(t)...};
// Library Fundamentals TS make_array design: the element type is T when
// supplied explicitly, otherwise the decayed common type of the arguments.
// convert forwards same-type arguments and static_casts the rest.
using TElement = etl::private_make::element_type_t<T, TValues...>;
return {etl::private_make::convert<TElement>(etl::forward<TValues>(values))...};
}
#endif

View File

@ -77,7 +77,7 @@ namespace
CHECK_EQUAL(data.max_size(), 0);
}
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
#if ETL_USING_CPP17 && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
//*************************************************************************
TEST(test_cpp17_deduced_constructor)
{
@ -861,7 +861,7 @@ namespace
}
//*************************************************************************
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
#if ETL_USING_CPP17 && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
TEST(test_array_template_deduction)
{
etl::array data{char(0), short(1), 2, long(3), 4, 5, 6, 7, 8, 9};
@ -883,7 +883,7 @@ namespace
#endif
//*************************************************************************
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
#if ETL_USING_CPP17
TEST(test_array_template_deduction_for_movable)
{
etl::array data{Moveable(0), Moveable(1), Moveable(2), Moveable(3), Moveable(4),
@ -906,7 +906,7 @@ namespace
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
#if ETL_USING_CPP11
TEST(test_make_array)
{
auto data = etl::make_array<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
@ -928,7 +928,7 @@ namespace
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
#if ETL_USING_CPP11
TEST(test_make_array_for_movable)
{
auto data = etl::make_array<Moveable>(Moveable(0), Moveable(1), Moveable(2), Moveable(3), Moveable(4), Moveable(5), Moveable(6), Moveable(7),
@ -951,7 +951,7 @@ namespace
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
#if ETL_USING_CPP11
// Arguments that are const-qualified lvalues of the element type used to be rejected:
// the old implementation forwarded each argument as T, and forward<T> cannot accept a
// const T lvalue (it requires a non-const T&, and T&& cannot bind to a reference-related
@ -974,7 +974,7 @@ namespace
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
#if ETL_USING_CPP11
// The arguments are converted to the element type with static_cast, so narrowing
// initialisers (int literals and int lvalues narrowed to char) must keep working.
// Plain forwarding into the braced initialiser list would reject them.
@ -998,7 +998,74 @@ namespace
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP14
#if ETL_USING_CPP11
// With no explicit element type, the element type is deduced as the
// decayed common type of the arguments (Library Fundamentals TS
// make_array design).
TEST(test_make_array_deduced_element_type)
{
static const int static_const_lvalue = 1;
auto data = etl::make_array(static_const_lvalue, 2L, 3);
CHECK((std::is_same<etl::array<long, 3U>, decltype(data)>::value));
CHECK_EQUAL(1L, data[0]);
CHECK_EQUAL(2L, data[1]);
CHECK_EQUAL(3L, data[2]);
}
#endif
//*************************************************************************
#if ETL_USING_CPP11
// An empty array requires the element type to be supplied explicitly.
// etl::make_array() with no element type and no arguments is ill-formed,
// as in the Library Fundamentals TS: there is nothing to deduce the
// element type from.
TEST(test_make_array_empty)
{
auto data = etl::make_array<int>();
CHECK((std::is_same<etl::array<int, 0U>, decltype(data)>::value));
CHECK_TRUE(data.empty());
CHECK_EQUAL(0U, data.size());
}
#endif
//*************************************************************************
#if ETL_USING_CPP11
// Arguments that already have the element type are forwarded rather than
// cast. Casting created a prvalue that, before C++17, had to be
// materialised through the move constructor, so a copyable type with a
// deleted move constructor was rejected.
TEST(test_make_array_for_copyable_non_movable)
{
struct NonMovable
{
explicit NonMovable(int v_)
: v(v_)
{
}
NonMovable(const NonMovable&) = default;
NonMovable(NonMovable&&) = delete;
int v;
};
NonMovable mutable_lvalue(1);
const NonMovable const_lvalue(2);
auto data = etl::make_array<NonMovable>(mutable_lvalue, const_lvalue);
using Type = etl::remove_reference_t<decltype(data[0])>;
CHECK((std::is_same<NonMovable, Type>::value));
CHECK_EQUAL(1, data[0].v);
CHECK_EQUAL(2, data[1].v);
}
#endif
//*************************************************************************
#if ETL_USING_CPP14
TEST(test_make_array_is_constexpr)
{
static constexpr unsigned char constexpr_value = 0x18U;

View File

@ -67,6 +67,123 @@ namespace
CHECK(data.crbegin() == data.crend());
}
//*************************************************************************
TEST(test_constructor_with_size)
{
etl::circular_buffer<int, SIZE> data(5U);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
}
//*************************************************************************
TEST(test_constructor_with_excess_size)
{
etl::circular_buffer<int, SIZE> data(SIZE + 3U);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
}
//*************************************************************************
TEST(test_constructor_with_size_and_value)
{
const Ndc value("value");
Data data(5U, value);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_constructor_with_excess_size_and_value)
{
const Ndc value("value");
Data data(SIZE + 3U, value);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_assign_size_and_value)
{
Data data;
data.push(Ndc("old"));
const Ndc value("value");
data.assign(5U, value);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
data.assign(0U, value);
CHECK(data.empty());
data.assign(SIZE + 3U, value);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_assign_range)
{
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
Compare expected(input.end() - SIZE, input.end());
Data data;
data.push(Ndc("old"));
data.assign(input.begin(), input.end());
CHECK(data.full());
CHECK_EQUAL(expected.size(), data.size());
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
data.assign(input.begin(), input.begin());
CHECK(data.empty());
}
//*************************************************************************
TEST(test_assign_self_range)
{
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
Compare expected(input.end() - SIZE, input.end());
Data data(input.begin(), input.end());
data.assign(data.begin(), data.end());
CHECK(data.full());
CHECK_EQUAL(expected.size(), data.size());
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
Data::const_iterator first = data.cbegin() + 2;
Data::const_iterator last = data.cend() - 2;
Compare partial_expected(expected.begin() + 2, expected.end() - 2);
data.assign(first, last);
CHECK_EQUAL(partial_expected.size(), data.size());
CHECK(std::equal(partial_expected.begin(), partial_expected.end(), data.begin()));
}
//*************************************************************************
TEST(test_assign_aliased_value)
{
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4")};
Data data(input.begin(), input.end());
const Ndc expected(data.front());
data.assign(7U, data.front());
CHECK_EQUAL(7U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&expected](const Ndc& item) { return item == expected; }));
}
#if ETL_HAS_INITIALIZER_LIST
//*************************************************************************
TEST(test_constructor_from_literal)

View File

@ -78,6 +78,131 @@ namespace
CHECK(data.crbegin() == data.crend());
}
//*************************************************************************
TEST(test_constructor_with_size)
{
etl::uninitialized_buffer_of<int, SIZE + 1> buffer1;
etl::circular_buffer_ext<int> data(5U, buffer1.raw, SIZE);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
}
//*************************************************************************
TEST(test_constructor_with_excess_size)
{
etl::uninitialized_buffer_of<int, SIZE + 1> buffer1;
etl::circular_buffer_ext<int> data(SIZE + 3U, buffer1.raw, SIZE);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
}
//*************************************************************************
TEST(test_constructor_with_size_and_value)
{
Buffer_t buffer1;
const Ndc value("value");
Data data(5U, value, buffer1.raw, SIZE);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_constructor_with_excess_size_and_value)
{
Buffer_t buffer1;
const Ndc value("value");
Data data(SIZE + 3U, value, buffer1.raw, SIZE);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_assign_size_and_value)
{
Buffer_t buffer1;
Data data(buffer1.raw, SIZE);
data.push(Ndc("old"));
const Ndc value("value");
data.assign(5U, value);
CHECK_EQUAL(5U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
data.assign(0U, value);
CHECK(data.empty());
data.assign(SIZE + 3U, value);
CHECK(data.full());
CHECK_EQUAL(SIZE, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
}
//*************************************************************************
TEST(test_assign_range)
{
Buffer_t buffer1;
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
Compare expected(input.end() - SIZE, input.end());
Data data(buffer1.raw, SIZE);
data.push(Ndc("old"));
data.assign(input.begin(), input.end());
CHECK(data.full());
CHECK_EQUAL(expected.size(), data.size());
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
data.assign(input.begin(), input.begin());
CHECK(data.empty());
}
//*************************************************************************
TEST(test_assign_self_range)
{
Buffer_t buffer1;
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
Compare expected(input.end() - SIZE, input.end());
Data data(input.begin(), input.end(), buffer1.raw, SIZE);
data.assign(data.begin(), data.end());
CHECK(data.full());
CHECK_EQUAL(expected.size(), data.size());
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
Data::const_iterator first = data.cbegin() + 2;
Data::const_iterator last = data.cend() - 2;
Compare partial_expected(expected.begin() + 2, expected.end() - 2);
data.assign(first, last);
CHECK_EQUAL(partial_expected.size(), data.size());
CHECK(std::equal(partial_expected.begin(), partial_expected.end(), data.begin()));
}
//*************************************************************************
TEST(test_assign_aliased_value)
{
Buffer_t buffer1;
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4")};
Data data(input.begin(), input.end(), buffer1.raw, SIZE);
const Ndc expected(data.front());
data.assign(7U, data.front());
CHECK_EQUAL(7U, data.size());
CHECK(std::all_of(data.begin(), data.end(), [&expected](const Ndc& item) { return item == expected; }));
}
//*************************************************************************
TEST(test_set_buffer_after_default_constructor)
{

View File

@ -2183,6 +2183,65 @@ namespace
}
#endif
#if ETL_USING_CPP17
//*************************************************************************
// Verify that copy assigning a delegate, and comparing against a default
// constructed one, are usable in a constant expression.
//*************************************************************************
TEST(test_constexpr_copy_assignment_and_clear)
{
using delegate_type = etl::delegate<void(void)>;
// Copy assignment from a bound delegate.
constexpr auto copy_assigned = []() constexpr
{
const delegate_type source(&free_void);
delegate_type d;
d = source;
return d;
};
constexpr delegate_type d1 = copy_assigned();
static_assert(d1.is_valid(), "a copy assigned delegate should be valid");
static_assert(d1 == delegate_type(&free_void), "a copy assigned delegate should compare equal to its source");
// Copy assignment from a default constructed delegate, and comparing an
// unbound delegate against another one. Neither may inspect the null stub
// pointer, which the undefined behaviour sanitizer makes non-constant.
constexpr auto cleared = []() constexpr
{
delegate_type d(&free_void);
d = delegate_type();
return d;
};
constexpr delegate_type d2 = cleared();
static_assert(!d2.is_valid(), "a delegate assigned from a default constructed one should be invalid");
static_assert(d2 == delegate_type(), "an unbound delegate should compare equal to a default constructed one");
static_assert(d2 != d1, "an unbound delegate should not compare equal to a bound one");
// The same operations must still behave identically at run time.
delegate_type d3;
d3 = d1;
CHECK_TRUE(d3.is_valid());
CHECK(d3 == d1);
d3 = delegate_type();
CHECK_FALSE(d3.is_valid());
CHECK(d3 == delegate_type());
// Assigning a null function pointer clears the delegate at run time.
// This is deliberately not checked in a constant expression: the null
// test cannot be folded there when the sanitizer instruments it.
delegate_type d4(&free_void);
d4 = static_cast<void (*)()>(ETL_NULLPTR);
CHECK_FALSE(d4.is_valid());
CHECK(d4 == delegate_type());
}
#endif
TEST(test_delegate_clear_equals_default_constructed)
{
using delegate_type = etl::delegate<void(int, int)>;

View File

@ -2346,6 +2346,25 @@ namespace
}
#endif
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
// With no explicit element type, the element type is deduced as the
// decayed common type of the arguments (Library Fundamentals TS
// make_array design).
TEST(test_make_deque_deduced_element_type)
{
static const int static_const_lvalue = 1;
auto data = etl::make_deque(static_const_lvalue, 2L, 3);
CHECK((std::is_same<etl::deque<long, 3U>, decltype(data)>::value));
CHECK_EQUAL(1L, data[0]);
CHECK_EQUAL(2L, data[1]);
CHECK_EQUAL(3L, data[2]);
}
#endif
//*************************************************************************
TEST(test_fill)
{
@ -2370,9 +2389,10 @@ namespace
#include "etl/private/diagnostic_uninitialized_push.h"
// Verify operator[] returns values matching sequential access
for (size_t i = 0; i < cdata.size(); ++i)
DataNDC::difference_type it_idx = 0;
for (size_t i = 0; i < cdata.size(); ++i, ++it_idx)
{
CHECK(cit[i] == cdata[i]);
CHECK(cit[it_idx] == cdata[i]);
}
// Verify const_iterator operator[] returns const_reference

View File

@ -1556,6 +1556,30 @@ namespace
}
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
// An explicit element type selects the element type and converts every
// argument (Library Fundamentals TS make_array design), accepting
// const-qualified lvalues and narrowing initialisers.
TEST(test_make_forward_list_explicit_element_type)
{
static const char static_const_lvalue = 42;
const char local_const_lvalue = 43;
char mutable_lvalue = 44;
auto data = etl::make_forward_list<char>(static_const_lvalue, local_const_lvalue, mutable_lvalue, 45, 46);
CHECK((std::is_same<etl::forward_list<char, 5U>, decltype(data)>::value));
auto itr = data.begin();
CHECK_EQUAL(42, *itr++);
CHECK_EQUAL(43, *itr++);
CHECK_EQUAL(44, *itr++);
CHECK_EQUAL(45, *itr++);
CHECK_EQUAL(46, *itr++);
}
#endif
//*************************************************************************
TEST(test_forward_list_exception_types)
{

View File

@ -1644,5 +1644,28 @@ namespace
CHECK_EQUAL(44, data[2]);
}
#endif
//*************************************************************************
#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
// An explicit element type selects the element type and converts every
// argument (Library Fundamentals TS make_array design), accepting
// const-qualified lvalues and narrowing initialisers.
TEST(test_make_indirect_vector_explicit_element_type)
{
static const char static_const_lvalue = 42;
const char local_const_lvalue = 43;
char mutable_lvalue = 44;
auto data = etl::make_indirect_vector<char>(static_const_lvalue, local_const_lvalue, mutable_lvalue, 45, 46);
CHECK((std::is_same<etl::indirect_vector<char, 5U>, decltype(data)>::value));
CHECK_EQUAL(42, data[0]);
CHECK_EQUAL(43, data[1]);
CHECK_EQUAL(44, data[2]);
CHECK_EQUAL(45, data[3]);
CHECK_EQUAL(46, data[4]);
}
#endif
}
} // namespace

View File

@ -29,6 +29,7 @@ SOFTWARE.
#include "unit_test_framework.h"
#include <algorithm>
#include <forward_list>
#include <list>
#include <queue>
#include <string>
@ -1420,6 +1421,55 @@ namespace
CHECK_EQUAL(1, *result);
}
//*************************************************************************
// etl::ranges::distance(first, last)
//*************************************************************************
TEST(ranges_distance_iterator_sentinel)
{
int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(&data[0], &data[10]));
CHECK_EQUAL(4, etl::ranges::distance(&data[3], &data[7]));
CHECK_EQUAL(0, etl::ranges::distance(&data[3], &data[3]));
non_random_iterator<int> first(&data[0]);
non_random_sentinel<int> last(&data[6]);
CHECK_EQUAL(6, etl::ranges::distance(first, last));
}
//*************************************************************************
// etl::ranges::distance(range)
//*************************************************************************
TEST(ranges_distance_range_with_size_member)
{
std::vector<int> data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(data));
const std::vector<int>& cdata = data;
CHECK_EQUAL(10, etl::ranges::distance(cdata));
std::vector<int> empty_data;
CHECK_EQUAL(0, etl::ranges::distance(empty_data));
}
//*************************************************************************
TEST(ranges_distance_c_array)
{
int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(data));
}
//*************************************************************************
TEST(ranges_distance_range_without_size_member)
{
std::forward_list<int> data = {0, 1, 2, 3, 4};
CHECK_EQUAL(5, etl::ranges::distance(data));
CHECK_EQUAL(etl::ranges::distance(data.begin(), data.end()), etl::ranges::distance(data));
}
TEST(test_is_range)
{
std::vector<int> vec;

View File

@ -2377,5 +2377,29 @@ namespace
CHECK_EQUAL(3, data2.begin()->value);
}
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
// An explicit element type selects the element type and converts every
// argument (Library Fundamentals TS make_array design), accepting
// const-qualified lvalues and narrowing initialisers.
TEST(test_make_list_explicit_element_type)
{
static const char static_const_lvalue = 42;
const char local_const_lvalue = 43;
char mutable_lvalue = 44;
auto data = etl::make_list<char>(static_const_lvalue, local_const_lvalue, mutable_lvalue, 45, 46);
CHECK((std::is_same<etl::list<char, 5U>, decltype(data)>::value));
auto itr = data.begin();
CHECK_EQUAL(42, *itr++);
CHECK_EQUAL(43, *itr++);
CHECK_EQUAL(44, *itr++);
CHECK_EQUAL(45, *itr++);
CHECK_EQUAL(46, *itr++);
}
#endif
}
} // namespace

View File

@ -103,6 +103,34 @@ namespace
return true;
}
template <typename R1, typename R2>
bool Check_Equal(R1 range1, R2 range2)
{
while (range1.first != range1.second)
{
if (range2.first == range2.second)
{
return false;
}
auto& pair1 = *range1.first;
auto& pair2 = *range2.first;
if ((pair1.first != pair2.first) || (pair1.second != pair2.second))
{
return false;
}
++range1.first;
++range2.first;
}
return range2.first == range2.second;
}
template <typename T1, typename T2>
bool Check_ContainsPair(T1 begin, T1 end, const T2& pair)
{
return std::find_if(begin, end, [&pair](typename T1::reference item) { return (item.first == pair.first) && (item.second == pair.second); })
!= end;
}
#include "etl/private/diagnostic_null_dereference_push.h"
//*************************************************************************
@ -694,13 +722,7 @@ namespace
ETL_OR_STD::pair<Compare_Data::iterator, Compare_Data::iterator> compare_result = compare_data.equal_range("1");
// Check that both return the same return results
CHECK(compare_result.first->first == data_result.first->first);
CHECK(compare_result.first->second == data_result.first->second);
CHECK(compare_result.second->first == data_result.second->first);
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
const bool isEqual = Check_Equal(data_result, compare_result);
CHECK(isEqual);
}
@ -718,13 +740,7 @@ namespace
ETL_OR_STD::pair<CMap::iterator, CMap::iterator> compare_result = compare_data.equal_range("1");
// Check that both return the same return results
CHECK(compare_result.first->first == data_result.first->first);
CHECK(compare_result.first->second == data_result.first->second);
CHECK(compare_result.second->first == data_result.second->first);
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
const bool isEqual = Check_Equal(data_result, compare_result);
CHECK(isEqual);
}
@ -739,13 +755,7 @@ namespace
ETL_OR_STD::pair<Compare_Data::const_iterator, Compare_Data::const_iterator> compare_result = compare_data.equal_range("2");
// Check that both return the same return results
CHECK(compare_result.first->first == data_result.first->first);
CHECK(compare_result.first->second == data_result.first->second);
CHECK(compare_result.second->first == data_result.second->first);
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
const bool isEqual = Check_Equal(data_result, compare_result);
CHECK(isEqual);
}
@ -763,13 +773,7 @@ namespace
ETL_OR_STD::pair<CMap::const_iterator, CMap::const_iterator> compare_result = compare_data.equal_range("2");
// Check that both return the same return results
CHECK(compare_result.first->first == data_result.first->first);
CHECK(compare_result.first->second == data_result.first->second);
CHECK(compare_result.second->first == data_result.second->first);
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
const bool isEqual = Check_Equal(data_result, compare_result);
CHECK(isEqual);
}
@ -1022,47 +1026,47 @@ namespace
Compare_Data compare_data(initial_data.begin(), initial_data.end());
Data data(initial_data.begin(), initial_data.end());
Data::iterator i_data = data.find("0");
Compare_Data::iterator i_compare = compare_data.find("0");
Data::iterator i_data = data.find("0");
auto i_compare = compare_data.equal_range("0");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("1");
i_compare = compare_data.find("1");
i_compare = compare_data.equal_range("1");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("2");
i_compare = compare_data.find("2");
i_compare = compare_data.equal_range("2");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("3");
i_compare = compare_data.find("3");
i_compare = compare_data.equal_range("3");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(".");
i_compare = compare_data.find(".");
i_compare = compare_data.equal_range(".");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
i_data = data.find("A");
i_compare = compare_data.find("A");
i_compare = compare_data.equal_range("A");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
}
//*************************************************************************
@ -1075,46 +1079,46 @@ namespace
CMap compare_data(initial_data.begin(), initial_data.end());
EMap::iterator i_data = data.find(Key("0"));
CMap::iterator i_compare = compare_data.find("0");
auto i_compare = compare_data.equal_range("0");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("1"));
i_compare = compare_data.find("1");
i_compare = compare_data.equal_range("1");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("2"));
i_compare = compare_data.find("2");
i_compare = compare_data.equal_range("2");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("3"));
i_compare = compare_data.find("3");
i_compare = compare_data.equal_range("3");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("."));
i_compare = compare_data.find(".");
i_compare = compare_data.equal_range(".");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
i_data = data.find(Key("A"));
i_compare = compare_data.find("A");
i_compare = compare_data.equal_range("A");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
}
//*************************************************************************
@ -1123,47 +1127,47 @@ namespace
const Compare_Data compare_data(initial_data.begin(), initial_data.end());
const Data data(initial_data.begin(), initial_data.end());
Data::const_iterator i_data = data.find("0");
Compare_Data::const_iterator i_compare = compare_data.find("0");
Data::const_iterator i_data = data.find("0");
auto i_compare = compare_data.equal_range("0");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("1");
i_compare = compare_data.find("1");
i_compare = compare_data.equal_range("1");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("2");
i_compare = compare_data.find("2");
i_compare = compare_data.equal_range("2");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find("3");
i_compare = compare_data.find("3");
i_compare = compare_data.equal_range("3");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(".");
i_compare = compare_data.find(".");
i_compare = compare_data.equal_range(".");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
i_data = data.find("A");
i_compare = compare_data.find("A");
i_compare = compare_data.equal_range("A");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
}
//*************************************************************************
@ -1176,46 +1180,46 @@ namespace
const CMap compare_data(initial_data.begin(), initial_data.end());
EMap::const_iterator i_data = data.find(Key("0"));
CMap::const_iterator i_compare = compare_data.find("0");
auto i_compare = compare_data.equal_range("0");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("1"));
i_compare = compare_data.find("1");
i_compare = compare_data.equal_range("1");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("2"));
i_compare = compare_data.find("2");
i_compare = compare_data.equal_range("2");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("3"));
i_compare = compare_data.find("3");
i_compare = compare_data.equal_range("3");
// Check that both return successful return results
CHECK(i_compare->first == i_data->first);
CHECK(i_compare->second == i_data->second);
CHECK(i_data != data.end());
CHECK(Check_ContainsPair(i_compare.first, i_compare.second, *i_data));
i_data = data.find(Key("."));
i_compare = compare_data.find(".");
i_compare = compare_data.equal_range(".");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
i_data = data.find(Key("A"));
i_compare = compare_data.find("A");
i_compare = compare_data.equal_range("A");
// Check that both return successful return results
CHECK(data.end() == i_data);
CHECK(compare_data.end() == i_compare);
CHECK(i_data == data.end());
CHECK(i_compare.first == i_compare.second);
}
//*************************************************************************

View File

@ -35,6 +35,12 @@ SOFTWARE.
#include <type_traits>
#include <utility>
// GCC can emit false positive -Wmaybe-uninitialized warnings inside the test data
// types when optional's storage is inspected through inlined, never-taken branches.
// The diagnostic is raised late (after inlining), so the suppression has to cover the
// whole translation unit. It is popped at the end of the file.
#include "etl/private/diagnostic_uninitialized_push.h"
#include "data.h"
#include "etl/algorithm.h"
#include "etl/optional.h"
@ -1603,5 +1609,351 @@ namespace
#endif
}
#endif
#if ETL_USING_CPP11
//*************************************************************************
TEST(test_transform)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
etl::optional<int> doubled = engaged.transform([](int i) { return i * 2; });
CHECK_TRUE(doubled.has_value());
CHECK_EQUAL(84, doubled.value());
etl::optional<int> from_empty = empty.transform([](int i) { return i * 2; });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_transform_const)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> doubled = engaged.transform([](int i) { return i * 2; });
CHECK_TRUE(doubled.has_value());
CHECK_EQUAL(84, doubled.value());
etl::optional<int> from_empty = empty.transform([](int i) { return i * 2; });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_transform_change_type)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
etl::optional<std::string> text = engaged.transform([](int) { return std::string("forty two"); });
CHECK_TRUE(text.has_value());
CHECK_EQUAL("forty two", text.value());
etl::optional<std::string> text_from_empty = empty.transform([](int) { return std::string("forty two"); });
CHECK_FALSE(text_from_empty.has_value());
}
//*************************************************************************
TEST(test_transform_non_pod)
{
etl::optional<Data> engaged(Data("transform"));
etl::optional<Data> empty;
etl::optional<size_t> length = engaged.transform([](const Data& d) { return d.value.size(); });
CHECK_TRUE(length.has_value());
CHECK_EQUAL(9U, length.value());
etl::optional<size_t> length_from_empty = empty.transform([](const Data& d) { return d.value.size(); });
CHECK_FALSE(length_from_empty.has_value());
}
//*************************************************************************
TEST(test_transform_move)
{
etl::optional<DataM> engaged(DataM(42U));
etl::optional<DataM> moved = etl::move(engaged).transform([](DataM&& d) { return DataM(etl::move(d)); });
CHECK_TRUE(moved.has_value());
CHECK_TRUE(moved.value().valid);
CHECK_EQUAL(42U, moved.value().value);
CHECK_FALSE(engaged.value().valid);
etl::optional<DataM> empty;
etl::optional<DataM> from_empty = etl::move(empty).transform([](DataM&& d) { return DataM(etl::move(d)); });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_and_then)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
etl::optional<int> incremented = engaged.and_then([](int i) { return etl::optional<int>(i + 1); });
CHECK_TRUE(incremented.has_value());
CHECK_EQUAL(43, incremented.value());
etl::optional<int> from_empty = empty.and_then([](int i) { return etl::optional<int>(i + 1); });
CHECK_FALSE(from_empty.has_value());
etl::optional<int> rejected = engaged.and_then([](int) { return etl::optional<int>(); });
CHECK_FALSE(rejected.has_value());
}
//*************************************************************************
TEST(test_and_then_const)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> incremented = engaged.and_then([](int i) { return etl::optional<int>(i + 1); });
CHECK_TRUE(incremented.has_value());
CHECK_EQUAL(43, incremented.value());
etl::optional<int> from_empty = empty.and_then([](int i) { return etl::optional<int>(i + 1); });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_and_then_change_type)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
etl::optional<std::string> text = engaged.and_then([](int) { return etl::optional<std::string>("forty two"); });
CHECK_TRUE(text.has_value());
CHECK_EQUAL("forty two", text.value());
etl::optional<std::string> text_from_empty = empty.and_then([](int) { return etl::optional<std::string>("forty two"); });
CHECK_FALSE(text_from_empty.has_value());
}
//*************************************************************************
TEST(test_and_then_move)
{
etl::optional<DataM> engaged(DataM(42U));
etl::optional<uint32_t> value = etl::move(engaged).and_then([](DataM&& d) { return etl::optional<uint32_t>(d.value); });
CHECK_TRUE(value.has_value());
CHECK_EQUAL(42U, value.value());
etl::optional<DataM> empty;
etl::optional<uint32_t> from_empty = etl::move(empty).and_then([](DataM&& d) { return etl::optional<uint32_t>(d.value); });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_or_else)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
bool called = false;
etl::optional<int> from_engaged = engaged.or_else(
[&called]()
{
called = true;
return etl::optional<int>(99);
});
CHECK_TRUE(from_engaged.has_value());
CHECK_EQUAL(42, from_engaged.value());
CHECK_FALSE(called);
etl::optional<int> from_empty = empty.or_else(
[&called]()
{
called = true;
return etl::optional<int>(99);
});
CHECK_TRUE(from_empty.has_value());
CHECK_EQUAL(99, from_empty.value());
CHECK_TRUE(called);
etl::optional<int> still_empty = empty.or_else([]() { return etl::optional<int>(); });
CHECK_FALSE(still_empty.has_value());
}
//*************************************************************************
TEST(test_or_else_const)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> from_engaged = engaged.or_else([]() { return etl::optional<int>(99); });
CHECK_TRUE(from_engaged.has_value());
CHECK_EQUAL(42, from_engaged.value());
etl::optional<int> from_empty = empty.or_else([]() { return etl::optional<int>(99); });
CHECK_TRUE(from_empty.has_value());
CHECK_EQUAL(99, from_empty.value());
}
//*************************************************************************
TEST(test_or_else_move)
{
etl::optional<DataM> engaged(DataM(42U));
etl::optional<DataM> from_engaged = etl::move(engaged).or_else([]() { return etl::optional<DataM>(DataM(99U)); });
CHECK_TRUE(from_engaged.has_value());
CHECK_EQUAL(42U, from_engaged.value().value);
etl::optional<DataM> empty;
etl::optional<DataM> from_empty = etl::move(empty).or_else([]() { return etl::optional<DataM>(DataM(99U)); });
CHECK_TRUE(from_empty.has_value());
CHECK_EQUAL(99U, from_empty.value().value);
}
//*************************************************************************
TEST(test_monadic_chaining)
{
etl::optional<int> engaged(8);
etl::optional<int> empty;
etl::optional<int> result = engaged.transform([](int i) { return i * 2; })
.and_then([](int i) { return etl::optional<int>(i + 1); })
.or_else([]() { return etl::optional<int>(0); });
CHECK_TRUE(result.has_value());
CHECK_EQUAL(17, result.value());
etl::optional<int> result_from_empty = empty.transform([](int i) { return i * 2; })
.and_then([](int i) { return etl::optional<int>(i + 1); })
.or_else([]() { return etl::optional<int>(123); });
CHECK_TRUE(result_from_empty.has_value());
CHECK_EQUAL(123, result_from_empty.value());
}
//*************************************************************************
TEST(test_is_optional)
{
CHECK_TRUE((etl::is_optional<etl::optional<int>>::value));
CHECK_TRUE((etl::is_optional<const etl::optional<int>>::value));
CHECK_TRUE((etl::is_optional<volatile etl::optional<int>>::value));
CHECK_TRUE((etl::is_optional<const volatile etl::optional<int>>::value));
CHECK_TRUE((etl::is_optional<etl::optional<Data>>::value));
CHECK_FALSE((etl::is_optional<int>::value));
CHECK_FALSE((etl::is_optional<Data>::value));
CHECK_FALSE((etl::is_optional<etl::optional<int>*>::value));
CHECK_FALSE((etl::is_optional<etl::optional<int>&>::value));
#if ETL_USING_CPP17
CHECK_TRUE((etl::is_optional_v<etl::optional<int>>));
CHECK_TRUE((etl::is_optional_v<const etl::optional<int>>));
CHECK_FALSE((etl::is_optional_v<int>));
#endif
}
//*************************************************************************
TEST(test_transform_const_rvalue)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> doubled = etl::move(engaged).transform([](const int&& i) { return i * 2; });
CHECK_TRUE(doubled.has_value());
CHECK_EQUAL(84, doubled.value());
CHECK_TRUE(engaged.has_value());
CHECK_EQUAL(42, engaged.value());
etl::optional<int> from_empty = etl::move(empty).transform([](const int&& i) { return i * 2; });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_and_then_const_rvalue)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> incremented = etl::move(engaged).and_then([](const int&& i) { return etl::optional<int>(i + 1); });
CHECK_TRUE(incremented.has_value());
CHECK_EQUAL(43, incremented.value());
etl::optional<int> from_empty = etl::move(empty).and_then([](const int&& i) { return etl::optional<int>(i + 1); });
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_or_else_const_rvalue)
{
const etl::optional<int> engaged(42);
const etl::optional<int> empty;
etl::optional<int> from_engaged = etl::move(engaged).or_else([]() { return etl::optional<int>(99); });
CHECK_TRUE(from_engaged.has_value());
CHECK_EQUAL(42, from_engaged.value());
etl::optional<int> from_empty = etl::move(empty).or_else([]() { return etl::optional<int>(99); });
CHECK_TRUE(from_empty.has_value());
CHECK_EQUAL(99, from_empty.value());
}
//*************************************************************************
/// Unlike std::optional, a callable returning a reference is accepted.
/// The reference is stripped from the result type and the value is copied.
//*************************************************************************
TEST(test_transform_callable_returning_reference)
{
etl::optional<int> engaged(42);
auto result = engaged.transform([](int& i) -> int& { return i; });
CHECK_TRUE((etl::is_same<etl::optional<int>, decltype(result)>::value));
CHECK_TRUE(result.has_value());
CHECK_EQUAL(42, result.value());
// The result is a copy, not an alias of the source.
result.value() = 1;
CHECK_EQUAL(42, engaged.value());
}
//*************************************************************************
TEST(test_and_then_callable_returning_reference)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
auto f = [](int i) -> etl::optional<int>&
{
static etl::optional<int> shared;
shared = i + 1;
return shared;
};
auto result = engaged.and_then(f);
CHECK_TRUE((etl::is_same<etl::optional<int>, decltype(result)>::value));
CHECK_TRUE(result.has_value());
CHECK_EQUAL(43, result.value());
auto from_empty = empty.and_then(f);
CHECK_FALSE(from_empty.has_value());
}
//*************************************************************************
TEST(test_or_else_callable_returning_reference)
{
etl::optional<int> engaged(42);
etl::optional<int> empty;
auto f = []() -> etl::optional<int>&
{
static etl::optional<int> shared(99);
return shared;
};
auto from_engaged = engaged.or_else(f);
CHECK_TRUE((etl::is_same<etl::optional<int>, decltype(from_engaged)>::value));
CHECK_TRUE(from_engaged.has_value());
CHECK_EQUAL(42, from_engaged.value());
auto from_empty = empty.or_else(f);
CHECK_TRUE(from_empty.has_value());
CHECK_EQUAL(99, from_empty.value());
}
#endif
}
} // namespace
#include "etl/private/diagnostic_pop.h"

View File

@ -542,6 +542,50 @@ namespace
CHECK(isEqual);
}
//*************************************************************************
TEST(test_remove_prefix_empty)
{
std::string original = "Hello World";
View view(original.c_str());
// remove n == size() should result in an empty view
view.remove_prefix(original.size());
CHECK_EQUAL(view.begin(), view.end());
CHECK(view.empty());
}
//*************************************************************************
TEST(test_remove_prefix_assert)
{
std::string original = "Hello World";
View view(original.c_str());
// remove n > size() should trigger ETL_ASSERT
CHECK_THROW(view.remove_prefix(original.size() + 1), etl::string_view_bounds);
}
//*************************************************************************
TEST(test_remove_suffix_empty)
{
std::string original = "Hello World";
View view(original.c_str());
// remove n == size() should result in an empty view
view.remove_suffix(original.size());
CHECK_EQUAL(view.begin(), view.end());
CHECK(view.empty());
}
//*************************************************************************
TEST(test_remove_suffix_assert)
{
std::string original = "Hello World";
View view(original.c_str());
// remove n > size() should trigger ETL_ASSERT
CHECK_THROW(view.remove_suffix(original.size() + 1), etl::string_view_bounds);
}
//*************************************************************************
TEST(test_copy)
{

View File

@ -1039,6 +1039,71 @@ namespace
CHECK_EQUAL(83, int(etl::to_arithmetic<int8_t>(ETLText(text.c_str(), text.size()), etl::radix::decimal).value()));
}
//*************************************************************************
TEST(test_comparison_operators)
{
const Text text(STR("123"));
const Text bad_text(STR("1X3"));
const Text other_bad_text(STR("2X3"));
const Text overflow_text(STR("99999999999999999999"));
const etl::to_arithmetic_result<int> result = etl::to_arithmetic<int>(text.c_str(), text.size());
const etl::to_arithmetic_result<int> same = etl::to_arithmetic<int>(text.c_str(), text.size());
const etl::to_arithmetic_result<int> bad_result = etl::to_arithmetic<int>(bad_text.c_str(), bad_text.size());
const etl::to_arithmetic_result<int> same_bad_result = etl::to_arithmetic<int>(other_bad_text.c_str(), other_bad_text.size());
const etl::to_arithmetic_result<int> overflow_result = etl::to_arithmetic<int>(overflow_text.c_str(), overflow_text.size());
// result <-> result
CHECK_TRUE(result == same);
CHECK_FALSE(result != same);
CHECK_TRUE(result != bad_result);
CHECK_FALSE(result == bad_result);
// Two errored results with the same status compare equal.
CHECK_EQUAL(bad_result.error(), same_bad_result.error());
CHECK_TRUE(bad_result == same_bad_result);
CHECK_FALSE(bad_result != same_bad_result);
// Two errored results with different statuses do not compare equal.
CHECK(bad_result.error() != overflow_result.error());
CHECK_TRUE(bad_result != overflow_result);
CHECK_FALSE(bad_result == overflow_result);
// result <-> value
CHECK_TRUE(result == 123);
CHECK_FALSE(result != 123);
CHECK_TRUE(result != 124);
CHECK_FALSE(result == 124);
// value <-> result
CHECK_TRUE(123 == result);
CHECK_FALSE(123 != result);
CHECK_TRUE(124 != result);
CHECK_FALSE(124 == result);
// An errored result never compares equal to a value.
CHECK_FALSE(bad_result == 123);
CHECK_TRUE(bad_result != 123);
CHECK_FALSE(123 == bad_result);
CHECK_TRUE(123 != bad_result);
// Heterogeneous result <-> value, using a different result value type.
const etl::to_arithmetic_result<long> long_result = etl::to_arithmetic<long>(text.c_str(), text.size());
const etl::to_arithmetic_result<int8_t> small_result = etl::to_arithmetic<int8_t>(text.c_str(), text.size());
CHECK_TRUE(long_result == 123);
CHECK_FALSE(long_result != 123);
CHECK_TRUE(123 == long_result);
CHECK_TRUE(long_result != 124);
CHECK_FALSE(123 != long_result);
CHECK_TRUE(124 != long_result);
CHECK_TRUE(small_result == 123);
CHECK_FALSE(small_result != 123);
CHECK_TRUE(123 == small_result);
CHECK_TRUE(small_result != 124);
}
//*************************************************************************
#if ETL_USING_CPP14
TEST(test_constexpr_integral)

File diff suppressed because it is too large Load Diff

View File

@ -1324,6 +1324,35 @@ namespace
CHECK(etl::get<TrivialAssignTracker>(variant_1).move_assigned);
}
//*************************************************************************
// Issue #1567: the variant propagates trivial copyability from its
// alternatives, as required by P0602R4.
TEST(test_trivially_copyable)
{
// Fundamental types are trivially copyable in every ETL configuration.
CHECK((std::is_trivially_copyable<etl::variant<char, int, double> >::value));
CHECK((std::is_trivially_copy_constructible<etl::variant<char, int, double> >::value));
CHECK((std::is_trivially_move_constructible<etl::variant<char, int, double> >::value));
CHECK((std::is_trivially_copy_assignable<etl::variant<char, int, double> >::value));
CHECK((std::is_trivially_move_assignable<etl::variant<char, int, double> >::value));
// An alternative that is not trivially copyable prevents propagation.
CHECK((!std::is_trivially_copyable<etl::variant<int, AssignTracker> >::value));
// The variant still copies and moves correctly.
typedef etl::variant<char, int, double> trivial_variant;
trivial_variant variant_1(1.5);
trivial_variant variant_2(variant_1);
CHECK_EQUAL(2U, variant_2.index());
CHECK_EQUAL(1.5, etl::get<double>(variant_2));
trivial_variant variant_3;
variant_3 = variant_2;
CHECK_EQUAL(2U, variant_3.index());
CHECK_EQUAL(1.5, etl::get<double>(variant_3));
}
//*************************************************************************
// Issue #1512: even though the copy operations are disabled at compile
// time, a move-only variant must still move construct / move assign

View File

@ -1531,8 +1531,12 @@ namespace
{
auto data = etl::make_vector<char>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// The explicit element type now selects the element type for all
// arguments (Library Fundamentals TS make_array design). Previously it
// pinned only the first argument's deduced type, and the element type
// was still the common type of the arguments - int for this call.
using Type = typename std::remove_reference<decltype(data[0])>::type;
CHECK((std::is_same<int, Type>::value));
CHECK((std::is_same<char, Type>::value));
CHECK_EQUAL(0, data[0]);
CHECK_EQUAL(1, data[1]);
@ -1590,6 +1594,29 @@ namespace
}
#endif
//*************************************************************************
#if ETL_HAS_INITIALIZER_LIST
// An explicit element type selects the element type and converts every
// argument (Library Fundamentals TS make_array design), accepting
// const-qualified lvalues and narrowing initialisers.
TEST(test_make_vector_explicit_element_type)
{
static const char static_const_lvalue = 42;
const char local_const_lvalue = 43;
char mutable_lvalue = 44;
auto data = etl::make_vector<char>(static_const_lvalue, local_const_lvalue, mutable_lvalue, 45, 46);
CHECK((std::is_same<etl::vector<char, 5U>, decltype(data)>::value));
CHECK_EQUAL(42, data[0]);
CHECK_EQUAL(43, data[1]);
CHECK_EQUAL(44, data[2]);
CHECK_EQUAL(45, data[3]);
CHECK_EQUAL(46, data[4]);
}
#endif
//*************************************************************************
TEST(test_fill)
{