diff --git a/.devcontainer/context/.gitkeep b/.devcontainer/context/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.devcontainer/powerpc/Dockerfile b/.devcontainer/powerpc/Dockerfile index a2442782..59809392 100644 --- a/.devcontainer/powerpc/Dockerfile +++ b/.devcontainer/powerpc/Dockerfile @@ -1,10 +1,32 @@ # powerpc Test Environment for ETL # Uses QEMU user-mode emulation to run powerpc binaries on x64 host -FROM debian:sid-20260406 +# +# NOTE: floating tags like "sid" or "sid-slim" drift over time and cannot be +# pinned retroactively (Docker Hub keeps only the latest manifest per tag). +# debian:sid-20260202 is a dated, immutable tag (built and pushed once, not +# retagged later), pinned here by digest for full reproducibility. All apt +# sources are also switched to the matching snapshot.debian.org archive +# before the first "apt-get update" runs. +FROM debian@sha256:9ab6e6f3543eeb30510c516377bbb05f95ebb7507a956c0b772184deb7ecd340 # Avoid prompts from apt ENV DEBIAN_FRONTEND=noninteractive +# Pin apt to the snapshot.debian.org archive for the given date BEFORE any +# package installation, so every apt-get update/install in this file (not +# just the ones after this point) resolves to the exact same package set. +RUN rm -f /etc/apt/sources.list /etc/apt/sources.list.d/*.sources + +RUN cat < /etc/apt/sources.list.d/debian.sources +Types: deb +URIs: http://snapshot.debian.org/archive/debian/20260202T000000Z +Suites: sid +Components: main +Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp +EOF + +RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid + # Install QEMU user-mode emulation and powerpc cross-compilation tools RUN dpkg --add-architecture powerpc && \ apt-get update && apt-get install -y --no-install-recommends \ @@ -20,25 +42,15 @@ RUN dpkg --add-architecture powerpc && \ debian-ports-archive-keyring \ && rm -rf /var/lib/apt/lists/* -RUN cat < /etc/apt/sources.list.d/debian.sources -Types: deb -URIs: http://snapshot.debian.org/archive/debian/20260406T000000Z -Suites: sid -Components: main -Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp -EOF - RUN cat < /etc/apt/sources.list.d/powerpc.sources Types: deb -URIs: http://snapshot.debian.org/archive/debian-ports/20260406T000000Z +URIs: http://snapshot.debian.org/archive/debian-ports/20260202T000000Z Suites: sid Components: main Architectures: powerpc Signed-By: /usr/share/keyrings/debian-ports-archive-keyring.gpg EOF -RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid - RUN apt-get update && apt-get install -y --no-install-recommends \ qemu-user-static \ qemu-user \ diff --git a/.github/workflows/bazel-gcc-c++23-no-stl.yml b/.github/workflows/bazel-gcc-c++23-no-stl.yml index b41765a2..648e0bcb 100644 --- a/.github/workflows/bazel-gcc-c++23-no-stl.yml +++ b/.github/workflows/bazel-gcc-c++23-no-stl.yml @@ -2,9 +2,37 @@ name: bazel-gcc-c++23-no-stl on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: bazel build //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL diff --git a/.github/workflows/clang-c++11.yml b/.github/workflows/clang-c++11.yml index edf2f2e5..6ca727ef 100644 --- a/.github/workflows/clang-c++11.yml +++ b/.github/workflows/clang-c++11.yml @@ -2,9 +2,37 @@ name: clang-c++11 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install libc++ run: | @@ -67,7 +95,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -79,4 +107,4 @@ jobs: make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests - run: ./test/etl_tests -v \ No newline at end of file + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++14.yml b/.github/workflows/clang-c++14.yml index b11f3407..3ddb0cfa 100644 --- a/.github/workflows/clang-c++14.yml +++ b/.github/workflows/clang-c++14.yml @@ -2,9 +2,37 @@ name: clang-c++14 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install libc++ run: | @@ -67,7 +95,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -79,4 +107,4 @@ jobs: make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests - run: ./test/etl_tests -v \ No newline at end of file + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++17.yml b/.github/workflows/clang-c++17.yml index 917d8da0..ccec532b 100644 --- a/.github/workflows/clang-c++17.yml +++ b/.github/workflows/clang-c++17.yml @@ -2,9 +2,37 @@ name: clang-c++17 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install libc++ run: | @@ -67,7 +95,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -79,4 +107,4 @@ jobs: make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests - run: ./test/etl_tests -v \ No newline at end of file + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++20.yml b/.github/workflows/clang-c++20.yml index 681d03c0..0d3fa3f7 100644 --- a/.github/workflows/clang-c++20.yml +++ b/.github/workflows/clang-c++20.yml @@ -2,9 +2,37 @@ name: clang-c++20 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - name: Install newer Clang @@ -50,7 +78,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - name: Install newer Clang @@ -79,7 +107,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - name: Install newer Clang @@ -108,7 +136,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - name: Install newer Clang @@ -137,7 +165,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -159,7 +187,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -181,7 +209,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -203,7 +231,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -216,4 +244,3 @@ jobs: - name: Run tests run: ./test/etl_tests -v - diff --git a/.github/workflows/clang-c++23.yml b/.github/workflows/clang-c++23.yml index 2cdb909d..d25a346c 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -2,9 +2,37 @@ name: clang-c++23 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install libc++ run: | @@ -45,7 +73,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -67,7 +95,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -89,7 +117,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -111,7 +139,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -133,7 +161,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -155,7 +183,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -177,7 +205,7 @@ jobs: os: [macos-15] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -190,4 +218,3 @@ jobs: - name: Run tests run: ./test/etl_tests -v - diff --git a/.github/workflows/clang-c++26.yml b/.github/workflows/clang-c++26.yml index 61dc931f..e118c66a 100644 --- a/.github/workflows/clang-c++26.yml +++ b/.github/workflows/clang-c++26.yml @@ -2,9 +2,37 @@ name: clang-c++26 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -38,7 +66,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -60,7 +88,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -82,7 +110,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -104,7 +132,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -129,7 +157,7 @@ jobs: os: [macos-26] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -151,7 +179,7 @@ jobs: os: [macos-26] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -173,7 +201,7 @@ jobs: os: [macos-26] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -195,7 +223,7 @@ jobs: os: [macos-26] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | diff --git a/.github/workflows/clang-format.yaml b/.github/workflows/clang-format.yaml index 083f265f..8f98f80d 100644 --- a/.github/workflows/clang-format.yaml +++ b/.github/workflows/clang-format.yaml @@ -7,12 +7,16 @@ on: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: clang-format: name: clang-format runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 with: fetch-depth: 0 diff --git a/.github/workflows/clang-format_update.yaml b/.github/workflows/clang-format_update.yaml index acaa3453..a15cc3f4 100644 --- a/.github/workflows/clang-format_update.yaml +++ b/.github/workflows/clang-format_update.yaml @@ -3,12 +3,16 @@ name: clang-format-update on: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: clang-format: runs-on: ubuntu-24.04 steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 - name: Install clang-format run: | diff --git a/.github/workflows/clang-syntax-checks.yml b/.github/workflows/clang-syntax-checks.yml index 2c6000e7..25795ebe 100644 --- a/.github/workflows/clang-syntax-checks.yml +++ b/.github/workflows/clang-syntax-checks.yml @@ -2,9 +2,37 @@ name: clang syntax checks on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build-clang-cpp03-linux-STL: @@ -15,7 +43,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -33,7 +61,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -51,7 +79,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -69,7 +97,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -87,7 +115,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -105,7 +133,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -123,7 +151,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -141,7 +169,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -159,7 +187,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -177,7 +205,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -195,7 +223,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -213,7 +241,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -231,7 +259,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -249,7 +277,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -267,7 +295,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -285,7 +313,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -303,7 +331,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -321,7 +349,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -339,7 +367,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -357,7 +385,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -375,7 +403,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -393,7 +421,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -408,7 +436,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -428,7 +456,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -448,7 +476,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -468,7 +496,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . diff --git a/.github/workflows/clang-tidy.yaml b/.github/workflows/clang-tidy.yaml index 214d30b2..ff368d50 100644 --- a/.github/workflows/clang-tidy.yaml +++ b/.github/workflows/clang-tidy.yaml @@ -3,16 +3,44 @@ name: clang-tidy on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: clang-tidy: name: clang-tidy runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 with: fetch-depth: 0 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5c05ebef..bf138cf9 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,13 +3,36 @@ name: coverage on: push: branches: [ master, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' -# Allow only one concurrent deployment to GitHub Pages concurrency: - group: coverage-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Grant GITHUB_TOKEN the minimum permissions needed at the workflow level @@ -23,7 +46,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install dependencies run: | diff --git a/.github/workflows/deploy-etl-documentation.yml b/.github/workflows/deploy-etl-documentation.yml index b7636de1..b33941b0 100644 --- a/.github/workflows/deploy-etl-documentation.yml +++ b/.github/workflows/deploy-etl-documentation.yml @@ -4,6 +4,10 @@ on: push: branches: [ master ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + jobs: deploy: runs-on: ubuntu-latest @@ -15,7 +19,7 @@ jobs: steps: # Check out the repository code - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 with: submodules: true fetch-depth: 0 diff --git a/.github/workflows/gcc-c++11.yml b/.github/workflows/gcc-c++11.yml index c9706aeb..4d33a909 100644 --- a/.github/workflows/gcc-c++11.yml +++ b/.github/workflows/gcc-c++11.yml @@ -2,9 +2,37 @@ name: gcc-c++11 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -39,7 +67,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | diff --git a/.github/workflows/gcc-c++14.yml b/.github/workflows/gcc-c++14.yml index a3277b66..bc7cca67 100644 --- a/.github/workflows/gcc-c++14.yml +++ b/.github/workflows/gcc-c++14.yml @@ -2,9 +2,37 @@ name: gcc-c++14 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -50,4 +78,4 @@ jobs: make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests - run: ./test/etl_tests -v \ No newline at end of file + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++17.yml b/.github/workflows/gcc-c++17.yml index dbeef7fa..1378fc69 100644 --- a/.github/workflows/gcc-c++17.yml +++ b/.github/workflows/gcc-c++17.yml @@ -2,9 +2,37 @@ name: gcc-c++17 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | diff --git a/.github/workflows/gcc-c++20.yml b/.github/workflows/gcc-c++20.yml index be4e6fb2..6e004456 100644 --- a/.github/workflows/gcc-c++20.yml +++ b/.github/workflows/gcc-c++20.yml @@ -2,9 +2,37 @@ name: gcc-c++20 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -60,7 +88,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -82,7 +110,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -94,4 +122,4 @@ jobs: make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests - run: ./test/etl_tests -v \ No newline at end of file + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++23-armhf.yml b/.github/workflows/gcc-c++23-armhf.yml index 1bd2912b..00cb78d6 100644 --- a/.github/workflows/gcc-c++23-armhf.yml +++ b/.github/workflows/gcc-c++23-armhf.yml @@ -2,9 +2,37 @@ name: gcc-c++23-armhf on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-armhf -f .devcontainer/armhf/Dockerfile . diff --git a/.github/workflows/gcc-c++23-i386.yml b/.github/workflows/gcc-c++23-i386.yml index 31bfc331..dec5833f 100644 --- a/.github/workflows/gcc-c++23-i386.yml +++ b/.github/workflows/gcc-c++23-i386.yml @@ -2,9 +2,37 @@ name: gcc-c++23-i386 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-i386 -f .devcontainer/i386/Dockerfile . diff --git a/.github/workflows/gcc-c++23-powerpc.yml b/.github/workflows/gcc-c++23-powerpc.yml index 7494ae55..71a90f20 100644 --- a/.github/workflows/gcc-c++23-powerpc.yml +++ b/.github/workflows/gcc-c++23-powerpc.yml @@ -2,9 +2,37 @@ name: gcc-c++23-powerpc on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-powerpc -f .devcontainer/powerpc/Dockerfile . diff --git a/.github/workflows/gcc-c++23-riscv64.yml b/.github/workflows/gcc-c++23-riscv64.yml index 695056a8..b7a2611d 100644 --- a/.github/workflows/gcc-c++23-riscv64.yml +++ b/.github/workflows/gcc-c++23-riscv64.yml @@ -2,9 +2,37 @@ name: gcc-c++23-riscv64 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-riscv64 -f .devcontainer/riscv64/Dockerfile . diff --git a/.github/workflows/gcc-c++23-s390x.yml b/.github/workflows/gcc-c++23-s390x.yml index f6a15aca..365f44dc 100644 --- a/.github/workflows/gcc-c++23-s390x.yml +++ b/.github/workflows/gcc-c++23-s390x.yml @@ -2,9 +2,37 @@ name: gcc-c++23-s390x on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-s390x -f .devcontainer/s390x/Dockerfile . diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index 842b6152..a7e29e56 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -2,9 +2,37 @@ name: gcc-c++23 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -16,7 +44,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -38,7 +66,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -60,7 +88,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -82,7 +110,7 @@ jobs: os: [ubuntu-24.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | diff --git a/.github/workflows/gcc-c++26.yml b/.github/workflows/gcc-c++26.yml index b7ff42d3..63677261 100644 --- a/.github/workflows/gcc-c++26.yml +++ b/.github/workflows/gcc-c++26.yml @@ -2,9 +2,37 @@ name: gcc-c++26 on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -35,7 +63,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -57,7 +85,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -79,7 +107,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . diff --git a/.github/workflows/gcc-syntax-checks.yml b/.github/workflows/gcc-syntax-checks.yml index b6b77bad..0faa94c0 100644 --- a/.github/workflows/gcc-syntax-checks.yml +++ b/.github/workflows/gcc-syntax-checks.yml @@ -2,9 +2,37 @@ name: gcc syntax checks on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build-gcc-cpp03-linux-STL: @@ -15,7 +43,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -33,7 +61,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -51,7 +79,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -69,7 +97,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -87,7 +115,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -105,7 +133,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -123,7 +151,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -141,7 +169,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -159,7 +187,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -177,7 +205,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -195,7 +223,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -213,7 +241,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -231,7 +259,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -249,7 +277,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -267,7 +295,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -285,7 +313,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -303,7 +331,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -321,7 +349,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -339,7 +367,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -357,7 +385,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -375,7 +403,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -393,7 +421,7 @@ jobs: os: [ubuntu-22.04] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build run: | @@ -408,7 +436,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -428,7 +456,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -448,7 +476,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . @@ -468,7 +496,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Build Docker image run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . diff --git a/.github/workflows/generator.yml b/.github/workflows/generator.yml index 1829c342..6cad5c54 100644 --- a/.github/workflows/generator.yml +++ b/.github/workflows/generator.yml @@ -6,13 +6,17 @@ on: branches: [ master, pull-request/* ] types: [opened, synchronize, reopened] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: generator-run: name: Header Generator runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6.0.3 - name: Install dependencies run: | diff --git a/.github/workflows/meson-gcc-c++23-no-stl.yml b/.github/workflows/meson-gcc-c++23-no-stl.yml index d8767317..0902f2f9 100644 --- a/.github/workflows/meson-gcc-c++23-no-stl.yml +++ b/.github/workflows/meson-gcc-c++23-no-stl.yml @@ -2,9 +2,37 @@ name: meson-gcc-c++23-no-stl on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: @@ -13,7 +41,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.3 - name: Install Meson run: sudo apt-get install -y meson diff --git a/.github/workflows/msvc.yml b/.github/workflows/msvc.yml index 32d7aee8..8f7d4c00 100644 --- a/.github/workflows/msvc.yml +++ b/.github/workflows/msvc.yml @@ -2,9 +2,37 @@ name: msvc on: push: branches: [ master, development, pull-request/* ] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' pull_request: branches: [ master, development, pull-request/* ] types: [opened, synchronize, reopened] + paths: + - '.github/workflows/**' + - 'include/**' + - 'test/**' + - 'CMakeLists.txt' + - 'cmake/**' + - 'BUILD.bazel' + - 'MODULE.bazel*' + - 'meson.build' + - 'meson_options.txt' + - 'subprojects/**' + - '.devcontainer/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build-windows-msvc-stl: @@ -13,7 +41,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 with: submodules: recursive @@ -34,7 +62,7 @@ jobs: runs-on: [windows-2022] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 with: submodules: recursive @@ -56,7 +84,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 with: submodules: recursive @@ -78,7 +106,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 with: submodules: recursive @@ -93,4 +121,3 @@ jobs: - name: Run tests run: test/Debug/etl_tests.exe -v - diff --git a/.github/workflows/platformio-update.yml b/.github/workflows/platformio-update.yml index 318cf953..ebc02081 100644 --- a/.github/workflows/platformio-update.yml +++ b/.github/workflows/platformio-update.yml @@ -4,13 +4,17 @@ on: release: types: [published] # Trigger only when a GitHub release is published +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: publish: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6.0.3 - name: Set up Python uses: actions/setup-python@v5 diff --git a/docs/IO/buffer_descriptors.md b/docs/IO/buffer_descriptors.md index 4e49278e..df7f77b6 100644 --- a/docs/IO/buffer_descriptors.md +++ b/docs/IO/buffer_descriptors.md @@ -188,7 +188,7 @@ A nested class that is sent to the user defined callback function. notification() ``` **Description** -Default contructor. +Default constructor. Initialises to a default constructed descriptor and a count of zero. --- diff --git a/docs/_index.md b/docs/_index.md index 4fbb737c..a1886a77 100644 --- a/docs/_index.md +++ b/docs/_index.md @@ -39,7 +39,7 @@ type: hextra-home
- coverage + coverage Codacy
diff --git a/docs/blog/graphics/determining-line-line-intersections.md b/docs/blog/graphics/determining-line-line-intersections.md index 279103ae..bcc6b12f 100644 --- a/docs/blog/graphics/determining-line-line-intersections.md +++ b/docs/blog/graphics/determining-line-line-intersections.md @@ -87,7 +87,7 @@ This means you can find intersection points relative to a fixed reference line. ![LineCross2](images/LineCross2.png) -## Refection +## Reflection This describes reflecting a point across a reference line. It uses the intersection method described above. diff --git a/docs/callbacks/function.md b/docs/callbacks/function.md index 7785b0f1..42f83b4e 100644 --- a/docs/callbacks/function.md +++ b/docs/callbacks/function.md @@ -18,7 +18,7 @@ This may be used to implement a platform abstraction layer that allows an embedd | Template | Description | | ----------------- | ------------------------------------------------------------------------- | | etl::function | Callbacks to free or member functions taking zero or one parameter.
Function pointer at runtime. | -| etl::function_fv | Callback to a free function taking no parameters. (Functiion Void).
Function pointer at compile time. | +| etl::function_fv | Callback to a free function taking no parameters. (Function Void).
Function pointer at compile time. | | etl::function_fp | Callback to a free function taking one parameter. (Function Parameter).
Function pointer at compile time. | etl::function_mv | Callback to a member function taking no parameters. (Member Void).
Function pointer at compile time. | | etl::function_imv | Callback to a member function taking no parameters. (Instance Member Void ).
Instance reference and function pointer at compile time. | diff --git a/docs/callbacks/signal.md b/docs/callbacks/signal.md index a8c19efc..53d05534 100644 --- a/docs/callbacks/signal.md +++ b/docs/callbacks/signal.md @@ -15,7 +15,7 @@ template ` ## Types diff --git a/docs/chrono/duration/duration.md b/docs/chrono/duration/duration.md index c75c6a7b..7900e8b3 100644 --- a/docs/chrono/duration/duration.md +++ b/docs/chrono/duration/duration.md @@ -112,7 +112,7 @@ ETL_CONSTEXPR14 etl::chrono::duration operator =(const etl::chrono::duration& other) ETL_NOEXCEPT ``` -### Convertion +### Conversion ```cpp ETL_CONSTEXPR14 TRep count() const diff --git a/docs/chrono/month/month_weekday.md b/docs/chrono/month/month_weekday.md index ab73505e..3d7037c6 100644 --- a/docs/chrono/month/month_weekday.md +++ b/docs/chrono/month/month_weekday.md @@ -20,7 +20,7 @@ class month_weekday ETL_CONSTEXPR month_weekday() ``` -**Decription** +**Description** Default constructor. --- @@ -31,7 +31,7 @@ month_weekday(const etl::chrono::month& m, const etl::chrono::weekday_indexed& wd) ETL_NOEXCEPT ``` -**Decription** +**Description** Construct from month and weekday_indexed. ## Access @@ -75,7 +75,7 @@ bool operator ==(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Equality operator. --- @@ -86,7 +86,7 @@ bool operator !=(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Inequality operator. --- @@ -97,7 +97,7 @@ bool operator <(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Less-than operator. --- @@ -108,7 +108,7 @@ bool operator <=(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Less-than-equal operator. --- @@ -119,7 +119,7 @@ bool operator <(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Greater-than operator. --- @@ -130,7 +130,7 @@ bool operator <=(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Greater-than-equal operator. --- @@ -141,7 +141,7 @@ auto operator <=>(const etl::chrono::month_weekday& lhs, const etl::chrono::month_weekday& rhs) ETL_NOEXCEPT ``` -**Decription** +**Description** Spaceship operator. C++20 @@ -151,6 +151,6 @@ C++20 template struct hash ``` -**Decription** +**Description** Hash function for `etl::chrono::month_weekday`. diff --git a/docs/chrono/year/year_month_day_last.md b/docs/chrono/year/year_month_day_last.md index 426a51ab..dc19db52 100644 --- a/docs/chrono/year/year_month_day_last.md +++ b/docs/chrono/year/year_month_day_last.md @@ -56,7 +56,7 @@ The year. --- -```coo +```cpp ETL_NODISCARD ETL_CONSTEXPR14 etl::chrono::month month() const diff --git a/docs/containers/Views/span.md b/docs/containers/Views/span.md index 8fb131f7..9e619b4e 100644 --- a/docs/containers/Views/span.md +++ b/docs/containers/Views/span.md @@ -356,7 +356,7 @@ bool equal(const etl::span& lhs, const etl::span& rhs) ``` **Description** Equality function. -Performs a comparision of the range values. +Performs a comparison of the range values. Returns `true` if one of the following are `true` 1. Both spans are empty. 2. They both point to the same range of data. diff --git a/docs/containers/arrays/array.md b/docs/containers/arrays/array.md index e2cda55d..fcf8af32 100644 --- a/docs/containers/arrays/array.md +++ b/docs/containers/arrays/array.md @@ -39,7 +39,7 @@ Defines data as an array of 'int', of length '10', containing the supplied data. ```cpp template -constexpr auto make_array(TValues&&... values) +constexpr auto make_array(TValues&&... values) -> etl::array ``` ### Example @@ -314,3 +314,42 @@ operator >= ``` **Description** `true` if the contents of the lhs are lexicographically greater than or equal to the contents of the rhs, otherwise `false`. + +--- + +```cpp +template +T& get(etl::array& a) + +template +const T& get(const etl::array& a) +``` +**Description** +Gets a reference to the element at `Index` in the array. + +## Structured bindings +`etl::array` provides the tuple-like interface required for C++17 structured bindings. + +```cpp +etl::array a = { 1, 2, 3 }; + +auto& [x, y, z] = a; // x, y, z are references to a[0], a[1], a[2] +``` + +```cpp +template +struct tuple_size> +``` +**Description** +Gets the number of elements in the array. +Specialised in namespaces `etl` and `std` (the `std` specialisation allows the use of C++ structured bindings). + +--- + +```cpp +template +struct tuple_element> +``` +**Description** +Gets the type of the element at `Index` in the array. +Specialised in namespaces `etl` and `std` (the `std` specialisation allows the use of C++ structured bindings). diff --git a/docs/containers/lists/forward-list.md b/docs/containers/lists/forward-list.md index 2be721e0..442d6b51 100644 --- a/docs/containers/lists/forward-list.md +++ b/docs/containers/lists/forward-list.md @@ -65,13 +65,15 @@ Defines data as an `forward_list` of int, of length 10, containing the supplied ## Make template **C++11 and above** ```cpp -template - constexpr auto make_forward_list(TValues&&... values) +template +constexpr auto make_forward_list(T&&... t) -> etl::forward_list, sizeof...(T)> ``` +The element type is deduced as the common type of the arguments. + ### Example ```cpp -auto data = etl::make_forward_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +auto data = etl::make_forward_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); ``` ## Member types diff --git a/docs/containers/lists/list.md b/docs/containers/lists/list.md index 8ae13fd3..0ae64e39 100644 --- a/docs/containers/lists/list.md +++ b/docs/containers/lists/list.md @@ -69,13 +69,15 @@ Defines data as an list of `int`, of length `10`, containing the supplied data. ## Make template **C++11 and above** ```cpp -template -constexpr auto make_list(TValues&&... values) +template +constexpr auto make_list(T&&... t) -> etl::list, sizeof...(T)> ``` +The element type is deduced as the common type of the arguments. + ### Example ```cpp -auto data = etl::make_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +auto data = etl::make_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); ``` ## Member types diff --git a/docs/containers/maps/flat-map.md b/docs/containers/maps/flat-map.md index dd1d1850..cc3ea886 100644 --- a/docs/containers/maps/flat-map.md +++ b/docs/containers/maps/flat-map.md @@ -40,13 +40,13 @@ template , typename... TPairs> -constexpr auto make_flat_map(TValues&&... values) +constexpr auto make_flat_map(TPairs&&... pairs) -> etl::flat_map ``` ### Example ```cpp -auto data = etl::make_flat_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_flat_map(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/maps/flat-multimap.md b/docs/containers/maps/flat-multimap.md index b6f6832d..58bda46b 100644 --- a/docs/containers/maps/flat-multimap.md +++ b/docs/containers/maps/flat-multimap.md @@ -33,20 +33,20 @@ etl::flat_multimap data{ etl::pair{0, 1}, etl::pair{2, 3}, etl::pair{4, 5}, etl: ``` Defines data as an `flat_multimap` of `int`/`int` pairs, of length 4, containing the supplied data. -## make_flat_map +## make_flat_multimap C++11 and above ```cpp template , typename... TPairs> -constexpr auto make_flat_map(TValues&&... values) +constexpr auto make_flat_multimap(TPairs&&... pairs) -> etl::flat_multimap ``` ### Example ```cpp -auto data = etl::make_flat_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_flat_multimap(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/maps/map.md b/docs/containers/maps/map.md index c2c26396..8b747fb8 100644 --- a/docs/containers/maps/map.md +++ b/docs/containers/maps/map.md @@ -38,13 +38,13 @@ template , typename... TPairs> -constexpr auto make_flat_map(TValues&&... values) +constexpr auto make_map(TPairs&&... pairs) -> etl::map ``` ### Example ```cpp -auto data = etl::make_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_map(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/maps/multimap.md b/docs/containers/maps/multimap.md index 09fda167..67c02108 100644 --- a/docs/containers/maps/multimap.md +++ b/docs/containers/maps/multimap.md @@ -38,13 +38,13 @@ template , typename... TPairs> -constexpr auto make_flat_map(TValues&&... values) +constexpr auto make_multimap(TPairs&&... pairs) -> etl::multimap ``` ### Example ```cpp -auto data = etl::make_multimap(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_multimap(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/maps/reference-flat-map.md b/docs/containers/maps/reference-flat-map.md index 57f7dda1..baa0a013 100644 --- a/docs/containers/maps/reference-flat-map.md +++ b/docs/containers/maps/reference-flat-map.md @@ -36,19 +36,32 @@ etl::reference_flat_map data{ etl::pair{0, 1}, etl::pair{2, 3}, etl::pair{4, 5}, Defines data as an reference_flat_map of int, of length 4, containing the supplied data. ## Make template -C++11 and above - +**C++11 and above** ```cpp -template , +template , typename... TPairs> -constexpr auto make_reference_flat_map(TValues&&... values) +constexpr auto make_reference_flat_map(TPairs&&... pairs) -> etl::reference_flat_map ``` ### Example -auto data = etl::make_reference_flat_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); + +{{< callout type="warning" >}} + This example does not currently compile: `make_reference_flat_map` cannot be + instantiated, because the reference containers have no `initializer_list` + constructor for its braced return value to bind to. This is a known defect. +{{< /callout >}} + +```cpp +// The referenced objects must outlive the container. +etl::pair p0{0, 1}; +etl::pair p1{2, 3}; +etl::pair p2{4, 5}; +etl::pair p3{6, 7}; + +auto data = etl::make_reference_flat_map(p0, p1, p2, p3); +``` ## Member types diff --git a/docs/containers/maps/reference-flat-multimap.md b/docs/containers/maps/reference-flat-multimap.md index 9d4ccd64..01bdb556 100644 --- a/docs/containers/maps/reference-flat-multimap.md +++ b/docs/containers/maps/reference-flat-multimap.md @@ -36,19 +36,32 @@ etl::reference_flat_multimap data{ etl::pair{0, 1}, etl::pair{2, 3}, etl::pair{4 Defines data as an reference_flat_multimap of int, of length 4, containing the supplied data. ## Make template -C++11 and above - +**C++11 and above** ```cpp -template , +template , typename... TPairs> -constexpr auto make_reference_flat_map(TValues&&... values) +constexpr auto make_reference_flat_multimap(TPairs&&... pairs) -> etl::reference_flat_multimap ``` ### Example -auto data = etl::make_reference_flat_multimap(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); + +{{< callout type="warning" >}} + This example does not currently compile: `make_reference_flat_multimap` cannot be + instantiated, because the reference containers have no `initializer_list` + constructor for its braced return value to bind to. This is a known defect. +{{< /callout >}} + +```cpp +// The referenced objects must outlive the container. +etl::pair p0{0, 1}; +etl::pair p1{2, 3}; +etl::pair p2{4, 5}; +etl::pair p3{6, 7}; + +auto data = etl::make_reference_flat_multimap(p0, p1, p2, p3); +``` ## Member types diff --git a/docs/containers/maps/unordered-map.md b/docs/containers/maps/unordered-map.md index bf2810ad..ba576cd6 100644 --- a/docs/containers/maps/unordered-map.md +++ b/docs/containers/maps/unordered-map.md @@ -44,17 +44,17 @@ C++11 and above ```cpp template , - typename TKeyEqual = etl::equal_to + typename T, + typename THash = etl::hash, + typename TKeyEqual = etl::equal_to, typename... TPairs> -constexpr auto make_unordered_map(TValues&&... values) +constexpr auto make_unordered_map(TPairs&&... pairs) -> etl::unordered_map ``` ### Example ```cpp -auto data = etl::make_unordered_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_unordered_map(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/maps/unordered-multimap.md b/docs/containers/maps/unordered-multimap.md index 5e50cba3..9622f558 100644 --- a/docs/containers/maps/unordered-multimap.md +++ b/docs/containers/maps/unordered-multimap.md @@ -42,17 +42,17 @@ C++11 and above ```cpp template , - typename TKeyEqual = etl::equal_to + typename T, + typename THash = etl::hash, + typename TKeyEqual = etl::equal_to, typename... TPairs> -constexpr auto make_unordered_map(TValues&&... values) +constexpr auto make_unordered_multimap(TPairs&&... pairs) -> etl::unordered_multimap ``` ### Example ```cpp -auto data = etl::make_unordered_map(etl::pair{0, 1}, etl::pair{2, 3}, - etl::pair{4, 5}, etl::pair{6, 7}); +auto data = etl::make_unordered_multimap(etl::pair{0, 1}, etl::pair{2, 3}, + etl::pair{4, 5}, etl::pair{6, 7}); ``` ## Member types diff --git a/docs/containers/pools/generic-pool.md b/docs/containers/pools/generic-pool.md index eb400d36..d4dba97b 100644 --- a/docs/containers/pools/generic-pool.md +++ b/docs/containers/pools/generic-pool.md @@ -72,7 +72,7 @@ generic_pool_ext(char* buffer, size_t size) ``` **Description** For `etl::generic_pool_ext`. -Constructs a generic_pool from an external bufffer. +Constructs a generic_pool from an external buffer. No elements are constructed. ## Operations diff --git a/docs/containers/pools/pool.md b/docs/containers/pools/pool.md index 4b1e6fbf..4f6b1c6e 100644 --- a/docs/containers/pools/pool.md +++ b/docs/containers/pools/pool.md @@ -94,7 +94,7 @@ pool_ext(char* buffer, size_t size) ``` **Description** For `etl::pool_ext`. -Constructs a pool from an external bufffer. +Constructs a pool from an external buffer. No elements are constructed. ## Operations diff --git a/docs/containers/queues & stacks/deque.md b/docs/containers/queues & stacks/deque.md index a4960607..f326e308 100644 --- a/docs/containers/queues & stacks/deque.md +++ b/docs/containers/queues & stacks/deque.md @@ -32,9 +32,11 @@ etl::deque data{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Defines data as an `deque` of `int`, of length `10`, containing the supplied data. ## Make template +**C++11 and above** +```cpp template - constexpr auto make_deque(TValues&&... values) - C++11 and above +constexpr auto make_deque(TValues&&... values) -> etl::deque +``` ### Example ```cpp diff --git a/docs/containers/sets/const-multiset.md b/docs/containers/sets/const-multiset.md index 8d8fc79a..f4200dad 100644 --- a/docs/containers/sets/const-multiset.md +++ b/docs/containers/sets/const-multiset.md @@ -17,7 +17,7 @@ Uses `etl::less` as the default key comparison method. etl::const_multiset ``` -**Enternal storage** +**Internal storage** ```cpp etl::const_multiset_ext ``` diff --git a/docs/containers/sets/const-set.md b/docs/containers/sets/const-set.md index 706eef0e..100549f7 100644 --- a/docs/containers/sets/const-set.md +++ b/docs/containers/sets/const-set.md @@ -17,7 +17,7 @@ Uses `etl::less` as the default key comparison method. etl::const_set ``` -**Enternal storage** +**Internal storage** ```cpp etl::const_set_ext ``` diff --git a/docs/containers/sets/flat-multiset.md b/docs/containers/sets/flat-multiset.md index 890fcd52..d88e4a17 100644 --- a/docs/containers/sets/flat-multiset.md +++ b/docs/containers/sets/flat-multiset.md @@ -33,17 +33,18 @@ etl::flat_multiset data{ 0, 1, 2, 3 }; ``` Defines data as an `flat_multiset` of `int`, of length 4, containing the supplied data. -## make_flat_set +## make_flat_multiset C++11 and above ```cpp -template > -constexpr auto make_flat_set(TValues&&... values) +template , + typename... T> +constexpr auto make_flat_multiset(T&&... keys) -> etl::flat_multiset ``` ### Example ```cpp -auto data = etl::make_flat_set({0, 1, 2, 3 }); +auto data = etl::make_flat_multiset(0, 1, 2, 3); ``` ## Member types diff --git a/docs/containers/sets/flat-set.md b/docs/containers/sets/flat-set.md index 6f9c0540..e5c08610 100644 --- a/docs/containers/sets/flat-set.md +++ b/docs/containers/sets/flat-set.md @@ -36,14 +36,15 @@ Defines data as an `flat_set` of `int`, of length 4, containing the supplied dat ## make_flat_set C++11 and above ```cpp -template > -constexpr auto make_flat_set(TValues&&... values) +template , + typename... T> +constexpr auto make_flat_set(T&&... keys) -> etl::flat_set ``` ### Example ```cpp -auto data = etl::make_flat_set({0, 1, 2, 3 }); +auto data = etl::make_flat_set(0, 1, 2, 3); ``` ## Member types diff --git a/docs/containers/sets/multiset.md b/docs/containers/sets/multiset.md index 9bf091c8..4e3de78f 100644 --- a/docs/containers/sets/multiset.md +++ b/docs/containers/sets/multiset.md @@ -37,13 +37,13 @@ Defines data as an multiset of `int`, of length 8, containing the supplied data. ```cpp template , - typename... TPairs> -constexpr auto make_set(TValues&&... values) + typename... T> +constexpr auto make_multiset(T&&... keys) -> etl::multiset ``` ### Example ```cpp -auto data = etl::make_set(0, 1, 2, 3, 4, 5, 6, 7); +auto data = etl::make_multiset(0, 1, 2, 3, 4, 5, 6, 7); ``` ## Member types diff --git a/docs/containers/sets/reference-flat-multiset.md b/docs/containers/sets/reference-flat-multiset.md index 9e7dd725..9bb622dc 100644 --- a/docs/containers/sets/reference-flat-multiset.md +++ b/docs/containers/sets/reference-flat-multiset.md @@ -32,13 +32,35 @@ etl::reference_flat_setdata{ 0, 1, 2, 3, 4, 5, 6, 7 }; Defines data as a set of int/int pairs, of length 8, containing the supplied data. ## Make template -C++11 and above -template , typename... T> -constexpr auto make_reference_flat_set(T&&... values) +constexpr auto make_reference_flat_multiset(T&&... keys) -> etl::reference_flat_multiset +``` ### Example -auto data = etl::make_reference_flat_set(0, 1, 2, 3, 4, 5, 6, 7); + +{{< callout type="warning" >}} + This example does not currently compile: `make_reference_flat_multiset` cannot be + instantiated, because the reference containers have no `initializer_list` + constructor for its braced return value to bind to. This is a known defect. +{{< /callout >}} + +```cpp +// The referenced objects must outlive the container. +int k0 = 0; +int k1 = 1; +int k2 = 2; +int k3 = 3; +int k4 = 4; +int k5 = 5; +int k6 = 6; +int k7 = 7; + +auto data = etl::make_reference_flat_multiset(k0, k1, k2, k3, k4, k5, k6, k7); +``` ## Member types diff --git a/docs/containers/sets/reference-flat-set.md b/docs/containers/sets/reference-flat-set.md index da2c9dc9..8ff1e296 100644 --- a/docs/containers/sets/reference-flat-set.md +++ b/docs/containers/sets/reference-flat-set.md @@ -32,13 +32,35 @@ etl::reference_flat_setdata{ 0, 1, 2, 3, 4, 5, 6, 7 }; Defines data as a set of int/int pairs, of length 8, containing the supplied data. ## Make template -C++11 and above -template , typename... T> -constexpr auto make_reference_flat_set(T&&... values) +constexpr auto make_reference_flat_set(T&&... keys) -> etl::reference_flat_set +``` ### Example -auto data = etl::make_reference_flat_set(0, 1, 2, 3, 4, 5, 6, 7); + +{{< callout type="warning" >}} + This example does not currently compile: `make_reference_flat_set` cannot be + instantiated, because the reference containers have no `initializer_list` + constructor for its braced return value to bind to. This is a known defect. +{{< /callout >}} + +```cpp +// The referenced objects must outlive the container. +int k0 = 0; +int k1 = 1; +int k2 = 2; +int k3 = 3; +int k4 = 4; +int k5 = 5; +int k6 = 6; +int k7 = 7; + +auto data = etl::make_reference_flat_set(k0, k1, k2, k3, k4, k5, k6, k7); +``` ## Member types diff --git a/docs/containers/sets/set.md b/docs/containers/sets/set.md index cec118bd..b6da157f 100644 --- a/docs/containers/sets/set.md +++ b/docs/containers/sets/set.md @@ -36,9 +36,9 @@ Defines data as an set of `int`, of length 8, containing the supplied data. ```cpp template , - typename... TPairs> -constexpr auto make_set(TValues&&... values) + typename TCompare = etl::less, + typename... T> +constexpr auto make_set(T&&... keys) -> etl::set ``` ### Example diff --git a/docs/containers/variadics/_index.md b/docs/containers/variadics/_index.md index 7c051c71..3789c5e4 100644 --- a/docs/containers/variadics/_index.md +++ b/docs/containers/variadics/_index.md @@ -3,4 +3,4 @@ title: "Variadics" weight: 100 --- -Containers tha accept multiple types. \ No newline at end of file +Containers that accept multiple types. \ No newline at end of file diff --git a/docs/containers/variadics/packet.md b/docs/containers/variadics/packet.md index 4533be50..9a420646 100644 --- a/docs/containers/variadics/packet.md +++ b/docs/containers/variadics/packet.md @@ -22,7 +22,7 @@ etl::packet `base_t` = `TBase` -## Contructors +## Constructors **C++03** ```cpp diff --git a/docs/getting-started/contribute.md b/docs/getting-started/contribute.md index 003fbef7..4d75959f 100644 --- a/docs/getting-started/contribute.md +++ b/docs/getting-started/contribute.md @@ -30,7 +30,7 @@ Lower case class and function names, separated by an underscore. `funky_container` `do_something` -### Nameing convension +### Naming convention Use the same naming convention as the STL. If appropriate for the class, a set of `typedef`s should often be present to define types such as... @@ -159,7 +159,7 @@ class my_new_class ``` ### Layout -When possible, try to tabluate the initialisation of multiple variables. It's a lot easier to read. +When possible, try to tabulate the initialisation of multiple variables. It's a lot easier to read. Don't be too strict about it, if it would result in giant amounts of whitespace. ```cpp @@ -240,4 +240,4 @@ When opening a new pull request, ensure that you include the following informati - Branches should be based on the branch `master`. `development` can change quite frequently, so I will rebase the your PR against it before merging. - For formatting help, you can use `clang-format`, or the convenience wrapper `treefmt`. See also [Source formatting]({{% relref "source-formatting.md" %}}). -- Update the relevent documentation markdown file, found in `etl/docs`. \ No newline at end of file +- Update the relevant documentation markdown file, found in `etl/docs`. \ No newline at end of file diff --git a/docs/getting-started/macros.md b/docs/getting-started/macros.md index 3444a3a9..23a6f37d 100644 --- a/docs/getting-started/macros.md +++ b/docs/getting-started/macros.md @@ -83,19 +83,19 @@ These may be defined in the project settings or the user created `etl_profile.h` | `ETL_NODISCARD` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `[[nodiscard]]`, otherwise defined as blank.| | `ETL_DEPRECATED` | If `ETL_CPP14_SUPPORTED` is defined as `1` then this macro is defined as `[[deprecated]]`, otherwise defined as blank.| | `ETL_DEPRECATED_REASON(reason)` | If `ETL_CPP14_SUPPORTED` is defined as `1` then this macro is defined as `[[deprecated(reason)]]`, otherwise defined as blank.| -| `ETL_FALLTHROUGH` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `[[falltrough]]`, otherwise defined as blank.| +| `ETL_FALLTHROUGH` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `[[fallthrough]]`, otherwise defined as blank.| | `ETL_NORETURN` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `[[noreturn]]`, otherwise defined as blank.| | `ETL_OR_STD` | If ETL_NO_STL is defined and ETL_IN_UNIT_TEST is not then `ETL_OR_STD` is defined as `etl`, otherwise it is defined as `std`.| | `ETL_IN_UNIT_TEST` | If defined, then the code is being compiled in the unit tests.
For internal ETL use only.| | `ETL_HAS_ATOMIC` | This is defined as `1` if the compiler supplies an atomic class, otherwise `0`.| | `ETL_INLINE_VAR` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `inline`, otherwise defined as blank.| -| `ETL_USING_STL` | This macro will be defined as `0` & `1` dependant of whether `ETL_NO_STL` is defined or not.| +| `ETL_USING_STL` | This macro will be defined as `0` & `1` depending on whether `ETL_NO_STL` is defined or not.| | `ETL_NOT_USING_STL` | Inversion of `ETL_USING_STL`.| -| `ETL_USING_STLPORT` | This macro will be defined as `0` & `1` dependant of whether `ETL_STLPORT` is defined or not.| +| `ETL_USING_STLPORT` | This macro will be defined as `0` & `1` depending on whether `ETL_STLPORT` is defined or not.| | `ETL_NOT_USING_STLPORT` | Inversion of `ETL_USING_STLPORT`.| -| `ETL_USING_8BIT_TYPES` | This macro will be defined as `0` & `1` dependant of whether `CHAR_BIT == 8` or not.| +| `ETL_USING_8BIT_TYPES` | This macro will be defined as `0` & `1` depending on whether `CHAR_BIT == 8` or not.| | `ETL_NOT_USING_8BIT_TYPES` | Inversion of `ETL_USING_8BIT_TYPES`.| -| `ETL_USING_64BIT_TYPES` | This macro will be defined as `0` & `1` dependant of whether `ETL_NO_64BIT_TYPES` is defined or not.| +| `ETL_USING_64BIT_TYPES` | This macro will be defined as `0` & `1` depending on whether `ETL_NO_64BIT_TYPES` is defined or not.| | `ETL_NOT_USING_64BIT_TYPES` | Inversion of `ETL_USING_64BIT_TYPES`.| | `ETL_HAS_ISTRING_REPAIR` | Set to `1` if the repair functionality for `etl::istring` is enabled, otherwise `0`.| | `ETL_HAS_IVECTOR_REPAIR` | Set to `1` if the repair functionality for `etl::ivector` is enabled, otherwise `0`.| @@ -103,7 +103,7 @@ These may be defined in the project settings or the user created `etl_profile.h` | `ETL_IS_DEBUG_BUILD` | Set to `1` if in a debug build, otherwise `0`.| | `ETL_HAS_POLYMORPHIC_MESSAGES` | Set to `1` if messages are polymorphic, otherwise `0`.| | `ETL_HAS_ERROR_ON_STRING_TRUNCATION` | Set to `1` if truncated strings are an error, otherwise `0`.| -| `ETL_USING_LIBC_WCHAR_H` | These macros will be defined as `0` & `1` dependant of whether `ETL_NO_LIBC_WCHAR_H` is defined or not.| +| `ETL_USING_LIBC_WCHAR_H` | These macros will be defined as `0` & `1` depending on whether `ETL_NO_LIBC_WCHAR_H` is defined or not.| | `ETL_NOT_USING_LIBC_WCHAR_H` | Inversion of `ETL_USING_LIBC_WCHAR_H`.| | `ETL_USING_CPP11` | This is defined as `1` if the compiler supports C++11, otherwise `0`.| | `ETL_USING_CPP14` | This is defined as `1` if the compiler supports C++14, otherwise `0`.| diff --git a/docs/iterators/fixed_iterator.md b/docs/iterators/fixed_iterator.md index 207a16d5..033081cc 100644 --- a/docs/iterators/fixed_iterator.md +++ b/docs/iterators/fixed_iterator.md @@ -30,13 +30,13 @@ etl::fixed_iterator(const etl::fixed_iterator&); ```cpp Titerator get() const; ``` -**Decscription** +**Description** Get the internal iterator. ```cpp void get(TIterator it); ``` -**Decscription** +**Description** Set the iterator. ## Operators @@ -44,7 +44,7 @@ Set the iterator. typename etl::iterator_traits::value_type operator *() const typename etl::iterator_traits::value_type operator *() const ``` -**Decscription** +**Description** Dereference operators --- @@ -53,7 +53,7 @@ Dereference operators TIterator operator ->() const TIterator operator ->() const ``` -**Decscription** +**Description** Member dereference operators --- @@ -61,7 +61,7 @@ Member dereference operators ```cpp operator TIterator() const ``` -**Decscription** +**Description** Conversion operator ## Example diff --git a/docs/messaging/message-bus.md b/docs/messaging/message-bus.md index 921e5b86..7277c01d 100644 --- a/docs/messaging/message-bus.md +++ b/docs/messaging/message-bus.md @@ -177,7 +177,7 @@ bus2.subscribe(routerD); bus2.subscribe(routerC); // Subscribe routerE to bus3. -bus3.subscibe(routerE); +bus3.subscribe(routerE); // Assume all routers accept the same messages. diff --git a/docs/releases/_index.md b/docs/releases/_index.md index 15553d90..aa737d96 100644 --- a/docs/releases/_index.md +++ b/docs/releases/_index.md @@ -73,7 +73,7 @@ Click on the links to see the original Github page. [#1432](https://github.com/ETLCPP/etl/pull/1432) Simplify and fix test/run-syntax-checks.sh [#1433](https://github.com/ETLCPP/etl/pull/1433) Fix the case of using STL without pthreads but with mutexes [#1434](https://github.com/ETLCPP/etl/pull/1434) Remove unnecessary includes -[#1437](https://github.com/ETLCPP/etl/pull/1437) ranges: Fix confict with Zephyr preprocessor definition +[#1437](https://github.com/ETLCPP/etl/pull/1437) ranges: Fix conflict with Zephyr preprocessor definition [#1440](https://github.com/ETLCPP/etl/pull/1440) Make etl::variant capable for ROM placement and optimize runtime size [#1441](https://github.com/ETLCPP/etl/pull/1441) Make etl::variant capable for ROM placement and optimize runtime size [#1442](https://github.com/ETLCPP/etl/pull/1442) Fix format: float zero-padding, nested replacement width, octal alter… @@ -152,7 +152,7 @@ Click on the links to see the original Github page. **Issues:** [#1184](https://github.com/ETLCPP/etl/issues/1184) Request: Adding a method to check whether a etl::callback_timer_atomic is currently running -[#1189](https://github.com/ETLCPP/etl/issues/1189) Request: make useage of osMutexRobust in etl::mutex optional +[#1189](https://github.com/ETLCPP/etl/issues/1189) Request: make usage of osMutexRobust in etl::mutex optional [#1207](https://github.com/ETLCPP/etl/issues/1207) Monadic Operations for etl::expected [#1240](https://github.com/ETLCPP/etl/issues/1240) Add redundant semicolon checks to CMakeLists.txt and fix issues [#1241](https://github.com/ETLCPP/etl/issues/1241) Add -pedantic-errors to unit test CMakeLists.txt and fix issues @@ -335,7 +335,7 @@ Removed redundant ETL_USING_WIDE_CHARACTERS Fixes: #1126 to_arithmetic-does-not-compile-on-C++98 #1128 Request: Make Delegate Methods noexcept -#1130 Use of etl::mem_copy for overlaped areas +#1130 Use of etl::mem_copy for overlapped areas #1132 Make type_def Methods Noexcept #1143 v20.41.x, risc-v (esp32-c3) "No user defined specialisation of etl::underlying_type for this type" @@ -510,11 +510,11 @@ Fixes: #942 Warning on pragma c++20-compat #951 Can't get call_if to work because of etl::optional #956 Fix build error (etl::circular_buffer) -#957 Support heterogenous lookup for maps +#957 Support heterogeneous lookup for maps #959 Treat bitset with size_type #972 Template not allowed warning in parameter pack #979 QueuedMessageRouter does not work : message are not sent to queue -#980 Documentation clarification: Add link from endianess to unaligned_type +#980 Documentation clarification: Add link from endianness to unaligned_type #982 Added return to etl::optional emplace, fixed typo #984 Update Base64 Documentation #986 Added const iterators to span @@ -639,7 +639,7 @@ Pull Requests: #905 Added support for type identity Other: -Reenabled address sanitizer for VS2022 +Re-enabled address sanitizer for VS2022 20.38.16 diff --git a/docs/timers/_index.md b/docs/timers/_index.md index 127fda77..a9129c17 100644 --- a/docs/timers/_index.md +++ b/docs/timers/_index.md @@ -3,4 +3,4 @@ title: "Timers" weight: 100 --- -Classes the implement timer based services. +Classes that implement timer-based services. diff --git a/docs/timers/callback-timer-interrupt.md b/docs/timers/callback-timer-interrupt.md index 45834642..54d3b116 100644 --- a/docs/timers/callback-timer-interrupt.md +++ b/docs/timers/callback-timer-interrupt.md @@ -196,7 +196,7 @@ Test test; //*************************************************************************** // The interrupt guard type. -// Saves and disables on contruction. +// Saves and disables interrupts on construction. // Restores on destruction. //*************************************************************************** struct InterruptGuard diff --git a/docs/timers/message-timer-interrupt.md b/docs/timers/message-timer-interrupt.md index 9cbc6d70..c41dc227 100644 --- a/docs/timers/message-timer-interrupt.md +++ b/docs/timers/message-timer-interrupt.md @@ -193,7 +193,7 @@ Message3 message3; //*************************************************************************** // The interrupt guard type. -// Saves and disables on contruction. +// Saves and disables on construction. // Restores on destruction. //*************************************************************************** struct InterruptGuard diff --git a/docs/timers/timer.md b/docs/timers/timer.md index b09785b3..d0d4ed63 100644 --- a/docs/timers/timer.md +++ b/docs/timers/timer.md @@ -15,7 +15,7 @@ struct timer { // Timer modes. struct mode - { + { enum { SINGLE_SHOT = false, diff --git a/docs/tutorials/callback-service.md b/docs/tutorials/callback-service.md index 972e97c1..fccf4a77 100644 --- a/docs/tutorials/callback-service.md +++ b/docs/tutorials/callback-service.md @@ -19,7 +19,7 @@ This code demonstrates using the callback service for five example ARM interrupt `Timer3` has no entry in the callback service and will therefore trigger execution of the unhandled handler. `USART1` and `USART2` interrupts are handled by instances of Uart. -There callbacks are defined withing the class and are initialised in the Uart constructor. +Their callbacks are defined within the class and are initialised in the Uart constructor. ```cpp #include @@ -146,7 +146,7 @@ Uart uart1(0, USART1_IRQ_HANDLER); Uart uart2(1, USART2_IRQ_HANDLER); // Declare a global callback for the timer. -// Uses the most efficient callback type for a class, as everthing is known at compile time. +// Uses the most efficient callback type for a class, as everything is known at compile time. etl::function_imp timer_member_callback; // Declare the callbacks for the free functions. diff --git a/docs/tutorials/delegate-service.md b/docs/tutorials/delegate-service.md index edb85f68..cc7dd612 100644 --- a/docs/tutorials/delegate-service.md +++ b/docs/tutorials/delegate-service.md @@ -13,7 +13,7 @@ This code demonstrates using the delegate service for five example ARM interrupt `Timer3` has no entry in the callback service and will therefore trigger execution of the unhandled handler. `USART1` and `USART2` interrupts are handled by instances of `Uart`. -There callbacks are defined withing the class and are initialised in the `Uart` constructor. +Their callbacks are defined within the class and are initialised in the `Uart` constructor. ```cpp #include @@ -137,7 +137,7 @@ Uart uart1(0, USART1_IRQ_HANDLER); Uart uart2(1, USART2_IRQ_HANDLER); // Declare a global callback for the timer. -// Uses the most efficient callback type for a class, as everthing is known at compile time. +// Uses the most efficient callback type for a class, as everything is known at compile time. etl::delegate timer_member_callback = etl::delegate::create(); diff --git a/docs/tutorials/shared-message_tutorial.md b/docs/tutorials/shared-message_tutorial.md index f94efb1b..e692a8d7 100644 --- a/docs/tutorials/shared-message_tutorial.md +++ b/docs/tutorials/shared-message_tutorial.md @@ -34,7 +34,7 @@ To this end a template alias is defined; `etl::atomic_counted_message`, which us In a muti-threaded or interrupt driven system, a method must be derived to manage access to the pool. All reference counted messages have an owner. -Owners are obects based on `etl::ireference_counted_message_pool`. +Owners are objects based on `etl::ireference_counted_message_pool`. A reference counted message pool will allocate reference counted messages. The storage for these are allocated from a supplied memory block allocator. @@ -256,7 +256,7 @@ private: }; //***************************************************************************** -// A message bus that can accomodate two subscribers. +// A message bus that can accommodate two subscribers. //***************************************************************************** struct Bus : public etl::message_bus<2U> { diff --git a/docs/types/tuple.md b/docs/types/tuple.md index 5981e34c..666719fa 100644 --- a/docs/types/tuple.md +++ b/docs/types/tuple.md @@ -249,3 +249,21 @@ template ETL_CONSTEXPR14 const T&& get(const tuple&&); ``` + +--- + +```cpp +template +ETL_CONSTEXPR14 +auto apply(TFunction&& f, TTuple&& t); +``` + +Invokes the callable object `f` (via `etl::invoke`) with the elements of the tuple `t` expanded as its arguments. Equivalent to `std::apply`. + +```cpp +int add(int a, int b, int c) { return a + b + c; } + +auto t = etl::make_tuple(1, 2, 3); +int sum = etl::apply(add, t); // sum == 6 +``` + diff --git a/docs/utilities/bit-stream-reader.md b/docs/utilities/bit-stream-reader.md index bba3e54c..64acaa66 100644 --- a/docs/utilities/bit-stream-reader.md +++ b/docs/utilities/bit-stream-reader.md @@ -248,15 +248,15 @@ namespace etl etl::optional read_unchecked(etl::bit_stream_reader& stream) { char c = stream.read_unchecked(); - short s = stream.read_unchecked(); - int32_t i = stream.read_unchecked(); + short s = stream.read_unchecked(11U); + int32_t i = stream.read_unchecked(25U); return CustomType { c, s, i }; } } std::array storage; // Assume the buffer gets filled with bit stream data. -etl::bit_stream_reader bit_stream(storage.data(), storage.size()); +etl::bit_stream_reader bit_stream(storage.data(), storage.size(), etl::bit_order::msb_first); // Read unchecked values from the stream. char c = etl::read_unchecked(bit_stream, 6U); diff --git a/docs/utilities/bit-stream-writer.md b/docs/utilities/bit-stream-writer.md index 3d83c0e4..5cc3f4a6 100644 --- a/docs/utilities/bit-stream-writer.md +++ b/docs/utilities/bit-stream-writer.md @@ -328,7 +328,7 @@ Sets the delegate to call after every write. callback_type get_callback() const ``` **Description** -Gets the function to call afer every write. +Gets the function to call after every write. --- @@ -397,13 +397,13 @@ namespace etl void write_unchecked(etl::bit_stream_reader& stream) { stream.write_unchecked(); - stream.write_unchecked(); + stream.write_unchecked(); stream.write_unchecked(); } } std::array storage; // Assume the buffer gets filled with bit stream data. -etl::bit_stream_reader bit_stream(storage.data(), storage.size()); +etl::bit_stream_writer bit_stream(storage.data(), storage.size(), etl::bit_order::msb_first); // Write unchecked values to the stream. etl::write_unchecked(bit_stream, 6U); diff --git a/docs/utilities/endian.md b/docs/utilities/endian.md index 1aa2c969..4de8014d 100644 --- a/docs/utilities/endian.md +++ b/docs/utilities/endian.md @@ -7,11 +7,11 @@ title: "endian" Since: `TBC` {{< /callout >}} -Constants & utilities for endianess. +Constants & utilities for endianness. For endian specific integral types, see `unaligned_type`. -The values for endianness are dependant on the platform setup. +The values for endianness are dependent on the platform setup. If `ETL_ENDIAN_NATIVE` is defined by the user, then  `etl::endian::little = 0` diff --git a/docs/utilities/error-handler.md b/docs/utilities/error-handler.md index ab317500..074b199e 100644 --- a/docs/utilities/error-handler.md +++ b/docs/utilities/error-handler.md @@ -16,7 +16,7 @@ You have a choice of: - Error log - No error checking -The type of error handler used is dependant on the compile time macro defined. +The type of error handler used is dependent on the compile time macro defined. Note: This are usually set as a project wide definition. | Macro | Actions | diff --git a/docs/utilities/initializer-list.md b/docs/utilities/initializer-list.md index 48cd46a1..054e1373 100644 --- a/docs/utilities/initializer-list.md +++ b/docs/utilities/initializer-list.md @@ -18,7 +18,7 @@ The `initializer_list` template class is a special case in that it *must* have a This header will either include the standard `` header, or attempt to define a `std::initializer_list` template class that is compatible with the current compiler. -The header will define `ETL_USING_INITIALIZER_LIST` to either `1` or `0` dependant of whether `std::initializer_list` is available or not. +The header will define `ETL_USING_INITIALIZER_LIST` to either `1` or `0` dependent on whether `std::initializer_list` is available or not. The ETL will select the STL version if you are using the STL and `ETL_FORCE_ETL_INITIALIZER_LIST` is not defined or, `ETL_FORCE_STD_INITIALIZER_LIST` is defined. diff --git a/docs/utilities/type-id.md b/docs/utilities/type-id.md deleted file mode 100644 index 1686c1bd..00000000 --- a/docs/utilities/type-id.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: "type_id" ---- - -{{< callout type="info">}} - Header: `type_id.h` - Since: `TBC` -{{< /callout >}} - -Below is a concise, technical overview of the `etl::type_id` facility, suitable for design documentation or code review context. - -## Overview: -`etl::type_id` is a lightweight, RTTI-free mechanism for uniquely identifying C++ types at runtime. It is designed for environments where standard RTTI (`typeid`, `std::type_info`) is unavailable, undesirable, or too costly—such as embedded systems or performance-constrained platforms. - -The implementation guarantees uniqueness per type within a program image while remaining constexpr-friendly and requiring no dynamic allocation. - -## Design Concept - -The core idea is to associate each distinct type `T` with the address of a unique static object. That address serves as the type’s identifier. - -This is achieved through: - -```cpp -template -struct type_id_anchor -{ - static char value; -}; -``` - -Each instantiation of `type_id_anchor` owns its own `static char value`, and the address of that variable is guaranteed to be unique for each distinct `T`. The address is stable for the lifetime of the program. - -## Key Components - -### Type Normalization - -When requesting a type ID via `type_id::get()`, the type is first normalised: - -```cpp -using type = typename etl::remove_cvref::type; -``` - -This ensures that: - -* `T`, `const T`, `T&`, and `T&&` all map to the same `type_id` -* Only the underlying type identity matters - -### Type ID Generation - -```cpp -template -static ETL_CONSTEXPR type_id get() ETL_NOEXCEPT; -``` - -* Returns a `type_id` that uniquely represents `T` -* Internally stores the address of `type_id_anchor::value` -* Requires no RTTI, no dynamic memory, and no runtime registration - -### Invalid Type ID - -```cpp -static ETL_CONSTEXPR type_id invalid_id() ETL_NOEXCEPT; -``` - -* Represents an invalid or uninitialised type ID -* Implemented as a null pointer (`id == nullptr`) -* Default constructor produces this state - -## `type_id` Class Semantics - -### Storage - -```cpp -const void* id; -``` - -* The identifier is stored as a pointer -* Comparison is purely pointer comparison (fast and deterministic) - -### Supported Operations - -| Operation | Behavior | -| ------------------ | -------------------------------------------------- | -| Equality (`==`) | True if both type IDs refer to the same type | -| Inequality (`!=`) | Logical negation of equality | -| Ordering (`<`) | Pointer comparison (useful for ordered containers) | -| Boolean conversion | `true` if valid, `false` if invalid | -| Integer conversion | Explicit conversion to `intptr_t` / `uintptr_t` | - -### Copy and Assignment - -* Copyable and assignable -* Copy semantics preserve identity (pointer value) - -## Guarantees and Properties - -* **Uniqueness**: Each distinct type has exactly one unique `type_id` -* **Stability**: Type IDs remain valid for the entire program lifetime -* **Zero overhead**: No dynamic allocation, no lookup tables -* **RTTI-free**: Suitable for builds with RTTI disabled -* **Comparable**: Can be used as keys in associative containers - -## Typical Use Cases - -* Type-safe containers (e.g., variant, any, message buses) -* Plugin or component systems -* Compile-time / runtime type discrimination in embedded systems -* Replacement for `std::type_index` in restricted environments - -## Summary - -`etl::type_id` provides a robust, minimal, and efficient alternative to C++ RTTI by encoding type identity as the address of a unique static object. Its design is particularly well-suited to embedded and low-level systems where determinism, performance, and binary size are critical. diff --git a/docs/utilities/utility.md b/docs/utilities/utility.md index 3e36bc7a..c4f76c5f 100644 --- a/docs/utilities/utility.md +++ b/docs/utilities/utility.md @@ -71,6 +71,82 @@ T exchange(T& object, const U& new_value) Copies the new value to object and returns the old value. Note: This is not an atomic operation. +## Integer comparison functions + +Safe comparison of integers of different signedness. Unlike the built-in +comparison operators, negative signed integers always compare less than (and +never equal to) unsigned integers, so the result is never affected by +value-changing implicit conversions. +The arguments must be standard signed or unsigned integer types, including +`signed char` and `unsigned char`. `bool`, `char` and the extended character +types are not permitted. +When the STL is available and the compiler provides +`__cpp_lib_integer_comparison_functions` (C++20), the `std` versions are used. +Since: `20.49.0` + +```cpp +template +constexpr bool cmp_equal(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is equal to `u`. + +--- + +```cpp +template +constexpr bool cmp_not_equal(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is not equal to `u`. + +--- + +```cpp +template +constexpr bool cmp_less(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is less than `u`. + +--- + +```cpp +template +constexpr bool cmp_greater(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is greater than `u`. + +--- + +```cpp +template +constexpr bool cmp_less_equal(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is less than or equal to `u`. + +--- + +```cpp +template +constexpr bool cmp_greater_equal(T t, U u) noexcept +``` +**Description** +Returns `true` if `t` is greater than or equal to `u`. + +--- + +```cpp +template +constexpr bool in_range(T t) noexcept +``` +**Description** +Returns `true` if the value of `t` is in the range of values that can be +represented by `R`, that is, if `t` can be converted to `R` without loss of its +value. + ## add_const ```cpp diff --git a/include/etl/alignment.h b/include/etl/alignment.h index 023acac2..497151bd 100644 --- a/include/etl/alignment.h +++ b/include/etl/alignment.h @@ -384,7 +384,7 @@ namespace etl /// constructor. //*************************************************************************** template - typed_storage(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + typed_storage(TArgs&&... args) : valid(false) { create(etl::forward(args)...); @@ -456,7 +456,7 @@ namespace etl /// the internal byte array. //*************************************************************************** template - reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + reference create(TArgs&&... args) { ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); pointer p = ::new (&storage.value) value_type(etl::forward(args)...); @@ -536,7 +536,7 @@ namespace etl //*************************************************************************** /// \returns a pointer of type T and asserts if has_value() is false. //*************************************************************************** - pointer operator->() ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + pointer operator->() { ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); @@ -546,7 +546,7 @@ namespace etl //*************************************************************************** /// \returns a const pointer of type T and asserts if has_value() is false. //*************************************************************************** - const_pointer operator->() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + const_pointer operator->() const { ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); @@ -556,7 +556,7 @@ namespace etl //*************************************************************************** /// \returns reference of type T and asserts if has_value() is false. //*************************************************************************** - reference operator*() ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + reference operator*() { return *operator->(); } @@ -564,15 +564,15 @@ namespace etl //*************************************************************************** /// \returns const_reference of type T and asserts if has_value() is false. //*************************************************************************** - const_reference operator*() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + const_reference operator*() const { return *operator->(); } private: - typed_storage(etl::typed_storage&) ETL_DELETE; - typed_storage& operator=(etl::typed_storage&) ETL_DELETE; + typed_storage(const etl::typed_storage&) ETL_DELETE; + typed_storage& operator=(const etl::typed_storage&) ETL_DELETE; struct dummy_t { @@ -620,7 +620,7 @@ namespace etl //*************************************************************************** /// Constructor. //*************************************************************************** - typed_storage_ext(void* pbuffer_) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + typed_storage_ext(void* pbuffer_) : pbuffer(reinterpret_cast(pbuffer_)) , valid(false) { @@ -633,7 +633,7 @@ namespace etl /// constructor. //*************************************************************************** template - typed_storage_ext(void* pbuffer_, TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + typed_storage_ext(void* pbuffer_, TArgs&&... args) : pbuffer(reinterpret_cast(pbuffer_)) , valid(false) { @@ -645,7 +645,7 @@ namespace etl /// Move constructor. /// Transfers ownership of the buffer from \p other to this. //*************************************************************************** - typed_storage_ext(typed_storage_ext&& other) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + typed_storage_ext(typed_storage_ext&& other) : pbuffer(other.pbuffer) , valid(other.valid) { @@ -727,7 +727,7 @@ namespace etl /// the external buffer. //*************************************************************************** template - reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + reference create(TArgs&&... args) { ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); pointer p = ::new (pbuffer) value_type(etl::forward(args)...); @@ -807,7 +807,7 @@ namespace etl //*************************************************************************** /// \returns a pointer of type T and asserts if has_value() is false. //*************************************************************************** - pointer operator->() ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + pointer operator->() { ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); @@ -817,7 +817,7 @@ namespace etl //*************************************************************************** /// \returns a const pointer of type T and asserts if has_value() is false. //*************************************************************************** - const_pointer operator->() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + const_pointer operator->() const { ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); @@ -827,7 +827,7 @@ namespace etl //*************************************************************************** /// \returns reference of type T and asserts if has_value() is false. //*************************************************************************** - reference operator*() ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + reference operator*() { return *operator->(); } @@ -835,15 +835,15 @@ namespace etl //*************************************************************************** /// \returns const_reference of type T and asserts if has_value() is false. //*************************************************************************** - const_reference operator*() const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + const_reference operator*() const { return *operator->(); } private: - typed_storage_ext(etl::typed_storage_ext&) ETL_DELETE; - typed_storage_ext& operator=(etl::typed_storage_ext&) ETL_DELETE; + typed_storage_ext(const etl::typed_storage_ext&) ETL_DELETE; + typed_storage_ext& operator=(const etl::typed_storage_ext&) ETL_DELETE; pointer pbuffer; bool valid; diff --git a/include/etl/array.h b/include/etl/array.h index ffa3a307..1bb92cea 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -40,6 +40,9 @@ SOFTWARE. #include "static_assert.h" #include "type_traits.h" +#include "private/tuple_element.h" +#include "private/tuple_size.h" + #include ///\defgroup array array @@ -111,7 +114,7 @@ namespace etl /// Returns a reference to the value at index 'i'. ///\param i The index of the element to access. //************************************************************************* - ETL_NODISCARD ETL_CONSTEXPR14 reference at(size_t i) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_NODISCARD ETL_CONSTEXPR14 reference at(size_t i) { ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); @@ -122,7 +125,7 @@ namespace etl /// Returns a const reference to the value at index 'i'. ///\param i The index of the element to access. //************************************************************************* - ETL_NODISCARD ETL_CONSTEXPR14 const_reference at(size_t i) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_NODISCARD ETL_CONSTEXPR14 const_reference at(size_t i) const { ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); @@ -709,7 +712,7 @@ namespace etl //************************************************************************* /// Returns a const reference to the last element. //************************************************************************* - ETL_NODISCARD ETL_CONSTEXPR const_reference back() const + ETL_NODISCARD ETL_CONSTEXPR const_reference back() const ETL_NOEXCEPT { return *data(); } @@ -1053,7 +1056,13 @@ namespace etl template constexpr auto make_array(TValues&&... values) ETL_NOEXCEPT -> etl::array { - return {etl::forward(values)...}; + // 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 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(0, 1)) working, which plain forwarding into the + // braced initialiser list would reject. + return {static_cast(etl::forward(values))...}; } #endif @@ -1063,7 +1072,7 @@ namespace etl ///\param rhs The second array. //************************************************************************* template - void swap(etl::array& lhs, etl::array& rhs) + ETL_CONSTEXPR14 void swap(etl::array& lhs, etl::array& rhs) ETL_NOEXCEPT_FROM(ETL_OR_STD::swap(etl::declval(), etl::declval())) { lhs.swap(rhs); } @@ -1100,7 +1109,7 @@ namespace etl /// second, otherwise false //************************************************************************* template - bool operator<(const etl::array& lhs, const etl::array& rhs) + ETL_CONSTEXPR14 bool operator<(const etl::array& lhs, const etl::array& rhs) { return etl::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); } @@ -1114,7 +1123,7 @@ namespace etl ///< b>false //************************************************************************* template - bool operator<=(const etl::array& lhs, const etl::array& rhs) + ETL_CONSTEXPR14 bool operator<=(const etl::array& lhs, const etl::array& rhs) { return !(lhs > rhs); } @@ -1127,7 +1136,7 @@ namespace etl /// the second, otherwise false template //************************************************************************* - bool operator>(const etl::array& lhs, const etl::array& rhs) + ETL_CONSTEXPR14 bool operator>(const etl::array& lhs, const etl::array& rhs) { return (rhs < lhs); } @@ -1141,7 +1150,7 @@ namespace etl ///< b>false //************************************************************************* template - bool operator>=(const etl::array& lhs, const etl::array& rhs) + ETL_CONSTEXPR14 bool operator>=(const etl::array& lhs, const etl::array& rhs) { return !(lhs < rhs); } @@ -1155,7 +1164,7 @@ namespace etl ///\return A reference to the element //************************************************************************* template - inline T& get(array& a) + ETL_NODISCARD ETL_CONSTEXPR14 T& get(array& a) ETL_NOEXCEPT { ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); return a[Index]; @@ -1170,11 +1179,106 @@ namespace etl ///\return A const reference to the element //************************************************************************* template - inline const T& get(const array& a) + ETL_NODISCARD ETL_CONSTEXPR14 const T& get(const array& a) ETL_NOEXCEPT { ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); return a[Index]; } + +#if ETL_USING_CPP11 + //************************************************************************* + /// Gets an rvalue reference to an element in the array. + ///\tparam Index The index. + ///\tparam T The type. + ///\tparam Size The array size. + ///\param a The array. + ///\return An rvalue reference to the element + //************************************************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 T&& get(array&& a) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); + return static_cast(a[Index]); + } + + //************************************************************************* + /// Gets a const rvalue reference to an element in the array. + ///\tparam Index The index. + ///\tparam T The type. + ///\tparam Size The array size. + ///\param a The array. + ///\return A const rvalue reference to the element + //************************************************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 const T&& get(const array&& a) ETL_NOEXCEPT + { + ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); + return static_cast(a[Index]); + } + + //************************************************************************* + /// Gets the number of elements in an array. + ///\tparam T The type. + ///\tparam Size The array size. + //************************************************************************* + template + struct tuple_size > : etl::integral_constant + { + }; + + //************************************************************************* + /// Gets the type of the element at Index in an array. + ///\tparam Index The index. + ///\tparam T The type. + ///\tparam Size The array size. + //************************************************************************* + template + struct tuple_element > + { + ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); + + using type = T; + }; +#endif } // namespace etl +#if ETL_USING_CPP11 +namespace std +{ + // libc++ already declares std::tuple_size / std::tuple_element in its inline + // namespace (std::__1), so re-declaring them here would make the name + // ambiguous. Detect libc++ via _LIBCPP_VERSION and skip the forward + // declarations in that case, even when not using the STL. + #if ETL_NOT_USING_STL && !defined(_LIBCPP_VERSION) \ + && !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000) && (ETL_COMPILER_FULL_VERSION < 210000)) \ + && defined(ETL_COMPILER_CLANG)) + template + struct tuple_size; + + template + struct tuple_element; + #endif + + //*************************************************************************** + /// Specialisation of tuple_size to allow the use of C++ structured bindings. + //*************************************************************************** + template + struct tuple_size > : etl::integral_constant + { + }; + + //*************************************************************************** + /// Specialisation of tuple_element to allow the use of C++ structured + /// bindings. + //*************************************************************************** + template + struct tuple_element > + { + ETL_STATIC_ASSERT(Index < Size, "Index out of bounds"); + + using type = T; + }; +} // namespace std +#endif + #endif diff --git a/include/etl/binary.h b/include/etl/binary.h index 230fbf4a..2e02c41e 100644 --- a/include/etl/binary.h +++ b/include/etl/binary.h @@ -2128,7 +2128,7 @@ namespace etl s = (s | (s << 2U)) & 0x33333333UL; s = (s | (s << 1U)) & 0x55555555UL; - return (f | (s << 1U)); + return static_cast(f | (s << 1U)); } #if ETL_USING_64BIT_TYPES @@ -2156,7 +2156,7 @@ namespace etl s = (s | (s << 2U)) & 0x3333333333333333ULL; s = (s | (s << 1U)) & 0x5555555555555555ULL; - return (f | (s << 1U)); + return static_cast(f | (s << 1U)); } #endif diff --git a/include/etl/bit.h b/include/etl/bit.h index 4947a17b..861c776d 100644 --- a/include/etl/bit.h +++ b/include/etl/bit.h @@ -50,15 +50,22 @@ namespace etl //*************************************************************************** template ETL_NODISCARD - typename etl::enable_if< !(etl::is_integral::value && etl::is_integral::value) && (sizeof(TDestination) == sizeof(TSource)) - && etl::is_trivially_copyable::value && etl::is_trivially_copyable::value, - TDestination>::type bit_cast(const TSource& source) ETL_NOEXCEPT +#if ETL_USING_BUILTIN_BIT_CAST + ETL_CONSTEXPR14 +#endif + typename etl::enable_if< !(etl::is_integral::value && etl::is_integral::value) && (sizeof(TDestination) == sizeof(TSource)) + && etl::is_trivially_copyable::value && etl::is_trivially_copyable::value, + TDestination>::type bit_cast(const TSource& source) ETL_NOEXCEPT { +#if ETL_USING_BUILTIN_BIT_CAST + return __builtin_bit_cast(TDestination, source); +#else TDestination destination; memcpy(&destination, &source, sizeof(TDestination)); return destination; +#endif } //*************************************************************************** diff --git a/include/etl/bit_stream.h b/include/etl/bit_stream.h index 8248d9ae..349aa12f 100644 --- a/include/etl/bit_stream.h +++ b/include/etl/bit_stream.h @@ -695,7 +695,7 @@ namespace etl template typename etl::enable_if::value, bool>::type write(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T)) { - bool success = (available(nbits) > 0U); + bool success = (nbits > 0U) && (available(nbits) > 0U); if (success) { @@ -914,6 +914,7 @@ namespace etl template void write_data(T value, uint_least8_t nbits) { + ETL_ASSERT(nbits > 0U, ETL_ERROR_GENERIC("bit_stream_writer::write_data: nbits is zero")); ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_writer::write_data: nbits too large")); // Apply the byte order (endianness). @@ -1305,6 +1306,7 @@ namespace etl template T read_value(uint_least8_t nbits, bool is_signed) { + ETL_ASSERT(nbits > 0U, ETL_ERROR_GENERIC("bit_stream_reader::read_value: nbits is zero")); ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_reader::read_value: nbits too large")); T value = 0; diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 51dc9e92..76a4bf04 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -508,6 +508,28 @@ namespace etl { } + //*************************************************************************** + /// Construct from span. + //*************************************************************************** + byte_stream_reader(etl::span span_, etl::endian stream_endianness_) + : pdata(reinterpret_cast(span_.begin())) + , pcurrent(reinterpret_cast(span_.begin())) + , stream_length(span_.size_bytes()) + , stream_endianness(stream_endianness_) + { + } + + //*************************************************************************** + /// Construct from span. + //*************************************************************************** + byte_stream_reader(etl::span span_, etl::endian stream_endianness_) + : pdata(reinterpret_cast(span_.begin())) + , pcurrent(reinterpret_cast(span_.begin())) + , stream_length(span_.size_bytes()) + , stream_endianness(stream_endianness_) + { + } + //*************************************************************************** /// Construct from range. //*************************************************************************** diff --git a/include/etl/const_map.h b/include/etl/const_map.h index f96f616b..051e6303 100644 --- a/include/etl/const_map.h +++ b/include/etl/const_map.h @@ -508,7 +508,8 @@ namespace etl //************************************************************************* ///\brief Construct a const_map from a variadic list of elements. - /// Static asserts if the elements are not of type value_type. + /// Static asserts if the elements are not constructible into + /// value_type. /// Static asserts if the number of elements is greater than the capacity of /// the const_map. //************************************************************************* @@ -517,7 +518,8 @@ namespace etl : iconst_map(element_list, sizeof...(elements), Size) , element_list{etl::forward(elements)...} { - static_assert((etl::are_all_same...>::value), "All elements must be value_type"); + static_assert((etl::conjunction>...>::value), + "All elements must be constructible into value_type"); static_assert(sizeof...(elements) <= Size, "Number of elements exceeds capacity"); } diff --git a/include/etl/const_multimap.h b/include/etl/const_multimap.h index dea60ee1..589fe331 100644 --- a/include/etl/const_multimap.h +++ b/include/etl/const_multimap.h @@ -458,7 +458,8 @@ namespace etl //************************************************************************* ///\brief Construct a const_map from a variadic list of elements. /// Static asserts if the element type is not constructible. - /// Static asserts if the elements are not of type value_type. + /// Static asserts if the elements are not constructible into + /// value_type. /// Static asserts if the number of elements is greater than the capacity of /// the const_map. //************************************************************************* @@ -467,7 +468,8 @@ namespace etl : iconst_multimap(element_list, sizeof...(elements), Size) , element_list{etl::forward(elements)...} { - static_assert((etl::are_all_same...>::value), "All elements must be value_type"); + static_assert((etl::conjunction>...>::value), + "All elements must be constructible into value_type"); static_assert(sizeof...(elements) <= Size, "Number of elements exceeds capacity"); } diff --git a/include/etl/debounce.h b/include/etl/debounce.h index 2618d5e3..20a13ab5 100644 --- a/include/etl/debounce.h +++ b/include/etl/debounce.h @@ -536,7 +536,10 @@ namespace etl } //************************************************************************* - /// Constructor. + /// Sets the count thresholds. + ///\param valid The count for a valid state. + ///\param hold The count after valid for a hold state. Default = 0. + ///\param repeat The count after hold for a key repeat. Default = 0. //************************************************************************* void set(count_t valid, count_t hold = 0, count_t repeat = 0) { diff --git a/include/etl/deque.h b/include/etl/deque.h index 4ac0ac92..a35eda34 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -2535,7 +2535,13 @@ namespace etl template constexpr auto make_deque(TValues&&... values) -> etl::deque { - return {etl::forward(values)...}; + // 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 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(0, 1)) working, which plain forwarding into the + // braced initialiser list would reject. + return {static_cast(etl::forward(values))...}; } #endif diff --git a/include/etl/expected.h b/include/etl/expected.h index 655be8b1..1feb1487 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -315,13 +315,13 @@ namespace etl //******************************************* /// Copy construct from unexpected type. //******************************************* - template ::value, bool>::type = false> + template ::value, bool> = false> ETL_CONSTEXPR14 explicit expected(const etl::unexpected& ue) : storage(etl::in_place_index_t(), ue.error()) { } - template ::value, bool>::type = false> + template ::value, bool> = false> ETL_CONSTEXPR14 expected(const etl::unexpected& ue) : storage(etl::in_place_index_t(), ue.error()) { @@ -338,13 +338,13 @@ namespace etl //******************************************* /// Move construct from unexpected type. //******************************************* - template ::value, bool>::type = false> + template ::value, bool> = false> ETL_CONSTEXPR14 explicit expected(etl::unexpected&& ue) : storage(etl::in_place_index_t(), etl::move(ue.error())) { } - template ::value, bool>::type = false> + template ::value, bool> = false> ETL_CONSTEXPR14 expected(etl::unexpected&& ue) : storage(etl::in_place_index_t(), etl::move(ue.error())) { @@ -746,7 +746,7 @@ namespace etl //******************************************* const value_type& operator*() const ETL_LVALUE_REF_QUALIFIER { - ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); + ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::get(storage); } @@ -757,7 +757,7 @@ namespace etl //******************************************* value_type&& operator*() && { - ETL_ASSERT_OR_RETURN_VALUE(has_value(), ETL_ERROR(expected_invalid), ETL_NULLPTR); + ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid)); return etl::move(etl::get(storage)); } @@ -807,97 +807,97 @@ namespace etl } #if ETL_USING_CPP11 - template ::type>::type> + template >> auto transform(F&& f) & -> expected { return transform_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto transform(F&& f) const& -> expected { return transform_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto transform(F&& f) && -> expected { return transform_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto transform(F&& f) const&& -> expected { return transform_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto and_then(F&& f) & -> U { return and_then_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto and_then(F&& f) const& -> U { return and_then_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto and_then(F&& f) && -> U { return and_then_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto and_then(F&& f) const&& -> U { return and_then_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto or_else(F&& f) & -> U { return or_else_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto or_else(F&& f) const& -> U { return or_else_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto or_else(F&& f) && -> U { return or_else_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto or_else(F&& f) const&& -> U { return or_else_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto transform_error(F&& f) & -> expected { return transform_error_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto transform_error(F&& f) const& -> expected { return transform_error_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto transform_error(F&& f) && -> expected { return transform_error_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t>> auto transform_error(F&& f) const&& -> expected { return transform_error_impl(etl::forward(f), etl::move(*this)); @@ -916,7 +916,7 @@ namespace etl storage_type storage; #if ETL_USING_CPP11 - template < typename F, typename TExp, typename TRet, typename TValueRef, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename TValueRef, typename = etl::enable_if_t::value>> auto transform_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) @@ -929,7 +929,7 @@ namespace etl } } - template < typename F, typename TExp, typename TRet, typename TValueRef, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename TValueRef, typename = etl::enable_if_t::value>> auto transform_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) @@ -944,8 +944,8 @@ namespace etl } template < typename F, typename TExp, typename TRet, typename TValueRef, - typename = typename etl::enable_if< !etl::is_void::value && etl::is_expected::value - && etl::is_same::value>::type> + typename = etl::enable_if_t::value && etl::is_expected::value + && etl::is_same::value>> auto and_then_impl(F&& f, TExp&& exp) const -> TRet { if (exp.has_value()) @@ -959,8 +959,8 @@ namespace etl } template < typename F, typename TExp, typename TRet, typename TErrorRef, - typename = typename etl::enable_if< !etl::is_void::value && etl::is_expected::value - && etl::is_same::value>::type> + typename = etl::enable_if_t::value && etl::is_expected::value + && etl::is_same::value>> auto or_else_impl(F&& f, TExp&& exp) const -> TRet { if (exp.has_value()) @@ -973,7 +973,7 @@ namespace etl } } - template < typename F, typename TExp, typename TRet, typename TErrorRef, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename TErrorRef, typename = etl::enable_if_t::value>> auto transform_error_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) @@ -1216,97 +1216,97 @@ namespace etl } #if ETL_USING_CPP11 - template ::type>::type> + template >> auto transform(F&& f) & -> expected { return transform_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto transform(F&& f) const& -> expected { return transform_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto transform(F&& f) && -> expected { return transform_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto transform(F&& f) const&& -> expected { return transform_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto and_then(F&& f) & -> U { return and_then_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto and_then(F&& f) const& -> U { return and_then_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto and_then(F&& f) && -> U { return and_then_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto and_then(F&& f) const&& -> U { return and_then_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto or_else(F&& f) & -> U { return or_else_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t>> auto or_else(F&& f) const& -> U { return or_else_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto or_else(F&& f) && -> U { return or_else_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t>> auto or_else(F&& f) const&& -> U { return or_else_impl(etl::forward(f), etl::move(*this)); } - template ::type>::type> + template >> auto transform_error(F&& f) & -> expected { return transform_error_impl(etl::forward(f), *this); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t>> auto transform_error(F&& f) const& -> expected { return transform_error_impl(etl::forward(f), *this); } - template ::type>::type> + template >> auto transform_error(F&& f) && -> expected { return transform_error_impl(etl::forward(f), etl::move(*this)); } - template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> + template < typename F, typename U = etl::remove_cvref_t>> auto transform_error(F&& f) const&& -> expected { return transform_error_impl(etl::forward(f), etl::move(*this)); @@ -1324,7 +1324,7 @@ namespace etl etl::variant storage; #if ETL_USING_CPP11 - template < typename F, typename TExp, typename TRet, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename = etl::enable_if_t::value>> auto transform_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) @@ -1337,7 +1337,7 @@ namespace etl } } - template < typename F, typename TExp, typename TRet, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename = etl::enable_if_t::value>> auto transform_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) @@ -1352,8 +1352,8 @@ namespace etl } template < typename F, typename TExp, typename TRet, - typename = typename etl::enable_if< !etl::is_void::value && etl::is_expected::value - && etl::is_same::value>::type> + typename = etl::enable_if_t< !etl::is_void::value && etl::is_expected::value + && etl::is_same::value>> auto and_then_impl(F&& f, TExp&& exp) const -> TRet { if (exp.has_value()) @@ -1367,8 +1367,8 @@ namespace etl } template ::value && etl::is_expected::value - && etl::is_same::value>::type> + typename = etl::enable_if_t< !etl::is_void::value && etl::is_expected::value + && etl::is_same::value>> auto or_else_impl(F&& f, TExp&& exp) const -> TRet { if (exp.has_value()) @@ -1381,7 +1381,7 @@ namespace etl } } - template < typename F, typename TExp, typename TRet, typename TErrorRef, typename = typename etl::enable_if::value>::type> + template < typename F, typename TExp, typename TRet, typename TErrorRef, typename = etl::enable_if_t::value>> auto transform_error_impl(F&& f, TExp&& exp) const -> expected { if (exp.has_value()) diff --git a/include/etl/format.h b/include/etl/format.h index 75ac5952..30152dc9 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -91,44 +91,70 @@ namespace etl POINTER // const void* }; - // Map a type to its category. Decays and removes cv-qualifiers. + // Trait mapping a type (with references and cv-qualifiers removed) to its type_category. + // + // NOTE: signed char/unsigned char (typically int8_t/uint8_t) are NOT + // categorised as CHAR here - only plain 'char' gets character semantics. + // signed/unsigned char are formatted as integers, matching basic_format_arg + // storage and std::format's formatter/. This is + // enforced structurally: the INTEGER partial specialisation is constrained + // with is_integral && !is_same && !is_same, so + // signed/unsigned char (is_integral == true) fall into INTEGER while the + // dedicated bool/char full specialisations take priority for those exact types. + template + struct type_category_trait + { + static constexpr type_category value = type_category::NONE; // unknown type: custom formatter, be permissive + }; + + template <> + struct type_category_trait + { + static constexpr type_category value = type_category::BOOLEAN; + }; + + template <> + struct type_category_trait + { + static constexpr type_category value = type_category::CHAR; + }; + + template + struct type_category_trait< + T, typename etl::enable_if::value && !etl::is_same::value && !etl::is_same::value>::type> + { + static constexpr type_category value = type_category::INTEGER; + }; + + template + struct type_category_trait::value>::type> + { + static constexpr type_category value = type_category::FLOAT; + }; + + template + struct type_category_trait::value || etl::is_same::value + || etl::is_same::value || etl::is_base_of::value>::type> + { + static constexpr type_category value = type_category::STRING; + }; + + template + struct type_category_trait< + T, typename etl::enable_if::value && !etl::is_same::value && !etl::is_same::value>::type> + { + static constexpr type_category value = type_category::POINTER; + }; + + // Map a type to its category. Removes references and cv-qualifiers, then defers + // entirely to the type_category_trait specialisations above. template constexpr type_category get_type_category() { using U = typename etl::remove_cv::type>::type; - // Order matters: bool before integral, char before integral - if (etl::is_same::value) - return type_category::BOOLEAN; - if (etl::is_same::value) - return type_category::CHAR; - if (etl::is_same::value) - return type_category::CHAR; - if (etl::is_same::value) - return type_category::CHAR; - if (etl::is_integral::value) - return type_category::INTEGER; - if (etl::is_same::value) - return type_category::FLOAT; - if (etl::is_same::value) - return type_category::FLOAT; - if (etl::is_same::value) - return type_category::FLOAT; - if (etl::is_same::value) - return type_category::STRING; - if (etl::is_same::value) - return type_category::STRING; - if (etl::is_same::value) - return type_category::STRING; - if (etl::is_base_of::value) - return type_category::STRING; - if (etl::is_pointer::value) - return type_category::POINTER; - if (etl::is_same::value) - return type_category::POINTER; - if (etl::is_same::value) - return type_category::POINTER; - return type_category::NONE; // unknown type: custom formatter, be permissive + return type_category_trait::value; } // Check if a format type character is valid for a given type category. @@ -727,13 +753,16 @@ namespace etl { } + // int8_t / uint8_t are typically defined as signed char / unsigned char, but + // (unlike plain char) they are formatted as integers by default, matching + // std::format's formatter/formatter behaviour. basic_format_arg(const signed char v) - : data(static_cast(v)) + : data(static_cast(v)) { } basic_format_arg(const unsigned char v) - : data(static_cast(v)) + : data(static_cast(v)) { } diff --git a/include/etl/list.h b/include/etl/list.h index c2bbdfc2..7be34fcc 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -2219,7 +2219,7 @@ namespace etl //************************************************************************* #if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST template - constexpr auto make_list(T... t) -> etl::list, sizeof...(T)> + constexpr auto make_list(T&&... t) -> etl::list, sizeof...(T)> { return {etl::forward(t)...}; } diff --git a/include/etl/not_null.h b/include/etl/not_null.h index 25823d68..dc1ada2f 100644 --- a/include/etl/not_null.h +++ b/include/etl/not_null.h @@ -46,7 +46,7 @@ namespace etl { public: - not_null_exception(string_type reason_, string_type file_name_, numeric_type line_number_) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + not_null_exception(string_type reason_, string_type file_name_, numeric_type line_number_) : exception(reason_, file_name_, line_number_) { } @@ -59,7 +59,7 @@ namespace etl { public: - not_null_contains_null(string_type file_name_, numeric_type line_number_) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + not_null_contains_null(string_type file_name_, numeric_type line_number_) : not_null_exception(ETL_ERROR_TEXT("not_null:contains null", ETL_NOT_NULL_FILE_ID"A"), file_name_, line_number_) { } @@ -92,7 +92,7 @@ namespace etl /// Constructs a not_null from a pointer. /// Asserts if the pointer is null. //********************************* - ETL_CONSTEXPR14 explicit not_null(underlying_type ptr_) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 explicit not_null(underlying_type ptr_) : ptr(ptr_) { ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null)); @@ -110,7 +110,7 @@ namespace etl /// Assignment from a pointer. /// Asserts if the pointer is null. //********************************* - ETL_CONSTEXPR14 not_null& operator=(underlying_type rhs) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 not_null& operator=(underlying_type rhs) { ETL_ASSERT_OR_RETURN_VALUE(rhs != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this); @@ -193,7 +193,7 @@ namespace etl /// Asserts if the unique_ptr contains null. /// Moves from the unique_ptr. //********************************* - ETL_CONSTEXPR14 explicit not_null(underlying_type&& u_ptr_) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 explicit not_null(underlying_type&& u_ptr_) : u_ptr(etl::move(u_ptr_)) { ETL_ASSERT(u_ptr.get() != ETL_NULLPTR, ETL_ERROR(not_null_contains_null)); @@ -204,7 +204,7 @@ namespace etl /// Asserts if the unique_ptr contains null. /// Moves from the unique_ptr. //********************************* - ETL_CONSTEXPR14 not_null& operator=(underlying_type&& rhs) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + ETL_CONSTEXPR14 not_null& operator=(underlying_type&& rhs) { ETL_ASSERT_OR_RETURN_VALUE(rhs.get() != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this); diff --git a/include/etl/optional.h b/include/etl/optional.h index 371c9f2a..eeb4b5c7 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -59,7 +59,7 @@ namespace etl // Convertible to any type of null non-member pointer. template - operator T*() const + ETL_CONSTEXPR operator T*() const ETL_NOEXCEPT { return 0; } @@ -74,7 +74,7 @@ namespace etl /// A null option. ///\ingroup utilities //***************************************************************************** - const nullopt_t nullopt = {}; + ETL_INLINE_VAR ETL_CONSTANT nullopt_t nullopt = {}; //*************************************************************************** /// Exception for optional. diff --git a/include/etl/platform.h b/include/etl/platform.h index 82e31588..494b4981 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -524,6 +524,20 @@ SOFTWARE. #define ETL_INDETERMINATE #endif +//************************************* +// inline +#if ETL_USING_GCC_COMPILER || ETL_USING_CLANG_COMPILER + #define ETL_NO_INLINE __attribute__((noinline)) + #define ETL_ALWAYS_INLINE __attribute__((always_inline)) +#elif ETL_USING_MICROSOFT_COMPILER + #define ETL_NO_INLINE __declspec(noinline) + #define ETL_ALWAYS_INLINE __forceinline +#else + // will trigger a compilation error if used + #define ETL_NO_INLINE unsupported compiler + #define ETL_ALWAYS_INLINE unsupported compiler +#endif + //************************************* // Determine if the ETL can use char8_t type. #if ETL_NO_SMALL_CHAR_SUPPORT diff --git a/include/etl/priority_queue.h b/include/etl/priority_queue.h index ea9df835..50174501 100644 --- a/include/etl/priority_queue.h +++ b/include/etl/priority_queue.h @@ -121,14 +121,14 @@ namespace etl ETL_STATIC_ASSERT(sizeof(TContainer) == 0, "Unsupported container type for etl::ipriority_queue"); }; - template - struct priority_queue_container_interface > + template + struct priority_queue_container_interface > { typedef etl::ivector type; }; - template - struct priority_queue_container_interface > + template + struct priority_queue_container_interface > { typedef etl::ideque type; }; diff --git a/include/etl/private/delegate_cpp11.h b/include/etl/private/delegate_cpp11.h index 0770e0f0..eafbde77 100644 --- a/include/etl/private/delegate_cpp11.h +++ b/include/etl/private/delegate_cpp11.h @@ -413,32 +413,23 @@ namespace etl //************************************************************************* /// Execute the delegate. //************************************************************************* - template - ETL_CONSTEXPR14 return_type operator()(TCallArgs&&... args) const + ETL_CONSTEXPR14 return_type operator()(TArgs... args) const { - ETL_STATIC_ASSERT((sizeof...(TCallArgs) == sizeof...(TArgs)), "Incorrect number of parameters passed to delegate"); - ETL_STATIC_ASSERT((etl::type_lists_are_convertible, argument_types>::value), - "Incompatible parameter types passed to delegate"); - ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised)); - return (*invocation.stub)(invocation, etl::forward(args)...); + return (*invocation.stub)(invocation, etl::forward(args)...); } //************************************************************************* /// Execute the delegate if valid. /// 'void' return delegate. //************************************************************************* - template - ETL_CONSTEXPR14 typename etl::enable_if_t::value, bool> call_if(TCallArgs&&... args) const + template + ETL_CONSTEXPR14 typename etl::enable_if_t::value, bool> call_if(TArgs... args) const { - ETL_STATIC_ASSERT((sizeof...(TCallArgs) == sizeof...(TArgs)), "Incorrect number of parameters passed to delegate"); - ETL_STATIC_ASSERT((etl::type_lists_are_convertible, argument_types>::value), - "Incompatible parameter types passed to delegate"); - if (is_valid()) { - (*invocation.stub)(invocation, etl::forward(args)...); + (*invocation.stub)(invocation, etl::forward(args)...); return true; } else @@ -451,18 +442,14 @@ namespace etl /// Execute the delegate if valid. /// Non 'void' return delegate. //************************************************************************* - template - ETL_CONSTEXPR14 typename etl::enable_if_t::value, etl::optional> call_if(TCallArgs&&... args) const + template + ETL_CONSTEXPR14 typename etl::enable_if_t::value, etl::optional> call_if(TArgs... args) const { - ETL_STATIC_ASSERT((sizeof...(TCallArgs) == sizeof...(TArgs)), "Incorrect number of parameters passed to delegate"); - ETL_STATIC_ASSERT((etl::type_lists_are_convertible, argument_types>::value), - "Incompatible parameter types passed to delegate"); - etl::optional result; if (is_valid()) { - result = (*invocation.stub)(invocation, etl::forward(args)...); + result = (*invocation.stub)(invocation, etl::forward(args)...); } return result; @@ -472,20 +459,16 @@ namespace etl /// Execute the delegate if valid or call alternative. /// Run time alternative. //************************************************************************* - template - ETL_CONSTEXPR14 TReturn call_or(TAlternative&& alternative, TCallArgs&&... args) const + template + ETL_CONSTEXPR14 TReturn call_or(TAlternative&& alternative, TArgs... args) const { - ETL_STATIC_ASSERT((sizeof...(TCallArgs) == sizeof...(TArgs)), "Incorrect number of parameters passed to delegate"); - ETL_STATIC_ASSERT((etl::type_lists_are_convertible, argument_types>::value), - "Incompatible parameter types passed to delegate"); - if (is_valid()) { - return (*invocation.stub)(invocation, etl::forward(args)...); + return (*invocation.stub)(invocation, etl::forward(args)...); } else { - return etl::forward(alternative)(etl::forward(args)...); + return etl::forward(alternative)(etl::forward(args)...); } } @@ -493,20 +476,16 @@ namespace etl /// Execute the delegate if valid or call alternative. /// Compile time alternative. //************************************************************************* - template - ETL_CONSTEXPR14 TReturn call_or(TCallArgs&&... args) const + template + ETL_CONSTEXPR14 TReturn call_or(TArgs... args) const { - ETL_STATIC_ASSERT((sizeof...(TCallArgs) == sizeof...(TArgs)), "Incorrect number of parameters passed to delegate"); - ETL_STATIC_ASSERT((etl::type_lists_are_convertible, argument_types>::value), - "Incompatible parameter types passed to delegate"); - if (is_valid()) { - return (*invocation.stub)(invocation, etl::forward(args)...); + return (*invocation.stub)(invocation, etl::forward(args)...); } else { - return (Method)(etl::forward(args)...); + return (Method)(etl::forward(args)...); } } @@ -690,6 +669,14 @@ namespace etl //*********************************************************************** ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT { + if (stub == function_ptr_stub) + { + ptr.fp = ETL_NULLPTR; + } + else + { + ptr.object = ETL_NULLPTR; + } stub = ETL_NULLPTR; } diff --git a/include/etl/private/variant_legacy.h b/include/etl/private/variant_legacy.h index 59d454d4..585f02e1 100644 --- a/include/etl/private/variant_legacy.h +++ b/include/etl/private/variant_legacy.h @@ -468,7 +468,7 @@ namespace etl explicit variant(etl::in_place_index_t, T const& value) : type_id(Index) { - ETL_STATIC_ASSERT(Type_Id_Lookup::type_id == Index, "Missmatched type"); + ETL_STATIC_ASSERT(Type_Id_Lookup::type_id == Index, "Mismatched type"); ::new (static_cast(data)) T(value); type_id = Index; } diff --git a/include/etl/private/variant_select_do_operator.h b/include/etl/private/variant_select_do_operator.h index 1fb1794a..42bcb0d0 100644 --- a/include/etl/private/variant_select_do_operator.h +++ b/include/etl/private/variant_select_do_operator.h @@ -34,7 +34,7 @@ SOFTWARE. namespace private_variant { //*************************************************************************** - // Selects a do_operator inplementation that is configured for the number of + // Selects a do_operator implementation that is configured for the number of // types. //*************************************************************************** template diff --git a/include/etl/private/variant_select_do_visitor.h b/include/etl/private/variant_select_do_visitor.h index e770af68..58a6e2d6 100644 --- a/include/etl/private/variant_select_do_visitor.h +++ b/include/etl/private/variant_select_do_visitor.h @@ -34,7 +34,7 @@ SOFTWARE. namespace private_variant { //*************************************************************************** - // Selects a do_visitor inplementation that is configured for the number of + // Selects a do_visitor implementation that is configured for the number of // types. //*************************************************************************** template diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 545fd5e8..b2b8771e 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -86,6 +86,8 @@ namespace etl static void destroy(char*, size_t) {} static void copy(char*, const char*, size_t) {} static void move(char*, const char*, size_t) {} + static void copy_assign(char*, const char*, size_t) {} + static void move_assign(char*, const char*, size_t) {} }; // Recursive case. @@ -128,6 +130,30 @@ namespace etl } } + static void copy_assign(char* dst, const char* src, size_t type_id) + { + if (type_id == Index) + { + copy_assign_impl(dst, src, etl::integral_constant::value>{}); + } + else + { + variant_operations::copy_assign(dst, src, type_id); + } + } + + static void move_assign(char* dst, const char* src, size_t type_id) + { + if (type_id == Index) + { + move_assign_impl(dst, src, etl::integral_constant::value>{}); + } + else + { + variant_operations::move_assign(dst, src, type_id); + } + } + private: static void copy_impl(char* dst, const char* src, etl::true_type) @@ -143,6 +169,20 @@ namespace etl } static void move_impl(char*, const char*, etl::false_type) {} + + static void copy_assign_impl(char* dst, const char* src, etl::true_type) + { + *reinterpret_cast(dst) = *reinterpret_cast(src); + } + + static void copy_assign_impl(char*, const char*, etl::false_type) {} + + static void move_assign_impl(char* dst, const char* src, etl::true_type) + { + *reinterpret_cast(dst) = etl::move(*reinterpret_cast(const_cast(src))); + } + + static void move_assign_impl(char*, const char*, etl::false_type) {} }; //******************************************* @@ -431,6 +471,80 @@ namespace etl { } + variant_base(const variant_base& other) noexcept(etl::conjunction...>::value) + : type_id(other.type_id) + { + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::copy(data, other.data, other.type_id); + } + } + + variant_base(variant_base&& other) noexcept(etl::conjunction...>::value) + : type_id(other.type_id) + { + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::move(data, other.data, other.type_id); + } + } + + variant_base& operator=(const variant_base& other) noexcept(etl::conjunction...>::value + && etl::conjunction...>::value) + { + if (this != &other) + { + if ((type_id != variant_npos) && (type_id == other.type_id)) + { + variant_operations<0, TTypes...>::copy_assign(data, other.data, type_id); + } + else + { + if (type_id != variant_npos) + { + variant_operations<0, TTypes...>::destroy(data, type_id); + type_id = variant_npos; + } + + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::copy(data, other.data, other.type_id); + type_id = other.type_id; + } + } + } + + return *this; + } + + variant_base& operator=(variant_base&& other) noexcept(etl::conjunction...>::value + && etl::conjunction...>::value) + { + if (this != &other) + { + if ((type_id != variant_npos) && (type_id == other.type_id)) + { + variant_operations<0, TTypes...>::move_assign(data, other.data, type_id); + } + else + { + if (type_id != variant_npos) + { + variant_operations<0, TTypes...>::destroy(data, type_id); + type_id = variant_npos; + } + + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::move(data, other.data, other.type_id); + type_id = other.type_id; + } + } + } + + return *this; + } + ~variant_base() { if (type_id != variant_npos) @@ -474,7 +588,259 @@ namespace etl { } + variant_base(const variant_base& other) noexcept(etl::conjunction...>::value) + : data() + , type_id(other.type_id) + { + copy_construct_from(other, is_all_trivially_copyable{}); + } + + variant_base(variant_base&& other) noexcept(etl::conjunction...>::value) + : data() + , type_id(other.type_id) + { + move_construct_from(other, is_all_trivially_copyable{}); + } + + variant_base& operator=(const variant_base& other) noexcept(etl::conjunction...>::value + && etl::conjunction...>::value) + { + if (this != &other) + { + copy_assign_from(other, is_all_trivially_copyable{}); + } + return *this; + } + + variant_base& operator=(variant_base&& other) noexcept(etl::conjunction...>::value + && etl::conjunction...>::value) + { + if (this != &other) + { + move_assign_from(other, is_all_trivially_copyable{}); + } + return *this; + } + ~variant_base() = default; + + private: + + // All alternatives trivially copyable => a raw-byte copy correctly + // reproduces both copy and move construction. + typedef etl::integral_constant...>::value> is_all_trivially_copyable; + + //******************************************* + // Trivially copyable fast path: raw-byte copy. + //******************************************* + void copy_construct_from(const variant_base& other, etl::true_type) noexcept + { + memcpy(static_cast(&data), static_cast(&other.data), sizeof(data)); + } + + void move_construct_from(const variant_base& other, etl::true_type) noexcept + { + memcpy(static_cast(&data), static_cast(&other.data), sizeof(data)); + } + + void copy_assign_from(const variant_base& other, etl::true_type) noexcept + { + type_id = other.type_id; + memcpy(static_cast(&data), static_cast(&other.data), sizeof(data)); + } + + void move_assign_from(const variant_base& other, etl::true_type) noexcept + { + type_id = other.type_id; + memcpy(static_cast(&data), static_cast(&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) + { + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::copy(reinterpret_cast(&data), reinterpret_cast(&other.data), other.type_id); + } + } + + void move_construct_from(variant_base& other, etl::false_type) + { + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::move(reinterpret_cast(&data), reinterpret_cast(&other.data), other.type_id); + } + } + + void copy_assign_from(const variant_base& other, etl::false_type) + { + if ((type_id != variant_npos) && (type_id == other.type_id)) + { + variant_operations<0, TTypes...>::copy_assign(reinterpret_cast(&data), reinterpret_cast(&other.data), type_id); + return; + } + + if (type_id != variant_npos) + { + variant_operations<0, TTypes...>::destroy(reinterpret_cast(&data), type_id); + type_id = variant_npos; + } + + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::copy(reinterpret_cast(&data), reinterpret_cast(&other.data), other.type_id); + type_id = other.type_id; + } + } + + void move_assign_from(variant_base& other, etl::false_type) + { + if ((type_id != variant_npos) && (type_id == other.type_id)) + { + variant_operations<0, TTypes...>::move_assign(reinterpret_cast(&data), reinterpret_cast(&other.data), type_id); + return; + } + + if (type_id != variant_npos) + { + variant_operations<0, TTypes...>::destroy(reinterpret_cast(&data), type_id); + type_id = variant_npos; + } + + if (other.type_id != variant_npos) + { + variant_operations<0, TTypes...>::move(reinterpret_cast(&data), reinterpret_cast(&other.data), other.type_id); + type_id = other.type_id; + } + } + }; + + //******************************************* + /// Trait: are all types copy constructible? + //******************************************* + template + struct are_all_copy_constructible : etl::conjunction...> + { + }; + + //******************************************* + /// Trait: are all types move constructible? + //******************************************* + template + struct are_all_move_constructible : etl::conjunction...> + { + }; + + //******************************************* + /// Trait: are all types copy assignable? + //******************************************* + template + struct are_all_copy_assignable : etl::conjunction...> + { + }; + + //******************************************* + /// Trait: are all types move assignable? + //******************************************* + template + struct are_all_move_assignable : etl::conjunction...> + { + }; + + //******************************************* + /// Flat base that conditionally deletes the copy and move CONSTRUCTORS. + /// Every special member is declared directly (no intermediate bases) so + /// that MSVC does not spuriously delete the defaulted move members when a + /// sibling/base subobject has a deleted special member. + //******************************************* + template + struct variant_constructor_control + { + variant_constructor_control() = default; + variant_constructor_control(const variant_constructor_control&) = default; + variant_constructor_control(variant_constructor_control&&) = default; + variant_constructor_control& operator=(const variant_constructor_control&) = default; + variant_constructor_control& operator=(variant_constructor_control&&) = default; + }; + + template <> + struct variant_constructor_control + { + variant_constructor_control() = default; + variant_constructor_control(const variant_constructor_control&) = delete; + variant_constructor_control(variant_constructor_control&&) = default; + variant_constructor_control& operator=(const variant_constructor_control&) = default; + variant_constructor_control& operator=(variant_constructor_control&&) = default; + }; + + template <> + struct variant_constructor_control + { + variant_constructor_control() = default; + variant_constructor_control(const variant_constructor_control&) = default; + variant_constructor_control(variant_constructor_control&&) = delete; + variant_constructor_control& operator=(const variant_constructor_control&) = default; + variant_constructor_control& operator=(variant_constructor_control&&) = default; + }; + + template <> + struct variant_constructor_control + { + variant_constructor_control() = default; + variant_constructor_control(const variant_constructor_control&) = delete; + variant_constructor_control(variant_constructor_control&&) = delete; + variant_constructor_control& operator=(const variant_constructor_control&) = default; + variant_constructor_control& operator=(variant_constructor_control&&) = default; + }; + + //******************************************* + /// Flat base that conditionally deletes the copy and move ASSIGNMENT + /// operators. Every special member is declared directly (see the note on + /// variant_constructor_control above). + //******************************************* + template + struct variant_assignment_control + { + variant_assignment_control() = default; + variant_assignment_control(const variant_assignment_control&) = default; + variant_assignment_control(variant_assignment_control&&) = default; + variant_assignment_control& operator=(const variant_assignment_control&) = default; + variant_assignment_control& operator=(variant_assignment_control&&) = default; + }; + + template <> + struct variant_assignment_control + { + variant_assignment_control() = default; + variant_assignment_control(const variant_assignment_control&) = default; + variant_assignment_control(variant_assignment_control&&) = default; + variant_assignment_control& operator=(const variant_assignment_control&) = delete; + variant_assignment_control& operator=(variant_assignment_control&&) = default; + }; + + template <> + struct variant_assignment_control + { + variant_assignment_control() = default; + variant_assignment_control(const variant_assignment_control&) = default; + variant_assignment_control(variant_assignment_control&&) = default; + variant_assignment_control& operator=(const variant_assignment_control&) = default; + variant_assignment_control& operator=(variant_assignment_control&&) = delete; + }; + + template <> + struct variant_assignment_control + { + variant_assignment_control() = default; + variant_assignment_control(const variant_assignment_control&) = default; + variant_assignment_control(variant_assignment_control&&) = default; + variant_assignment_control& operator=(const variant_assignment_control&) = delete; + variant_assignment_control& operator=(variant_assignment_control&&) = delete; }; } // namespace private_variant @@ -483,7 +849,13 @@ namespace etl ///\ingroup variant //*************************************************************************** template - class variant : private private_variant::variant_base::value, TTypes...> + class variant + : private private_variant::variant_base::value, TTypes...> + , private private_variant::variant_constructor_control< private_variant::are_all_copy_constructible::value, + private_variant::are_all_move_constructible::value> + , private private_variant::variant_assignment_control< + private_variant::are_all_copy_constructible::value && private_variant::are_all_copy_assignable::value, + private_variant::are_all_move_constructible::value && private_variant::are_all_move_assignable::value> { using base_type = private_variant::variant_base::value, TTypes...>; @@ -671,31 +1043,13 @@ namespace etl /// Copy constructor. ///\param other The other variant object to copy. //*************************************************************************** - #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(const variant& other) noexcept(etl::conjunction...>::value) - : base_type(other.type_id) - { - if (other.index() != variant_npos) - { - do_copy_from(other, etl::integral_constant{}); - } - } - #include "diagnostic_pop.h" + variant(const variant& other) = default; //*************************************************************************** /// Move constructor. ///\param other The other variant object to copy. //*************************************************************************** - #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(variant&& other) noexcept(etl::conjunction...>::value) - : base_type(other.type_id) - { - if (other.index() != variant_npos) - { - do_move_from(other, etl::integral_constant{}); - } - } - #include "diagnostic_pop.h" + variant(variant&& other) = default; //*************************************************************************** /// Destructor. @@ -806,51 +1160,13 @@ namespace etl /// Assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(const variant& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) - { - if (this != &other) - { - if (other.index() == variant_npos) - { - type_id = variant_npos; - } - else - { - do_destroy(); - - do_copy_from(other, etl::integral_constant{}); - - type_id = other.type_id; - } - } - - return *this; - } + variant& operator=(const variant& other) = default; //*************************************************************************** - /// Assignment operator for variant type. + /// Move assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(variant&& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) - { - if (this != &other) - { - if (other.index() == variant_npos) - { - type_id = variant_npos; - } - else - { - do_destroy(); - - do_move_from(other, etl::integral_constant{}); - - type_id = other.type_id; - } - } - - return *this; - } + variant& operator=(variant&& other) = default; //*************************************************************************** /// Checks whether the variant doesn't contain a valid value. @@ -1084,6 +1400,8 @@ namespace etl void do_destroy() { do_destroy_impl(etl::integral_constant{}); + + type_id = variant_npos; } void do_destroy_impl(etl::integral_constant) @@ -1149,36 +1467,6 @@ namespace etl ::new (static_cast(data)) T(etl::forward(value)); } - //*************************************************************************** - /// Copy from another variant. - //*************************************************************************** - void do_copy_from(const variant& other, etl::integral_constant) - { - // Trivially destructible: copy via memcpy to avoid issues with non-trivial copy assignment in union. - memcpy(static_cast(&data), static_cast(&other.data), sizeof(data)); - } - - void do_copy_from(const variant& other, etl::integral_constant) - { - // Non-trivially destructible: use switch-based dispatch. - private_variant::variant_operations<0, TTypes...>::copy(data, other.data, other.type_id); - } - - //*************************************************************************** - /// Move from another variant. - //*************************************************************************** - void do_move_from(variant& other, etl::integral_constant) - { - // Trivially destructible: copy via memcpy (trivial move == copy). - memcpy(static_cast(&data), static_cast(&other.data), sizeof(data)); - } - - void do_move_from(variant& other, etl::integral_constant) - { - // Non-trivially destructible: use switch-based dispatch. - private_variant::variant_operations<0, TTypes...>::move(data, other.data, other.type_id); - } - #if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11) //*************************************************************************** /// Call the relevant visitor by attempting each one. diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index b73c9ecd..deadec8c 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -68,6 +68,10 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED) #define ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED 1 #endif + + #if !defined(ETL_USING_BUILTIN_BIT_CAST) + #define ETL_USING_BUILTIN_BIT_CAST 1 + #endif #endif #if defined(ETL_USE_BUILTIN_MEM_FUNCTIONS) // Set all of them to be true if not @@ -132,6 +136,10 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED __has_builtin(__builtin_is_constant_evaluated) #endif + #if !defined(ETL_USING_BUILTIN_BIT_CAST) + #define ETL_USING_BUILTIN_BIT_CAST __has_builtin(__builtin_bit_cast) + #endif + #if !defined(ETL_USING_BUILTIN_MEMCPY) #define ETL_USING_BUILTIN_MEMCPY __has_builtin(__builtin_memcpy) #endif @@ -174,6 +182,13 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 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. + #if !defined(ETL_USING_BUILTIN_BIT_CAST) && (_MSC_VER >= 1926) + #define ETL_USING_BUILTIN_BIT_CAST 1 + #endif #endif // The default. Set to 0, if not already set. @@ -245,6 +260,17 @@ SOFTWARE. #define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE 0 #endif +#if !defined(ETL_USING_BUILTIN_BIT_CAST) + #define ETL_USING_BUILTIN_BIT_CAST 0 +#endif + +// __builtin_bit_cast is only of use to the ETL from C++11 onwards. +// Disable it for older standards, so that the generated code for those users is unchanged. +#if ETL_USING_BUILTIN_BIT_CAST && !ETL_USING_CPP11 + #undef ETL_USING_BUILTIN_BIT_CAST + #define ETL_USING_BUILTIN_BIT_CAST 0 +#endif + namespace etl { namespace traits @@ -268,6 +294,7 @@ namespace etl static ETL_CONSTANT bool using_builtin_is_virtual_base_of = (ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF == 1); static ETL_CONSTANT bool using_builtin_is_trivially_relocatable = (ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE == 1); static ETL_CONSTANT bool using_builtin_builtin_is_cpp_trivially_relocatable = (ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE == 1); + static ETL_CONSTANT bool using_builtin_bit_cast = (ETL_USING_BUILTIN_BIT_CAST == 1); } // namespace traits } // namespace etl diff --git a/include/etl/ranges.h b/include/etl/ranges.h index b502f82d..82ae3502 100644 --- a/include/etl/ranges.h +++ b/include/etl/ranges.h @@ -150,7 +150,8 @@ namespace etl return *etl::prev(cend()); } - constexpr decltype(auto) operator[](size_t i) + template < typename D2 = D, etl::enable_if_t().begin())>::value, int> = 0> + constexpr decltype(auto) operator[](range_difference_t i) { auto it{static_cast(this)->begin()}; etl::advance(it, i); @@ -158,13 +159,13 @@ namespace etl } template < typename D2 = D, etl::enable_if_t().begin())>::value, int> = 0> - constexpr decltype(auto) operator[](size_t i) + constexpr decltype(auto) operator[](range_difference_t i) { return static_cast(this)->begin()[i]; } template < typename D2 = D, etl::enable_if_t().begin())>::value, int> = 0> - constexpr decltype(auto) operator[](size_t i) const + constexpr decltype(auto) operator[](range_difference_t i) const { return cbegin()[i]; } @@ -502,6 +503,11 @@ namespace etl return _i; } + constexpr value_type operator[](difference_type n) const + { + return *(*this + n); + } + private: value_type _i; @@ -673,6 +679,11 @@ namespace etl return _value; } + constexpr value_type operator[](difference_type n) const + { + return *(*this + n); + } + private: value_type _value; @@ -4489,7 +4500,7 @@ namespace etl /// An iterator adaptor that extracts the Nth element from a tuple-like /// value type using etl::get or std::get (found via ADL). //************************************************************************* - template + template class elements_iterator { public: @@ -4498,7 +4509,7 @@ namespace etl using base_iterator = typename trait::iterator; using base_value_type = typename trait::value_type; - using value_type = etl::tuple_element_t; + using value_type = etl::tuple_element_t; using difference_type = typename trait::difference_type; private: @@ -4510,7 +4521,7 @@ namespace etl static decltype(auto) deref_element(const base_iterator& it) { using etl::get; - return get(*it); + return get(*it); } public: @@ -4574,13 +4585,13 @@ namespace etl /// A range adaptor that takes a view of tuple-like values and produces /// a view of the Nth element of each tuple-like value. //************************************************************************* - template - class elements_view : public etl::ranges::view_interface> + template + class elements_view : public etl::ranges::view_interface> { public: - using iterator = elements_iterator; - using const_iterator = elements_iterator; + using iterator = elements_iterator; + using const_iterator = elements_iterator; elements_view(Range&& r) : _r{etl::move(r)} @@ -4614,29 +4625,29 @@ namespace etl mutable Range _r; }; - template - elements_view(Range&&, etl::integral_constant) -> elements_view, N>; + template + elements_view(Range&&, etl::integral_constant) -> elements_view, Index>; - template - struct elements_range_adapter_closure : public range_adapter_closure> + template + struct elements_range_adapter_closure : public range_adapter_closure> { template - using target_view_type = elements_view; + using target_view_type = elements_view; elements_range_adapter_closure() = default; template constexpr auto operator()(Range&& r) { - return elements_view, N>(views::all(etl::forward(r))); + return elements_view, Index>(views::all(etl::forward(r))); } }; - /// keys_view is an alias for elements_view with N=0. + /// keys_view is an alias for elements_view with Index=0. template using keys_view = elements_view; - /// values_view is an alias for elements_view with N=1. + /// values_view is an alias for elements_view with Index=1. template using values_view = elements_view; @@ -4644,39 +4655,39 @@ namespace etl { namespace private_views { - template + template struct elements_fn : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const { - return elements_view, N>(views::all(etl::forward(r))); + return elements_view, Index>(views::all(etl::forward(r))); } constexpr auto operator()() const { - return ranges::elements_range_adapter_closure(); + return ranges::elements_range_adapter_closure(); } }; } // namespace private_views - template - inline constexpr private_views::elements_fn elements{}; + template + inline constexpr private_views::elements_fn elements{}; inline constexpr private_views::elements_fn<0> keys{}; inline constexpr private_views::elements_fn<1> values{}; } // namespace views //************************************************************************* - /// Helper: create a tuple type that repeats T exactly N times. + /// Helper: create a tuple type that repeats T exactly Index times. //************************************************************************* namespace private_ranges { - template > + template > struct repeat_tuple; - template - struct repeat_tuple> + template + struct repeat_tuple> { template using always = T; @@ -4684,16 +4695,16 @@ namespace etl using type = etl::tuple...>; }; - template - using repeat_tuple_t = typename repeat_tuple::type; + template + using repeat_tuple_t = typename repeat_tuple::type; - /// Helper: compute invoke_result_t with T repeated N + /// Helper: compute invoke_result_t with T repeated Index /// times. - template > + template > struct repeat_invoke_result; - template - struct repeat_invoke_result> + template + struct repeat_invoke_result> { template using always = T; @@ -4701,20 +4712,20 @@ namespace etl using type = etl::invoke_result_t...>; }; - template - using repeat_invoke_result_t = typename repeat_invoke_result::type; + template + using repeat_invoke_result_t = typename repeat_invoke_result::type; } // namespace private_ranges //************************************************************************* /// adjacent_iterator - /// An iterator adaptor that produces tuples of N consecutive elements - /// from the underlying range. Each increment advances all N internal + /// An iterator adaptor that produces tuples of Index consecutive elements + /// from the underlying range. Each increment advances all Index internal /// iterators by one position. //************************************************************************* - template + template class adjacent_iterator { - static_assert(N > 0, "adjacent window size must be > 0"); + static_assert(Index > 0, "adjacent window size must be > 0"); public: @@ -4723,17 +4734,17 @@ namespace etl using base_iterator = typename trait::iterator; using base_value_type = typename trait::value_type; using base_reference = decltype(*etl::declval()); - using value_type = private_ranges::repeat_tuple_t; + using value_type = private_ranges::repeat_tuple_t; using difference_type = typename trait::difference_type; // Each tuple element is a reference into the underlying range, so the // window elements remain mutable when the underlying range is non-const, // as required for std::ranges::adjacent_view. - using reference = private_ranges::repeat_tuple_t; + using reference = private_ranges::repeat_tuple_t; using pointer = value_type*; using iterator_category = ETL_OR_STD::forward_iterator_tag; - /// Construct from an array of N iterators (the sliding window). + /// Construct from an array of Index iterators (the sliding window). template constexpr adjacent_iterator(base_iterator first, base_iterator last, etl::index_sequence) : _iters{advance_copy(first, last, Is)...} @@ -4747,7 +4758,7 @@ namespace etl constexpr adjacent_iterator& operator++() { - increment(etl::make_index_sequence{}); + increment(etl::make_index_sequence{}); return *this; } @@ -4760,14 +4771,14 @@ namespace etl constexpr reference operator*() const { - return deref(etl::make_index_sequence{}); + return deref(etl::make_index_sequence{}); } friend constexpr bool operator==(const adjacent_iterator& lhs, const adjacent_iterator& rhs) { - // Compare the last iterator in the window (index N-1). + // Compare the last iterator in the window (index Index-1). // When it reaches end, the window is exhausted. - return lhs._iters[N - 1] == rhs._iters[N - 1]; + return lhs._iters[Index - 1] == rhs._iters[Index - 1]; } friend constexpr bool operator!=(const adjacent_iterator& lhs, const adjacent_iterator& rhs) @@ -4798,27 +4809,27 @@ namespace etl return reference(*_iters[Is]...); } - base_iterator _iters[N]; + base_iterator _iters[Index]; base_iterator _end; }; //************************************************************************* /// adjacent_view - /// A range adaptor that takes a range and a compile-time window size N + /// A range adaptor that takes a range and a compile-time window size Index /// and produces a view of tuples, where the i-th tuple contains the - /// elements at positions [i, i+1, ..., i+N-1] from the underlying range. - /// The resulting view has (size - N + 1) elements, or is empty if the - /// underlying range has fewer than N elements. + /// elements at positions [i, i+1, ..., i+Index-1] from the underlying range. + /// The resulting view has (size - Index + 1) elements, or is empty if the + /// underlying range has fewer than Index elements. //************************************************************************* - template - class adjacent_view : public etl::ranges::view_interface> + template + class adjacent_view : public etl::ranges::view_interface> { - static_assert(N > 0, "adjacent window size must be > 0"); + static_assert(Index > 0, "adjacent window size must be > 0"); public: - using iterator = adjacent_iterator; - using const_iterator = adjacent_iterator; + using iterator = adjacent_iterator; + using const_iterator = adjacent_iterator; constexpr adjacent_view(Range&& r) : _r{etl::move(r)} @@ -4834,19 +4845,19 @@ namespace etl constexpr const_iterator begin() const { - return const_iterator(ETL_OR_STD::begin(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); + return const_iterator(ETL_OR_STD::begin(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); } constexpr const_iterator end() const { - // The end iterator has all N internal iterators at the end position. - return const_iterator(ETL_OR_STD::end(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); + // The end iterator has all Index internal iterators at the end position. + return const_iterator(ETL_OR_STD::end(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); } constexpr size_t size() const { auto total = static_cast(etl::distance(ETL_OR_STD::cbegin(_r), ETL_OR_STD::cend(_r))); - return (total >= N) ? (total - N + 1) : 0; + return (total >= Index) ? (total - Index + 1) : 0; } private: @@ -4854,21 +4865,21 @@ namespace etl mutable Range _r; }; - template - adjacent_view(Range&&, etl::integral_constant) -> adjacent_view, N>; + template + adjacent_view(Range&&, etl::integral_constant) -> adjacent_view, Index>; - template - struct adjacent_range_adapter_closure : public range_adapter_closure> + template + struct adjacent_range_adapter_closure : public range_adapter_closure> { template - using target_view_type = adjacent_view; + using target_view_type = adjacent_view; adjacent_range_adapter_closure() = default; template constexpr auto operator()(Range&& r) { - return adjacent_view, N>(views::all(etl::forward(r))); + return adjacent_view, Index>(views::all(etl::forward(r))); } }; @@ -4876,24 +4887,24 @@ namespace etl { namespace private_views { - template + template struct adjacent_fn : public range_adapter_closure_base { template constexpr auto operator()(Range&& r) const { - return adjacent_view, N>(views::all(etl::forward(r))); + return adjacent_view, Index>(views::all(etl::forward(r))); } constexpr auto operator()() const { - return ranges::adjacent_range_adapter_closure(); + return ranges::adjacent_range_adapter_closure(); } }; } // namespace private_views - template - inline constexpr private_views::adjacent_fn adjacent{}; + template + inline constexpr private_views::adjacent_fn adjacent{}; /// pairwise is an alias for adjacent<2>. inline constexpr private_views::adjacent_fn<2> pairwise{}; @@ -4901,14 +4912,14 @@ namespace etl //************************************************************************* /// adjacent_transform_iterator - /// An iterator adaptor that takes a sliding window of N consecutive + /// An iterator adaptor that takes a sliding window of Index consecutive /// elements from the underlying range and applies a transformation /// function to them, producing a single value per window position. //************************************************************************* - template + template class adjacent_transform_iterator { - static_assert(N > 0, "adjacent window size must be > 0"); + static_assert(Index > 0, "adjacent window size must be > 0"); public: @@ -4916,7 +4927,7 @@ namespace etl using base_iterator = typename trait::const_iterator; using base_value_type = typename trait::value_type; - using value_type = private_ranges::repeat_invoke_result_t; + using value_type = private_ranges::repeat_invoke_result_t; using difference_type = typename trait::difference_type; using pointer = const value_type*; using reference = value_type; @@ -4939,7 +4950,7 @@ namespace etl constexpr adjacent_transform_iterator& operator++() { - increment(etl::make_index_sequence{}); + increment(etl::make_index_sequence{}); return *this; } @@ -4952,14 +4963,14 @@ namespace etl constexpr value_type operator*() const { - return deref(etl::make_index_sequence{}); + return deref(etl::make_index_sequence{}); } friend constexpr bool operator==(const adjacent_transform_iterator& lhs, const adjacent_transform_iterator& rhs) { - // Compare the last iterator in the window (index N-1). + // Compare the last iterator in the window (index Index-1). // When it reaches end, the window is exhausted. - return lhs._iters[N - 1] == rhs._iters[N - 1]; + return lhs._iters[Index - 1] == rhs._iters[Index - 1]; } friend constexpr bool operator!=(const adjacent_transform_iterator& lhs, const adjacent_transform_iterator& rhs) @@ -4991,28 +5002,28 @@ namespace etl } Fun _f; - base_iterator _iters[N]; + base_iterator _iters[Index]; base_iterator _end; }; //************************************************************************* /// adjacent_transform_view - /// A range adaptor that takes a range, a compile-time window size N, and + /// A range adaptor that takes a range, a compile-time window size Index, and /// a transformation function, and produces a view whose elements are the - /// result of applying the function to each sliding window of N consecutive + /// result of applying the function to each sliding window of Index consecutive /// elements from the underlying range. - /// The resulting view has (size - N + 1) elements, or is empty if the - /// underlying range has fewer than N elements. + /// The resulting view has (size - Index + 1) elements, or is empty if the + /// underlying range has fewer than Index elements. //************************************************************************* - template - class adjacent_transform_view : public etl::ranges::view_interface< adjacent_transform_view> + template + class adjacent_transform_view : public etl::ranges::view_interface< adjacent_transform_view> { - static_assert(N > 0, "adjacent window size must be > 0"); + static_assert(Index > 0, "adjacent window size must be > 0"); public: - using iterator = adjacent_transform_iterator; - using const_iterator = adjacent_transform_iterator; + using iterator = adjacent_transform_iterator; + using const_iterator = adjacent_transform_iterator; constexpr adjacent_transform_view(Fun f, Range&& r) : _f{f} @@ -5029,19 +5040,19 @@ namespace etl constexpr const_iterator begin() const { - return const_iterator(_f, ETL_OR_STD::begin(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); + return const_iterator(_f, ETL_OR_STD::begin(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); } constexpr const_iterator end() const { - // The end iterator has all N internal iterators at the end position. - return const_iterator(_f, ETL_OR_STD::end(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); + // The end iterator has all Index internal iterators at the end position. + return const_iterator(_f, ETL_OR_STD::end(_r), ETL_OR_STD::end(_r), etl::make_index_sequence{}); } constexpr size_t size() const { auto total = static_cast(etl::distance(ETL_OR_STD::cbegin(_r), ETL_OR_STD::cend(_r))); - return (total >= N) ? (total - N + 1) : 0; + return (total >= Index) ? (total - Index + 1) : 0; } private: @@ -5050,14 +5061,14 @@ namespace etl mutable Range _r; }; - template - adjacent_transform_view(Fun, Range&&, etl::integral_constant) -> adjacent_transform_view, Fun, N>; + template + adjacent_transform_view(Fun, Range&&, etl::integral_constant) -> adjacent_transform_view, Fun, Index>; - template - struct adjacent_transform_range_adapter_closure : public range_adapter_closure< adjacent_transform_range_adapter_closure> + template + struct adjacent_transform_range_adapter_closure : public range_adapter_closure< adjacent_transform_range_adapter_closure> { template - using target_view_type = adjacent_transform_view; + using target_view_type = adjacent_transform_view; adjacent_transform_range_adapter_closure(Fun f) : _f{f} @@ -5067,7 +5078,7 @@ namespace etl template constexpr auto operator()(Range&& r) { - return adjacent_transform_view, Fun, N>(_f, views::all(etl::forward(r))); + return adjacent_transform_view, Fun, Index>(_f, views::all(etl::forward(r))); } Fun _f; @@ -5077,25 +5088,25 @@ namespace etl { namespace private_views { - template + template struct adjacent_transform_fn { template constexpr auto operator()(Range&& r, Fun&& f) const { - return adjacent_transform_view, etl::decay_t, N>(etl::forward(f), views::all(etl::forward(r))); + return adjacent_transform_view, etl::decay_t, Index>(etl::forward(f), views::all(etl::forward(r))); } template constexpr auto operator()(Fun&& f) const { - return ranges::adjacent_transform_range_adapter_closure< N, etl::decay_t>(etl::forward(f)); + return ranges::adjacent_transform_range_adapter_closure< Index, etl::decay_t>(etl::forward(f)); } }; } // namespace private_views - template - inline constexpr private_views::adjacent_transform_fn adjacent_transform{}; + template + inline constexpr private_views::adjacent_transform_fn adjacent_transform{}; /// pairwise_transform is an alias for adjacent_transform<2>. inline constexpr private_views::adjacent_transform_fn<2> pairwise_transform{}; diff --git a/include/etl/reference_flat_map.h b/include/etl/reference_flat_map.h index b6bf0447..c8be6dcb 100644 --- a/include/etl/reference_flat_map.h +++ b/include/etl/reference_flat_map.h @@ -330,6 +330,16 @@ namespace etl return comp(key, element.first); } + bool operator()(const value_type* element, const key_type& key) const + { + return comp(element->first, key); + } + + bool operator()(const key_type& key, const value_type* element) const + { + return comp(key, element->first); + } + #if ETL_USING_CPP11 template ::value, int> = 0> bool operator()(const value_type& element, const K& key) const @@ -342,6 +352,18 @@ namespace etl { return comp(key, element.first); } + + template ::value, int> = 0> + bool operator()(const value_type* element, const K& key) const + { + return comp(element->first, key); + } + + template ::value, int> = 0> + bool operator()(const K& key, const value_type* element) const + { + return comp(key, element->first); + } #endif key_compare comp; @@ -802,7 +824,7 @@ namespace etl //********************************************************************* iterator lower_bound(key_parameter_t key) { - return etl::lower_bound(begin(), end(), key, compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, compare)); } #if ETL_USING_CPP11 @@ -810,7 +832,7 @@ namespace etl template ::value, int> = 0> iterator lower_bound(const K& key) { - return etl::lower_bound(begin(), end(), key, compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, compare)); } #endif @@ -821,7 +843,7 @@ namespace etl //********************************************************************* const_iterator lower_bound(key_parameter_t key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #if ETL_USING_CPP11 @@ -829,7 +851,7 @@ namespace etl template ::value, int> = 0> const_iterator lower_bound(const K& key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #endif @@ -840,7 +862,7 @@ namespace etl //********************************************************************* iterator upper_bound(key_parameter_t key) { - return etl::upper_bound(begin(), end(), key, compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, compare)); } #if ETL_USING_CPP11 @@ -848,7 +870,7 @@ namespace etl template ::value, int> = 0> iterator upper_bound(const K& key) { - return etl::upper_bound(begin(), end(), key, compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, compare)); } #endif @@ -859,7 +881,7 @@ namespace etl //********************************************************************* const_iterator upper_bound(key_parameter_t key) const { - return etl::upper_bound(begin(), end(), key, compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #if ETL_USING_CPP11 @@ -867,7 +889,7 @@ namespace etl template ::value, int> = 0> const_iterator upper_bound(const K& key) const { - return etl::upper_bound(begin(), end(), key, compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #endif @@ -878,9 +900,10 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(key_parameter_t key) { - iterator i_lower = etl::lower_bound(begin(), end(), key, compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, end(), key, compare)); + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #if ETL_USING_CPP11 @@ -888,9 +911,10 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) { - iterator i_lower = etl::lower_bound(begin(), end(), key, compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, end(), key, compare)); + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #endif @@ -901,9 +925,10 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(key_parameter_t key) const { - const_iterator i_lower = etl::lower_bound(cbegin(), cend(), key, compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, cend(), key, compare)); + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #if ETL_USING_CPP11 @@ -911,9 +936,10 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) const { - const_iterator i_lower = etl::lower_bound(cbegin(), cend(), key, compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, cend(), key, compare)); + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #endif diff --git a/include/etl/reference_flat_multimap.h b/include/etl/reference_flat_multimap.h index 57934215..9e077044 100644 --- a/include/etl/reference_flat_multimap.h +++ b/include/etl/reference_flat_multimap.h @@ -303,6 +303,16 @@ namespace etl return comp(key, element.first); } + bool operator()(const value_type* element, key_type key) const + { + return comp(element->first, key); + } + + bool operator()(key_type key, const value_type* element) const + { + return comp(key, element->first); + } + #if ETL_USING_CPP11 template ::value, int> = 0> bool operator()(const value_type& element, const K& key) const @@ -315,6 +325,18 @@ namespace etl { return comp(key, element.first); } + + template ::value, int> = 0> + bool operator()(const value_type* element, const K& key) const + { + return comp(element->first, key); + } + + template ::value, int> = 0> + bool operator()(const K& key, const value_type* element) const + { + return comp(key, element->first); + } #endif key_compare comp; @@ -730,7 +752,7 @@ namespace etl //********************************************************************* iterator lower_bound(key_parameter_t key) { - return etl::lower_bound(begin(), end(), key, compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, compare)); } #if ETL_USING_CPP11 @@ -738,7 +760,7 @@ namespace etl template ::value, int> = 0> iterator lower_bound(const K& key) { - return etl::lower_bound(begin(), end(), key, compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, compare)); } #endif @@ -749,7 +771,7 @@ namespace etl //********************************************************************* const_iterator lower_bound(key_parameter_t key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #if ETL_USING_CPP11 @@ -757,7 +779,7 @@ namespace etl template ::value, int> = 0> const_iterator lower_bound(const K& key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #endif @@ -768,7 +790,7 @@ namespace etl //********************************************************************* iterator upper_bound(key_parameter_t key) { - return etl::upper_bound(begin(), end(), key, compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, compare)); } #if ETL_USING_CPP11 @@ -776,7 +798,7 @@ namespace etl template ::value, int> = 0> iterator upper_bound(const K& key) { - return etl::upper_bound(begin(), end(), key, compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, compare)); } #endif @@ -787,7 +809,7 @@ namespace etl //********************************************************************* const_iterator upper_bound(key_parameter_t key) const { - return etl::upper_bound(begin(), end(), key, compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #if ETL_USING_CPP11 @@ -795,7 +817,7 @@ namespace etl template ::value, int> = 0> const_iterator upper_bound(const K& key) const { - return etl::upper_bound(begin(), end(), key, compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, compare)); } #endif @@ -806,9 +828,10 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(key_parameter_t key) { - iterator i_lower = etl::lower_bound(begin(), end(), key, compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, end(), key, compare)); + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #if ETL_USING_CPP11 @@ -816,9 +839,10 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) { - iterator i_lower = etl::lower_bound(begin(), end(), key, compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, end(), key, compare)); + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #endif @@ -829,9 +853,10 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(key_parameter_t key) const { - const_iterator i_lower = etl::lower_bound(cbegin(), cend(), key, compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, cend(), key, compare)); + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #if ETL_USING_CPP11 @@ -839,9 +864,10 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) const { - const_iterator i_lower = etl::lower_bound(cbegin(), cend(), key, compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, compare); - return ETL_OR_STD::make_pair(i_lower, etl::upper_bound(i_lower, cend(), key, compare)); + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #endif diff --git a/include/etl/reference_flat_multiset.h b/include/etl/reference_flat_multiset.h index 8b2d0b41..3836dbcf 100644 --- a/include/etl/reference_flat_multiset.h +++ b/include/etl/reference_flat_multiset.h @@ -294,6 +294,47 @@ namespace etl typedef typename etl::parameter_type::type parameter_t; + //********************************************************************* + /// Compares a pointer to an element (as stored in 'lookup') against a + /// key, allowing binary searches directly over the random-access + /// 'lookup' container instead of the bidirectional iterator/const_iterator. + //********************************************************************* + class Compare + { + public: + + Compare(const TKeyCompare& comp_) + : comp(comp_) + { + } + + bool operator()(const value_type* element, parameter_t key) const + { + return comp(*element, key); + } + + bool operator()(parameter_t key, const value_type* element) const + { + return comp(key, *element); + } + +#if ETL_USING_CPP11 + template ::value, int> = 0> + bool operator()(const value_type* element, const K& key) const + { + return comp(*element, key); + } + + template ::value, int> = 0> + bool operator()(const K& key, const value_type* element) const + { + return comp(key, *element); + } +#endif + + const TKeyCompare& comp; + }; + public: typedef ETL_OR_STD::reverse_iterator reverse_iterator; @@ -458,7 +499,7 @@ namespace etl ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full)); - iterator i_element = etl::upper_bound(begin(), end(), value, compare); + iterator i_element = upper_bound(value); if (i_element == end()) { @@ -606,13 +647,14 @@ namespace etl //********************************************************************* iterator find(parameter_t key) { - iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator itr = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.end()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return iterator(itr); } else { @@ -628,13 +670,14 @@ namespace etl template ::value, int> = 0> iterator find(const K& key) { - iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator itr = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.end()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return iterator(itr); } else { @@ -653,13 +696,14 @@ namespace etl //********************************************************************* const_iterator find(parameter_t key) const { - const_iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator itr = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.cend()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return const_iterator(itr); } else { @@ -675,13 +719,14 @@ namespace etl template ::value, int> = 0> const_iterator find(const K& key) const { - const_iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator itr = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.cend()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return const_iterator(itr); } else { @@ -723,7 +768,8 @@ namespace etl //********************************************************************* iterator lower_bound(parameter_t key) { - return etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -731,7 +777,8 @@ namespace etl template ::value, int> = 0> iterator lower_bound(const K& key) { - return etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #endif @@ -742,7 +789,8 @@ namespace etl //********************************************************************* const_iterator lower_bound(parameter_t key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -750,7 +798,8 @@ namespace etl template ::value, int> = 0> const_iterator lower_bound(const K& key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #endif @@ -761,7 +810,8 @@ namespace etl //********************************************************************* iterator upper_bound(parameter_t key) { - return etl::upper_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -769,7 +819,8 @@ namespace etl template ::value, int> = 0> iterator upper_bound(const K& key) { - return etl::upper_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #endif @@ -780,7 +831,8 @@ namespace etl //********************************************************************* const_iterator upper_bound(parameter_t key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -788,7 +840,8 @@ namespace etl template ::value, int> = 0> const_iterator upper_bound(const K& key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #endif @@ -799,7 +852,11 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(parameter_t key) { - return etl::equal_range(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, ptr_compare); + + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #if ETL_USING_CPP11 @@ -807,7 +864,11 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) { - return etl::equal_range(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, ptr_compare); + + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #endif @@ -835,7 +896,11 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(parameter_t key) const { - return etl::equal_range(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, ptr_compare); + + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } //************************************************************************* diff --git a/include/etl/reference_flat_set.h b/include/etl/reference_flat_set.h index 5da865aa..9cfd2d6e 100644 --- a/include/etl/reference_flat_set.h +++ b/include/etl/reference_flat_set.h @@ -295,6 +295,47 @@ namespace etl typedef typename etl::parameter_type::type parameter_t; + //********************************************************************* + /// Compares a pointer to an element (as stored in 'lookup') against a + /// key, allowing binary searches directly over the random-access + /// 'lookup' container instead of the bidirectional iterator/const_iterator. + //********************************************************************* + class Compare + { + public: + + Compare(const TKeyCompare& comp_) + : comp(comp_) + { + } + + bool operator()(const value_type* element, parameter_t key) const + { + return comp(*element, key); + } + + bool operator()(parameter_t key, const value_type* element) const + { + return comp(key, *element); + } + +#if ETL_USING_CPP11 + template ::value, int> = 0> + bool operator()(const value_type* element, const K& key) const + { + return comp(*element, key); + } + + template ::value, int> = 0> + bool operator()(const K& key, const value_type* element) const + { + return comp(key, *element); + } +#endif + + const TKeyCompare& comp; + }; + public: typedef ETL_OR_STD::reverse_iterator reverse_iterator; @@ -581,13 +622,14 @@ namespace etl //********************************************************************* iterator find(parameter_t key) { - iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator itr = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.end()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return iterator(itr); } else { @@ -603,13 +645,14 @@ namespace etl template ::value, int> = 0> iterator find(const K& key) { - iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator itr = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.end()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return iterator(itr); } else { @@ -628,13 +671,14 @@ namespace etl //********************************************************************* const_iterator find(parameter_t key) const { - const_iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator itr = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.cend()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return const_iterator(itr); } else { @@ -650,13 +694,14 @@ namespace etl template ::value, int> = 0> const_iterator find(const K& key) const { - const_iterator itr = etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator itr = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); - if (itr != end()) + if (itr != lookup.cend()) { - if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + if (!compare(**itr, key) && !compare(key, **itr)) { - return itr; + return const_iterator(itr); } else { @@ -694,7 +739,8 @@ namespace etl //********************************************************************* iterator lower_bound(parameter_t key) { - return etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -702,7 +748,8 @@ namespace etl template ::value, int> = 0> iterator lower_bound(const K& key) { - return etl::lower_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #endif @@ -713,7 +760,8 @@ namespace etl //********************************************************************* const_iterator lower_bound(parameter_t key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -721,7 +769,8 @@ namespace etl template ::value, int> = 0> const_iterator lower_bound(const K& key) const { - return etl::lower_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #endif @@ -732,7 +781,8 @@ namespace etl //********************************************************************* iterator upper_bound(parameter_t key) { - return etl::upper_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -740,7 +790,8 @@ namespace etl template ::value, int> = 0> iterator upper_bound(const K& key) { - return etl::upper_bound(begin(), end(), key, compare); + Compare ptr_compare(compare); + return iterator(etl::upper_bound(lookup.begin(), lookup.end(), key, ptr_compare)); } #endif @@ -751,7 +802,8 @@ namespace etl //********************************************************************* const_iterator upper_bound(parameter_t key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #if ETL_USING_CPP11 @@ -759,7 +811,8 @@ namespace etl template ::value, int> = 0> const_iterator upper_bound(const K& key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + return const_iterator(etl::upper_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare)); } #endif @@ -770,7 +823,11 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(parameter_t key) { - return etl::equal_range(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, ptr_compare); + + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #if ETL_USING_CPP11 @@ -778,7 +835,11 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) { - return etl::equal_range(begin(), end(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::iterator i_lower = etl::lower_bound(lookup.begin(), lookup.end(), key, ptr_compare); + typename lookup_t::iterator i_upper = etl::upper_bound(i_lower, lookup.end(), key, ptr_compare); + + return ETL_OR_STD::make_pair(iterator(i_lower), iterator(i_upper)); } #endif @@ -789,7 +850,11 @@ namespace etl //********************************************************************* ETL_OR_STD::pair equal_range(parameter_t key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, ptr_compare); + + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #if ETL_USING_CPP11 @@ -797,7 +862,11 @@ namespace etl template ::value, int> = 0> ETL_OR_STD::pair equal_range(const K& key) const { - return etl::upper_bound(cbegin(), cend(), key, compare); + Compare ptr_compare(compare); + typename lookup_t::const_iterator i_lower = etl::lower_bound(lookup.cbegin(), lookup.cend(), key, ptr_compare); + typename lookup_t::const_iterator i_upper = etl::upper_bound(i_lower, lookup.cend(), key, ptr_compare); + + return ETL_OR_STD::make_pair(const_iterator(i_lower), const_iterator(i_upper)); } #endif diff --git a/include/etl/signal.h b/include/etl/signal.h index b78e7e58..695bd0c1 100644 --- a/include/etl/signal.h +++ b/include/etl/signal.h @@ -185,7 +185,7 @@ namespace etl ///\param slot: The slot to connect. ///\return false if not all slots could be connected. //************************************************************************* - bool connect(const slot_type& slot) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + bool connect(const slot_type& slot) { if (!connected(slot)) { @@ -204,7 +204,7 @@ namespace etl ///\param slots: std::initializer_list of slots to connect. ///\return false if not all slots could be connected. //************************************************************************* - bool connect(std::initializer_list slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + bool connect(std::initializer_list slots) { for (const slot_type& slot : slots) { @@ -226,7 +226,7 @@ namespace etl ///\param slots: etl::span of slots to connect. ///\return false if not all slots could be connected. //************************************************************************* - bool connect(const span_type slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) + bool connect(const span_type slots) { for (const slot_type& slot : slots) { diff --git a/include/etl/span.h b/include/etl/span.h index 1724a87d..d948c355 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -66,8 +66,8 @@ namespace etl { }; #if ETL_USING_STL && ETL_USING_CPP11 - template - struct is_std_array> : etl::true_type + template + struct is_std_array> : etl::true_type { }; #endif @@ -88,8 +88,8 @@ namespace etl struct is_etl_array : etl::false_type { }; - template - struct is_etl_array > : etl::true_type + template + struct is_etl_array > : etl::true_type { }; template @@ -211,6 +211,7 @@ namespace etl typedef T element_type; typedef typename etl::remove_cv::type value_type; typedef size_t size_type; + typedef ptrdiff_t difference_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; @@ -248,7 +249,7 @@ namespace etl /// Construct from iterator + size //************************************************************************* template - explicit ETL_CONSTEXPR14 span(const TIterator begin_, const size_t size_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS) + explicit ETL_CONSTEXPR14 span(const TIterator begin_, const size_t size_) : pbegin(etl::to_address(begin_)) { ETL_ASSERT(size_ == Extent, ETL_ERROR(span_size_mismatch)); @@ -260,7 +261,7 @@ namespace etl //************************************************************************* template ETL_CONSTEXPR14 span(const TIteratorBegin begin_, const TIteratorEnd end_, - typename etl::enable_if< !etl::is_integral::value, void>::type* = 0) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS) + typename etl::enable_if< !etl::is_integral::value, void>::type* = 0) : pbegin(etl::to_address(begin_)) { ETL_ASSERT(etl::distance(begin_, end_) == Extent, ETL_ERROR(span_size_mismatch)); @@ -292,7 +293,7 @@ namespace etl && etl::is_convertible< decltype(etl::declval< typename etl::remove_reference::type&>().data()), pointer>::value && etl::is_same< typename etl::remove_cv::type, typename etl::remove_cv::type::value_type>::type>::value, - void>::type* = 0) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS) + void>::type* = 0) : pbegin(a.data()) { ETL_ASSERT(a.size() == Extent, ETL_ERROR(span_size_mismatch)); @@ -788,6 +789,7 @@ namespace etl typedef T element_type; typedef typename etl::remove_cv::type value_type; typedef size_t size_type; + typedef ptrdiff_t difference_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; @@ -1507,6 +1509,11 @@ namespace etl template span(const std::array&) -> span; #endif + + // Any other type that supports data() and size() member functions + template ::value && etl::has_size::value + && etl::is_lvalue_reference::value>> + span(TContainer&&) -> span().data())>, etl::dynamic_extent>; #endif //************************************************************************* diff --git a/include/etl/string.h b/include/etl/string.h index 33e3d2d8..3f46a815 100644 --- a/include/etl/string.h +++ b/include/etl/string.h @@ -80,7 +80,7 @@ namespace etl /// Constructor. //************************************************************************* string() - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->initialise(); } @@ -90,7 +90,7 @@ namespace etl ///\param other The other string. //************************************************************************* string(const etl::string& other) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(other); } @@ -100,7 +100,7 @@ namespace etl ///\param other The other istring. //************************************************************************* string(const etl::istring& other) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(other); } @@ -112,7 +112,7 @@ namespace etl ///\param length The number of characters. Default = npos. //************************************************************************* string(const etl::istring& other, size_t position, size_t length = npos) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); @@ -124,7 +124,7 @@ namespace etl ///\param text The initial text of the string. //************************************************************************* ETL_EXPLICIT_STRING_FROM_CHAR string(const value_type* text) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(text); } @@ -135,7 +135,7 @@ namespace etl ///\param count The number of characters to copy. //************************************************************************* string(const value_type* text, size_t count) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(text, text + count); } @@ -146,7 +146,7 @@ namespace etl ///\param value The value to fill the string with. //************************************************************************* string(size_type count, value_type c) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->initialise(); this->resize(count, c); @@ -160,7 +160,7 @@ namespace etl //************************************************************************* template string(TIterator first, TIterator last, typename etl::enable_if::value, int>::type = 0) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(first, last); } @@ -170,7 +170,7 @@ namespace etl /// Construct from initializer_list. //************************************************************************* string(std::initializer_list init) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(init.begin(), init.end()); } @@ -181,7 +181,7 @@ namespace etl ///\param view The string_view. //************************************************************************* explicit string(const etl::string_view& view) - : istring(reinterpret_cast(&buffer), MAX_SIZE) + : istring(buffer, MAX_SIZE) { this->assign(view.begin(), view.end()); } diff --git a/include/etl/tuple.h b/include/etl/tuple.h index 5b7257ec..a20def79 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -39,6 +39,7 @@ SOFTWARE. #endif #include "functional.h" + #include "invoke.h" #include "nth_type.h" #include "type_list.h" #include "type_traits.h" @@ -934,6 +935,35 @@ namespace etl return tuple(etl::forward(args)...); } + namespace private_tuple + { + //********************************** + // Helper for apply. + // Invokes the callable with the tuple elements expanded via the index sequence. + // Uses an unqualified 'get' so that argument-dependent lookup finds the + // appropriate overload for etl::tuple, etl::array, std::tuple, std::pair, etc. + //********************************** + template + ETL_CONSTEXPR14 auto apply_impl(TFunction&& f, TTuple&& t, etl::index_sequence) + -> decltype(etl::invoke(etl::forward(f), get(etl::forward(t))...)) + { + return etl::invoke(etl::forward(f), get(etl::forward(t))...); + } + } // namespace private_tuple + + //*************************************************************************** + /// Invokes the callable object 'f' with the elements of the tuple 't' as + /// arguments. Equivalent to std::apply. + //*************************************************************************** + template + ETL_CONSTEXPR14 auto apply(TFunction&& f, TTuple&& t) + -> decltype(private_tuple::apply_impl(etl::forward(f), etl::forward(t), + etl::make_index_sequence>::value>{})) + { + return private_tuple::apply_impl(etl::forward(f), etl::forward(t), + etl::make_index_sequence>::value>{}); + } + namespace private_tuple { //********************************** diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 52fd9859..6ecf9451 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -3317,15 +3317,36 @@ namespace etl #else //********************************************* - // Assume that anything other than arithmetics + // Assume that anything other than arithmetic // and pointers return false for the traits. //********************************************* //********************************************* // is_assignable + #if !ETL_USING_BUILTIN_IS_ASSIGNABLE && ETL_USING_CPP11 + namespace private_type_traits + { + template + struct is_assignable_ : etl::false_type + { + }; + + template + struct is_assignable_() = etl::declval())>, T1, T2> : etl::true_type + { + }; + } // namespace private_type_traits + #endif + template #if ETL_USING_BUILTIN_IS_ASSIGNABLE struct is_assignable : public etl::bool_constant<__is_assignable(T1, T2)> + #elif ETL_USING_CPP11 + // Builtin-free assignability detection. Used when the __is_assignable builtin + // is unavailable (e.g. MSVC, where determine_builtin_support.h disables the + // __has_builtin block). Mirrors the void_t-based is_constructible above so + // that class types are correctly reported as (copy/move) assignable. + struct is_assignable : public private_type_traits::is_assignable_, T1, T2> #else struct is_assignable : public etl::bool_constant< (etl::is_arithmetic::value || etl::is_pointer::value) @@ -3703,7 +3724,7 @@ namespace etl struct common_type : etl::conditional< etl::is_same::type>::value && etl::is_same::type>::value, private_common_type::common_type_2_impl, - common_type::type, typename etl::decay::type>>::type + common_type::type, typename etl::decay::type>>::type { }; diff --git a/include/etl/u16string.h b/include/etl/u16string.h index 741a61c2..03810b7d 100644 --- a/include/etl/u16string.h +++ b/include/etl/u16string.h @@ -77,7 +77,7 @@ namespace etl /// Constructor. //************************************************************************* u16string() - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->initialise(); } @@ -87,7 +87,7 @@ namespace etl ///\param other The other string. //************************************************************************* u16string(const etl::u16string& other) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(other); } @@ -97,7 +97,7 @@ namespace etl ///\param other The other iu16string. //************************************************************************* u16string(const etl::iu16string& other) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(other); } @@ -109,7 +109,7 @@ namespace etl ///\param length The number of characters. Default = npos. //************************************************************************* u16string(const etl::iu16string& other, size_type position, size_type length = npos) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); @@ -121,7 +121,7 @@ namespace etl ///\param text The initial text of the u16string. //************************************************************************* ETL_EXPLICIT_STRING_FROM_CHAR u16string(const value_type* text) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(text); } @@ -132,7 +132,7 @@ namespace etl ///\param count The number of characters to copy. //************************************************************************* u16string(const value_type* text, size_type count) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(text, text + count); } @@ -143,7 +143,7 @@ namespace etl ///\param value The value to fill the u16string with. //************************************************************************* u16string(size_type count, value_type c) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->initialise(); this->resize(count, c); @@ -157,7 +157,7 @@ namespace etl //************************************************************************* template u16string(TIterator first, TIterator last, typename etl::enable_if::value, int>::type = 0) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(first, last); } @@ -167,7 +167,7 @@ namespace etl /// Construct from initializer_list. //************************************************************************* u16string(std::initializer_list init) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(init.begin(), init.end()); } @@ -178,7 +178,7 @@ namespace etl ///\param view The string_view. //************************************************************************* explicit u16string(const etl::u16string_view& view) - : iu16string(reinterpret_cast(&buffer), MAX_SIZE) + : iu16string(buffer, MAX_SIZE) { this->assign(view.begin(), view.end()); } diff --git a/include/etl/u32string.h b/include/etl/u32string.h index 87327cf8..418bd514 100644 --- a/include/etl/u32string.h +++ b/include/etl/u32string.h @@ -77,7 +77,7 @@ namespace etl /// Constructor. //************************************************************************* u32string() - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->initialise(); } @@ -87,7 +87,7 @@ namespace etl ///\param other The other string. //************************************************************************* u32string(const etl::u32string& other) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(other); } @@ -97,7 +97,7 @@ namespace etl ///\param other The other iu32string. //************************************************************************* u32string(const etl::iu32string& other) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(other); } @@ -109,7 +109,7 @@ namespace etl ///\param length The number of characters. Default = npos. //************************************************************************* u32string(const etl::iu32string& other, size_type position, size_type length = npos) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); @@ -121,7 +121,7 @@ namespace etl ///\param text The initial text of the u32string. //************************************************************************* ETL_EXPLICIT_STRING_FROM_CHAR u32string(const value_type* text) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(text); } @@ -132,7 +132,7 @@ namespace etl ///\param count The number of characters to copy. //************************************************************************* u32string(const value_type* text, size_type count) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(text, text + count); } @@ -143,7 +143,7 @@ namespace etl ///\param value The value to fill the u32string with. //************************************************************************* u32string(size_type count, value_type c) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->initialise(); this->resize(count, c); @@ -157,7 +157,7 @@ namespace etl //************************************************************************* template u32string(TIterator first, TIterator last, typename etl::enable_if::value, int>::type = 0) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(first, last); } @@ -167,7 +167,7 @@ namespace etl /// Construct from initializer_list. //************************************************************************* u32string(std::initializer_list init) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(init.begin(), init.end()); } @@ -178,7 +178,7 @@ namespace etl ///\param view The string_view. //************************************************************************* explicit u32string(const etl::u32string_view& view) - : iu32string(reinterpret_cast(&buffer), MAX_SIZE) + : iu32string(buffer, MAX_SIZE) { this->assign(view.begin(), view.end()); } diff --git a/include/etl/u8string.h b/include/etl/u8string.h index 4561f58c..ffea798f 100644 --- a/include/etl/u8string.h +++ b/include/etl/u8string.h @@ -80,7 +80,7 @@ namespace etl /// Constructor. //************************************************************************* u8string() - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->initialise(); } @@ -90,7 +90,7 @@ namespace etl ///\param other The other u8string. //************************************************************************* u8string(const etl::u8string& other) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(other); } @@ -100,7 +100,7 @@ namespace etl ///\param other The other iu8string. //************************************************************************* u8string(const etl::iu8string& other) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(other); } @@ -112,7 +112,7 @@ namespace etl ///\param length The number of characters. Default = npos. //************************************************************************* u8string(const etl::iu8string& other, size_t position, size_t length = npos) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); @@ -124,7 +124,7 @@ namespace etl ///\param text The initial text of the u8string. //************************************************************************* ETL_EXPLICIT_STRING_FROM_CHAR u8string(const value_type* text) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(text); } @@ -135,7 +135,7 @@ namespace etl ///\param count The number of characters to copy. //************************************************************************* u8string(const value_type* text, size_t count) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(text, text + count); } @@ -146,7 +146,7 @@ namespace etl ///\param value The value to fill the u8string with. //************************************************************************* u8string(size_type count, value_type c) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->initialise(); this->resize(count, c); @@ -160,7 +160,7 @@ namespace etl //************************************************************************* template u8string(TIterator first, TIterator last, typename etl::enable_if::value, int>::type = 0) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(first, last); } @@ -170,7 +170,7 @@ namespace etl /// Construct from initializer_list. //************************************************************************* u8string(std::initializer_list init) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(init.begin(), init.end()); } @@ -181,7 +181,7 @@ namespace etl ///\param view The string_view. //************************************************************************* explicit u8string(const etl::u8string_view& view) - : iu8string(reinterpret_cast(&buffer), MAX_SIZE) + : iu8string(buffer, MAX_SIZE) { this->assign(view.begin(), view.end()); } diff --git a/include/etl/unaligned_type.h b/include/etl/unaligned_type.h index 504317f7..cba1874f 100644 --- a/include/etl/unaligned_type.h +++ b/include/etl/unaligned_type.h @@ -46,10 +46,7 @@ SOFTWARE. #include "iterator.h" #include "type_traits.h" -#if ETL_USING_CPP20 && ETL_USING_STL - #include -#endif - +#include #include namespace etl @@ -102,12 +99,14 @@ namespace etl //************************************************************************* /// Default constructor //************************************************************************* - unaligned_type_common() {} + ETL_CONSTEXPR14 unaligned_type_common() + { + } //************************************************************************* /// Size of the storage. //************************************************************************* - size_t size() const + ETL_CONSTEXPR14 size_t size() const { return Size_; } @@ -115,7 +114,7 @@ namespace etl //************************************************************************* /// Pointer to the beginning of the storage. //************************************************************************* - pointer data() + ETL_CONSTEXPR14 pointer data() { return get_storage(); } @@ -123,7 +122,7 @@ namespace etl //************************************************************************* /// Const pointer to the beginning of the storage. //************************************************************************* - const_pointer data() const + ETL_CONSTEXPR14 const_pointer data() const { return get_storage(); } @@ -245,7 +244,7 @@ namespace etl //************************************************************************* /// Get a pointer to the storage. //************************************************************************* - pointer get_storage() + ETL_CONSTEXPR14 pointer get_storage() { return static_cast(this)->storage; } @@ -253,7 +252,7 @@ namespace etl //************************************************************************* /// Get a const pointer to the storage. //************************************************************************* - const_pointer get_storage() const + ETL_CONSTEXPR14 const_pointer get_storage() const { return static_cast(this)->storage; } @@ -277,7 +276,7 @@ namespace etl protected: //******************************* - unaligned_type_storage() + ETL_CONSTEXPR14 unaligned_type_storage() : storage() { } @@ -326,6 +325,52 @@ namespace etl }; ETL_END_PACKED + //************************************************************************* + /// The shift, in bits, that positions byte 'index' of a value of 'Size' + /// bytes, for the target endianness. + //************************************************************************* + template + ETL_CONSTEXPR size_t byte_shift(size_t index) + { + return ((Endian == ETL_ENDIAN_LITTLE) ? index : (Size - 1U - index)) * 8U; + } + +#if ETL_USING_BUILTIN_BIT_CAST + //************************************************************************* + /// Unsigned integer type of a given byte size, used as a constexpr-capable + /// 'proxy' for extracting/inserting the bytes of a floating point value. + //************************************************************************* + template + struct uint_of_size; + + template <> + struct uint_of_size<2U> + { + typedef uint16_t type; + }; + + template <> + struct uint_of_size<4U> + { + typedef uint32_t type; + }; + + template <> + struct uint_of_size<8U> + { + typedef uint64_t type; + }; + + //************************************************************************* + /// Whether the bit_cast fast path may be used for a type of 'Size' bytes. + /// It requires a same-size unsigned integer proxy type to exist. + //************************************************************************* + template + struct use_bit_cast : etl::conditional<(Size == 2U) || (Size == 4U) || (Size == 8U), etl::true_type, etl::false_type> + { + }; +#endif + //************************************************************************* /// Unaligned copy //************************************************************************* @@ -335,6 +380,10 @@ namespace etl //************************************************************************* /// Unaligned copy /// For integrals. + /// Bytes are extracted/inserted directly in the target endianness using + /// shifts, rather than a native-endianness memcpy + conditional reverse. + /// This makes the conversion independent of the host's endianness and + /// usable in a constexpr context (C++14 and later). //************************************************************************* template ETL_PACKED_CLASS(unaligned_copy) @@ -347,44 +396,42 @@ namespace etl //******************************* template - static void copy_value_to_store(const T& value, pointer store) + static ETL_CONSTEXPR14 void copy_value_to_store(const T& value, pointer store) { - memcpy(store, &value, Size_); + // Note: 'etl::unsigned_type' is used rather than 'etl::make_unsigned', as the + // latter is not defined for 'bool'. + typedef typename etl::unsigned_type::type unsigned_t; -#if ETL_HAS_CONSTEXPR_ENDIANNESS - if ETL_IF_CONSTEXPR (Endian_ != etl::endianness::value()) -#else - if (Endian_ != etl::endianness::value()) -#endif + unsigned_t uvalue = static_cast(value); + + for (size_t i = 0UL; i < Size_; ++i) { - etl::reverse(store, store + Size_); + store[i] = static_cast(uvalue >> private_unaligned_type::byte_shift(i)); } } //******************************* template - static void copy_store_to_value(const_pointer store, T & value) + static ETL_CONSTEXPR14 void copy_store_to_value(const_pointer store, T & value) { - memcpy(&value, store, Size_); + typedef typename etl::unsigned_type::type unsigned_t; -#if ETL_HAS_CONSTEXPR_ENDIANNESS - if ETL_IF_CONSTEXPR (Endian_ != etl::endianness::value()) -#else - if (Endian_ != etl::endianness::value()) -#endif + unsigned_t uvalue = unsigned_t(0); + + for (size_t i = 0UL; i < Size_; ++i) { - value = etl::reverse_bytes(value); + uvalue = static_cast(uvalue | (static_cast(store[i]) << private_unaligned_type::byte_shift(i))); } + + value = static_cast(uvalue); } //******************************* - static void copy_store_to_store(const_pointer src, int endian_src, pointer dst) + static ETL_CONSTEXPR14 void copy_store_to_store(const_pointer src, int endian_src, pointer dst) { - memcpy(dst, src, Size_); - - if (Endian_ != endian_src) + for (size_t i = 0UL; i < Size_; ++i) { - etl::reverse(dst, dst + Size_); + dst[i] = (Endian_ == endian_src) ? src[i] : src[Size_ - 1U - i]; } } }; @@ -404,8 +451,28 @@ namespace etl typedef typename private_unaligned_type::unaligned_type_storage< Size_>::const_pointer const_pointer; //******************************* + // The bit_cast fast path is only valid when a same-size unsigned integer + // proxy type exists (currently 2, 4 or 8 bytes, e.g. a 16-bit float, float, + // or double). Other sizes (e.g. 80/96/128-bit 'long double') fall back to + // memcpy. + //******************************* +#if ETL_USING_BUILTIN_BIT_CAST template - static void copy_value_to_store(const T& value, pointer store) + static ETL_CONSTEXPR14 void do_copy_value_to_store(const T& value, pointer store, etl::true_type) + { + typedef typename private_unaligned_type::uint_of_size::type uint_t; + + uint_t uvalue = etl::bit_cast(value); + + for (size_t i = 0UL; i < Size_; ++i) + { + store[i] = static_cast(uvalue >> private_unaligned_type::byte_shift(i)); + } + } +#endif + + template + static void do_copy_value_to_store(const T& value, pointer store, etl::false_type) { memcpy(store, &value, Size_); @@ -421,7 +488,41 @@ namespace etl //******************************* template - static void copy_store_to_value(const_pointer store, T & value) + static +#if ETL_USING_BUILTIN_BIT_CAST + ETL_CONSTEXPR14 +#endif + void + copy_value_to_store(const T& value, pointer store) + { +#if ETL_USING_BUILTIN_BIT_CAST + typedef typename private_unaligned_type::use_bit_cast::type use_bit_cast_t; +#else + typedef etl::false_type use_bit_cast_t; +#endif + do_copy_value_to_store(value, store, use_bit_cast_t()); + } + + //******************************* +#if ETL_USING_BUILTIN_BIT_CAST + template + static ETL_CONSTEXPR14 void do_copy_store_to_value(const_pointer store, T & value, etl::true_type) + { + typedef typename private_unaligned_type::uint_of_size::type uint_t; + + uint_t uvalue = uint_t(0); + + for (size_t i = 0UL; i < Size_; ++i) + { + uvalue = static_cast(uvalue | (static_cast(store[i]) << private_unaligned_type::byte_shift(i))); + } + + value = etl::bit_cast(uvalue); + } +#endif + + template + static void do_copy_store_to_value(const_pointer store, T & value, etl::false_type) { memcpy(&value, store, Size_); @@ -436,13 +537,32 @@ namespace etl } //******************************* - static void copy_store_to_store(const_pointer src, int endian_src, pointer dst) + template + static +#if ETL_USING_BUILTIN_BIT_CAST + ETL_CONSTEXPR14 +#endif + void + copy_store_to_value(const_pointer store, T & value) { - memcpy(dst, src, Size_); +#if ETL_USING_BUILTIN_BIT_CAST + typedef typename private_unaligned_type::use_bit_cast::type use_bit_cast_t; +#else + typedef etl::false_type use_bit_cast_t; +#endif + do_copy_store_to_value(store, value, use_bit_cast_t()); + } - if (Endian_ != endian_src) + //******************************* + // This is pure byte manipulation (copy + optional reversal), with no + // floating point arithmetic involved, so it is always constexpr-capable + // (C++14 and later), regardless of bit_cast/builtin availability. + //******************************* + static ETL_CONSTEXPR14 void copy_store_to_store(const_pointer src, int endian_src, pointer dst) + { + for (size_t i = 0UL; i < Size_; ++i) { - etl::reverse(dst, dst + Size_); + dst[i] = (Endian_ == endian_src) ? src[i] : src[Size_ - 1U - i]; } } }; @@ -486,7 +606,7 @@ namespace etl //************************************************************************* /// Construct from a value. //************************************************************************* - unaligned_type(T value) + ETL_CONSTEXPR14 unaligned_type(T value) { unaligned_copy::copy_value_to_store(value, this->storage); } @@ -501,6 +621,10 @@ namespace etl //************************************************************************* /// Construct from an address and buffer size. + /// \note 'buffer_size' must be greater than or equal to 'sizeof(T)'. + /// This is a precondition, checked by ETL_ASSERT. If the checks are + /// disabled (e.g. ETL_NO_CHECKS) then passing a smaller buffer size + /// results in a read beyond the end of the buffer. //************************************************************************* unaligned_type(const void* address, size_t buffer_size) { @@ -509,10 +633,38 @@ namespace etl etl::copy_n(reinterpret_cast(address), sizeof(T), this->storage); } + //************************************************************************* + /// Construct from a byte buffer. + /// Unlike the 'const void*' overload above, this does not require a + /// reinterpret_cast, so it is usable in a constexpr context (C++14 and + /// later), allowing compile time decoding of a byte buffer with an + /// explicit endianness. + //************************************************************************* + ETL_CONSTEXPR14 unaligned_type(const unsigned char* address) + { + etl::copy_n(address, sizeof(T), this->storage); + } + + //************************************************************************* + /// Construct from a byte buffer and buffer size. + /// See the note on the 'const unsigned char*' overload above regarding + /// constexpr usability. + /// \note 'buffer_size' must be greater than or equal to 'sizeof(T)'. + /// This is a precondition, checked by ETL_ASSERT. If the checks are + /// disabled (e.g. ETL_NO_CHECKS) then passing a smaller buffer size + /// results in a read beyond the end of the buffer. + //************************************************************************* + ETL_CONSTEXPR14 unaligned_type(const unsigned char* address, size_t buffer_size) + { + ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::unaligned_type_buffer_size)); + + etl::copy_n(address, sizeof(T), this->storage); + } + //************************************************************************* /// Copy constructor //************************************************************************* - unaligned_type(const unaligned_type& other) + ETL_CONSTEXPR14 unaligned_type(const unaligned_type& other) { unaligned_copy::copy_store_to_store(other.data(), Endian, this->storage); } @@ -521,7 +673,7 @@ namespace etl /// Copy constructor //************************************************************************* template - unaligned_type(const unaligned_type& other) + ETL_CONSTEXPR14 unaligned_type(const unaligned_type& other) { unaligned_copy::copy_store_to_store(other.data(), Endian_Other, this->storage); } @@ -529,7 +681,7 @@ namespace etl //************************************************************************* /// Assignment operator //************************************************************************* - unaligned_type& operator=(T value) + ETL_CONSTEXPR14 unaligned_type& operator=(T value) { unaligned_copy::copy_value_to_store(value, this->storage); @@ -539,7 +691,7 @@ namespace etl //************************************************************************* /// Assignment operator. //************************************************************************* - unaligned_type& operator=(const unaligned_type& other) + ETL_CONSTEXPR14 unaligned_type& operator=(const unaligned_type& other) { unaligned_copy::copy_store_to_store(other.data(), Endian_, this->storage); @@ -550,7 +702,7 @@ namespace etl /// Assignment operator from other endianness. //************************************************************************* template - unaligned_type& operator=(const unaligned_type& other) + ETL_CONSTEXPR14 unaligned_type& operator=(const unaligned_type& other) { unaligned_copy::copy_store_to_store(other.data(), Endian_Other, this->storage); @@ -560,7 +712,7 @@ namespace etl //************************************************************************* /// Conversion operator //************************************************************************* - operator T() const + ETL_CONSTEXPR14 operator T() const { T value = T(); @@ -572,7 +724,7 @@ namespace etl //************************************************************************* /// Get the value. //************************************************************************* - T value() const + ETL_CONSTEXPR14 T value() const { T value = T(); @@ -666,7 +818,7 @@ namespace etl unaligned_type_ext(unaligned_type_ext && other) : private_unaligned_type::unaligned_type_storage_ext(other.storage) { - // If we're constructing from a different endianess then we need to + // If we're constructing from a different endianness then we need to // reverse the data order. if (Endian != Endian_Other) { @@ -728,7 +880,7 @@ namespace etl { this->storage = other.storage; - // If we're assigning from a different endianess then we need to reverse + // If we're assigning from a different endianness then we need to reverse // the data order. if (Endian != Endian_Other) { diff --git a/include/etl/utility.h b/include/etl/utility.h index addd7ca1..3c7da3a5 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -32,6 +32,7 @@ SOFTWARE. #define ETL_UTILITY_INCLUDED #include "platform.h" +#include "limits.h" #include "type_traits.h" #include "private/tuple_element.h" @@ -142,6 +143,200 @@ namespace etl return static_cast::type>(value); } +#if ETL_USING_STL && ETL_USING_CPP20 && defined(__cpp_lib_integer_comparison_functions) + //*************************************************************************** + // Safe integer comparison functions. + //*************************************************************************** + using std::cmp_equal; + using std::cmp_greater; + using std::cmp_greater_equal; + using std::cmp_less; + using std::cmp_less_equal; + using std::cmp_not_equal; + using std::in_range; +#else + namespace private_utility + { + //*********************************** + /// Determines whether T is one of the standard integer types permitted as + /// an argument to the safe integer comparison functions. The permitted + /// types are the signed and unsigned standard integer types, including + /// signed char and unsigned char. bool, char and the extended character + /// types are excluded, matching the C++ standard's constraints on + /// etl::cmp_* and etl::in_range. + //*********************************** + template + struct is_standard_integer : etl::false_type + { + }; + + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + template <> + struct is_standard_integer : etl::true_type + { + }; + + template + struct is_standard_integer : is_standard_integer + { + }; + template + struct is_standard_integer : is_standard_integer + { + }; + template + struct is_standard_integer : is_standard_integer + { + }; + + //*********************************** + /// Enabled when both T and U are permitted comparison types. + //*********************************** + template + struct enable_if_comparable : etl::enable_if::value && is_standard_integer::value, TReturn> + { + }; + + //*********************************** + /// cmp_less implementation helpers, selected by SFINAE to avoid + /// signed/unsigned comparison warnings in dead code branches. + //*********************************** + + // Both same signedness. + template + ETL_NODISCARD ETL_CONSTEXPR typename etl::enable_if::value == etl::is_signed::value, bool>::type cmp_less_impl(T t, U u) + ETL_NOEXCEPT + { + return t < u; + } + + // T is signed, U is unsigned. + template + ETL_NODISCARD ETL_CONSTEXPR typename etl::enable_if::value && !etl::is_signed::value, bool>::type cmp_less_impl(T t, U u) + ETL_NOEXCEPT + { + return (t < T(0)) || (typename etl::make_unsigned::type(t) < u); + } + + // T is unsigned, U is signed. + template + ETL_NODISCARD ETL_CONSTEXPR typename etl::enable_if::value && etl::is_signed::value, bool>::type cmp_less_impl(T t, U u) + ETL_NOEXCEPT + { + return (u >= U(0)) && (t < typename etl::make_unsigned::type(u)); + } + } // namespace private_utility + + //*************************************************************************** + /// Compares the values of two integers. + /// Unlike the built-in comparison operators, negative signed integers always + /// compare less than (and not equal to) unsigned integers. + /// The comparison is safe against value-changing implicit conversions. + /// https://en.cppreference.com/w/cpp/utility/intcmp + ///\ingroup utility + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_equal(T t, U u) ETL_NOEXCEPT + { + return (etl::is_signed::value == etl::is_signed::value) ? (t == u) + : etl::is_signed::value ? ((t >= T(0)) && (typename etl::make_unsigned::type(t) == u)) + : ((u >= U(0)) && (t == typename etl::make_unsigned::type(u))); + } + + //*************************************************************************** + /// See @ref cmp_equal. + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_not_equal(T t, U u) ETL_NOEXCEPT + { + return !etl::cmp_equal(t, u); + } + + //*************************************************************************** + /// See @ref cmp_equal. + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_less(T t, U u) ETL_NOEXCEPT + { + return etl::private_utility::cmp_less_impl(t, u); + } + + //*************************************************************************** + /// See @ref cmp_equal. + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_greater(T t, U u) ETL_NOEXCEPT + { + return etl::cmp_less(u, t); + } + + //*************************************************************************** + /// See @ref cmp_equal. + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_less_equal(T t, U u) ETL_NOEXCEPT + { + return !etl::cmp_less(u, t); + } + + //*************************************************************************** + /// See @ref cmp_equal. + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type cmp_greater_equal(T t, U u) ETL_NOEXCEPT + { + return !etl::cmp_less(t, u); + } + + //*************************************************************************** + /// Returns whether the value of t is in the range of values that can be + /// represented by R, that is, whether t can be converted to R without loss + /// of its value. + /// https://en.cppreference.com/w/cpp/utility/in_range + ///\ingroup utility + //*************************************************************************** + template + ETL_NODISCARD ETL_CONSTEXPR typename private_utility::enable_if_comparable::type in_range(T t) ETL_NOEXCEPT + { + return etl::cmp_greater_equal(t, etl::numeric_limits::min()) && etl::cmp_less_equal(t, etl::numeric_limits::max()); + } +#endif + // We can't have std::swap and etl::swap templates coexisting in the unit // tests as the compiler will be unable to decide which one to use, due to // ADL. diff --git a/include/etl/vector.h b/include/etl/vector.h index 492247be..2c5b3713 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -1212,8 +1212,6 @@ namespace etl typedef pvoidvector base_t; - typedef typename etl::remove_const::type>::type* element_type; - template struct is_compatible_iterator : etl::bool_constant::value_type>::value @@ -1728,7 +1726,10 @@ namespace etl // Convert from pointer to void** static ETL_CONSTEXPR14 void** to_void_pptr(pointer p_buffer) ETL_NOEXCEPT { - return reinterpret_cast(const_cast(p_buffer)); + ETL_STATIC_ASSERT(!etl::is_const::type>::value, + "to_void_pptr must not remove const from the pointed-to element type"); + + return static_cast(const_cast(static_cast(p_buffer))); } }; diff --git a/include/etl/wstring.h b/include/etl/wstring.h index 0f9e9567..4d7cebde 100644 --- a/include/etl/wstring.h +++ b/include/etl/wstring.h @@ -77,7 +77,7 @@ namespace etl /// Constructor. //************************************************************************* wstring() - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->initialise(); } @@ -87,7 +87,7 @@ namespace etl ///\param other The other string. //************************************************************************* wstring(const etl::wstring& other) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(other); } @@ -97,7 +97,7 @@ namespace etl ///\param other The other iwstring. //************************************************************************* wstring(const etl::iwstring& other) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(other); } @@ -109,7 +109,7 @@ namespace etl ///\param length The number of characters. Default = npos. //************************************************************************* wstring(const etl::iwstring& other, size_type position, size_type length = npos) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); @@ -121,7 +121,7 @@ namespace etl ///\param text The initial text of the wstring. //************************************************************************* ETL_EXPLICIT_STRING_FROM_CHAR wstring(const value_type* text) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(text); } @@ -132,7 +132,7 @@ namespace etl ///\param count The number of characters to copy. //************************************************************************* wstring(const value_type* text, size_type count) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(text, text + count); } @@ -143,7 +143,7 @@ namespace etl ///\param value The value to fill the wstring with. //************************************************************************* wstring(size_type count, value_type c) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->initialise(); this->resize(count, c); @@ -157,7 +157,7 @@ namespace etl //************************************************************************* template wstring(TIterator first, TIterator last, typename etl::enable_if::value, int>::type = 0) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(first, last); } @@ -167,7 +167,7 @@ namespace etl /// Construct from initializer_list. //************************************************************************* wstring(std::initializer_list init) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(init.begin(), init.end()); } @@ -178,7 +178,7 @@ namespace etl ///\param view The string_view. //************************************************************************* explicit wstring(const etl::wstring_view& view) - : iwstring(reinterpret_cast(&buffer), MAX_SIZE) + : iwstring(buffer, MAX_SIZE) { this->assign(view.begin(), view.end()); } diff --git a/test/test_array.cpp b/test/test_array.cpp index 7a5d0130..8c8fa168 100644 --- a/test/test_array.cpp +++ b/test/test_array.cpp @@ -35,6 +35,9 @@ SOFTWARE. #include #include #include +#if ETL_USING_CPP11 + #include +#endif #include #include "etl/integral_limits.h" @@ -400,6 +403,96 @@ namespace // int i = etl::get<11>(data2); } +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_get_rvalue) + { + Data data1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const Data data2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + int&& r0 = etl::get<3>(std::move(data1)); + const int&& r1 = etl::get<3>(std::move(data2)); + + CHECK_EQUAL(3, r0); + CHECK_EQUAL(3, r1); + + // The rvalue overloads must be selected and return rvalue references. + CHECK((std::is_same(std::move(data1)))>::value)); + CHECK((std::is_same(std::move(data2)))>::value)); + + // Moving out of an rvalue array element actually moves. + etl::array data3 = {Moveable(1), Moveable(2)}; + + Moveable moved(etl::get<0>(std::move(data3))); + + CHECK_EQUAL(1, moved.value); + CHECK(!data3[0].valid); + } +#endif + + //************************************************************************* + TEST(test_get_constexpr) + { + ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + ETL_CONSTEXPR14 int result = etl::get<3>(data); + CHECK_EQUAL(3, result); + } + +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_tuple_size) + { + CHECK_EQUAL(SIZE, (etl::tuple_size::value)); + CHECK_EQUAL(SIZE, (std::tuple_size::value)); + + #if ETL_USING_CPP17 + CHECK_EQUAL(SIZE, (etl::tuple_size_v)); + CHECK_EQUAL(SIZE, (std::tuple_size_v)); + #endif + } + + //************************************************************************* + TEST(test_tuple_element) + { + CHECK_TRUE((std::is_same>::value)); + CHECK_TRUE((std::is_same>::value)); + + CHECK_TRUE((std::is_same::type>::value)); + CHECK_TRUE((std::is_same::type>::value)); + } +#endif + +#if ETL_USING_CPP17 + //************************************************************************* + TEST(test_structured_bindings) + { + etl::array data = {1, 2, 3}; + + // Bind by reference and modify. + auto& [a, b, c] = data; + + CHECK_EQUAL(1, a); + CHECK_EQUAL(2, b); + CHECK_EQUAL(3, c); + + a = 10; + b = 20; + c = 30; + + CHECK_EQUAL(10, data[0]); + CHECK_EQUAL(20, data[1]); + CHECK_EQUAL(30, data[2]); + + // Bind by const reference. + const auto& [x, y, z] = data; + + CHECK_EQUAL(10, x); + CHECK_EQUAL(20, y); + CHECK_EQUAL(30, z); + } +#endif + //************************************************************************* TEST(test_assign) { @@ -691,6 +784,16 @@ namespace CHECK(!(greater < data)); } + //************************************************************************* + TEST(test_less_than_constexpr) + { + ETL_CONSTEXPR14 Data lesser = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9}; + ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + ETL_CONSTEXPR14 bool result = (lesser < data); + CHECK(result); + } + //************************************************************************* TEST(test_less_than_equal) { @@ -703,6 +806,16 @@ namespace CHECK(!(greater <= data)); } + //************************************************************************* + TEST(test_less_than_equal_constexpr) + { + ETL_CONSTEXPR14 Data lesser = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9}; + ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + ETL_CONSTEXPR14 bool result = (lesser <= data); + CHECK(result); + } + //************************************************************************* TEST(test_greater_than) { @@ -715,6 +828,16 @@ namespace CHECK(!(lesser > data)); } + //************************************************************************* + TEST(test_greater_than_constexpr) + { + ETL_CONSTEXPR14 Data greater = {0, 1, 2, 3, 5, 5, 6, 7, 8, 9}; + ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + ETL_CONSTEXPR14 bool result = (greater > data); + CHECK(result); + } + //************************************************************************* TEST(test_greater_than_equal) { @@ -727,6 +850,16 @@ namespace CHECK(!(lesser >= data)); } + //************************************************************************* + TEST(test_greater_than_equal_constexpr) + { + ETL_CONSTEXPR14 Data greater = {0, 1, 2, 3, 5, 5, 6, 7, 8, 9}; + ETL_CONSTEXPR14 Data data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + ETL_CONSTEXPR14 bool result = (greater >= data); + CHECK(result); + } + //************************************************************************* #if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED) TEST(test_array_template_deduction) @@ -817,6 +950,69 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the element type used to be rejected: + // the old implementation forwarded each argument as T, and forward cannot accept a + // const T lvalue (it requires a non-const T&, and T&& cannot bind to a reference-related + // const lvalue). + TEST(test_make_array_from_const_lvalues_of_element_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_array(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + using Type = etl::remove_reference_t; + CHECK((std::is_same::value)); + + CHECK_EQUAL(42, data[0]); + CHECK_EQUAL(43, data[1]); + CHECK_EQUAL(44, data[2]); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // 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. + TEST(test_make_array_from_narrowing_values) + { + static const int static_const_int = 45; + const int local_const_int = 46; + int mutable_int = 47; + + auto data = etl::make_array(0, 1, static_const_int, local_const_int, mutable_int); + + using Type = etl::remove_reference_t; + CHECK((std::is_same::value)); + + CHECK_EQUAL(0, data[0]); + CHECK_EQUAL(1, data[1]); + CHECK_EQUAL(45, data[2]); + CHECK_EQUAL(46, data[3]); + CHECK_EQUAL(47, data[4]); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP14 + TEST(test_make_array_is_constexpr) + { + static constexpr unsigned char constexpr_value = 0x18U; + + constexpr auto data = etl::make_array(constexpr_value, constexpr_value); + + static_assert(data.size() == 2U, "make_array size"); + static_assert(data[0] == 0x18U, "make_array element"); + + CHECK_EQUAL(0x18U, data[0]); + CHECK_EQUAL(0x18U, data[1]); + } +#endif + #if ETL_USING_CPP14 //************************************************************************* using Array = etl::array; diff --git a/test/test_base64_RFC2152_decoder.cpp b/test/test_base64_RFC2152_decoder.cpp index f1ff542e..e7f1cc3e 100644 --- a/test/test_base64_RFC2152_decoder.cpp +++ b/test/test_base64_RFC2152_decoder.cpp @@ -32,20 +32,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-2152 //***************************************************************************** diff --git a/test/test_base64_RFC2152_encoder.cpp b/test/test_base64_RFC2152_encoder.cpp index 07e5b9a3..cfeb62f9 100644 --- a/test/test_base64_RFC2152_encoder.cpp +++ b/test/test_base64_RFC2152_encoder.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-2152 with no padding // Using minimum buffer size, with callback. diff --git a/test/test_base64_RFC3501_decoder.cpp b/test/test_base64_RFC3501_decoder.cpp index 7dc5baec..75439d63 100644 --- a/test/test_base64_RFC3501_decoder.cpp +++ b/test/test_base64_RFC3501_decoder.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-3501 //***************************************************************************** diff --git a/test/test_base64_RFC3501_encoder.cpp b/test/test_base64_RFC3501_encoder.cpp index 57a4f3a1..032057b5 100644 --- a/test/test_base64_RFC3501_encoder.cpp +++ b/test/test_base64_RFC3501_encoder.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-3501 with no padding // Using minimum buffer size, with callback. diff --git a/test/test_base64_RFC4648_URL_decoder_with_no_padding.cpp b/test/test_base64_RFC4648_URL_decoder_with_no_padding.cpp index 16bc0935..c0abb3bd 100644 --- a/test/test_base64_RFC4648_URL_decoder_with_no_padding.cpp +++ b/test/test_base64_RFC4648_URL_decoder_with_no_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648-URL with no padding //***************************************************************************** diff --git a/test/test_base64_RFC4648_URL_decoder_with_padding.cpp b/test/test_base64_RFC4648_URL_decoder_with_padding.cpp index d7cc35d3..d99758ed 100644 --- a/test/test_base64_RFC4648_URL_decoder_with_padding.cpp +++ b/test/test_base64_RFC4648_URL_decoder_with_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648-URL with no padding //***************************************************************************** diff --git a/test/test_base64_RFC4648_URL_encoder_with_no_padding.cpp b/test/test_base64_RFC4648_URL_encoder_with_no_padding.cpp index c1cb2b9c..3c32c94f 100644 --- a/test/test_base64_RFC4648_URL_encoder_with_no_padding.cpp +++ b/test/test_base64_RFC4648_URL_encoder_with_no_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648-URL with no padding // Using minimum buffer size, with callback. diff --git a/test/test_base64_RFC4648_URL_encoder_with_padding.cpp b/test/test_base64_RFC4648_URL_encoder_with_padding.cpp index 4bb21b13..f1327786 100644 --- a/test/test_base64_RFC4648_URL_encoder_with_padding.cpp +++ b/test/test_base64_RFC4648_URL_encoder_with_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648-URL with padding // Using minimum buffer size, with callback. diff --git a/test/test_base64_RFC4648_decoder_with_no_padding.cpp b/test/test_base64_RFC4648_decoder_with_no_padding.cpp index 77533716..0e31ee4e 100644 --- a/test/test_base64_RFC4648_decoder_with_no_padding.cpp +++ b/test/test_base64_RFC4648_decoder_with_no_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648 with no padding //***************************************************************************** diff --git a/test/test_base64_RFC4648_decoder_with_padding.cpp b/test/test_base64_RFC4648_decoder_with_padding.cpp index f4cd0c4a..54d0f2fc 100644 --- a/test/test_base64_RFC4648_decoder_with_padding.cpp +++ b/test/test_base64_RFC4648_decoder_with_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_decoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648 with no padding //***************************************************************************** diff --git a/test/test_base64_RFC4648_encoder_with_no_padding.cpp b/test/test_base64_RFC4648_encoder_with_no_padding.cpp index d925b4d8..d71b44b1 100644 --- a/test/test_base64_RFC4648_encoder_with_no_padding.cpp +++ b/test/test_base64_RFC4648_encoder_with_no_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648 with no padding // Using minimum buffer size, with callback. diff --git a/test/test_base64_RFC4648_encoder_with_padding.cpp b/test/test_base64_RFC4648_encoder_with_padding.cpp index f40fc733..92c63c0f 100644 --- a/test/test_base64_RFC4648_encoder_with_padding.cpp +++ b/test/test_base64_RFC4648_encoder_with_padding.cpp @@ -30,20 +30,16 @@ SOFTWARE. #include "etl/base64_encoder.h" +#include "etl/integral_limits.h" #include "etl/string.h" #include "etl/vector.h" #include #include +#include #include #include -#if ETL_USING_STL - #include -#endif - -#include "etl/integral_limits.h" - //***************************************************************************** // Encode/decode using RFC-4648 with padding // Using minimum buffer size, with callback. diff --git a/test/test_byte_stream.cpp b/test/test_byte_stream.cpp index 06b2a453..514dbd81 100644 --- a/test/test_byte_stream.cpp +++ b/test/test_byte_stream.cpp @@ -188,6 +188,59 @@ namespace CHECK(reader_little.get_endianness() == etl::endian::little); } + //************************************************************************* + TEST(byte_stream_writer_construct_from_span) + { + char storage[8]; + + etl::span char_span(storage, storage + ETL_OR_STD17::size(storage)); + etl::byte_stream_writer writer_char(char_span, etl::endian::little); + CHECK_EQUAL(char_span.size(), writer_char.capacity()); + + etl::span uchar_span(reinterpret_cast(storage), ETL_OR_STD17::size(storage)); + etl::byte_stream_writer writer_uchar(uchar_span, etl::endian::little); + CHECK_EQUAL(uchar_span.size(), writer_uchar.capacity()); + } + + //************************************************************************* + TEST(byte_stream_reader_construct_from_span) + { + char storage[8] = {0}; + + etl::span char_span(storage, storage + ETL_OR_STD17::size(storage)); + etl::byte_stream_reader reader_char(char_span, etl::endian::little); + CHECK_EQUAL(char_span.size(), reader_char.size_bytes()); + + etl::span const_char_span(storage, storage + ETL_OR_STD17::size(storage)); + etl::byte_stream_reader reader_const_char(const_char_span, etl::endian::little); + CHECK_EQUAL(const_char_span.size(), reader_const_char.size_bytes()); + + etl::span uchar_span(reinterpret_cast(storage), ETL_OR_STD17::size(storage)); + etl::byte_stream_reader reader_uchar(uchar_span, etl::endian::little); + CHECK_EQUAL(uchar_span.size(), reader_uchar.size_bytes()); + + etl::span const_uchar_span(reinterpret_cast(storage), ETL_OR_STD17::size(storage)); + etl::byte_stream_reader reader_const_uchar(const_uchar_span, etl::endian::little); + CHECK_EQUAL(const_uchar_span.size(), reader_const_uchar.size_bytes()); + } + + //************************************************************************* + // https://github.com/ETLCPP/etl/issues/1533 + // Passing an etl::span to byte_stream_writer/byte_stream_reader + // must not be ambiguous. + TEST(byte_stream_reader_writer_construct_from_span_uint8_t_no_ambiguity) + { + uint8_t storage[8] = {0}; + + etl::span data(storage, ETL_OR_STD17::size(storage)); + + etl::byte_stream_writer writer(etl::span(data), etl::endian::little); + etl::byte_stream_reader reader(etl::span(data), etl::endian::little); + + CHECK_EQUAL(data.size(), writer.capacity()); + CHECK_EQUAL(data.size(), reader.size_bytes()); + } + //************************************************************************* TEST(write_bool) { diff --git a/test/test_circular_buffer.cpp b/test/test_circular_buffer.cpp index 34452537..2bbf9feb 100644 --- a/test/test_circular_buffer.cpp +++ b/test/test_circular_buffer.cpp @@ -67,7 +67,7 @@ namespace CHECK(data.crbegin() == data.crend()); } -#if ETL_USING_STL +#if ETL_HAS_INITIALIZER_LIST //************************************************************************* TEST(test_constructor_from_literal) { diff --git a/test/test_circular_buffer_external_buffer.cpp b/test/test_circular_buffer_external_buffer.cpp index a1374986..cd0c40cd 100644 --- a/test/test_circular_buffer_external_buffer.cpp +++ b/test/test_circular_buffer_external_buffer.cpp @@ -99,7 +99,7 @@ namespace CHECK(data.crbegin() == data.crend()); } -#if ETL_USING_STL +#if ETL_HAS_INITIALIZER_LIST //************************************************************************* TEST(test_constructor_from_literal) { diff --git a/test/test_const_map.cpp b/test/test_const_map.cpp index fe998a7d..a3dc8f14 100644 --- a/test/test_const_map.cpp +++ b/test/test_const_map.cpp @@ -257,6 +257,27 @@ namespace CHECK_TRUE(data.max_size() == Max_Size); CHECK_FALSE(data.begin() == data.end()); } + + //************************************************************************* + TEST(test_cpp17_deduced_constructor_of_plain_pair) + { + static const etl::const_map data{ETL_OR_STD::pair{Key('A'), 0}, ETL_OR_STD::pair{Key('B'), 1}, ETL_OR_STD::pair{Key('C'), 2}, + ETL_OR_STD::pair{Key('D'), 3}, ETL_OR_STD::pair{Key('E'), 4}, ETL_OR_STD::pair{Key('F'), 5}, + ETL_OR_STD::pair{Key('G'), 6}, ETL_OR_STD::pair{Key('H'), 7}, ETL_OR_STD::pair{Key('I'), 8}, + ETL_OR_STD::pair{Key('J'), 9}}; + etl::const_map check{ETL_OR_STD::pair{Key('A'), 0}, ETL_OR_STD::pair{Key('B'), 1}, ETL_OR_STD::pair{Key('C'), 2}, + ETL_OR_STD::pair{Key('D'), 3}, ETL_OR_STD::pair{Key('E'), 4}, ETL_OR_STD::pair{Key('F'), 5}, + ETL_OR_STD::pair{Key('G'), 6}, ETL_OR_STD::pair{Key('H'), 7}, ETL_OR_STD::pair{Key('I'), 8}, + ETL_OR_STD::pair{Key('J'), 9}}; + + CHECK_TRUE(data.is_valid()); + CHECK_TRUE(data.size() == Max_Size); + CHECK_FALSE(data.empty()); + CHECK_TRUE(data.full()); + CHECK_TRUE(data.capacity() == Max_Size); + CHECK_TRUE(data.max_size() == Max_Size); + CHECK_FALSE(data.begin() == data.end()); + } #endif //************************************************************************* diff --git a/test/test_const_multimap.cpp b/test/test_const_multimap.cpp index 8c134899..3e181311 100644 --- a/test/test_const_multimap.cpp +++ b/test/test_const_multimap.cpp @@ -226,6 +226,28 @@ namespace CHECK_TRUE(data.max_size() == Max_Size); CHECK_FALSE(data.begin() == data.end()); } + + //************************************************************************* + TEST(test_cpp17_deduced_constructor_of_plain_pair) + { + static const etl::const_multimap data{ETL_OR_STD::pair{Key('A'), 0}, ETL_OR_STD::pair{Key('B'), 1}, ETL_OR_STD::pair{Key('C'), 2}, + ETL_OR_STD::pair{Key('D'), 3}, ETL_OR_STD::pair{Key('E'), 4}, ETL_OR_STD::pair{Key('F'), 5}, + ETL_OR_STD::pair{Key('G'), 6}, ETL_OR_STD::pair{Key('G'), 7}, ETL_OR_STD::pair{Key('G'), 8}, + ETL_OR_STD::pair{Key('J'), 9}}; + + etl::const_multimap check{ETL_OR_STD::pair{Key('A'), 0}, ETL_OR_STD::pair{Key('B'), 1}, ETL_OR_STD::pair{Key('C'), 2}, + ETL_OR_STD::pair{Key('D'), 3}, ETL_OR_STD::pair{Key('E'), 4}, ETL_OR_STD::pair{Key('F'), 5}, + ETL_OR_STD::pair{Key('G'), 6}, ETL_OR_STD::pair{Key('H'), 7}, ETL_OR_STD::pair{Key('I'), 8}, + ETL_OR_STD::pair{Key('J'), 9}}; + + CHECK_TRUE(data.is_valid()); + CHECK_TRUE(data.size() == Max_Size); + CHECK_FALSE(data.empty()); + CHECK_TRUE(data.full()); + CHECK_TRUE(data.capacity() == Max_Size); + CHECK_TRUE(data.max_size() == Max_Size); + CHECK_FALSE(data.begin() == data.end()); + } #endif //************************************************************************* diff --git a/test/test_delegate.cpp b/test/test_delegate.cpp index f990e115..c4e870bd 100644 --- a/test/test_delegate.cpp +++ b/test/test_delegate.cpp @@ -96,7 +96,11 @@ namespace MoveableOnlyData& operator=(const MoveableOnlyData&) = delete; MoveableOnlyData(MoveableOnlyData&&) = default; MoveableOnlyData& operator=(MoveableOnlyData&&) = default; - int d; + MoveableOnlyData(int _d) + : d{_d} + { + } + int d; }; //***************************************************************************** @@ -583,6 +587,17 @@ namespace CHECK(parameter_correct); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_free_moveableonly_deduced_type) + { + auto d = etl::delegate::create(); + + d({VALUE1}); // deduce argument type from braced initializer list + + CHECK(function_called == FunctionCalled::Free_Moveableonly_Called); + CHECK(parameter_correct); + } + //************************************************************************* #if ETL_USING_CPP17 TEST_FIXTURE(SetupFixture, test_make_delegate_free_moveableonly) @@ -2167,6 +2182,20 @@ namespace #endif } #endif + + TEST(test_delegate_clear_equals_default_constructed) + { + using delegate_type = etl::delegate; + + delegate_type delegate = {}; + const delegate_type default_constructed; + + CHECK(delegate == default_constructed); + delegate = delegate_type::create(free_int); + CHECK(delegate != default_constructed); + delegate = {}; + CHECK(delegate == default_constructed); + } } } // namespace diff --git a/test/test_deque.cpp b/test/test_deque.cpp index a09f67d5..85365284 100644 --- a/test/test_deque.cpp +++ b/test/test_deque.cpp @@ -2299,6 +2299,53 @@ namespace } #endif + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the element type used to be rejected: + // the old implementation forwarded each argument as T, and forward cannot accept a + // const T lvalue (it requires a non-const T&, and T&& cannot bind to a reference-related + // const lvalue). + TEST(test_make_deque_from_const_lvalues_of_element_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_deque(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + using Type = etl::remove_reference_t; + CHECK((std::is_same::value)); + + CHECK_EQUAL(42, data[0]); + CHECK_EQUAL(43, data[1]); + CHECK_EQUAL(44, data[2]); + } +#endif + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // 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. + TEST(test_make_deque_from_narrowing_values) + { + static const int static_const_int = 45; + const int local_const_int = 46; + int mutable_int = 47; + + auto data = etl::make_deque(0, 1, static_const_int, local_const_int, mutable_int); + + using Type = etl::remove_reference_t; + CHECK((std::is_same::value)); + + CHECK_EQUAL(0, data[0]); + CHECK_EQUAL(1, data[1]); + CHECK_EQUAL(45, data[2]); + CHECK_EQUAL(46, data[3]); + CHECK_EQUAL(47, data[4]); + } +#endif + //************************************************************************* TEST(test_fill) { diff --git a/test/test_expected.cpp b/test/test_expected.cpp index 621727b2..b7bee13d 100644 --- a/test/test_expected.cpp +++ b/test/test_expected.cpp @@ -618,6 +618,20 @@ namespace etl::expected_invalid); } + //************************************************************************* + // See https://github.com/ETLCPP/etl/issues/1532 + TEST(test_dereference_const_and_rvalue_expected) + { + typedef etl::expected Expected1532; + + Expected1532 e = 42; + const Expected1532& ce = e; + + CHECK_EQUAL(42, *e); + CHECK_EQUAL(42, *ce); + CHECK_EQUAL(42, *Expected1532(42)); + } + //************************************************************************* struct value_or_helper { diff --git a/test/test_flat_map.cpp b/test/test_flat_map.cpp index c88bedd9..ae9ddbdd 100644 --- a/test/test_flat_map.cpp +++ b/test/test_flat_map.cpp @@ -1544,6 +1544,29 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_flat_map_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_flat_map(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.at('a')); + CHECK_EQUAL(1, data.at('b')); + CHECK_EQUAL(2, data.at('c')); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_flat_multimap.cpp b/test/test_flat_multimap.cpp index 41962cc2..d1f3ccd9 100644 --- a/test/test_flat_multimap.cpp +++ b/test/test_flat_multimap.cpp @@ -1300,6 +1300,29 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_flat_multimap_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_flat_multimap(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.find('a')->second); + CHECK_EQUAL(1, data.find('b')->second); + CHECK_EQUAL(2, data.find('c')->second); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_flat_multiset.cpp b/test/test_flat_multiset.cpp index 694bb802..2d91748e 100644 --- a/test/test_flat_multiset.cpp +++ b/test/test_flat_multiset.cpp @@ -1293,6 +1293,34 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_flat_multiset_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_flat_multiset(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + auto v = *data.begin(); + using Type = decltype(v); + CHECK((std::is_same::value)); + + decltype(data)::const_iterator itr = data.begin(); + + CHECK_EQUAL(42, *itr); + ++itr; + CHECK_EQUAL(43, *itr); + ++itr; + CHECK_EQUAL(44, *itr); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_flat_set.cpp b/test/test_flat_set.cpp index 1355f8c0..7930c72d 100644 --- a/test/test_flat_set.cpp +++ b/test/test_flat_set.cpp @@ -1292,6 +1292,34 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_flat_set_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_flat_set(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + auto v = *data.begin(); + using Type = decltype(v); + CHECK((std::is_same::value)); + + decltype(data)::const_iterator itr = data.begin(); + + CHECK_EQUAL(42, *itr); + ++itr; + CHECK_EQUAL(43, *itr); + ++itr; + CHECK_EQUAL(44, *itr); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_format.cpp b/test/test_format.cpp index 6fd2cbf4..480345b5 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -218,10 +218,9 @@ namespace { etl::string<100> s; - // mapped to unsigned char - // CHECK_EQUAL("34", test_format(s, "{}", static_cast(34))); - // mapped to signed char - // CHECK_EQUAL("-14", test_format(s, "{}", static_cast(-14))); + // int8_t/uint8_t are formatted as integers (issue #1549), not as characters + CHECK_EQUAL("34", test_format(s, "{}", static_cast(34))); + CHECK_EQUAL("-14", test_format(s, "{}", static_cast(-14))); CHECK_EQUAL("6534", test_format(s, "{}", static_cast(6534))); CHECK_EQUAL("-9414", test_format(s, "{}", static_cast(-9414))); CHECK_EQUAL("236534", test_format(s, "{}", static_cast(236534))); @@ -619,45 +618,35 @@ namespace //************************************************************************* TEST(test_format_signed_char) { + // signed char (typically int8_t) is formatted as an integer by default + // (issue #1549), matching std::format. Only {:c} converts it to a character. + // '?' (debug-escape) is NOT a valid presentation type for signed char. etl::string<100> s; - CHECK_EQUAL("a s b", test_format(s, "a {} b", static_cast('s'))); + CHECK_EQUAL("a 115 b", test_format(s, "a {} b", static_cast('s'))); CHECK_EQUAL("a s b", test_format(s, "a {:c} b", static_cast('s'))); - CHECK_EQUAL("a 's' b", test_format(s, "a {:?} b", static_cast('s'))); - CHECK_EQUAL("a \t b", test_format(s, "a {} b", static_cast('\t'))); - CHECK_EQUAL("a '\\t' b", test_format(s, "a {:?} b", static_cast('\t'))); - CHECK_EQUAL("a '\\n' b", test_format(s, "a {:?} b", static_cast('\n'))); - CHECK_EQUAL("a '\\r' b", test_format(s, "a {:?} b", static_cast('\r'))); - CHECK_EQUAL("a '\\\"' b", test_format(s, "a {:?} b", static_cast('"'))); - CHECK_EQUAL("a '\\'' b", test_format(s, "a {:?} b", static_cast('\''))); - CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); - CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); CHECK_EQUAL("a 97 b", test_format(s, "a {:d} b", static_cast('a'))); CHECK_EQUAL("a 61 b", test_format(s, "a {:X} b", static_cast('a'))); CHECK_EQUAL("a 61 b", test_format(s, "a {:x} b", static_cast('a'))); CHECK_EQUAL("a 0x61 b", test_format(s, "a {:#x} b", static_cast('a'))); + CHECK_EQUAL("a -12 b", test_format(s, "a {} b", static_cast(-12))); } //************************************************************************* TEST(test_format_unsigned_char) { + // unsigned char (typically uint8_t) is formatted as an integer by default + // (issue #1549), matching std::format. Only {:c} converts it to a character. + // '?' (debug-escape) is NOT a valid presentation type for unsigned char. etl::string<100> s; - CHECK_EQUAL("a s b", test_format(s, "a {} b", static_cast('s'))); + CHECK_EQUAL("a 115 b", test_format(s, "a {} b", static_cast('s'))); CHECK_EQUAL("a s b", test_format(s, "a {:c} b", static_cast('s'))); - CHECK_EQUAL("a 's' b", test_format(s, "a {:?} b", static_cast('s'))); - CHECK_EQUAL("a \t b", test_format(s, "a {} b", static_cast('\t'))); - CHECK_EQUAL("a '\\t' b", test_format(s, "a {:?} b", static_cast('\t'))); - CHECK_EQUAL("a '\\n' b", test_format(s, "a {:?} b", static_cast('\n'))); - CHECK_EQUAL("a '\\r' b", test_format(s, "a {:?} b", static_cast('\r'))); - CHECK_EQUAL("a '\\\"' b", test_format(s, "a {:?} b", static_cast('"'))); - CHECK_EQUAL("a '\\'' b", test_format(s, "a {:?} b", static_cast('\''))); - CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); - CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", static_cast('\\'))); CHECK_EQUAL("a 97 b", test_format(s, "a {:d} b", static_cast('a'))); CHECK_EQUAL("a 61 b", test_format(s, "a {:X} b", static_cast('a'))); CHECK_EQUAL("a 61 b", test_format(s, "a {:x} b", static_cast('a'))); CHECK_EQUAL("a 0x61 b", test_format(s, "a {:#x} b", static_cast('a'))); + CHECK_EQUAL("a 65 b", test_format(s, "a {} b", static_cast(65))); } //************************************************************************* diff --git a/test/test_forward_list.cpp b/test/test_forward_list.cpp index 3f805b7f..8687bf82 100644 --- a/test/test_forward_list.cpp +++ b/test/test_forward_list.cpp @@ -1445,6 +1445,117 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues must be accepted and must not + // affect the deduced element type. Guards against the defect fixed for + // make_array and make_deque, which forwarded each argument as the element + // type rather than as its own deduced type and so rejected const lvalues. + TEST(test_make_forward_list_from_const_lvalues_of_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(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + auto v = *data.begin(); + using Type = decltype(v); + CHECK((std::is_same::value)); + + decltype(data)::const_iterator itr = data.begin(); + + CHECK_EQUAL(42, *itr++); + CHECK_EQUAL(43, *itr++); + CHECK_EQUAL(44, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + TEST(test_make_forward_list_common_type_from_mixed_types) + { + auto data = etl::make_forward_list(1, 2L, 3); + + CHECK((std::is_same, decltype(data)>::value)); + + auto itr = data.begin(); + CHECK_EQUAL(1L, *itr++); + CHECK_EQUAL(2L, *itr++); + CHECK_EQUAL(3L, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + struct CopyMoveCounted + { + explicit CopyMoveCounted(int value_) + : value(value_) + { + } + + CopyMoveCounted(const CopyMoveCounted& other) + : value(other.value) + { + ++copy_count; + } + + CopyMoveCounted(CopyMoveCounted&& other) + : value(other.value) + { + ++move_count; + } + + int value; + + static size_t copy_count; + static size_t move_count; + }; + + size_t CopyMoveCounted::copy_count = 0; + size_t CopyMoveCounted::move_count = 0; + + // The arguments must be forwarded into the initializer list, not taken by + // value: a by-value parameter pack would cost an extra move per argument + // (the defect fixed for make_list). Each element is then copied from the + // initializer_list backing array into its node, which is why lvalue + // arguments count two copies. + TEST(test_make_forward_list_argument_copy_and_move_counts) + { + const CopyMoveCounted const_lvalue(1); + CopyMoveCounted mutable_lvalue(2); + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data = etl::make_forward_list(const_lvalue, mutable_lvalue); + + CHECK_EQUAL(4U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + // The exact move counts rely on guaranteed copy elision. Before C++17 the + // returned forward_list may be move-constructed once more, which moves each + // element, so only the copy counts are checked there. + CHECK_EQUAL(0U, CopyMoveCounted::move_count); + #endif + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data2 = etl::make_forward_list(CopyMoveCounted(3)); + + CHECK_EQUAL(1U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + CHECK_EQUAL(1U, CopyMoveCounted::move_count); + #endif + + auto itr = data.begin(); + CHECK_EQUAL(1, (*itr++).value); + CHECK_EQUAL(2, (*itr).value); + CHECK_EQUAL(3, data2.begin()->value); + } +#endif + //************************************************************************* TEST(test_forward_list_exception_types) { diff --git a/test/test_histogram.cpp b/test/test_histogram.cpp index 40f5de20..b0db0263 100644 --- a/test/test_histogram.cpp +++ b/test/test_histogram.cpp @@ -270,7 +270,7 @@ namespace { IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end()); - IntRuntimeOffsetHistogram histogram2(Start); + IntRuntimeOffsetHistogram histogram2(Start + 1); histogram2 = histogram1; for (int key = Start; key < Start + static_cast(Size); ++key) @@ -300,7 +300,7 @@ namespace IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end()); IntRuntimeOffsetHistogram histogram_source(Start, input2.begin(), input2.end()); - IntRuntimeOffsetHistogram histogram2(Start); + IntRuntimeOffsetHistogram histogram2(Start + 1); histogram2 = etl::move(histogram_source); for (int key = Start; key < Start + static_cast(Size); ++key) diff --git a/test/test_indirect_vector.cpp b/test/test_indirect_vector.cpp index f0a5d54e..2d8033cd 100644 --- a/test/test_indirect_vector.cpp +++ b/test/test_indirect_vector.cpp @@ -1621,5 +1621,28 @@ namespace CHECK(std::equal(blank_data.begin(), blank_data.end(), data.begin())); } + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues must be accepted and must not + // affect the deduced element type. Guards against the defect fixed for + // make_array and make_deque, which forwarded each argument as the element + // type rather than as its own deduced type and so rejected const lvalues. + TEST(test_make_indirect_vector_from_const_lvalues_of_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(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + using Type = typename std::remove_reference::type; + CHECK((std::is_same::value)); + + CHECK_EQUAL(42, data[0]); + CHECK_EQUAL(43, data[1]); + CHECK_EQUAL(44, data[2]); + } +#endif } } // namespace diff --git a/test/test_list.cpp b/test/test_list.cpp index 00574f24..767166e7 100644 --- a/test/test_list.cpp +++ b/test/test_list.cpp @@ -2272,5 +2272,110 @@ namespace CHECK_EQUAL(ItemNDC("F"), *itr++); } #endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Const-qualified lvalue arguments must be accepted and must not affect the + // deduced element type (the deduced reference types decay via common_type). + TEST(test_make_list_from_const_lvalues_of_element_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_list(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK((std::is_same, decltype(data)>::value)); + + auto itr = data.begin(); + CHECK_EQUAL(42, *itr++); + CHECK_EQUAL(43, *itr++); + CHECK_EQUAL(44, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + TEST(test_make_list_common_type_from_mixed_types) + { + auto data = etl::make_list(1, 2L, 3); + + CHECK((std::is_same, decltype(data)>::value)); + + auto itr = data.begin(); + CHECK_EQUAL(1L, *itr++); + CHECK_EQUAL(2L, *itr++); + CHECK_EQUAL(3L, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + struct CopyMoveCounted + { + explicit CopyMoveCounted(int value_) + : value(value_) + { + } + + CopyMoveCounted(const CopyMoveCounted& other) + : value(other.value) + { + ++copy_count; + } + + CopyMoveCounted(CopyMoveCounted&& other) + : value(other.value) + { + ++move_count; + } + + int value; + + static size_t copy_count; + static size_t move_count; + }; + + size_t CopyMoveCounted::copy_count = 0; + size_t CopyMoveCounted::move_count = 0; + + // The arguments must be forwarded into the initializer list, not taken by + // value: a by-value parameter pack costs an extra move per argument. + // Each element is then copied from the initializer_list backing array into + // its list node, which is why lvalue arguments count two copies. + TEST(test_make_list_argument_copy_and_move_counts) + { + const CopyMoveCounted const_lvalue(1); + CopyMoveCounted mutable_lvalue(2); + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data = etl::make_list(const_lvalue, mutable_lvalue); + + CHECK_EQUAL(4U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + // The exact move counts rely on guaranteed copy elision. Before C++17 the + // returned list may be move-constructed once more, which moves each element, + // so only the copy counts are checked there. + CHECK_EQUAL(0U, CopyMoveCounted::move_count); + #endif + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data2 = etl::make_list(CopyMoveCounted(3)); + + CHECK_EQUAL(1U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + CHECK_EQUAL(1U, CopyMoveCounted::move_count); + #endif + + auto itr = data.begin(); + CHECK_EQUAL(1, (*itr++).value); + CHECK_EQUAL(2, (*itr).value); + CHECK_EQUAL(3, data2.begin()->value); + } +#endif } } // namespace diff --git a/test/test_map.cpp b/test/test_map.cpp index c57b5b5e..9ce01897 100644 --- a/test/test_map.cpp +++ b/test/test_map.cpp @@ -1765,6 +1765,29 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_map_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_map(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.at('a')); + CHECK_EQUAL(1, data.at('b')); + CHECK_EQUAL(2, data.at('c')); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_message_router_registry.cpp b/test/test_message_router_registry.cpp index 22da80cb..17e27797 100644 --- a/test/test_message_router_registry.cpp +++ b/test/test_message_router_registry.cpp @@ -187,7 +187,7 @@ namespace CHECK_EQUAL(Registry_Size, registry.max_size()); } -#if ETL_USING_STL +#if ETL_HAS_INITIALIZER_LIST //************************************************************************* TEST(test_initializer_list_construction) { diff --git a/test/test_multimap.cpp b/test/test_multimap.cpp index 86f9af0f..4273932b 100644 --- a/test/test_multimap.cpp +++ b/test/test_multimap.cpp @@ -1685,6 +1685,29 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_multimap_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_multimap(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.find('a')->second); + CHECK_EQUAL(1, data.find('b')->second); + CHECK_EQUAL(2, data.find('c')->second); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains_with_transparent_comparator) { diff --git a/test/test_multiset.cpp b/test/test_multiset.cpp index fcbae16a..7a31a65f 100644 --- a/test/test_multiset.cpp +++ b/test/test_multiset.cpp @@ -1608,6 +1608,34 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_multiset_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_multiset(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + auto v = *data.begin(); + using Type = decltype(v); + CHECK((std::is_same::value)); + + decltype(data)::const_iterator itr = data.begin(); + + CHECK_EQUAL(42, *itr); + ++itr; + CHECK_EQUAL(43, *itr); + ++itr; + CHECK_EQUAL(44, *itr); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_numeric.cpp b/test/test_numeric.cpp index f7407fef..8251a27c 100644 --- a/test/test_numeric.cpp +++ b/test/test_numeric.cpp @@ -135,7 +135,6 @@ namespace CHECK_EQUAL(*c, v); } -#if ETL_USING_STL //************************************************************************* TEST(test_midpoint_std_random_access_iterator) { @@ -163,7 +162,6 @@ namespace CHECK_EQUAL(*c, v); } -#endif //************************************************************************* TEST(test_lerp_floating_point) diff --git a/test/test_ranges.cpp b/test/test_ranges.cpp index efe64148..f7a668fe 100644 --- a/test/test_ranges.cpp +++ b/test/test_ranges.cpp @@ -41,7 +41,7 @@ SOFTWARE. // Issue #1391: include when available to verify etl::operator| // does not conflict with std::ranges::operator|. -#if ETL_USING_STL && ETL_USING_CPP20 && defined(__has_include) +#if ETL_USING_CPP20 && defined(__has_include) #if __has_include() #include #endif @@ -473,6 +473,20 @@ namespace CHECK_EQUAL(iv3.empty(), true); } + TEST(test_ranges_iota_view_const) + { + const auto iv = etl::ranges::iota_view(1, 7); + + int compare = 1; + for (auto i : iv) + { + CHECK_EQUAL(i, compare); + ++compare; + } + + CHECK_EQUAL(iv[4], 5); + } + TEST(test_ranges_views_iota) { auto iv = etl::ranges::views::iota(1, 7); @@ -540,6 +554,18 @@ namespace CHECK_EQUAL(iv3.empty(), true); } + TEST(test_ranges_repeat_view_const) + { + const auto rv = etl::ranges::repeat_view(1, 7); + + for (auto i : rv) + { + CHECK_EQUAL(i, 1); + } + + CHECK_EQUAL(rv[4], 1); + } + TEST(test_ranges_views_repeat) { auto iv = etl::ranges::views::repeat(1, 7); diff --git a/test/test_set.cpp b/test/test_set.cpp index 863325c0..e23ca03a 100644 --- a/test/test_set.cpp +++ b/test/test_set.cpp @@ -1465,6 +1465,34 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST_FIXTURE(SetupFixture, test_make_set_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_set(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + auto v = *data.begin(); + using Type = decltype(v); + CHECK((std::is_same::value)); + + decltype(data)::const_iterator itr = data.begin(); + + CHECK_EQUAL(42, *itr); + ++itr; + CHECK_EQUAL(43, *itr); + ++itr; + CHECK_EQUAL(44, *itr); + } +#endif + //************************************************************************* TEST_FIXTURE(SetupFixture, test_contains) { diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index b19a4032..05f56880 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -983,6 +983,51 @@ namespace CHECK((std::is_same_v>)); } + //************************************************************************* + TEST(test_template_deduction_guide_for_std_vector) + { + std::vector data = {1, 2, 3, 4}; + const std::vector data2 = {1, 2, 3, 4}; + + etl::span span = data; + etl::span span2 = data2; + + CHECK_EQUAL(etl::dynamic_extent, span.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data), span.size()); + CHECK_EQUAL(etl::dynamic_extent, span2.extent); + CHECK_EQUAL(ETL_OR_STD17::size(data2), span2.size()); + + CHECK((std::is_same_v>)); + CHECK((std::is_same_v>)); + } + + //************************************************************************* + TEST(test_template_deduction_guide_for_type_with_data_and_size) + { + struct DataAndSize + { + int buffer[4] = {1, 2, 3, 4}; + int* data() + { + return buffer; + } + size_t size() const + { + return 4U; + } + + using value_type = int; + }; + + DataAndSize data; + + etl::span span = data; + + CHECK_EQUAL(etl::dynamic_extent, span.extent); + CHECK_EQUAL(data.size(), span.size()); + CHECK((std::is_same_v>)); + } + //************************************************************************* TEST(test_template_deduction_guide_for_iterators) { diff --git a/test/test_tuple.cpp b/test/test_tuple.cpp index d3816d6f..18b10bdf 100644 --- a/test/test_tuple.cpp +++ b/test/test_tuple.cpp @@ -76,6 +76,32 @@ namespace int i; }; + //********************************* + int apply_sum(int a, int b, int c) + { + return a + b + c; + } + + //********************************* + struct Summer + { + int operator()(int a, int b) const + { + return a + b; + } + }; + + //********************************* + struct Accumulator + { + int total; + + void add(int a, int b) + { + total = a + b; + } + }; + SUITE(test_tuple) { //************************************************************************* @@ -930,5 +956,61 @@ namespace CHECK_EQUAL(1, i); CHECK_EQUAL(std::string("2"), d.value); } + + //************************************************************************* + TEST(test_apply_free_function) + { + etl::tuple t(1, 2, 3); + + CHECK_EQUAL(6, etl::apply(apply_sum, t)); + } + + //************************************************************************* + TEST(test_apply_function_object) + { + etl::tuple t(10, 20); + + CHECK_EQUAL(30, etl::apply(Summer(), t)); + } + + //************************************************************************* +#if ETL_USING_CPP11 + TEST(test_apply_lambda) + { + etl::tuple t(2, 3, 4); + + int result = etl::apply([](int a, int b, int c) { return a * b * c; }, t); + + CHECK_EQUAL(24, result); + } +#endif + + //************************************************************************* + TEST(test_apply_member_function) + { + Accumulator acc = {0}; + + etl::apply(&Accumulator::add, etl::make_tuple(&acc, 5, 7)); + + CHECK_EQUAL(12, acc.total); + } + + //************************************************************************* + TEST(test_apply_rvalue_tuple) + { + CHECK_EQUAL(6, etl::apply(apply_sum, etl::make_tuple(1, 2, 3))); + } + + //************************************************************************* +#if ETL_USING_CPP11 + TEST(test_apply_empty_tuple) + { + etl::tuple<> t; + + int result = etl::apply([]() { return 42; }, t); + + CHECK_EQUAL(42, result); + } +#endif } } // namespace diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index 6756d6d9..531557de 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -759,6 +759,7 @@ namespace CHECK(etl::is_fundamental::value == std::is_fundamental::value); CHECK(etl::is_fundamental::value == std::is_fundamental::value); #if ETL_USING_STL + // etl::is_fundamental does not report std::nullptr_t as fundamental when not using the STL. CHECK(etl::is_fundamental::value == std::is_fundamental::value); #endif } @@ -2268,5 +2269,23 @@ namespace CHECK_TRUE(etl::is_unsigned::value); #endif } + +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_common_type) + { + // Reference types must decay to the same result as std::common_type. + CHECK((etl::is_same, long>::value)); + CHECK((etl::is_same, std::common_type::type>::value)); + CHECK((etl::is_same, long>::value)); + CHECK((etl::is_same, std::common_type::type>::value)); + CHECK((etl::is_same, char>::value)); + CHECK((etl::is_same, std::common_type::type>::value)); + + // Already decayed types. + CHECK((etl::is_same, long>::value)); + CHECK((etl::is_same, std::common_type::type>::value)); + } +#endif } } // namespace diff --git a/test/test_unaligned_type.cpp b/test/test_unaligned_type.cpp index 62cf500e..ad1e50c9 100644 --- a/test/test_unaligned_type.cpp +++ b/test/test_unaligned_type.cpp @@ -34,9 +34,69 @@ SOFTWARE. #include "etl/private/diagnostic_useless_cast_push.h" #include +#include namespace { + //*************************************************************************** + /// Representation level helpers. + /// 'memcpy' is used rather than 'etl::bit_cast' so that these work in every + /// configuration, including those without a bit_cast builtin. + //*************************************************************************** + uint32_t bits_of(float value) + { + uint32_t bits = 0U; + std::memcpy(&bits, &value, sizeof(bits)); + return bits; + } + + //*************************************************************************** + float float_from_bits(uint32_t bits) + { + float value = 0.0f; + std::memcpy(&value, &bits, sizeof(value)); + return value; + } + + //*************************************************************************** + uint64_t bits_of(double value) + { + uint64_t bits = 0U; + std::memcpy(&bits, &value, sizeof(bits)); + return bits; + } + + //*************************************************************************** + double double_from_bits(uint64_t bits) + { + double value = 0.0; + std::memcpy(&value, &bits, sizeof(value)); + return value; + } + +#if ETL_USING_CPP14 && ETL_USING_BUILTIN_BIT_CAST + //*************************************************************************** + /// Encodes 'bits' as a floating point value in the storage of 'TUnaligned', + /// then decodes it back, returning the resulting bit pattern. + /// Used to check that the constexpr bit_cast path is representation + /// preserving. + //*************************************************************************** + template + constexpr TBits round_trip_bits(TBits bits) + { + return etl::bit_cast(TUnaligned(etl::bit_cast(bits)).value()); + } + + //*************************************************************************** + /// The storage byte at 'index' when 'bits' is encoded in 'TUnaligned'. + //*************************************************************************** + template + constexpr unsigned char storage_byte_of(TBits bits, size_t index) + { + return TUnaligned(etl::bit_cast(bits)).data()[index]; + } +#endif + SUITE(test_unaligned_type) { //************************************************************************* @@ -175,6 +235,490 @@ namespace CHECK_THROW(etl::be_uint32_t be_v3(buffer.data(), buffer.size() - 1), etl::unaligned_type_buffer_size); } + //************************************************************************* + /// The 'const unsigned char*' overloads are distinct from the + /// 'const void*' ones above, so check their buffer size contract too. + /// Note that the size check is an ETL_ASSERT, so this only holds when + /// checks are enabled. See the note on the constructor. + //************************************************************************* + TEST(test_construction_from_byte_buffer_size_boundary) + { + const std::array buffer = {0x12, 0x34, 0x56, 0x78, 0x9A}; + + // Exactly the required number of bytes. + etl::le_uint32_t le_exact(buffer.data(), sizeof(uint32_t)); + etl::be_uint32_t be_exact(buffer.data(), sizeof(uint32_t)); + + CHECK_EQUAL(uint32_t(0x78563412), le_exact.value()); + CHECK_EQUAL(uint32_t(0x12345678), be_exact.value()); + + // More bytes than required. The surplus is ignored. + etl::le_uint32_t le_larger(buffer.data(), buffer.size()); + etl::be_uint32_t be_larger(buffer.data(), buffer.size()); + + CHECK_EQUAL(uint32_t(0x78563412), le_larger.value()); + CHECK_EQUAL(uint32_t(0x12345678), be_larger.value()); + + // One byte short. + CHECK_THROW(etl::le_uint32_t le_short(buffer.data(), sizeof(uint32_t) - 1U), etl::unaligned_type_buffer_size); + CHECK_THROW(etl::be_uint32_t be_short(buffer.data(), sizeof(uint32_t) - 1U), etl::unaligned_type_buffer_size); + + // Empty buffer. + CHECK_THROW(etl::le_uint32_t le_empty(buffer.data(), 0U), etl::unaligned_type_buffer_size); + CHECK_THROW(etl::be_uint32_t be_empty(buffer.data(), 0U), etl::unaligned_type_buffer_size); + + // The widest type is checked too, as it has the largest storage. + CHECK_THROW(etl::le_uint64_t le_wide(buffer.data(), buffer.size()), etl::unaligned_type_buffer_size); + CHECK_THROW(etl::be_uint64_t be_wide(buffer.data(), buffer.size()), etl::unaligned_type_buffer_size); + + // Single byte types accept a single byte buffer. + etl::le_uint8_t le_byte(buffer.data(), 1U); + etl::be_uint8_t be_byte(buffer.data(), 1U); + + CHECK_EQUAL(uint8_t(0x12), le_byte.value()); + CHECK_EQUAL(uint8_t(0x12), be_byte.value()); + + CHECK_THROW(etl::le_uint8_t le_byte_empty(buffer.data(), 0U), etl::unaligned_type_buffer_size); + CHECK_THROW(etl::be_uint8_t be_byte_empty(buffer.data(), 0U), etl::unaligned_type_buffer_size); + } + + //************************************************************************* + // The following tests demonstrate the 'decode' direction: given a raw byte + // buffer (e.g. as received from a file, network socket or memory-mapped + // device), interpret it as an explicitly little/big endian unaligned_type + // and read back the correctly decoded native value. + //************************************************************************* + TEST(test_decode_buffer_uint16) + { + // The same two bytes, interpreted with an explicit endianness. + const std::array buffer = {0x12, 0x34}; + + etl::le_uint16_t le_v(buffer.data(), buffer.size()); + etl::be_uint16_t be_v(buffer.data(), buffer.size()); + + CHECK_EQUAL(uint16_t(0x3412), le_v.value()); + CHECK_EQUAL(uint16_t(0x1234), be_v.value()); + } + + //************************************************************************* + // 'bool' has no 'make_unsigned' equivalent, so check that it is supported. + TEST(test_bool) + { + etl::unaligned_type le_v(true); + etl::unaligned_type be_v(false); + + CHECK_EQUAL(true, le_v.value()); + CHECK_EQUAL(false, be_v.value()); + + le_v = false; + be_v = true; + + CHECK_EQUAL(false, le_v.value()); + CHECK_EQUAL(true, be_v.value()); + } + + //************************************************************************* + TEST(test_decode_buffer_int32) + { + const std::array buffer = {0x12, 0x34, 0x56, 0x78}; + + etl::le_int32_t le_v(buffer.data(), buffer.size()); + etl::be_int32_t be_v(buffer.data(), buffer.size()); + + CHECK_EQUAL(int32_t(0x78563412), le_v.value()); + CHECK_EQUAL(int32_t(0x12345678), be_v.value()); + } + + //************************************************************************* + TEST(test_decode_buffer_uint64) + { + const std::array buffer = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + + etl::le_uint64_t le_v(buffer.data(), buffer.size()); + etl::be_uint64_t be_v(buffer.data(), buffer.size()); + + CHECK_EQUAL(uint64_t(0xEFCDAB8967452301), le_v.value()); + CHECK_EQUAL(uint64_t(0x0123456789ABCDEF), be_v.value()); + } + + //************************************************************************* + /// The decode tests above cover a subset of the widths only, and no + /// negative or extreme values. These cover every signed and unsigned + /// width at its boundary values, in both directions. + //************************************************************************* + template + void check_boundary_value(TValue value) + { + ETL_STATIC_ASSERT(sizeof(TValue) == TLittle::Size, "Mismatched size"); + ETL_STATIC_ASSERT(sizeof(TValue) == TBig::Size, "Mismatched size"); + + const TLittle le_v(value); + const TBig be_v(value); + + // The two encodings are byte reversals of each other. + for (size_t i = 0U; i < sizeof(TValue); ++i) + { + CHECK_EQUAL(int(le_v.data()[i]), int(be_v.data()[sizeof(TValue) - 1U - i])); + } + + // Decoding the encoded bytes returns the original value. + CHECK_EQUAL(value, TLittle(le_v.data(), sizeof(TValue)).value()); + CHECK_EQUAL(value, TBig(be_v.data(), sizeof(TValue)).value()); + } + + //************************************************************************* + TEST(test_integral_boundary_values) + { + check_boundary_value(0); + check_boundary_value(-1); + check_boundary_value(etl::integral_limits::min); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0U); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0); + check_boundary_value(-1); + check_boundary_value(etl::integral_limits::min); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0U); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0); + check_boundary_value(-1); + check_boundary_value(etl::integral_limits::min); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0U); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0); + check_boundary_value(-1); + check_boundary_value(etl::integral_limits::min); + check_boundary_value(etl::integral_limits::max); + + check_boundary_value(0U); + check_boundary_value(etl::integral_limits::max); + } + + //************************************************************************* + /// Explicit byte level checks for the widths that the decode tests above + /// do not cover, using negative values so that the sign bit is exercised. + //************************************************************************* + TEST(test_decode_buffer_negative_values) + { + // -2 == 0xFE, 0xFFFE, 0xFFFFFFFE, 0xFFFFFFFFFFFFFFFE. + const std::array buffer = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + CHECK_EQUAL(int8_t(-2), etl::le_int8_t(buffer.data(), buffer.size()).value()); + CHECK_EQUAL(int8_t(-2), etl::be_int8_t(buffer.data(), buffer.size()).value()); + + CHECK_EQUAL(int16_t(-2), etl::le_int16_t(buffer.data(), buffer.size()).value()); + CHECK_EQUAL(int32_t(-2), etl::le_int32_t(buffer.data(), buffer.size()).value()); + CHECK_EQUAL(int64_t(-2), etl::le_int64_t(buffer.data(), buffer.size()).value()); + + // Big endian reads the same bytes in the opposite order. + CHECK_EQUAL(int16_t(-257), etl::be_int16_t(buffer.data(), buffer.size()).value()); + CHECK_EQUAL(int32_t(-16777217), etl::be_int32_t(buffer.data(), buffer.size()).value()); + CHECK_EQUAL(int64_t(-72057594037927937LL), etl::be_int64_t(buffer.data(), buffer.size()).value()); + } + + //************************************************************************* + TEST(test_decode_buffer_float) + { + // 1.5f in IEEE-754 single precision is 0x3FC00000. + const std::array le_buffer = {0x00, 0x00, 0xC0, 0x3F}; + const std::array be_buffer = {0x3F, 0xC0, 0x00, 0x00}; + + etl::le_float_t le_v(le_buffer.data(), le_buffer.size()); + etl::be_float_t be_v(be_buffer.data(), be_buffer.size()); + + CHECK_EQUAL(1.5f, le_v.value()); + CHECK_EQUAL(1.5f, be_v.value()); + } + + //************************************************************************* + TEST(test_decode_buffer_double) + { + // 1.5 in IEEE-754 double precision is 0x3FF8000000000000. + const std::array le_buffer = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F}; + const std::array be_buffer = {0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + etl::le_double_t le_v(le_buffer.data(), le_buffer.size()); + etl::be_double_t be_v(be_buffer.data(), be_buffer.size()); + + CHECK_EQUAL(1.5, le_v.value()); + CHECK_EQUAL(1.5, be_v.value()); + } + + //************************************************************************* + /// Representation level checks for 'float'. + /// Ordinary values such as 1.5f have a zero mantissa tail, a clear sign + /// bit and a mid range exponent, so they would still pass under several + /// plausible masking or byte ordering faults. These patterns exercise the + /// sign of zero, the infinities, a NaN payload, the subnormal range and + /// the normal range limits. + //************************************************************************* + TEST(test_float_representations) + { + static const uint32_t patterns[] = { + 0x00000000U, // +0.0 + 0x80000000U, // -0.0 + 0x7F800000U, // +infinity + 0xFF800000U, // -infinity + 0x7FC0DEADU, // Quiet NaN with a payload. + 0xFFC0DEADU, // Negative quiet NaN with a payload. + 0x00000001U, // Smallest positive subnormal. + 0x007FFFFFU, // Largest subnormal. + 0x00800000U, // Smallest positive normal. + 0x7F7FFFFFU, // Largest normal. + 0xBFC00000U // -1.5 + }; + + for (size_t i = 0U; i < (sizeof(patterns) / sizeof(patterns[0])); ++i) + { + const uint32_t bits = patterns[i]; + + etl::le_float_t le_v(float_from_bits(bits)); + etl::be_float_t be_v(float_from_bits(bits)); + + // The storage must hold the exact IEEE-754 bytes, in the requested order. + for (size_t b = 0U; b < sizeof(float); ++b) + { + CHECK_EQUAL(int((bits >> (8U * b)) & 0xFFU), int(le_v.data()[b])); + CHECK_EQUAL(int((bits >> (8U * (sizeof(float) - 1U - b))) & 0xFFU), int(be_v.data()[b])); + } + + // The value must survive the round trip bit for bit, including the + // sign of zero and the NaN payload. + CHECK_EQUAL(bits, bits_of(le_v.value())); + CHECK_EQUAL(bits, bits_of(be_v.value())); + + // Decoding the raw bytes must give the same result as encoding them. + etl::le_float_t le_decoded(le_v.data(), le_v.size()); + etl::be_float_t be_decoded(be_v.data(), be_v.size()); + + CHECK_EQUAL(bits, bits_of(le_decoded.value())); + CHECK_EQUAL(bits, bits_of(be_decoded.value())); + } + } + + //************************************************************************* + /// Representation level checks for 'double'. See the note on the 'float' + /// test above. + //************************************************************************* + TEST(test_double_representations) + { + static const uint64_t patterns[] = { + 0x0000000000000000ULL, // +0.0 + 0x8000000000000000ULL, // -0.0 + 0x7FF0000000000000ULL, // +infinity + 0xFFF0000000000000ULL, // -infinity + 0x7FF80000DEADBEEFULL, // Quiet NaN with a payload. + 0xFFF80000DEADBEEFULL, // Negative quiet NaN with a payload. + 0x0000000000000001ULL, // Smallest positive subnormal. + 0x000FFFFFFFFFFFFFULL, // Largest subnormal. + 0x0010000000000000ULL, // Smallest positive normal. + 0x7FEFFFFFFFFFFFFFULL, // Largest normal. + 0xBFF8000000000000ULL // -1.5 + }; + + for (size_t i = 0U; i < (sizeof(patterns) / sizeof(patterns[0])); ++i) + { + const uint64_t bits = patterns[i]; + + etl::le_double_t le_v(double_from_bits(bits)); + etl::be_double_t be_v(double_from_bits(bits)); + + for (size_t b = 0U; b < sizeof(double); ++b) + { + CHECK_EQUAL(int((bits >> (8U * b)) & 0xFFU), int(le_v.data()[b])); + CHECK_EQUAL(int((bits >> (8U * (sizeof(double) - 1U - b))) & 0xFFU), int(be_v.data()[b])); + } + + CHECK_EQUAL(bits, bits_of(le_v.value())); + CHECK_EQUAL(bits, bits_of(be_v.value())); + + etl::le_double_t le_decoded(le_v.data(), le_v.size()); + etl::be_double_t be_decoded(be_v.data(), be_v.size()); + + CHECK_EQUAL(bits, bits_of(le_decoded.value())); + CHECK_EQUAL(bits, bits_of(be_decoded.value())); + } + } + + //************************************************************************* + /// 'long double' is typically 80, 96 or 128 bits wide, so it has no same + /// sized unsigned integer proxy and falls back to the non bit_cast, + /// non constexpr path. That fallback still has to work. + //************************************************************************* + TEST(test_long_double_round_trip) + { + const long double value = 1.5L; + + etl::le_long_double_t le_v(value); + etl::be_long_double_t be_v(value); + + CHECK_EQUAL(sizeof(long double), le_v.size()); + CHECK_EQUAL(sizeof(long double), be_v.size()); + + // The little and big endian storage must be byte reversals of each other. + for (size_t i = 0U; i < sizeof(long double); ++i) + { + CHECK_EQUAL(int(le_v.data()[i]), int(be_v.data()[sizeof(long double) - 1U - i])); + } + + CHECK_EQUAL(value, le_v.value()); + CHECK_EQUAL(value, be_v.value()); + + // Decoding the raw bytes must give the same result as encoding them. + etl::le_long_double_t le_decoded(le_v.data(), le_v.size()); + etl::be_long_double_t be_decoded(be_v.data(), be_v.size()); + + CHECK_EQUAL(value, le_decoded.value()); + CHECK_EQUAL(value, be_decoded.value()); + } + +#if ETL_HAS_CONSTEXPR_ENDIANNESS + //************************************************************************* + TEST(test_decode_buffer_host_order) + { + // Decoding a buffer known to be in host order must yield the same + // value regardless of what that host order actually is. + const uint32_t value = 0x12345678U; + + const etl::host_uint32_t encoded(value); + etl::host_uint32_t decoded(encoded.data(), encoded.size()); + + CHECK_EQUAL(value, decoded.value()); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + // Demonstrates that decoding a raw byte buffer with an explicit endianness + // is now usable at compile time (constexpr), via the 'const unsigned char*' + // constructor overloads - not just runtime CHECK_EQUAL. + //************************************************************************* + TEST(test_constexpr_decode_buffer_integral) + { + static ETL_CONSTANT unsigned char le_buffer[4] = {0x78, 0x56, 0x34, 0x12}; + static ETL_CONSTANT unsigned char be_buffer[4] = {0x12, 0x34, 0x56, 0x78}; + + constexpr etl::le_uint32_t le_v(le_buffer, sizeof(le_buffer)); + constexpr etl::be_uint32_t be_v(be_buffer, sizeof(be_buffer)); + + static_assert(le_v.value() == 0x12345678U, "le_uint32_t constexpr decode from buffer + size"); + static_assert(be_v.value() == 0x12345678U, "be_uint32_t constexpr decode from buffer + size"); + + // Buffer-only overload (no explicit size). + constexpr etl::le_uint32_t le_v2(le_buffer); + constexpr etl::be_uint32_t be_v2(be_buffer); + + static_assert(le_v2.value() == 0x12345678U, "le_uint32_t constexpr decode from buffer"); + static_assert(be_v2.value() == 0x12345678U, "be_uint32_t constexpr decode from buffer"); + + // Prove the checks above are genuine compile-time facts, not just + // syntactically valid constexpr, by also exercising them at runtime. + CHECK_EQUAL(0x12345678U, le_v.value()); + CHECK_EQUAL(0x12345678U, be_v.value()); + } + + #if ETL_USING_BUILTIN_BIT_CAST + //************************************************************************* + TEST(test_constexpr_decode_buffer_float) + { + // 1.5f in IEEE-754 single precision is 0x3FC00000. + static ETL_CONSTANT unsigned char le_buffer[4] = {0x00, 0x00, 0xC0, 0x3F}; + static ETL_CONSTANT unsigned char be_buffer[4] = {0x3F, 0xC0, 0x00, 0x00}; + + constexpr etl::le_float_t le_v(le_buffer, sizeof(le_buffer)); + constexpr etl::be_float_t be_v(be_buffer, sizeof(be_buffer)); + + // Bit patterns are compared, rather than the float values, to avoid + // '-Wfloat-equal'. + static_assert(etl::bit_cast(le_v.value()) == 0x3FC00000U, "le_float_t constexpr decode from buffer"); + static_assert(etl::bit_cast(be_v.value()) == 0x3FC00000U, "be_float_t constexpr decode from buffer"); + + CHECK_EQUAL(1.5f, le_v.value()); + CHECK_EQUAL(1.5f, be_v.value()); + } + + //************************************************************************* + /// The constexpr path bit_casts through a same sized unsigned integer. + /// Check, at compile time, that this is exact for the awkward + /// representations too, not just for ordinary values such as 1.5f. + //************************************************************************* + TEST(test_constexpr_float_representations) + { + // Encode, then decode, and require the bit pattern to be unchanged. + static_assert(round_trip_bits(0x00000000U) == 0x00000000U, "le +0.0"); + static_assert(round_trip_bits(0x80000000U) == 0x80000000U, "le -0.0"); + static_assert(round_trip_bits(0x7F800000U) == 0x7F800000U, "le +infinity"); + static_assert(round_trip_bits(0xFF800000U) == 0xFF800000U, "le -infinity"); + static_assert(round_trip_bits(0x7FC0DEADU) == 0x7FC0DEADU, "le NaN payload"); + static_assert(round_trip_bits(0x00000001U) == 0x00000001U, "le smallest subnormal"); + static_assert(round_trip_bits(0x007FFFFFU) == 0x007FFFFFU, "le largest subnormal"); + static_assert(round_trip_bits(0x00800000U) == 0x00800000U, "le smallest normal"); + static_assert(round_trip_bits(0x7F7FFFFFU) == 0x7F7FFFFFU, "le largest normal"); + + static_assert(round_trip_bits(0x80000000U) == 0x80000000U, "be -0.0"); + static_assert(round_trip_bits(0xFF800000U) == 0xFF800000U, "be -infinity"); + static_assert(round_trip_bits(0x7FC0DEADU) == 0x7FC0DEADU, "be NaN payload"); + static_assert(round_trip_bits(0x00000001U) == 0x00000001U, "be smallest subnormal"); + static_assert(round_trip_bits(0x7F7FFFFFU) == 0x7F7FFFFFU, "be largest normal"); + + // The stored bytes must be the IEEE-754 bytes, in the requested order. + static_assert(storage_byte_of(0x7FC0DEADU, 0U) == 0xAD, "le NaN byte 0"); + static_assert(storage_byte_of(0x7FC0DEADU, 1U) == 0xDE, "le NaN byte 1"); + static_assert(storage_byte_of(0x7FC0DEADU, 2U) == 0xC0, "le NaN byte 2"); + static_assert(storage_byte_of(0x7FC0DEADU, 3U) == 0x7F, "le NaN byte 3"); + + static_assert(storage_byte_of(0x7FC0DEADU, 0U) == 0x7F, "be NaN byte 0"); + static_assert(storage_byte_of(0x7FC0DEADU, 1U) == 0xC0, "be NaN byte 1"); + static_assert(storage_byte_of(0x7FC0DEADU, 2U) == 0xDE, "be NaN byte 2"); + static_assert(storage_byte_of(0x7FC0DEADU, 3U) == 0xAD, "be NaN byte 3"); + + // Prove the checks above are genuine compile time facts, not just + // syntactically valid constexpr, by also exercising them at runtime. + CHECK_EQUAL(0x80000000U, (round_trip_bits(0x80000000U))); + CHECK_EQUAL(0x7FC0DEADU, (round_trip_bits(0x7FC0DEADU))); + } + + //************************************************************************* + /// As 'test_constexpr_float_representations', for the 8 byte proxy. + //************************************************************************* + TEST(test_constexpr_double_representations) + { + static_assert(round_trip_bits(0x0000000000000000ULL) == 0x0000000000000000ULL, "le +0.0"); + static_assert(round_trip_bits(0x8000000000000000ULL) == 0x8000000000000000ULL, "le -0.0"); + static_assert(round_trip_bits(0x7FF0000000000000ULL) == 0x7FF0000000000000ULL, "le +infinity"); + static_assert(round_trip_bits(0xFFF0000000000000ULL) == 0xFFF0000000000000ULL, "le -infinity"); + static_assert(round_trip_bits(0x7FF80000DEADBEEFULL) == 0x7FF80000DEADBEEFULL, "le NaN payload"); + static_assert(round_trip_bits(0x0000000000000001ULL) == 0x0000000000000001ULL, "le smallest subnormal"); + static_assert(round_trip_bits(0x000FFFFFFFFFFFFFULL) == 0x000FFFFFFFFFFFFFULL, "le largest subnormal"); + static_assert(round_trip_bits(0x0010000000000000ULL) == 0x0010000000000000ULL, "le smallest normal"); + static_assert(round_trip_bits(0x7FEFFFFFFFFFFFFFULL) == 0x7FEFFFFFFFFFFFFFULL, "le largest normal"); + + static_assert(round_trip_bits(0x8000000000000000ULL) == 0x8000000000000000ULL, "be -0.0"); + static_assert(round_trip_bits(0xFFF0000000000000ULL) == 0xFFF0000000000000ULL, "be -infinity"); + static_assert(round_trip_bits(0x7FF80000DEADBEEFULL) == 0x7FF80000DEADBEEFULL, "be NaN payload"); + static_assert(round_trip_bits(0x0000000000000001ULL) == 0x0000000000000001ULL, "be smallest subnormal"); + static_assert(round_trip_bits(0x7FEFFFFFFFFFFFFFULL) == 0x7FEFFFFFFFFFFFFFULL, "be largest normal"); + + static_assert(storage_byte_of(0x7FF80000DEADBEEFULL, 0U) == 0xEF, "le NaN byte 0"); + static_assert(storage_byte_of(0x7FF80000DEADBEEFULL, 7U) == 0x7F, "le NaN byte 7"); + + static_assert(storage_byte_of(0x7FF80000DEADBEEFULL, 0U) == 0x7F, "be NaN byte 0"); + static_assert(storage_byte_of(0x7FF80000DEADBEEFULL, 7U) == 0xEF, "be NaN byte 7"); + + CHECK_EQUAL(0x8000000000000000ULL, (round_trip_bits(0x8000000000000000ULL))); + CHECK_EQUAL(0x7FF80000DEADBEEFULL, (round_trip_bits(0x7FF80000DEADBEEFULL))); + } + #endif +#endif + //************************************************************************* TEST(test_endianness) { @@ -1122,6 +1666,74 @@ namespace CHECK_EQUAL(value, uint16_t(be_from_host)); } #endif + +#if ETL_USING_CPP14 + //************************************************************************* + // Demonstrates that integral endian conversion is now usable at compile + // time (constexpr), via genuine static_assert checks - not just runtime + // CHECK_EQUAL. The conversion is evaluated entirely by the compiler. + //************************************************************************* + TEST(test_constexpr_integral_endian_conversion) + { + // Constructing from a value and reading it back via value()/operator T() + // is constexpr for integral types, regardless of endianness. + constexpr etl::le_uint32_t le_v(0x12345678U); + constexpr etl::be_uint32_t be_v(0x12345678U); + + static_assert(le_v.value() == 0x12345678U, "le_uint32_t constexpr value() round trip"); + static_assert(be_v.value() == 0x12345678U, "be_uint32_t constexpr value() round trip"); + + static_assert(uint32_t(le_v) == 0x12345678U, "le_uint32_t constexpr operator T() round trip"); + static_assert(uint32_t(be_v) == 0x12345678U, "be_uint32_t constexpr operator T() round trip"); + + // Verify the underlying byte order is also usable at compile time. + static_assert(le_v.data()[0] == 0x78, "le_uint32_t constexpr byte 0"); + static_assert(le_v.data()[1] == 0x56, "le_uint32_t constexpr byte 1"); + static_assert(le_v.data()[2] == 0x34, "le_uint32_t constexpr byte 2"); + static_assert(le_v.data()[3] == 0x12, "le_uint32_t constexpr byte 3"); + + static_assert(be_v.data()[0] == 0x12, "be_uint32_t constexpr byte 0"); + static_assert(be_v.data()[1] == 0x34, "be_uint32_t constexpr byte 1"); + static_assert(be_v.data()[2] == 0x56, "be_uint32_t constexpr byte 2"); + static_assert(be_v.data()[3] == 0x78, "be_uint32_t constexpr byte 3"); + + // Prove the checks above are genuine compile-time facts, not just + // syntactically valid constexpr, by also exercising them at runtime. + CHECK_EQUAL(0x12345678U, uint32_t(le_v)); + CHECK_EQUAL(0x12345678U, uint32_t(be_v)); + } +#endif + +#if ETL_USING_CPP14 && ETL_USING_BUILTIN_BIT_CAST + //************************************************************************* + // Demonstrates that floating point endian conversion is now usable at + // compile time (constexpr) too, via etl::bit_cast (no std::bit_cast or + // STL dependency required). + //************************************************************************* + TEST(test_constexpr_float_endian_conversion) + { + constexpr etl::le_float_t le_v(1.5f); + constexpr etl::be_float_t be_v(1.5f); + + // Bit patterns are compared, rather than the float values, to avoid + // '-Wfloat-equal'. + static_assert(etl::bit_cast(le_v.value()) == 0x3FC00000U, "le_float_t constexpr value() round trip"); + static_assert(etl::bit_cast(be_v.value()) == 0x3FC00000U, "be_float_t constexpr value() round trip"); + + static_assert(etl::bit_cast(float(le_v)) == 0x3FC00000U, "le_float_t constexpr operator T() round trip"); + static_assert(etl::bit_cast(float(be_v)) == 0x3FC00000U, "be_float_t constexpr operator T() round trip"); + + // LE and BE storage bytes must be the reverse of each other, checked at + // compile time. + static_assert(le_v.data()[0] == be_v.data()[3], "byte 0/3 mismatch"); + static_assert(le_v.data()[1] == be_v.data()[2], "byte 1/2 mismatch"); + static_assert(le_v.data()[2] == be_v.data()[1], "byte 2/1 mismatch"); + static_assert(le_v.data()[3] == be_v.data()[0], "byte 3/0 mismatch"); + + CHECK_EQUAL(1.5f, float(le_v)); + CHECK_EQUAL(1.5f, float(be_v)); + } +#endif } } // namespace diff --git a/test/test_unordered_map.cpp b/test/test_unordered_map.cpp index 793343eb..57ccd928 100644 --- a/test/test_unordered_map.cpp +++ b/test/test_unordered_map.cpp @@ -1484,5 +1484,28 @@ namespace CHECK_TRUE(data.contains("FF")); CHECK_FALSE(data.contains(not_inserted)); } + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST(test_make_unordered_map_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_unordered_map(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.at('a')); + CHECK_EQUAL(1, data.at('b')); + CHECK_EQUAL(2, data.at('c')); + } +#endif } } // namespace diff --git a/test/test_unordered_multimap.cpp b/test/test_unordered_multimap.cpp index bf2c2aa6..2207f642 100644 --- a/test/test_unordered_multimap.cpp +++ b/test/test_unordered_multimap.cpp @@ -1243,5 +1243,28 @@ namespace CHECK_TRUE(data.contains("FF")); CHECK_FALSE(data.contains(not_inserted)); } + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the pair type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST(test_make_unordered_multimap_from_const_lvalues_of_pair_type) + { + using Pair = ETL_OR_STD::pair; + + static const Pair static_const_lvalue('a', 0); + const Pair local_const_lvalue('b', 1); + Pair mutable_lvalue('c', 2); + + auto data = etl::make_unordered_multimap(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(0, data.find('a')->second); + CHECK_EQUAL(1, data.find('b')->second); + CHECK_EQUAL(2, data.find('c')->second); + } +#endif } } // namespace diff --git a/test/test_unordered_multiset.cpp b/test/test_unordered_multiset.cpp index 9a05aca8..862baa6c 100644 --- a/test/test_unordered_multiset.cpp +++ b/test/test_unordered_multiset.cpp @@ -1113,5 +1113,26 @@ namespace CHECK_TRUE(data.contains("FF")); CHECK_FALSE(data.contains(not_inserted)); } + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST(test_make_unordered_multiset_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_unordered_multiset(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(1U, data.count(42)); + CHECK_EQUAL(1U, data.count(43)); + CHECK_EQUAL(1U, data.count(44)); + } +#endif } } // namespace diff --git a/test/test_unordered_set.cpp b/test/test_unordered_set.cpp index da0831c8..cd959a2a 100644 --- a/test/test_unordered_set.cpp +++ b/test/test_unordered_set.cpp @@ -1122,6 +1122,27 @@ namespace CHECK_TRUE(data.contains("FF")); CHECK_FALSE(data.contains(not_inserted)); } + + //************************************************************************* +#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues of the key type must be + // accepted. Guards against the defect fixed for make_array and make_deque, + // which forwarded each argument as the element type rather than as its own + // deduced type and so rejected const lvalues. + TEST(test_make_unordered_set_from_const_lvalues_of_key_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_unordered_set(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK_EQUAL(3U, data.size()); + CHECK_EQUAL(1U, data.count(42)); + CHECK_EQUAL(1U, data.count(43)); + CHECK_EQUAL(1U, data.count(44)); + } +#endif } #include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 5b824aa3..2093a355 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -785,6 +785,161 @@ namespace } #endif + //********************************* + TEST(test_cmp_equal) + { + // Same signedness. + CHECK_TRUE(etl::cmp_equal(1, 1)); + CHECK_FALSE(etl::cmp_equal(1, 2)); + CHECK_TRUE(etl::cmp_equal(1U, 1U)); + CHECK_FALSE(etl::cmp_equal(1U, 2U)); + + // Mixed signedness where the built-in operator would give the wrong result. + // -1 as unsigned would be a large value, so a naive (a == b) would be false anyway, + // but the classic trap is comparing a negative signed with an equal-bit-pattern unsigned. + CHECK_FALSE(etl::cmp_equal(-1, static_cast(-1))); + CHECK_FALSE(etl::cmp_equal(static_cast(-1), -1)); + + // Non-negative signed compared with unsigned. + CHECK_TRUE(etl::cmp_equal(5, 5U)); + CHECK_TRUE(etl::cmp_equal(5U, 5)); + CHECK_FALSE(etl::cmp_equal(-5, 5U)); + CHECK_FALSE(etl::cmp_equal(5U, -5)); + + // Different widths. + CHECK_TRUE(etl::cmp_equal(int8_t(100), int64_t(100))); + CHECK_FALSE(etl::cmp_equal(int8_t(-1), uint64_t(0xFFFFFFFFFFFFFFFFULL))); + } + + //********************************* + TEST(test_cmp_not_equal) + { + CHECK_FALSE(etl::cmp_not_equal(1, 1)); + CHECK_TRUE(etl::cmp_not_equal(1, 2)); + CHECK_TRUE(etl::cmp_not_equal(-1, static_cast(-1))); + CHECK_FALSE(etl::cmp_not_equal(5, 5U)); + CHECK_TRUE(etl::cmp_not_equal(-5, 5U)); + } + + //********************************* + TEST(test_cmp_less) + { + // Same signedness. + CHECK_TRUE(etl::cmp_less(1, 2)); + CHECK_FALSE(etl::cmp_less(2, 1)); + CHECK_FALSE(etl::cmp_less(1, 1)); + CHECK_TRUE(etl::cmp_less(1U, 2U)); + CHECK_FALSE(etl::cmp_less(2U, 1U)); + + // A negative signed value is always less than any unsigned value. + CHECK_TRUE(etl::cmp_less(-1, 0U)); + CHECK_TRUE(etl::cmp_less(-1, static_cast(-1))); + CHECK_FALSE(etl::cmp_less(static_cast(-1), -1)); + + // Non-negative signed with unsigned. + CHECK_TRUE(etl::cmp_less(5, 6U)); + CHECK_FALSE(etl::cmp_less(6, 5U)); + CHECK_TRUE(etl::cmp_less(5U, 6)); + CHECK_FALSE(etl::cmp_less(6U, 5)); + + // Large unsigned is not less than a small signed. + CHECK_FALSE(etl::cmp_less(0xFFFFFFFFU, 1)); + CHECK_TRUE(etl::cmp_less(1, 0xFFFFFFFFU)); + } + + //********************************* + TEST(test_cmp_greater) + { + CHECK_TRUE(etl::cmp_greater(2, 1)); + CHECK_FALSE(etl::cmp_greater(1, 2)); + CHECK_FALSE(etl::cmp_greater(1, 1)); + + CHECK_FALSE(etl::cmp_greater(-1, 0U)); + CHECK_TRUE(etl::cmp_greater(static_cast(-1), -1)); + CHECK_TRUE(etl::cmp_greater(0xFFFFFFFFU, 1)); + CHECK_FALSE(etl::cmp_greater(1, 0xFFFFFFFFU)); + } + + //********************************* + TEST(test_cmp_less_equal) + { + CHECK_TRUE(etl::cmp_less_equal(1, 1)); + CHECK_TRUE(etl::cmp_less_equal(1, 2)); + CHECK_FALSE(etl::cmp_less_equal(2, 1)); + + CHECK_TRUE(etl::cmp_less_equal(-1, static_cast(-1))); + CHECK_FALSE(etl::cmp_less_equal(static_cast(-1), -1)); + CHECK_TRUE(etl::cmp_less_equal(5U, 5)); + CHECK_FALSE(etl::cmp_less_equal(6U, 5)); + } + + //********************************* + TEST(test_cmp_greater_equal) + { + CHECK_TRUE(etl::cmp_greater_equal(1, 1)); + CHECK_TRUE(etl::cmp_greater_equal(2, 1)); + CHECK_FALSE(etl::cmp_greater_equal(1, 2)); + + CHECK_FALSE(etl::cmp_greater_equal(-1, static_cast(-1))); + CHECK_TRUE(etl::cmp_greater_equal(static_cast(-1), -1)); + CHECK_TRUE(etl::cmp_greater_equal(5, 5U)); + CHECK_FALSE(etl::cmp_greater_equal(-5, 5U)); + } + + //********************************* + TEST(test_in_range) + { + // Signed target type. + CHECK_TRUE(etl::in_range(0)); + CHECK_TRUE(etl::in_range(127)); + CHECK_TRUE(etl::in_range(-128)); + CHECK_FALSE(etl::in_range(128)); + CHECK_FALSE(etl::in_range(-129)); + CHECK_FALSE(etl::in_range(200)); + + // Unsigned target type. + CHECK_TRUE(etl::in_range(0)); + CHECK_TRUE(etl::in_range(255)); + CHECK_FALSE(etl::in_range(256)); + CHECK_FALSE(etl::in_range(-1)); + + // Unsigned source that would be negative if reinterpreted as signed. + CHECK_FALSE(etl::in_range(static_cast(-1))); + CHECK_TRUE(etl::in_range(static_cast(-1))); + + // Wider target always contains a narrower value. + CHECK_TRUE(etl::in_range(int8_t(-1))); + CHECK_TRUE(etl::in_range(uint32_t(0xFFFFFFFFU))); + } + +#if ETL_USING_CPP14 + //********************************* + TEST(test_cmp_and_in_range_constexpr) + { + constexpr bool ce0 = etl::cmp_equal(1, 1); + constexpr bool ce1 = etl::cmp_not_equal(-1, static_cast(-1)); + constexpr bool ce2 = etl::cmp_less(-1, 0U); + constexpr bool ce3 = etl::cmp_greater(static_cast(-1), -1); + constexpr bool ce4 = etl::cmp_less_equal(-1, static_cast(-1)); + constexpr bool ce5 = etl::cmp_greater_equal(static_cast(-1), -1); + constexpr bool ce6 = etl::in_range(100); + constexpr bool ce7 = etl::in_range(200); + + static_assert(ce0, "cmp_equal constexpr"); + static_assert(ce1, "cmp_not_equal constexpr"); + static_assert(ce2, "cmp_less constexpr"); + static_assert(ce3, "cmp_greater constexpr"); + static_assert(ce4, "cmp_less_equal constexpr"); + static_assert(ce5, "cmp_greater_equal constexpr"); + static_assert(ce6, "in_range true constexpr"); + static_assert(!ce7, "in_range false constexpr"); + + CHECK_TRUE(ce0); + CHECK_TRUE(ce6); + CHECK_FALSE(ce7); + } +#endif + #if ETL_HAS_PACKED //********************************* TEST(test_packed) diff --git a/test/test_variant_variadic.cpp b/test/test_variant_variadic.cpp index 5b558e05..0680f79a 100644 --- a/test/test_variant_variadic.cpp +++ b/test/test_variant_variadic.cpp @@ -321,6 +321,26 @@ namespace bool copied_to; }; + //********************************************* + // Copy constructible, but copy assignment is deleted. + struct CopyConstructibleNonCopyAssignable + { + CopyConstructibleNonCopyAssignable() = default; + CopyConstructibleNonCopyAssignable(const CopyConstructibleNonCopyAssignable&) = default; + CopyConstructibleNonCopyAssignable& operator=(const CopyConstructibleNonCopyAssignable&) = delete; + }; + + //********************************************* + // Move constructible, but move assignment is deleted. + struct MoveConstructibleNonMoveAssignable + { + MoveConstructibleNonMoveAssignable() = default; + MoveConstructibleNonMoveAssignable(MoveConstructibleNonMoveAssignable&&) = default; + MoveConstructibleNonMoveAssignable& operator=(MoveConstructibleNonMoveAssignable&&) = delete; + MoveConstructibleNonMoveAssignable(const MoveConstructibleNonMoveAssignable&) = delete; + MoveConstructibleNonMoveAssignable& operator=(const MoveConstructibleNonMoveAssignable&) = delete; + }; + //********************************************* // Trivially destructible, but non-copyable and non-movable. // Exercises the trivially-destructible (variadic_union) emplace path. @@ -420,6 +440,109 @@ namespace int value; }; + + //********************************************* + // Non-trivially destructible type whose copy/move ASSIGNMENT has a + // distinguishable effect from copy/move CONSTRUCTION. Used to verify that + // same-type variant assignment dispatches through the alternative's own + // assignment operator (no destroy + reconstruct). Exercises the + // uninitialized_buffer (non-trivial) path. + struct AssignTracker + { + AssignTracker(int value_) + : value(value_) + , constructed(true) + , copy_assigned(false) + , move_assigned(false) + { + } + + AssignTracker(const AssignTracker& other) + : value(other.value) + , constructed(true) + , copy_assigned(false) + , move_assigned(false) + { + } + + AssignTracker(AssignTracker&& other) + : value(other.value) + , constructed(true) + , copy_assigned(false) + , move_assigned(false) + { + } + + ~AssignTracker() {} + + AssignTracker& operator=(const AssignTracker& rhs) + { + value = rhs.value; + copy_assigned = true; + move_assigned = false; + return *this; + } + + AssignTracker& operator=(AssignTracker&& rhs) + { + value = rhs.value; + copy_assigned = false; + move_assigned = true; + return *this; + } + + int value; + bool constructed; + bool copy_assigned; + bool move_assigned; + }; + + //********************************************* + // Trivially destructible variant of AssignTracker (no user destructor) that + // exercises the trivially-destructible (variadic_union) path. + struct TrivialAssignTracker + { + TrivialAssignTracker(int value_) + : value(value_) + , copy_assigned(false) + , move_assigned(false) + { + } + + TrivialAssignTracker(const TrivialAssignTracker& other) + : value(other.value) + , copy_assigned(false) + , move_assigned(false) + { + } + + TrivialAssignTracker(TrivialAssignTracker&& other) + : value(other.value) + , copy_assigned(false) + , move_assigned(false) + { + } + + TrivialAssignTracker& operator=(const TrivialAssignTracker& rhs) + { + value = rhs.value; + copy_assigned = true; + move_assigned = false; + return *this; + } + + TrivialAssignTracker& operator=(TrivialAssignTracker&& rhs) + { + value = rhs.value; + copy_assigned = false; + move_assigned = true; + return *this; + } + + int value; + bool copy_assigned; + bool move_assigned; + }; } // namespace // Moved from the top of the file otherwise clang has issues with @@ -560,6 +683,26 @@ struct etl::is_move_constructible : public etl::false_type template <> struct etl::is_move_constructible : public etl::true_type { +}; + +template <> +struct etl::is_copy_constructible : public etl::true_type +{ +}; + +template <> +struct etl::is_move_constructible : public etl::true_type +{ +}; + +template <> +struct etl::is_copy_constructible : public etl::true_type +{ +}; + +template <> +struct etl::is_move_constructible : public etl::true_type +{ }; #endif @@ -954,6 +1097,71 @@ namespace } #endif + #if ETL_USING_EXCEPTIONS + //************************************************************************* + // A throwing emplace() must leave the variant valueless-after-exception + // (index() == variant_npos) rather than reporting the stale old index. + struct ThrowOnConstruct + { + struct exception + { + }; + + ThrowOnConstruct() = default; + explicit ThrowOnConstruct(int) + { + throw exception(); + } + }; + + TEST(test_emplace_throwing_is_valueless_by_exception) + { + // Trivially destructible suite (variadic_union storage). + { + etl::variant v; + v.emplace(42); + CHECK(!v.valueless_by_exception()); + CHECK_EQUAL(0U, v.index()); + + bool threw = false; + try + { + v.emplace(1); + } + catch (const ThrowOnConstruct::exception&) + { + threw = true; + } + + CHECK(threw); + CHECK(v.valueless_by_exception()); + CHECK_EQUAL(etl::variant_npos, v.index()); + } + + // Non-trivially destructible suite (uninitialized_buffer storage). + { + etl::variant v; + v.emplace("Some Text"); + CHECK(!v.valueless_by_exception()); + CHECK_EQUAL(0U, v.index()); + + bool threw = false; + try + { + v.emplace<1>(1); + } + catch (const ThrowOnConstruct::exception&) + { + threw = true; + } + + CHECK(threw); + CHECK(v.valueless_by_exception()); + CHECK_EQUAL(etl::variant_npos, v.index()); + } + } + #endif + //************************************************************************* TEST(test_copy_constructor) { @@ -999,6 +1207,146 @@ namespace CHECK_EQUAL(variant_1_etl.index(), variant_2_etl.index()); } + //************************************************************************* + // Issue #1512: a variant must only be copy constructible / copy assignable + // when every alternative is copy constructible. Moveable is move-only + // (its copy operations are deleted), so a variant containing it must not + // be copyable, while remaining move constructible / move assignable. + TEST(test_copy_disabled_with_non_copyable_alternative) + { + typedef etl::variant non_copyable_variant; + + CHECK(!etl::is_copy_constructible::value); + CHECK(!etl::is_copy_assignable::value); + CHECK(etl::is_move_constructible::value); + CHECK(etl::is_move_assignable::value); + + // A variant of purely copyable alternatives must remain copyable. + typedef etl::variant copyable_variant; + + CHECK(etl::is_copy_constructible::value); + CHECK(etl::is_copy_assignable::value); + } + + //************************************************************************* + // A non-copy-assignable alternative must disable the variant's copy + // assignment operator, and a non-move-assignable alternative must disable + // the variant's move assignment operator, while leaving the corresponding + // constructors available. + TEST(test_assignment_disabled_with_non_assignable_alternative) + { + typedef etl::variant copy_non_assignable_variant; + + CHECK(etl::is_copy_constructible::value); + CHECK(!etl::is_copy_assignable::value); + + typedef etl::variant move_non_assignable_variant; + + CHECK(etl::is_move_constructible::value); + CHECK(!etl::is_move_assignable::value); + } + + //************************************************************************* + // When source and destination hold the SAME alternative, assignment must + // dispatch through that alternative's own assignment operator rather than + // destroying and reconstructing it. Non-trivially-destructible path. + TEST(test_copy_assign_same_type_uses_alternative_assignment) + { + typedef etl::variant tracker_variant; + + tracker_variant variant_1(etl::in_place_type_t{}, 1); + tracker_variant variant_2(etl::in_place_type_t{}, 2); + + variant_1 = variant_2; + + CHECK_EQUAL(1U, variant_1.index()); + CHECK_EQUAL(2, etl::get(variant_1).value); + CHECK(etl::get(variant_1).copy_assigned); + CHECK(!etl::get(variant_1).move_assigned); + } + + //************************************************************************* + TEST(test_move_assign_same_type_uses_alternative_assignment) + { + typedef etl::variant tracker_variant; + + tracker_variant variant_1(etl::in_place_type_t{}, 1); + tracker_variant variant_2(etl::in_place_type_t{}, 2); + + variant_1 = etl::move(variant_2); + + CHECK_EQUAL(1U, variant_1.index()); + CHECK_EQUAL(2, etl::get(variant_1).value); + CHECK(!etl::get(variant_1).copy_assigned); + CHECK(etl::get(variant_1).move_assigned); + } + + //************************************************************************* + // When source and destination hold DIFFERENT alternatives, assignment must + // still destroy and reconstruct. + TEST(test_copy_assign_different_type_reconstructs) + { + typedef etl::variant tracker_variant; + + tracker_variant variant_1(etl::in_place_type_t{}, 5); + tracker_variant variant_2(etl::in_place_type_t{}, 2); + + variant_1 = variant_2; + + CHECK_EQUAL(1U, variant_1.index()); + CHECK_EQUAL(2, etl::get(variant_1).value); + CHECK(etl::get(variant_1).constructed); + CHECK(!etl::get(variant_1).copy_assigned); + CHECK(!etl::get(variant_1).move_assigned); + } + + //************************************************************************* + // Same as above but for the trivially-destructible (variadic_union) path. + TEST(test_assign_same_type_uses_alternative_assignment_trivial) + { + typedef etl::variant tracker_variant; + + tracker_variant variant_1(etl::in_place_type_t{}, 1); + tracker_variant variant_2(etl::in_place_type_t{}, 2); + + variant_1 = variant_2; + + CHECK_EQUAL(1U, variant_1.index()); + CHECK_EQUAL(2, etl::get(variant_1).value); + CHECK(etl::get(variant_1).copy_assigned); + CHECK(!etl::get(variant_1).move_assigned); + + tracker_variant variant_3(etl::in_place_type_t{}, 3); + variant_1 = etl::move(variant_3); + + CHECK_EQUAL(1U, variant_1.index()); + CHECK_EQUAL(3, etl::get(variant_1).value); + CHECK(etl::get(variant_1).move_assigned); + } + + //************************************************************************* + // Issue #1512: even though the copy operations are disabled at compile + // time, a move-only variant must still move construct / move assign + // correctly, preserving the active alternative. + TEST(test_move_only_variant_moves_correctly) + { + typedef etl::variant non_copyable_variant; + + non_copyable_variant variant_1(etl::in_place_type_t{}); + CHECK_EQUAL(1U, variant_1.index()); + + // Move construction preserves the active alternative. + non_copyable_variant variant_2(etl::move(variant_1)); + CHECK_EQUAL(1U, variant_2.index()); + CHECK(etl::get(variant_2).moved_to); + + // Move assignment preserves the active alternative. + non_copyable_variant variant_3; + variant_3 = etl::move(variant_2); + CHECK_EQUAL(1U, variant_3.index()); + CHECK(etl::get(variant_3).moved_to); + } + //************************************************************************* TEST(test_assign_from_value) { diff --git a/test/test_vector.cpp b/test/test_vector.cpp index b9957e5d..0340c4cb 100644 --- a/test/test_vector.cpp +++ b/test/test_vector.cpp @@ -1143,9 +1143,12 @@ namespace Compare_Data compare_data(initial_data.begin(), initial_data.end()); Data data(initial_data.begin(), initial_data.end()); - compare_data.erase(compare_data.begin() + 2, compare_data.begin() + 4); + Compare_Data::iterator cdi = compare_data.erase(compare_data.begin() + 2, compare_data.begin() + 4); - data.erase(data.begin() + 2, data.begin() + 4); + Data::iterator di = data.erase(data.begin() + 2, data.begin() + 4); + + CHECK(cdi == compare_data.begin() + 2); + CHECK(di == data.begin() + 2); CHECK_EQUAL(compare_data.size(), data.size()); @@ -1564,6 +1567,29 @@ namespace } #endif + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Arguments that are const-qualified lvalues must be accepted and must not + // affect the deduced element type. Guards against the defect fixed for + // make_array and make_deque, which forwarded each argument as the element + // type rather than as its own deduced type and so rejected const lvalues. + TEST(test_make_vector_from_const_lvalues_of_element_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_vector(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + using Type = typename std::remove_reference::type; + CHECK((std::is_same::value)); + + CHECK_EQUAL(42, data[0]); + CHECK_EQUAL(43, data[1]); + CHECK_EQUAL(44, data[2]); + } +#endif + //************************************************************************* TEST(test_fill) { diff --git a/test/test_vector_function_pointer.cpp b/test/test_vector_function_pointer.cpp index 62b18a71..0f95ae4f 100644 --- a/test/test_vector_function_pointer.cpp +++ b/test/test_vector_function_pointer.cpp @@ -301,7 +301,7 @@ namespace CHECK_EQUAL(0U, data.size()); CHECK_EQUAL(initial_data.size(), other_data.size()); - bool is_equal = std::equal(data.begin(), data.end(), other_data.begin()); + bool is_equal = std::equal(initial_data.begin(), initial_data.end(), other_data.begin()); CHECK(is_equal); } diff --git a/test/test_vector_function_pointer_external_buffer.cpp b/test/test_vector_function_pointer_external_buffer.cpp index 4a6d5a86..70ef97ec 100644 --- a/test/test_vector_function_pointer_external_buffer.cpp +++ b/test/test_vector_function_pointer_external_buffer.cpp @@ -288,7 +288,7 @@ namespace CHECK_EQUAL(0U, data.size()); CHECK_EQUAL(initial_data.size(), other_data.size()); - bool is_equal = std::equal(data.begin(), data.end(), other_data.begin()); + bool is_equal = std::equal(initial_data.begin(), initial_data.end(), other_data.begin()); CHECK(is_equal); } diff --git a/test/test_vector_member_function_pointer.cpp b/test/test_vector_member_function_pointer.cpp index a1828db7..6b8e1512 100644 --- a/test/test_vector_member_function_pointer.cpp +++ b/test/test_vector_member_function_pointer.cpp @@ -311,7 +311,7 @@ namespace CHECK_EQUAL(0U, data.size()); CHECK_EQUAL(initial_data.size(), other_data.size()); - bool is_equal = std::equal(data.begin(), data.end(), other_data.begin()); + bool is_equal = std::equal(initial_data.begin(), initial_data.end(), other_data.begin()); CHECK(is_equal); } diff --git a/test/test_vector_member_function_pointer_external_buffer.cpp b/test/test_vector_member_function_pointer_external_buffer.cpp index 644fbf92..b94358c3 100644 --- a/test/test_vector_member_function_pointer_external_buffer.cpp +++ b/test/test_vector_member_function_pointer_external_buffer.cpp @@ -316,7 +316,7 @@ namespace CHECK_EQUAL(0U, data.size()); CHECK_EQUAL(initial_data.size(), other_data.size()); - bool is_equal = std::equal(data.begin(), data.end(), other_data.begin()); + bool is_equal = std::equal(initial_data.begin(), initial_data.end(), other_data.begin()); CHECK(is_equal); }