diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 00000000..22cc390f --- /dev/null +++ b/.bazelrc @@ -0,0 +1,26 @@ +# Bazel settings for ETL +build --enable_bzlmod +build --cxxopt=-std=c++17 + +# Cross-compilation: build flags + QEMU (mirrors .devcontainer/run-tests.sh) +# Each config sets CC + tool env vars so Bazel's auto-configured toolchain +# finds the full cross-tool suite, and --run_under for QEMU execution. +build:armhf --repo_env=CC=arm-linux-gnueabihf-gcc --repo_env=AR=arm-linux-gnueabihf-ar --repo_env=LD=arm-linux-gnueabihf-ld --repo_env=NM=arm-linux-gnueabihf-nm --repo_env=STRIP=arm-linux-gnueabihf-strip --repo_env=OBJDUMP=arm-linux-gnueabihf-objdump +build:armhf --cxxopt=-std=c++23 --copt=-DETL_NO_STL --copt=-O0 +test:armhf --run_under=/usr/bin/qemu-arm-static + +build:i386 --repo_env=CC=i686-linux-gnu-gcc --repo_env=AR=i686-linux-gnu-ar --repo_env=LD=i686-linux-gnu-ld --repo_env=NM=i686-linux-gnu-nm --repo_env=STRIP=i686-linux-gnu-strip --repo_env=OBJDUMP=i686-linux-gnu-objdump +build:i386 --cxxopt=-std=c++23 --copt=-DETL_NO_STL --copt=-O0 +test:i386 --run_under=/usr/bin/qemu-i386-static + +build:powerpc --repo_env=CC=powerpc-linux-gnu-gcc --repo_env=AR=powerpc-linux-gnu-ar --repo_env=LD=powerpc-linux-gnu-ld --repo_env=NM=powerpc-linux-gnu-nm --repo_env=STRIP=powerpc-linux-gnu-strip --repo_env=OBJDUMP=powerpc-linux-gnu-objdump +build:powerpc --cxxopt=-std=c++23 --copt=-DETL_NO_STL --copt=-O0 +test:powerpc --run_under=/usr/bin/qemu-ppc + +build:riscv64 --repo_env=CC=riscv64-linux-gnu-gcc --repo_env=AR=riscv64-linux-gnu-ar --repo_env=LD=riscv64-linux-gnu-ld --repo_env=NM=riscv64-linux-gnu-nm --repo_env=STRIP=riscv64-linux-gnu-strip --repo_env=OBJDUMP=riscv64-linux-gnu-objdump +build:riscv64 --cxxopt=-std=c++23 --copt=-DETL_NO_STL --copt=-O0 +test:riscv64 --run_under=/usr/bin/qemu-riscv64-static + +build:s390x --repo_env=CC=s390x-linux-gnu-gcc --repo_env=AR=s390x-linux-gnu-ar --repo_env=LD=s390x-linux-gnu-ld --repo_env=NM=s390x-linux-gnu-nm --repo_env=STRIP=s390x-linux-gnu-strip --repo_env=OBJDUMP=s390x-linux-gnu-objdump +build:s390x --cxxopt=-std=c++23 --copt=-DETL_NO_STL --copt=-O0 +test:s390x --run_under=/usr/bin/qemu-s390x-static diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 00000000..f9c71a52 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.5.1 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f51b1a16..2e08080a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -36,15 +36,32 @@ RUN set -eux \ && apt-get -y install --no-install-recommends \ python3-full \ python3-pip \ + python3-cogapp \ git \ wget \ cmake \ - && rm -rf /var/lib/apt/lists/* \ - && if pip help install | grep -q '\-\-break-system-packages'; then \ - pip install --no-cache-dir --break-system-packages cogapp; \ - else \ - pip install --no-cache-dir cogapp; \ - fi + clang-format \ + clang-format-18 \ + lcov \ + && rm -rf /var/lib/apt/lists/* + +RUN set -eux; \ + VERSION="2.4.1"; \ + case "$(uname -m)" in \ + x86_64) ARCH="amd64"; SHA256="bdaa2c0fbee03e5c2f99e605d9419386ce5d558440baac2017398faada839e04" ;; \ + aarch64) ARCH="arm64"; SHA256="0a09e1f04a0f8a86fd4e709552613f5d82adf6bc72f0a4b5e217670894e79fbf" ;; \ + *) echo "Unsupported architecture: $(uname -m)"; exit 1 ;; \ + esac; \ + wget -O treefmt.tar.gz "https://github.com/numtide/treefmt/releases/download/v${VERSION}/treefmt_${VERSION}_linux_${ARCH}.tar.gz" \ + && echo "${SHA256} treefmt.tar.gz" | sha256sum -c \ + && tar xzf treefmt.tar.gz treefmt \ + && install -m 755 treefmt /usr/bin/treefmt \ + && rm treefmt.tar.gz treefmt + +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel RUN set -eux \ && echo "Pip version: " \ diff --git a/.devcontainer/armhf/Dockerfile b/.devcontainer/armhf/Dockerfile new file mode 100644 index 00000000..a6f866df --- /dev/null +++ b/.devcontainer/armhf/Dockerfile @@ -0,0 +1,61 @@ +# armhf Test Environment for ETL +# Uses QEMU user-mode emulation to run armhf binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and armhf cross-compilation tools +RUN dpkg --add-architecture armhf && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-arm-linux-gnueabihf \ + g++-arm-linux-gnueabihf \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + ca-certificates \ + file \ + libc6:armhf \ + libstdc++6:armhf \ + libatomic1:armhf \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== armhf Cross Compiler ===" && \ + arm-linux-gnueabihf-gcc --version && \ + echo "" && \ + echo "=== QEMU arm ===" && \ + qemu-arm-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/armhf/devcontainer.json b/.devcontainer/armhf/devcontainer.json new file mode 100644 index 00000000..a1dc285e --- /dev/null +++ b/.devcontainer/armhf/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "armhf (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/armhf/toolchain-armhf.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-armhf", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/armhf/toolchain-armhf.cmake b/.devcontainer/armhf/toolchain-armhf.cmake new file mode 100644 index 00000000..a7f9f00a --- /dev/null +++ b/.devcontainer/armhf/toolchain-armhf.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for armhf cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) + +# Specify the cross compiler +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) +set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) +set(CMAKE_AR arm-linux-gnueabihf-ar) +set(CMAKE_RANLIB arm-linux-gnueabihf-ranlib) +set(CMAKE_STRIP arm-linux-gnueabihf-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-arm-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/context/reinstall-cmake.sh b/.devcontainer/context/reinstall-cmake.sh deleted file mode 100644 index 280d8145..00000000 --- a/.devcontainer/context/reinstall-cmake.sh +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/env bash - -# For more detailed debugging, uncomment the next line -# set -x - -# Explicitly set CMAKE_VERSION from first argument, default to "none" -CMAKE_VERSION=${1:-"none"} - -# --- Configuration --- -DOWNLOAD_ATTEMPTS=3 -DOWNLOAD_RETRY_DELAY=5 # seconds - -# --- Global Variables --- -TMP_DIR="" # Initialize TMP_DIR, will be set by mktemp -# Filenames used within TMP_DIR -CMAKE_INSTALLER_SCRIPT_LOCAL_NAME="cmake-installer.sh" -CMAKE_CHECKSUM_FILE_LOCAL_NAME="cmake-checksums.txt" -# This will be the actual name of the CMake binary, derived from version and arch -# It's important for matching against the checksum file. -DERIVED_CMAKE_BINARY_FILENAME="" - -# --- Cleanup Function --- -# This trap will execute on EXIT, ERR, SIGINT, SIGTERM -# It's crucial for debugging to see the state of TMP_DIR if things go wrong. -cleanup() { - # $? is the exit code of the last command before the trap was triggered - # or the argument to exit if the script called exit explicitly. - LAST_EXIT_CODE=$? - echo # Newline for readability - - # Only proceed with detailed cleanup if TMP_DIR was actually created - if [[ -n "${TMP_DIR}" && -d "${TMP_DIR}" ]]; then - echo "--- Cleanup: Temporary Directory Inspector (${TMP_DIR}) ---" - echo "Listing contents of TMP_DIR:" - ls -la "${TMP_DIR}" - - # Check and display checksum file content - if [[ -f "${TMP_DIR}/${CMAKE_CHECKSUM_FILE_LOCAL_NAME}" ]]; then - echo "--- Content of downloaded checksum file (${CMAKE_CHECKSUM_FILE_LOCAL_NAME}) ---" - cat "${TMP_DIR}/${CMAKE_CHECKSUM_FILE_LOCAL_NAME}" - echo "--- End of checksum file ---" - else - echo "Checksum file (${CMAKE_CHECKSUM_FILE_LOCAL_NAME}) not found in TMP_DIR." - fi - - # Check and display head of (potentially) installer script - # Useful to see if it's an HTML error page - if [[ -f "${TMP_DIR}/${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}" ]]; then - echo "--- First 10 lines of downloaded installer script (${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}) ---" - head -n 10 "${TMP_DIR}/${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}" - echo "--- End of installer script head ---" - elif [[ -f "${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}" ]]; then - # If it was renamed - echo "--- First 10 lines of downloaded installer script (${DERIVED_CMAKE_BINARY_FILENAME}) ---" - head -n 10 "${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}" - echo "--- End of installer script head ---" - else - echo "Installer script not found in TMP_DIR (checked for ${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME} and ${DERIVED_CMAKE_BINARY_FILENAME})." - fi - - echo "Attempting to remove temporary directory: ${TMP_DIR}" - rm -Rf "${TMP_DIR}" - echo "Temporary directory removed." - echo "--- End of Cleanup ---" - else - echo "--- Cleanup: TMP_DIR was not set or not a directory, no temp files to inspect or clean. ---" - fi - - # Ensure the script exits with the LAST_EXIT_CODE observed by the trap - # unless it was 0 and the script is exiting due to an explicit non-zero exit. - # The 'exit' command within the trap will override the script's natural exit code. - # So, if the script was going to exit 0, but cleanup had an issue, this could change it. - # However, for debugging an exit code 8, we want to preserve the code that *caused* the trap. - echo "Script finished with exit code: ${LAST_EXIT_CODE}." - exit "${LAST_EXIT_CODE}" -} -trap cleanup EXIT ERR SIGINT SIGTERM - -# Immediately turn on `set -e` after trap setup -set -e - -# --- Helper Functions --- -# Function to download a file with retries and basic validation -download_file() { - local url="$1" - local output_filename="$2" - local attempts_left=$DOWNLOAD_ATTEMPTS - local wget_exit_code=0 - - while [ $attempts_left -gt 0 ]; do - echo "Downloading: ${url}" - echo "Saving to: ${TMP_DIR}/${output_filename}" - echo "Attempt $((DOWNLOAD_ATTEMPTS - attempts_left + 1)) of ${DOWNLOAD_ATTEMPTS}..." - - # Use wget with: - # -O: specify output file - # --timeout: connection/read timeout - # --tries: number of retries (wget's own retry, distinct from this loop) - # --quiet: suppress normal output, but errors still go to stderr - # --show-progress: if not quiet, shows a progress bar (optional) - # Using -q for less verbose logs, but on failure, we need to know. - wget -O "${TMP_DIR}/${output_filename}" --timeout=30 --tries=1 "${url}" - wget_exit_code=$? - - if [ ${wget_exit_code} -eq 0 ]; then - echo "Download command successful for ${output_filename}." - if [ -s "${TMP_DIR}/${output_filename}" ]; then # -s: file exists and has a size greater than 0 - # Basic check for common HTML error page indicators - # This is a heuristic and might not catch all error pages. - if head -n 5 "${TMP_DIR}/${output_filename}" | grep -Eiq ' /dev/null; then - echo "wget not found. Attempting to install wget via apt-get..." - if command -v apt-get > /dev/null; then - apt-get update -y - apt-get install -y --no-install-recommends wget - echo "wget installed." - else - echo "ERROR: apt-get not found. Cannot install wget. Please install wget manually." - exit 1 - fi -else - echo "wget is available." -fi - -# 2. (Optional) Remove existing CMake installed via apt -echo "Attempting to remove any existing CMake installed via apt..." -if command -v apt-get > /dev/null; then - if dpkg -s cmake &> /dev/null; then # Check if cmake package is actually installed - apt-get -y purge --auto-remove cmake - echo "cmake package purged." - else - echo "cmake package not found via dpkg, skipping purge." - fi -else - echo "apt-get not found, skipping removal of CMake via apt." -fi - -# 3. Create installation and temporary directories -echo "Creating CMake installation directory /opt/cmake..." -mkdir -p /opt/cmake - -TMP_DIR=$(mktemp -d -t cmake-install-XXXXXXXXXX) -echo "Temporary directory created: ${TMP_DIR}" -# Crucial: subsequent operations needing temp files should happen in or relative to TMP_DIR -# We will cd into TMP_DIR later, or use full paths like ${TMP_DIR}/filename - -# 4. Determine system architecture -echo "Determining system architecture..." -architecture=$(dpkg --print-architecture) -case "${architecture}" in - arm64) ARCH="aarch64" ;; - amd64) ARCH="x86_64" ;; - *) - echo "ERROR: Unsupported architecture '${architecture}' reported by dpkg." - exit 1 - ;; -esac -echo "Detected architecture: ${architecture} (mapped to CMake arch: ${ARCH})" - -# 5. Define CMake download URLs and the filename expected by checksum -DERIVED_CMAKE_BINARY_FILENAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh" -CMAKE_BINARY_URL="https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${DERIVED_CMAKE_BINARY_FILENAME}" -CMAKE_CHECKSUM_FILE_URL="https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-SHA-256.txt" - -# 6. Download CMake binary and checksum file -echo "--- Downloading Files ---" -if ! download_file "${CMAKE_BINARY_URL}" "${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}"; then - echo "ERROR: Failed to download CMake binary installer. See messages above." - exit 1 -fi - -if ! download_file "${CMAKE_CHECKSUM_FILE_URL}" "${CMAKE_CHECKSUM_FILE_LOCAL_NAME}"; then - echo "ERROR: Failed to download CMake checksum file. See messages above." - exit 1 -fi -echo "Downloads complete." -echo "--- End of Downloading Files ---" -echo # Newline for readability - -# Before checksum, rename the downloaded installer to its derived name, -# as the checksum file refers to this specific name. -echo "Renaming downloaded installer from '${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}' to '${DERIVED_CMAKE_BINARY_FILENAME}' for checksum verification." -mv "${TMP_DIR}/${CMAKE_INSTALLER_SCRIPT_LOCAL_NAME}" "${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}" -if [ ! -f "${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}" ]; then - echo "ERROR: Failed to rename installer script for checksum. File '${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}' does not exist after move." - exit 1 -fi - -# 7. Verify checksum -echo "--- Verifying Checksum ---" -echo "Checksum file is: ${TMP_DIR}/${CMAKE_CHECKSUM_FILE_LOCAL_NAME}" -echo "Binary file to check is: ${TMP_DIR}/${DERIVED_CMAKE_BINARY_FILENAME}" - -# Ensure the checksum file actually contains an entry for our binary -# This is important because the SHA-256.txt file contains checksums for *all* release assets -echo "Checking if checksum file contains entry for '${DERIVED_CMAKE_BINARY_FILENAME}'..." -if ! grep -q "${DERIVED_CMAKE_BINARY_FILENAME}" "${TMP_DIR}/${CMAKE_CHECKSUM_FILE_LOCAL_NAME}"; then - echo "ERROR: The downloaded checksum file '${CMAKE_CHECKSUM_FILE_LOCAL_NAME}' does NOT contain an entry for '${DERIVED_CMAKE_BINARY_FILENAME}'." - echo "This strongly suggests that the CMAKE_VERSION ('${CMAKE_VERSION}') or ARCH ('${ARCH}') is incorrect, or the specified version does not provide a .sh installer for this architecture." - echo "Please verify the version and available files at https://github.com/Kitware/CMake/releases/tag/v${CMAKE_VERSION}" - exit 1 -fi -echo "Checksum file contains an entry for '${DERIVED_CMAKE_BINARY_FILENAME}'." - -# Perform the checksum. We need to be in the directory where the files are. -echo "Changing directory to ${TMP_DIR} for checksum verification." -cd "${TMP_DIR}" # <<<<<<< IMPORTANT: sha256sum -c needs to find files - -echo "Verifying checksum of '${DERIVED_CMAKE_BINARY_FILENAME}' using '${CMAKE_CHECKSUM_FILE_LOCAL_NAME}'..." -# The --ignore-missing flag is good, as the .txt file has many checksums. -# The --strict flag would cause it to error if there are improperly formatted lines. -# We rely on the grep check above to ensure our specific file is mentioned. -if sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_FILE_LOCAL_NAME}"; then - echo "Checksum verification successful for '${DERIVED_CMAKE_BINARY_FILENAME}'." -else - SHA_EXIT_CODE=$? - echo "ERROR: Checksum verification FAILED for '${DERIVED_CMAKE_BINARY_FILENAME}' with exit code ${SHA_EXIT_CODE}." - # Cleanup trap will show file contents. - exit 1 # Critical failure -fi -echo "--- End of Verifying Checksum ---" -echo # Newline for readability - -# 8. Install CMake -echo "--- Installing CMake ---" -echo "Making the CMake installer script '${DERIVED_CMAKE_BINARY_FILENAME}' executable..." -chmod +x "${DERIVED_CMAKE_BINARY_FILENAME}" # Still in TMP_DIR - -echo "Executing CMake installer script: ./${DERIVED_CMAKE_BINARY_FILENAME} --prefix=/opt/cmake --skip-license" -# Execute the script. If this script exits with 8, this is our culprit. -if ./"${DERIVED_CMAKE_BINARY_FILENAME}" --prefix=/opt/cmake --skip-license; then - echo "CMake installer script executed successfully." -else - INSTALLER_EXIT_CODE=$? - echo "ERROR: CMake installer script FAILED with exit code ${INSTALLER_EXIT_CODE}." - # This is the most likely place for an exit code 8 if downloads and checksums were okay. - # The trap will handle cleanup. The script will exit with INSTALLER_EXIT_CODE due to the trap. - exit ${INSTALLER_EXIT_CODE} # Explicitly exit with the installer's code -fi -echo "--- End of Installing CMake ---" -echo # Newline for readability - -# 9. Create symlinks -echo "Creating symbolic links for cmake and ctest in /usr/local/bin/..." -ln -sf /opt/cmake/bin/cmake /usr/local/bin/cmake -ln -sf /opt/cmake/bin/ctest /usr/local/bin/ctest -echo "Symbolic links created." - -echo # Newline for readability -echo "SUCCESS: CMake ${CMAKE_VERSION} installation and setup complete." - -# The script will exit with 0 here. The trap will run, see $? is 0, and then exit 0. -exit 0 \ No newline at end of file diff --git a/.devcontainer/i386/Dockerfile b/.devcontainer/i386/Dockerfile new file mode 100644 index 00000000..b879ee00 --- /dev/null +++ b/.devcontainer/i386/Dockerfile @@ -0,0 +1,61 @@ +# i386 Test Environment for ETL +# Uses QEMU user-mode emulation to run i386 binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and i386 cross-compilation tools +RUN dpkg --add-architecture i386 && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-i686-linux-gnu \ + g++-i686-linux-gnu \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + ca-certificates \ + file \ + libc6:i386 \ + libstdc++6:i386 \ + libatomic1:i386 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== i386 Cross Compiler ===" && \ + i686-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU i386 ===" && \ + qemu-i386-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/i386/devcontainer.json b/.devcontainer/i386/devcontainer.json new file mode 100644 index 00000000..84e28a8e --- /dev/null +++ b/.devcontainer/i386/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "i386 (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/i386/toolchain-i386.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-i386", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/i386/toolchain-i386.cmake b/.devcontainer/i386/toolchain-i386.cmake new file mode 100644 index 00000000..502e2285 --- /dev/null +++ b/.devcontainer/i386/toolchain-i386.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for i386 cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR i386) + +# Specify the cross compiler +set(CMAKE_C_COMPILER i686-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER i686-linux-gnu-g++) +set(CMAKE_AR i686-linux-gnu-ar) +set(CMAKE_RANLIB i686-linux-gnu-ranlib) +set(CMAKE_STRIP i686-linux-gnu-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-i386-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/powerpc/Dockerfile b/.devcontainer/powerpc/Dockerfile new file mode 100644 index 00000000..a2442782 --- /dev/null +++ b/.devcontainer/powerpc/Dockerfile @@ -0,0 +1,85 @@ +# powerpc Test Environment for ETL +# Uses QEMU user-mode emulation to run powerpc binaries on x64 host +FROM debian:sid-20260406 + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# 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 \ + binfmt-support \ + gpg \ + ca-certificates \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + file \ + 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 +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 \ + gcc-powerpc-linux-gnu \ + g++-powerpc-linux-gnu \ + libc6:powerpc \ + libstdc++6:powerpc \ + libatomic1:powerpc \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== powerpc Cross Compiler ===" && \ + powerpc-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU powerpc ===" && \ + qemu-ppc-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/powerpc/devcontainer.json b/.devcontainer/powerpc/devcontainer.json new file mode 100644 index 00000000..1d7a9a05 --- /dev/null +++ b/.devcontainer/powerpc/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "powerpc (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/powerpc/toolchain-powerpc.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=ON", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-powerpc", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/powerpc/toolchain-powerpc.cmake b/.devcontainer/powerpc/toolchain-powerpc.cmake new file mode 100644 index 00000000..1afea7da --- /dev/null +++ b/.devcontainer/powerpc/toolchain-powerpc.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for powerpc cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR powerpc) + +# Specify the cross compiler +set(CMAKE_C_COMPILER powerpc-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER powerpc-linux-gnu-g++) +set(CMAKE_AR powerpc-linux-gnu-ar) +set(CMAKE_RANLIB powerpc-linux-gnu-ranlib) +set(CMAKE_STRIP powerpc-linux-gnu-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-ppc CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/riscv64/Dockerfile b/.devcontainer/riscv64/Dockerfile new file mode 100644 index 00000000..90a95a4c --- /dev/null +++ b/.devcontainer/riscv64/Dockerfile @@ -0,0 +1,61 @@ +# riscv64 Test Environment for ETL +# Uses QEMU user-mode emulation to run riscv64 binaries on x64 host +FROM debian:trixie + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install QEMU user-mode emulation and riscv64 cross-compilation tools +RUN dpkg --add-architecture riscv64 && \ + apt-get update && apt-get install -y --no-install-recommends \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-riscv64-linux-gnu \ + g++-riscv64-linux-gnu \ + cmake \ + make \ + ninja-build \ + git \ + wget \ + ca-certificates \ + file \ + libc6:riscv64 \ + libstdc++6:riscv64 \ + libatomic1:riscv64 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user with stable UID/GID +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + +# Set working directory +WORKDIR /workspaces/etl + +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel + +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== riscv64 Cross Compiler ===" && \ + riscv64-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU riscv64 ===" && \ + qemu-riscv64-static --version | head -n1 + +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/riscv64/devcontainer.json b/.devcontainer/riscv64/devcontainer.json new file mode 100644 index 00000000..0e673f24 --- /dev/null +++ b/.devcontainer/riscv64/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "riscv64 (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ], + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/riscv64/toolchain-riscv64.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=23" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-riscv64", + "cmake.generator": "Ninja" + } + } + }, + "remoteUser": "root" +} diff --git a/.devcontainer/riscv64/toolchain-riscv64.cmake b/.devcontainer/riscv64/toolchain-riscv64.cmake new file mode 100644 index 00000000..adc1c7f3 --- /dev/null +++ b/.devcontainer/riscv64/toolchain-riscv64.cmake @@ -0,0 +1,20 @@ +# CMake toolchain file for riscv64 cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +# Specify the cross compiler +set(CMAKE_C_COMPILER riscv64-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER riscv64-linux-gnu-g++) +set(CMAKE_AR riscv64-linux-gnu-ar) +set(CMAKE_RANLIB riscv64-linux-gnu-ranlib) +set(CMAKE_STRIP riscv64-linux-gnu-strip) +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-riscv64-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") diff --git a/.devcontainer/run-tests.sh b/.devcontainer/run-tests.sh new file mode 100755 index 00000000..9618a15b --- /dev/null +++ b/.devcontainer/run-tests.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Run tests inside the separately created docker container for different hardware architecture +# +# Strategy: +# * Create docker image +# * Enter image +# * Cross build tests +# * Run tests via QEMU +# + +set -e + +usage() +{ + echo "Usage: run-tests.sh " + echo "Architecture: armhf|i386|powerpc|riscv64|s390x" + echo "(run from project root)" +} + +ARCHLIST="armhf i386 powerpc riscv64 s390x" + +if [[ " $ARCHLIST " =~ " $1 " ]] ; then + ARCH=$1 +else + echo "Unsupported architecture: $1" + usage + exit 1 +fi + +if [ "$2" = "" ] ; then + echo "Creating docker image..." + docker build -t $ARCH .devcontainer/$ARCH + + echo "Entering container..." + docker run -it --rm -v "$PWD":/workspaces/etl -w /workspaces/etl $ARCH /bin/bash .devcontainer/run-tests.sh $ARCH inside_container + +elif [ "$2" = "inside_container" ] ; then + echo "Cross building tests..." + mkdir -p build-$ARCH + cd build-$ARCH + cmake -DCMAKE_TOOLCHAIN_FILE=../.devcontainer/$ARCH/toolchain-$ARCH.cmake \ + -DBUILD_TESTS=ON -DNO_STL=ON -DETL_CXX_STANDARD=23 \ + -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=-O0 -DETL_ENABLE_SANITIZER=OFF -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF \ + ../test + export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) + cmake --build . + + echo "Running tests via CTest (using QEMU emulator from toolchain)..." + ctest -V --output-on-failure + echo "Tests successful." +else + echo "Invalid second argument: $2" + usage + exit 1 +fi diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index 21a6289c..536f2de4 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive # Install QEMU user-mode emulation and s390x cross-compilation tools RUN dpkg --add-architecture s390x && \ - apt-get update && apt-get install -y --no-install-recommends\ + apt-get update && apt-get install -y --no-install-recommends \ qemu-user-static \ qemu-user \ binfmt-support \ @@ -18,14 +18,29 @@ RUN dpkg --add-architecture s390x && \ ninja-build \ git \ wget \ + ca-certificates \ file \ libc6:s390x \ libstdc++6:s390x \ + libatomic1:s390x \ && rm -rf /var/lib/apt/lists/* +# Create non-root user with stable UID/GID +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid ${USER_GID} ${USERNAME} && \ + useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME} + # Set working directory WORKDIR /workspaces/etl +# Install Bazelisk as 'bazel' +RUN ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ + wget -qO /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${ARCH} && \ + chmod +x /usr/local/bin/bazel + # Verify QEMU and cross-compilation setup RUN echo "=== Host Architecture ===" && \ uname -m && \ @@ -36,5 +51,11 @@ RUN echo "=== Host Architecture ===" && \ echo "=== QEMU s390x ===" && \ qemu-s390x-static --version | head -n1 +# Ensure workspace directory ownership for non-root user +RUN mkdir -p /workspaces/etl && chown -R ${USERNAME}:${USERNAME} /workspaces + +# Switch to non-root user +USER ${USERNAME} + # Default command CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json index 8b7f8235..535a0799 100644 --- a/.devcontainer/s390x/devcontainer.json +++ b/.devcontainer/s390x/devcontainer.json @@ -18,7 +18,7 @@ "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/s390x/toolchain-s390x.cmake", "-DBUILD_TESTS=ON", "-DNO_STL=OFF", - "-DETL_CXX_STANDARD=17" + "-DETL_CXX_STANDARD=23" ], "cmake.buildDirectory": "${workspaceFolder}/build-s390x", "cmake.generator": "Ninja" diff --git a/.devcontainer/ubuntu-26.04/Dockerfile b/.devcontainer/ubuntu-26.04/Dockerfile new file mode 100644 index 00000000..ddd21706 --- /dev/null +++ b/.devcontainer/ubuntu-26.04/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:26.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + git \ + ninja-build \ + python3 \ + python3-pip \ + clang \ + docker.io \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -s /bin/bash vscode + +WORKDIR /etl + +CMD ["/bin/bash"] diff --git a/.github/workflows/bazel-gcc-c++23-no-stl.yml b/.github/workflows/bazel-gcc-c++23-no-stl.yml new file mode 100644 index 00000000..b41765a2 --- /dev/null +++ b/.github/workflows/bazel-gcc-c++23-no-stl.yml @@ -0,0 +1,22 @@ +name: bazel-gcc-c++23-no-stl +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-bazel-gcc-cpp23-no-stl: + name: Bazel GCC C++23 Linux - No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: bazel build //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL + + - name: Run tests + run: bazel test //test:etl_tests --cxxopt=-std=c++23 --copt=-DETL_NO_STL --test_output=all diff --git a/.github/workflows/clang-c++11.yml b/.github/workflows/clang-c++11.yml index d511f5b7..6b73b7c1 100644 --- a/.github/workflows/clang-c++11.yml +++ b/.github/workflows/clang-c++11.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++14.yml b/.github/workflows/clang-c++14.yml index d06778b1..830832b5 100644 --- a/.github/workflows/clang-c++14.yml +++ b/.github/workflows/clang-c++14.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++17.yml b/.github/workflows/clang-c++17.yml index 9fb4611f..6ae2f4b9 100644 --- a/.github/workflows/clang-c++17.yml +++ b/.github/workflows/clang-c++17.yml @@ -25,7 +25,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++20.yml b/.github/workflows/clang-c++20.yml index c68f9870..e246a795 100644 --- a/.github/workflows/clang-c++20.yml +++ b/.github/workflows/clang-c++20.yml @@ -32,7 +32,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -61,7 +61,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -90,7 +90,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -112,7 +112,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -134,7 +134,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -156,7 +156,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -178,7 +178,7 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - 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 ffa88744..0c2d8c9b 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -13,26 +13,19 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ - clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -42,26 +35,19 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ - clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -71,26 +57,19 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 - # Temporary fix. See https://github.com/actions/runner-images/issues/8659 - - name: Install newer Clang - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x ./llvm.sh - sudo ./llvm.sh 17 - - name: Build run: | - export CC=clang-17 - export CXX=clang++-17 + export CC=clang + export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ - clang-17 --version - make -j $(getconf _NPROCESSORS_ONLN) + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -110,9 +89,9 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -132,9 +111,9 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -154,9 +133,9 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -176,9 +155,9 @@ jobs: export CC=clang export CXX=clang++ export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 - cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++26.yml b/.github/workflows/clang-c++26.yml new file mode 100644 index 00000000..35d127bf --- /dev/null +++ b/.github/workflows/clang-c++26.yml @@ -0,0 +1,185 @@ +name: clang-c++26 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-clang-cpp26-linux-stl: + name: Clang C++26 Linux - STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \ + clang --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-clang-cpp26-linux-no-stl: + name: Clang C++26 Linux - No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \ + clang --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-clang-cpp26-linux-stl-force-cpp03: + name: Clang C++26 Linux - STL - Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \ + clang --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-clang-cpp26-linux-no-stl-force-cpp03: + name: Clang C++26 Linux - No STL - Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \ + clang --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-clang-cpp26-osx-stl: + name: Clang C++26 OSX - STL + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-no-stl: + name: Clang C++26 OSX - No STL + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-stl-force-cpp03: + name: Clang C++26 OSX - STL - Force C++03 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v + + build-clang-cpp26-osx-no-stl-force-cpp03: + name: Clang C++26 OSX - No STL - Force C++03 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-26] + + steps: + - uses: actions/checkout@v4 + + - name: Build + run: | + export CC=clang + export CXX=clang++ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 + cmake -D BUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ + clang --version + make -j "$(getconf _NPROCESSORS_ONLN)" + + - name: Run tests + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-syntax-checks.yml b/.github/workflows/clang-syntax-checks.yml index 700b2087..2c6000e7 100644 --- a/.github/workflows/clang-syntax-checks.yml +++ b/.github/workflows/clang-syntax-checks.yml @@ -23,10 +23,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp03-linux-No-STL: - name: Syntax Check - Clang C++03 Linux No STL + name: Syntax Check - Clang C++03 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -41,7 +41,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-STL: name: Syntax Check - Clang C++11 Linux STL @@ -59,10 +59,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-No-STL: - name: Syntax Check - Clang C++11 Linux No STL + name: Syntax Check - Clang C++11 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -77,7 +77,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-STL-Force-CPP03: name: Syntax Check - Clang C++11 Linux STL Force C++03 @@ -95,7 +95,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp11-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++11 Linux No STL Force C++03 @@ -113,7 +113,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-STL: name: Syntax Check - Clang C++14 Linux STL @@ -131,10 +131,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-No-STL: - name: Syntax Check - Clang C++14 Linux No STL + name: Syntax Check - Clang C++14 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -149,7 +149,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-STL-Force-CPP03: name: Syntax Check - Clang C++14 Linux STL Force C++03 @@ -167,7 +167,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp14-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++14 Linux No STL Force C++03 @@ -185,7 +185,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-STL: name: Syntax Check - Clang C++17 Linux STL @@ -203,10 +203,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-No-STL: - name: Syntax Check - Clang C++17 Linux No STL + name: Syntax Check - Clang C++17 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -221,7 +221,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-STL-Force-CPP03: name: Syntax Check - Clang C++17 Linux STL Force C++03 @@ -239,7 +239,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp17-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++17 Linux No STL Force C++03 @@ -257,7 +257,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-STL: name: Syntax Check - Clang C++20 Linux STL @@ -275,10 +275,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-No-STL: - name: Syntax Check - Clang C++20 Linux No STL + name: Syntax Check - Clang C++20 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -293,7 +293,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-STL-Force-CPP03: name: Syntax Check - Clang C++20 Linux STL Force C++03 @@ -311,7 +311,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp20-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++20 Linux No STL Force C++03 @@ -329,7 +329,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-STL: name: Syntax Check - Clang C++23 Linux STL @@ -347,10 +347,10 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-No-STL: - name: Syntax Check - Clang C++23 Linux No STL + name: Syntax Check - Clang C++23 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -365,7 +365,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-STL-Force-CPP03: name: Syntax Check - Clang C++23 Linux STL Force C++03 @@ -383,7 +383,7 @@ jobs: export CXX=clang++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-clang-cpp23-linux-No-STL-Force-CPP03: name: Syntax Check - Clang C++23 Linux No STL Force C++03 @@ -401,4 +401,84 @@ jobs: export CXX=clang++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check clang --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-STL: + name: Syntax Check - Clang C++26 Linux STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + clang++ --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-No-STL: + name: Syntax Check - Clang C++26 Linux No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + clang++ --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-STL-Force-CPP03: + name: Syntax Check - Clang C++26 Linux STL Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + clang++ --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-clang-cpp26-linux-No-STL-Force-CPP03: + name: Syntax Check - Clang C++26 Linux No STL Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=clang && \ + export CXX=clang++ && \ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + clang++ --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 79f9553e..5c05ebef 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -65,8 +65,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 - -# GitHub Repository settings -# -> Settings -> Pages -# -> Source: gh actions + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/gcc-c++11.yml b/.github/workflows/gcc-c++11.yml index 571c6d6e..c9706aeb 100644 --- a/.github/workflows/gcc-c++11.yml +++ b/.github/workflows/gcc-c++11.yml @@ -26,7 +26,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -49,7 +49,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++14.yml b/.github/workflows/gcc-c++14.yml index f623af08..a3277b66 100644 --- a/.github/workflows/gcc-c++14.yml +++ b/.github/workflows/gcc-c++14.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++17.yml b/.github/workflows/gcc-c++17.yml index fc0ddd97..dbeef7fa 100644 --- a/.github/workflows/gcc-c++17.yml +++ b/.github/workflows/gcc-c++17.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++20.yml b/.github/workflows/gcc-c++20.yml index 5965e05e..be4e6fb2 100644 --- a/.github/workflows/gcc-c++20.yml +++ b/.github/workflows/gcc-c++20.yml @@ -25,7 +25,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -47,7 +47,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -69,7 +69,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -91,7 +91,7 @@ jobs: export CXX=g++ cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++23-armhf.yml b/.github/workflows/gcc-c++23-armhf.yml new file mode 100644 index 00000000..1bd2912b --- /dev/null +++ b/.github/workflows/gcc-c++23-armhf.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-armhf +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-armhf: + name: GCC C++23 Linux - No STL - armhf + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-armhf -f .devcontainer/armhf/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-armhf bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/armhf/toolchain-armhf.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-i386.yml b/.github/workflows/gcc-c++23-i386.yml new file mode 100644 index 00000000..31bfc331 --- /dev/null +++ b/.github/workflows/gcc-c++23-i386.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-i386 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-i386: + name: GCC C++23 Linux - No STL - i386 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-i386 -f .devcontainer/i386/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-i386 bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/i386/toolchain-i386.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-powerpc.yml b/.github/workflows/gcc-c++23-powerpc.yml new file mode 100644 index 00000000..7494ae55 --- /dev/null +++ b/.github/workflows/gcc-c++23-powerpc.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-powerpc +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-powerpc: + name: GCC C++23 Linux - No STL - powerpc + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-powerpc -f .devcontainer/powerpc/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-powerpc bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/powerpc/toolchain-powerpc.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-riscv64.yml b/.github/workflows/gcc-c++23-riscv64.yml new file mode 100644 index 00000000..695056a8 --- /dev/null +++ b/.github/workflows/gcc-c++23-riscv64.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-riscv64 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-riscv64: + name: GCC C++23 Linux - No STL - riscv64 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-riscv64 -f .devcontainer/riscv64/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-riscv64 bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/riscv64/toolchain-riscv64.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23-s390x.yml b/.github/workflows/gcc-c++23-s390x.yml new file mode 100644 index 00000000..f6a15aca --- /dev/null +++ b/.github/workflows/gcc-c++23-s390x.yml @@ -0,0 +1,29 @@ +name: gcc-c++23-s390x +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp23-linux-no-stl-s390x: + name: GCC C++23 Linux - No STL - s390x + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-s390x -f .devcontainer/s390x/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-s390x bash -c "\ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ + -DETL_CXX_STANDARD=23 -DCMAKE_TOOLCHAIN_FILE=.devcontainer/s390x/toolchain-s390x.cmake \ + -DEXTRA_TESTING_FLAGS=-v \ + ./ && \ + cmake --build . -- -j \$(getconf _NPROCESSORS_ONLN) && \ + ctest -V" diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index f91924bd..9ca6baf0 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -23,9 +23,9 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -35,7 +35,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -45,9 +45,9 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=OFF -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -57,7 +57,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -67,9 +67,9 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v @@ -79,7 +79,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-24.04] steps: - uses: actions/checkout@v4 @@ -89,9 +89,9 @@ jobs: export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 export CC=gcc export CXX=g++ - cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03=ON -DETL_CXX_STANDARD=23 ./ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 -DETL_OPTIMISATION=-O3 ./ gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" - name: Run tests run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++26.yml b/.github/workflows/gcc-c++26.yml new file mode 100644 index 00000000..b7ff42d3 --- /dev/null +++ b/.github/workflows/gcc-c++26.yml @@ -0,0 +1,97 @@ +name: gcc-c++26 +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-gcc-cpp26-linux-stl: + name: GCC C++26 Linux - STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-gcc-cpp26-linux-no-stl: + name: GCC C++26 Linux - No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./ && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-gcc-cpp26-linux-stl-force-cpp03: + name: GCC C++26 Linux - STL - Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" + + build-gcc-cpp26-linux-no-stl-force-cpp03: + name: GCC C++26 Linux - No STL - Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build and run tests + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export ASAN_OPTIONS=alloc_dealloc_mismatch=0,detect_leaks=0 && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./ && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN) && \ + ./test/etl_tests -v" diff --git a/.github/workflows/gcc-syntax-checks.yml b/.github/workflows/gcc-syntax-checks.yml index 5f3753b1..b6b77bad 100644 --- a/.github/workflows/gcc-syntax-checks.yml +++ b/.github/workflows/gcc-syntax-checks.yml @@ -23,10 +23,10 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp03-linux-No-STL: - name: Syntax Check - GCC C++03 Linux No STL + name: Syntax Check - GCC C++03 Linux No STL runs-on: ${{ matrix.os }} strategy: matrix: @@ -41,7 +41,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=03 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-STL: name: Syntax Check - GCC C++11 Linux STL @@ -59,7 +59,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-No-STL: name: Syntax Check - GCC C++11 Linux No STL @@ -77,7 +77,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-STL-Force-CPP03: name: Syntax Check - GCC C++11 Linux STL Force C++03 @@ -95,7 +95,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp11-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++11 Linux No STL Force C++03 @@ -113,7 +113,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=11 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-STL: name: Syntax Check - GCC C++14 Linux STL @@ -131,7 +131,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-No-STL: name: Syntax Check - GCC C++14 Linux No STL @@ -149,7 +149,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-STL-Force-CPP03: name: Syntax Check - GCC C++14 Linux STL Force C++03 @@ -167,7 +167,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp14-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++14 Linux No STL Force C++03 @@ -185,7 +185,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=14 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-STL: name: Syntax Check - GCC C++17 Linux STL @@ -203,7 +203,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-No-STL: name: Syntax Check - GCC C++17 Linux No STL @@ -221,7 +221,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-STL-Force-CPP03: name: Syntax Check - GCC C++17 Linux STL Force C++03 @@ -239,7 +239,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp17-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++17 Linux No STL Force C++03 @@ -257,7 +257,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=17 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-STL: name: Syntax Check - GCC C++20 Linux STL @@ -275,7 +275,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-No-STL: name: Syntax Check - GCC C++20 Linux No STL @@ -293,7 +293,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-STL-Force-CPP03: name: Syntax Check - GCC C++20 Linux STL Force C++03 @@ -311,7 +311,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp20-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++20 Linux No STL Force C++03 @@ -329,7 +329,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=20 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-STL: name: Syntax Check - GCC C++23 Linux STL @@ -347,7 +347,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-No-STL: name: Syntax Check - GCC C++23 Linux No STL @@ -365,7 +365,7 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-STL-Force-CPP03: name: Syntax Check - GCC C++23 Linux STL Force C++03 @@ -383,7 +383,7 @@ jobs: export CXX=g++ cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) + make -j "$(getconf _NPROCESSORS_ONLN)" build-gcc-cpp23-linux-No-STL-Force-CPP03: name: Syntax Check - GCC C++23 Linux No STL Force C++03 @@ -401,4 +401,84 @@ jobs: export CXX=g++ cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=23 ./test/syntax_check gcc --version - make -j $(getconf _NPROCESSORS_ONLN) \ No newline at end of file + make -j "$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-STL: + name: Syntax Check - GCC C++26 Linux STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-No-STL: + name: Syntax Check - GCC C++26 Linux No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-STL-Force-CPP03: + name: Syntax Check - GCC C++26 Linux STL Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" + + build-gcc-cpp26-linux-No-STL-Force-CPP03: + name: Syntax Check - GCC C++26 Linux No STL Force C++03 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t etl-ubuntu-2604 -f .devcontainer/ubuntu-26.04/Dockerfile . + + - name: Build + run: | + docker run --rm --user root -v ${{ github.workspace }}:/workspaces/etl etl-ubuntu-2604 bash -c "\ + cd /workspaces/etl && \ + export CC=gcc && \ + export CXX=g++ && \ + cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=26 ./test/syntax_check && \ + gcc --version && \ + make -j \$(getconf _NPROCESSORS_ONLN)" diff --git a/.github/workflows/generator.yml b/.github/workflows/generator.yml index 032ffd1e..1829c342 100644 --- a/.github/workflows/generator.yml +++ b/.github/workflows/generator.yml @@ -14,12 +14,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Generate + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y python3-cogapp - cd include/etl/generators && bash generate.bat - - name: Check Generated Headers For Changes + - name: Run generator_test.py run: | - git diff --exit-code + cd scripts && python3 generator_test.py diff --git a/.github/workflows/meson-gcc-c++23-no-stl.yml b/.github/workflows/meson-gcc-c++23-no-stl.yml new file mode 100644 index 00000000..d8767317 --- /dev/null +++ b/.github/workflows/meson-gcc-c++23-no-stl.yml @@ -0,0 +1,31 @@ +name: meson-gcc-c++23-no-stl +on: + push: + branches: [ master, development, pull-request/* ] + pull_request: + branches: [ master, development, pull-request/* ] + types: [opened, synchronize, reopened] + +jobs: + + build-meson-gcc-cpp23-no-stl: + name: Meson GCC C++23 Linux - No STL + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v6 + + - name: Install Meson + run: sudo apt-get install -y meson + + - name: Configure + run: | + export CC=gcc + export CXX=g++ + meson setup builddir -Duse_stl=false -Dcpp_std=c++23 + + - name: Build + run: meson compile -C builddir + + - name: Run tests + run: meson test -C builddir -v diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 00000000..3bdb072e --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,9 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "etl", + hdrs = glob(["include/**/*.h"]), + includes = ["include"], +) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 00000000..a52b73e8 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,7 @@ +module( + name = "etl", + version = "0.0.0", +) + +bazel_dep(name = "platforms", version = "0.0.11") +bazel_dep(name = "rules_cc", version = "0.1.1") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 00000000..c6bcd5ce --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,205 @@ +{ + "lockFileVersion": 24, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615", + "https://bcr.bazel.build/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": "b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "rL/34P1aFDq2GqVC2zCFgQ8nTuOC6ziogocpvG50Qz8=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + }, + "facts": {} +} diff --git a/README.md b/README.md index 869455a0..1af9c518 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub release (latest by date)](https://img.shields.io/github/v/release/jwellbelove/etl) [![Release date](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3)](https://img.shields.io/github/release-date/jwellbelove/etl?color=%231182c3) -[![Standard](https://img.shields.io/badge/c%2B%2B-98/03/11/14/17/20/23-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) +[![Standard](https://img.shields.io/badge/c%2B%2B-98/03/11/14/17/20/23/26-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) ![GitHub contributors](https://img.shields.io/github/contributors-anon/ETLCPP/etl) ![GitHub forks](https://img.shields.io/github/forks/ETLCPP/etl?style=flat) @@ -15,6 +15,7 @@ ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++17.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++20.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++23.yml/badge.svg?branch=master) +![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-c++26.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/gcc-syntax-checks.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++11.yml/badge.svg?branch=master) @@ -22,6 +23,7 @@ ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++17.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++20.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++23.yml/badge.svg?branch=master) +![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-c++26.yml/badge.svg?branch=master) ![CI](https://github.com/ETLCPP/etl/actions/workflows/clang-syntax-checks.yml/badge.svg?branch=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3c14cd918ccf40008d0bcd7b083d5946)](https://www.codacy.com/manual/jwellbelove/etl?utm_source=github.com&utm_medium=referral&utm_content=ETLCPP/etl&utm_campaign=Badge_Grade) @@ -49,7 +51,7 @@ Its design goals include: - Offering APIs that closely resemble those of the STL, enabling familiar and consistent usage. - Maintaining compatibility with C++98 while implementing many features introduced in later standards -(C++11/14/17/20/23) where possible. +(C++11/14/17/20/23/26) where possible. - Ensuring deterministic behavior, which is critical in real-time and resource-constrained environments. diff --git a/docs/bazel.md b/docs/bazel.md new file mode 100644 index 00000000..7ab5168d --- /dev/null +++ b/docs/bazel.md @@ -0,0 +1,295 @@ +# Building ETL with Bazel + +ETL provides first-class [Bazel](https://bazel.build/) support, both for developing ETL itself and for consuming it as a dependency in your own projects. + +## Prerequisites + +- [Bazelisk](https://github.com/bazelbuild/bazelisk) (recommended) or [Bazel](https://bazel.build/install) 7.0 or later (with Bzlmod support) + +[Bazelisk](https://github.com/bazelbuild/bazelisk) is a launcher that automatically downloads and runs the Bazel version specified in the `.bazelversion` file at the project root. This ensures all contributors use a consistent Bazel version. Simply install Bazelisk and use `bazel` as usual — it transparently delegates to the correct version. + +## Syntax Checks + +To validate that every ETL header is well-formed and compiles on its own (equivalent to `test/run-syntax-checks.sh` for CMake): + +```sh +bazel build //test/syntax_check:syntax_check +``` + +This compiles a set of minimal `.t.cpp` files, each of which includes a single ETL header, with strict warning flags enabled. + +## Cleaning Build Artifacts + +To remove all build outputs and symlinks (`bazel-bin`, `bazel-out`, `bazel-etl`, etc.): + +```sh +bazel clean +``` + +For a full cleanup including the external dependency cache: + +```sh +bazel clean --expunge +``` + +## Running Unit Tests + +To run the full test suite: + +```sh +bazel test //test:etl_tests +``` + +You can also pass standard Bazel flags: + +```sh +# Run with verbose test output +bazel test //test:etl_tests --test_output=all + +# Run tests matching a filter (UnitTest++ subset) +bazel test //test:etl_tests --test_arg= +``` + +## Using ETL in Your Project + +### With Bzlmod (recommended, Bazel 7+) + +Add ETL as a dependency in your project's `MODULE.bazel`: + +```python +bazel_dep(name = "etl", version = "20.47.1") + +git_override( + module_name = "etl", + remote = "https://github.com/ETLCPP/etl.git", + tag = "20.47.1", # or a specific commit +) +``` + +Then depend on it in your `BUILD.bazel`: + +```python +cc_library( + name = "my_library", + srcs = ["my_library.cpp"], + hdrs = ["my_library.h"], + deps = ["@etl//:etl"], +) +``` + +### With WORKSPACE (legacy) + +In your `WORKSPACE` file: + +```python +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "etl", + remote = "https://github.com/ETLCPP/etl.git", + tag = "20.47.1", +) +``` + +Then use `deps = ["@etl//:etl"]` in your targets as shown above. + +## Project Structure + +| File | Purpose | +|---|---| +| `MODULE.bazel` | Module definition and dependencies | +| `BUILD.bazel` | Exposes ETL as a `cc_library` | +| `.bazelversion` | Bazel version for Bazelisk | +| `.bazelrc` | Default Bazel settings | +| `test/BUILD.bazel` | Unit test target | +| `test/syntax_check/BUILD.bazel` | Header syntax check target | +| `test/UnitTest++/BUILD.bazel` | Vendored UnitTest++ framework | + +## Cross-Compilation + +Bazel supports cross-compilation through its [platforms](https://bazel.build/extending/platforms) and [toolchains](https://bazel.build/extending/toolchains) system. Since ETL is a header-only library, there is nothing to cross-compile for the library itself. However, when building tests or consuming ETL in an application targeting a different architecture, you need to define a platform and register an appropriate C++ toolchain. + +Example platform definition (e.g. in a `platforms/BUILD.bazel`): + +```python +platform( + name = "linux_arm64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:aarch64", + ], +) +``` + +Then build with: + +```sh +bazel build //:etl --platforms=//platforms:linux_arm64 +``` + +> **Note:** You must also have a C++ toolchain registered that supports the target platform. +> See the [Bazel toolchains documentation](https://bazel.build/extending/toolchains) for details. + +### Running Cross-Compiled Tests under QEMU + +Cross-compiled test binaries cannot run natively on the host. Pre-defined configurations in `.bazelrc` select the correct cross-compiler via `--repo_env=CC`, set the build flags to match `.devcontainer/run-tests.sh` (C++23, No-STL, `-O0`), and use `--run_under` to execute the resulting binary under the appropriate QEMU emulator: + +```sh +# Cross-build and run tests for ARM (armhf) +bazel test //test:etl_tests --config=armhf + +# Other architectures +bazel test //test:etl_tests --config=i386 +bazel test //test:etl_tests --config=powerpc +bazel test //test:etl_tests --config=riscv64 +bazel test //test:etl_tests --config=s390x +``` + +These configs are designed to run inside the Docker containers under `.devcontainer/`, which provide the cross-compiler toolchains and QEMU binaries. Each config sets `CC`, `AR`, `LD`, `NM`, `STRIP`, and `OBJDUMP` via `--repo_env` so that Bazel's auto-configured toolchain finds the complete prefixed cross-tool suite. + +You can also use `--run_under` directly for custom setups: + +```sh +bazel test //test:etl_tests --run_under=/usr/bin/qemu-arm-static +``` + +## Compiler and Build Configuration + +Unlike CMake where options like `ETL_CXX_STANDARD` and `CMAKE_CXX_COMPILER` are set at configure time, Bazel uses command-line flags and `.bazelrc` configurations. + +### C++ Standard Version + +Use `--cxxopt` to pass the desired standard flag: + +```sh +# C++17 (default in .bazelrc) +bazel test //test:etl_tests --cxxopt=-std=c++17 + +# C++20 +bazel test //test:etl_tests --cxxopt=-std=c++20 + +# C++23 +bazel test //test:etl_tests --cxxopt=-std=c++23 + +# C++14 +bazel test //test:etl_tests --cxxopt=-std=c++14 +``` + +### Optimization Level + +Use `--compilation_mode` (shorthand `-c`) for standard profiles, or `--copt` for explicit flags: + +```sh +# Debug (default) — no optimization, debug symbols +bazel test //test:etl_tests -c dbg + +# Optimized — O2 with NDEBUG +bazel test //test:etl_tests -c opt + +# Fast build — no optimization, no debug symbols +bazel test //test:etl_tests -c fastbuild + +# Custom optimization level +bazel test //test:etl_tests --copt=-O3 +bazel test //test:etl_tests --copt=-O1 +bazel test //test:etl_tests --copt=-Os +``` + +### Selecting the Compiler (GCC vs Clang) + +Bazel uses the system's default `CC` environment variable. Override it to switch compilers: + +```sh +# Use Clang +bazel test //test:etl_tests --repo_env=CC=clang + +# Use a specific GCC version +bazel test //test:etl_tests --repo_env=CC=gcc-13 + +# Use a specific Clang version +bazel test //test:etl_tests --repo_env=CC=clang-18 +``` + +> **Note:** Bazel's auto-configured toolchain infers the C++ compiler from `CC` automatically +> (e.g. `CC=gcc-13` → `g++-13` for C++ compilation). There is no need to set `CXX` separately. + +### Combining Options + +Flags can be combined freely: + +```sh +# Clang, C++20, optimized +bazel test //test:etl_tests --repo_env=CC=clang --cxxopt=-std=c++20 -c opt + +# GCC 13, C++23, debug +bazel test //test:etl_tests --repo_env=CC=gcc-13 --cxxopt=-std=c++23 -c dbg +``` + +### STL vs. No-STL Mode + +ETL can operate without the standard library, which is common on bare-metal embedded targets. Use `--copt` to define `ETL_NO_STL`: + +```sh +# Build and test without STL +bazel test //test:etl_tests --copt=-DETL_NO_STL + +# Build with STL (default, no flag needed) +bazel test //test:etl_tests +``` + +When `ETL_NO_STL` is defined, ETL provides its own implementations of containers, algorithms, and utilities instead of delegating to ``, ``, etc. + +### Type Traits Configuration + +ETL supports three type traits strategies, controlled via preprocessor defines: + +| Mode | Define | Description | +|---|---|---| +| **STL type traits** | *(default)* | Uses `` from the standard library | +| **Compiler builtins** | `ETL_USE_TYPE_TRAITS_BUILTINS` | Uses compiler intrinsics (`__is_trivially_copyable`, etc.) — useful when STL headers are unavailable or incomplete | +| **User-defined** | `ETL_USER_DEFINED_TYPE_TRAITS` | Uses ETL's own type traits implementations | + +```sh +# Use compiler built-in type traits +bazel test //test:etl_tests --copt=-DETL_USE_TYPE_TRAITS_BUILTINS + +# Use ETL's own user-defined type traits +bazel test //test:etl_tests --copt=-DETL_USER_DEFINED_TYPE_TRAITS +``` + +These are mutually exclusive — define at most one. If neither is defined and STL is available, ETL uses ``. + +### Other Configuration Defines + +Additional defines can be passed the same way via `--copt=-D...`: + +| Define | Description | +|---|---| +| `ETL_FORCE_TEST_CPP03_IMPLEMENTATION` | Force C++03 code paths even when a newer standard is available | +| `ETL_MESSAGES_ARE_NOT_VIRTUAL` | Use non-virtual message types | + +```sh +# Force C++03 implementation paths +bazel test //test:etl_tests --copt=-DETL_FORCE_TEST_CPP03_IMPLEMENTATION +``` + +### Using `.bazelrc` Presets + +To avoid retyping flags, add configurations to `.bazelrc`: + +``` +# .bazelrc + +# Named configurations +build:clang --repo_env=CC=clang +build:gcc13 --repo_env=CC=gcc-13 +build:c++20 --cxxopt=-std=c++20 +build:c++23 --cxxopt=-std=c++23 +build:release --compilation_mode=opt +``` + +Then use them with `--config`: + +```sh +bazel test //test:etl_tests --config=clang --config=c++20 --config=release +``` diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 00000000..2dc8d25d --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,289 @@ +# Docker for Development + +## Overview + +The ETL repository ships a set of Docker-based development environments under +`.devcontainer/`. They give every contributor an identical, reproducible toolchain +regardless of host operating system. Three flavours are provided: + +| Flavour | Path | Purpose | +|---|---|---| +| **Default** | `.devcontainer/` | Day-to-day development (Microsoft C++ dev-container base image) | +| **Compiler-specific** | `.devcontainer/gcc09/` … `.devcontainer/gcc15/`, `.devcontainer/clang7/` … `.devcontainer/clang21/` | Test against a specific GCC or Clang version | +| **s390x big-endian** | `.devcontainer/s390x/` | Cross-compile and run tests on an s390x target via QEMU | + +All containers include CMake, Make, Git, Python 3, cogapp (the code generator used +by ETL), clang-format 18, and treefmt. + +## Prerequisites + +- **Docker** (or Docker Desktop) – any recent version that supports `docker build` + and `docker run`. +- **VS Code** with the + [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + extension (optional, but recommended for the smoothest experience). +- **Git** – to clone the repository. + +## Quick Start + +### Using the helper script + +The fastest way to get a shell inside the default container from the project root: + +```bash +./scripts/run-docker.sh +``` + +This script performs two steps: + +1. **Builds** the image from `.devcontainer/Dockerfile` and tags it `etl`. +2. **Runs** an interactive container that bind-mounts the repository at + `/home/vscode/etl` so that edits made inside the container are visible on + the host (and vice versa). + +You are dropped into a Bash shell as the `vscode` user with the working +directory set to the repository root. + +### Using VS Code Dev Containers + +1. Open the repository folder in VS Code. +2. When prompted, click **Reopen in Container** – or run the command + *Dev Containers: Reopen in Container* from the command palette. +3. VS Code reads `.devcontainer/devcontainer.json`, builds the image, and + attaches to the running container automatically. + +To open a **specific compiler variant** instead, run +*Dev Containers: Open Folder in Container…* and pick the sub-folder (e.g. +`.devcontainer/gcc14/`), or use the command palette action +*Dev Containers: Open Named Container Configuration…* and select the desired +name (e.g. "Gcc 14", "Clang 18"). + +## Default Development Container + +The file `.devcontainer/Dockerfile` is a multi-purpose image used by the +default configuration **and** by every compiler-specific variant (they simply +override the `BASE_IMAGE_NAME` build argument). + +### Base image + +```text +mcr.microsoft.com/devcontainers/cpp:2 +``` + +The exact digest is pinned in `devcontainer.json` so that builds are +reproducible even if the upstream tag is updated. + +### Installed tools + +The Dockerfile installs the following on top of the base image: + +| Tool | Purpose | +|---|---| +| `python3`, `pip` | Runtime for helper scripts | +| `python3-cogapp` / `cogapp` | ETL code generator | +| `git` | Version control | +| `wget` | Downloading additional tooling | +| `cmake`, `make` | Build system | +| `clang-format` (v18) | Source formatting (see [source-formatting.md](source-formatting.md)) | +| `treefmt` (v2.4.1) | Single-command formatting wrapper | + +### Reproducible builds with Debian snapshots + +The default configuration sets the build argument +`DEBIAN_SNAPSHOT=20260223T000000Z`. When this value is not `"none"`, the +Dockerfile rewrites the APT sources to point at +`snapshot.debian.org/archive/debian/`, ensuring that every +contributor installs identical package versions. Compiler-specific variants +that are based on upstream `gcc:*` or `silkeh/clang:*` images set +`DEBIAN_SNAPSHOT=none` because those images manage their own package sources. + +## Compiler-Specific Containers + +Each sub-folder under `.devcontainer/` contains a `devcontainer.json` that +reuses the **same** `Dockerfile` (`../Dockerfile`) but overrides the +`BASE_IMAGE_NAME` build argument to select a different compiler. + +### GCC variants + +| Folder | Base image | Name | +|---|---|---| +| `gcc09/` | `gcc:9` | Gcc 09 | +| `gcc10/` | `gcc:10` | Gcc 10 | +| `gcc11/` | `gcc:11` | Gcc 11 | +| `gcc12/` | `gcc:12` | Gcc 12 | +| `gcc13/` | `gcc:13` | Gcc 13 | +| `gcc14/` | `gcc:14` | Gcc 14 | +| `gcc15/` | `gcc:15` | Gcc 15 | + +### Clang variants + +| Folder | Base image | Name | +|---|---|---| +| `clang7/` | `silkeh/clang:7` | Clang 7 | +| `clang8/` | `silkeh/clang:8` | Clang 8 | +| `clang9/` | `silkeh/clang:9` | Clang 9 | +| `clang10/` | `silkeh/clang:10` | Clang 10 | +| `clang11/` | `silkeh/clang:11` | Clang 11 | +| `clang12/` | `silkeh/clang:12` | Clang 12 | +| `clang13/` | `silkeh/clang:13` | Clang 13 | +| `clang14/` | `silkeh/clang:14` | Clang 14 | +| `clang15/` | `silkeh/clang:15` | Clang 15 | +| `clang16/` | `silkeh/clang:16` | Clang 16 | +| `clang17/` | `silkeh/clang:17` | Clang 17 | +| `clang18/` | `silkeh/clang:18` | Clang 18 | +| `clang19/` | `silkeh/clang:19` | Clang 19 | +| `clang20/` | `silkeh/clang:20` | Clang 20 | +| `clang21/` | `silkeh/clang:21` | Clang 21 | + +All compiler-specific variants set `DEBIAN_SNAPSHOT` to `"none"` because they +rely on the upstream image's own package sources. + +## s390x Big-Endian Cross-Compilation + +The `s390x` container lives in `.devcontainer/s390x/` and has its **own** +Dockerfile (it does not reuse the default one). It is based on +`debian:trixie` and installs: + +- QEMU user-mode emulation (`qemu-user-static`, `qemu-user`, `binfmt-support`) +- s390x cross-compilation toolchain (`gcc-s390x-linux-gnu`, + `g++-s390x-linux-gnu`) +- CMake, Make, Ninja, Git, wget + +### Container setup + +Open `.devcontainer/s390x/` as a Dev Container in VS Code, or build manually: + +```bash +docker build -t etl-s390x .devcontainer/s390x +docker run -it --rm -v .:/workspaces/etl -w /workspaces/etl etl-s390x +``` + +### CMake toolchain + +A CMake toolchain file is provided at +`.devcontainer/s390x/toolchain-s390x.cmake`. It sets: + +- `CMAKE_SYSTEM_PROCESSOR` to `s390x` +- Cross-compilers `s390x-linux-gnu-gcc` / `g++` +- `CMAKE_CROSSCOMPILING_EMULATOR` to `/usr/bin/qemu-s390x-static` + +The VS Code Dev Container configuration already passes this toolchain file +via `cmake.configureArgs`, so CMake Tools picks it up automatically. + +### Running tests under QEMU + +Because the toolchain file sets `CMAKE_CROSSCOMPILING_EMULATOR`, CTest +automatically invokes `qemu-s390x-static` when running test binaries. +No extra flags are needed: + +```bash +cmake -S test -B build-s390x \ + -DCMAKE_TOOLCHAIN_FILE=.devcontainer/s390x/toolchain-s390x.cmake \ + -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_CXX_STANDARD=17 -G Ninja +cmake --build build-s390x +ctest --test-dir build-s390x +``` + +## Building and Running Tests + +Once inside any container (default, compiler-specific, or s390x) you can +build and run the ETL test suite. + +### Quick CMake workflow + +```bash +# Configure – build tests with C++17 +cmake -S test -B build -DBUILD_TESTS=ON -DETL_CXX_STANDARD=17 + +# Build +cmake --build build -j $(nproc) + +# Run tests +ctest --test-dir build +``` + +Change `DETL_CXX_STANDARD` to `11`, `14`, `17`, `20`, or `23` as needed. +Add `-DNO_STL=ON` to build without the standard library. + +### Using the run-tests script + +The repository also provides a convenience script in `test/`: + +```bash +cd test +./run-tests.sh [optimisation] [threads] [sanitizer] [compiler] [verbose] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ standard | `11`, `14`, `17`, `20`, `23` | *(required)* | +| Optimisation | `0`, `1`, `2`, `3` | `0` | +| Threads | any integer | `4` | +| Sanitizer | `s` (enable) / `n` (disable) | `n` | +| Compiler | `gcc` / `clang` | all | +| Verbose | `v` (enable) / `n` (disable) | `n` | + +Example – run C++17 tests at `-O2` with 8 threads using GCC: + +```bash +./run-tests.sh 17 2 8 n gcc n +``` + +## Formatting Inside the Container + +The default container ships with **clang-format 18** and **treefmt**. +See [source-formatting.md](source-formatting.md) for the full formatting guide. + +Quick reference: + +```bash +# Format all tracked C/C++ files with treefmt +treefmt + +# Or use clang-format directly via the wrapper +./scripts/clang-format-wrapper -i include/etl/*.h +``` + +The wrapper script `scripts/clang-format-wrapper` resolves the correct +clang-format binary (prefers `clang-format-18`, falls back to `clang-format` +after checking the major version). + +## Customisation + +To add extra packages or tools to the default container, edit +`.devcontainer/Dockerfile`. The image follows a straightforward +`apt-get install` pattern, so adding a new package is as simple as appending +it to the existing `apt-get` line. + +To create a new compiler variant: + +1. Create a folder under `.devcontainer/` (e.g. `.devcontainer/gcc16/`). +2. Add a `devcontainer.json` that references `"../Dockerfile"` and sets + `BASE_IMAGE_NAME` to the desired image (e.g. `gcc:16`). +3. Set `DEBIAN_SNAPSHOT` to `"none"` for upstream compiler images. + +Example: + +```jsonc +{ + "name": "Gcc 16", + "build": { + "dockerfile": "../Dockerfile", + "args": { + "BASE_IMAGE_NAME": "gcc:16", + "DEBIAN_SNAPSHOT": "none" + }, + "context": "../context" + } +} +``` + +## Troubleshooting + +| Symptom | Cause / Fix | +|---|---| +| `apt-get` fails with *"Release file … is not valid yet"* | The Debian snapshot timestamp is in the future relative to the build host clock. Either update `DEBIAN_SNAPSHOT` in `devcontainer.json` or set it to `"none"`. | +| `clang-format` reports the wrong version | The wrapper expects version **18**. Make sure the image installs `clang-format` (or `clang-format-18`) and that the binary is on `PATH`. | +| Permission errors on mounted files | The `run-docker.sh` script runs as user `vscode`. Ensure your host UID matches, or adjust the `--user` flag. | +| s390x tests crash immediately | Verify that `qemu-user-static` is installed and that `binfmt-support` is active. On some hosts you may need to register binfmt handlers with `docker run --privileged --rm tonistiigi/binfmt --install all`. | +| Build is very slow the first time | Docker is downloading and building the image from scratch. Subsequent builds use the layer cache and are much faster. | diff --git a/docs/format.md b/docs/format.md new file mode 100644 index 00000000..02b4edda --- /dev/null +++ b/docs/format.md @@ -0,0 +1,389 @@ +# ETL Format & Print + +## 1. Overview + +ETL provides text formatting facilities modelled on C++20 `std::format` and C++23 +`std::print`. They allow type-safe, positional formatting of values into strings +or directly to a character output device — without heap allocation. + +**Minimum language standard:** C++11 (`ETL_USING_CPP11`). + +**Headers:** + +| Header | Provides | +|---|---| +| `etl/format.h` | `etl::format_to`, `etl::format_to_n`, `etl::formatted_size` | +| `etl/print.h` | `etl::print`, `etl::println` (includes `etl/format.h`) | + +## 2. `etl::format_to` + +### Generic output-iterator overload + +```cpp +template +OutputIt format_to(OutputIt out, format_string fmt, Args&&... args); +``` + +Formats `args` according to the format string `fmt` and writes the result through +the output iterator `out`. Returns an iterator past the last character written. + +`OutputIt` can be any output iterator whose dereferenced type is assignable from +`char`, for example `etl::istring::iterator` or +`etl::back_insert_iterator`. + +```cpp +etl::string<100> s; + +// Using a raw iterator — you must resize the string yourself +etl::istring::iterator result = etl::format_to(s.begin(), "{0} {1}", 34, 56); +s.uninitialized_resize(static_cast(result - s.begin())); +// s == "34 56" + +// Using a back_insert_iterator — string grows automatically +s.clear(); +etl::back_insert_iterator it(s); +etl::format_to(it, "{} {}", 65, 34); +// s == "65 34" +``` + +### `etl::istring&` overload (ETL-specific) + +```cpp +template +etl::istring::iterator format_to(etl::istring& out, + format_string fmt, + Args&&... args); +``` + +Convenience overload that writes into an `etl::istring` (or any derived +`etl::string`). The string is automatically resized to the number of +characters written, up to `out.max_size()`. Returns an iterator past the +last character written. + +```cpp +etl::string<100> s; +etl::format_to(s, "Hello, {}!", "world"); +// s == "Hello, world!" +``` + +### `etl::format_to_n` + +```cpp +template +OutputIt format_to_n(OutputIt out, size_t n, + format_string fmt, Args&&... args); +``` + +Like `format_to`, but writes **at most** `n` characters. Characters beyond the +limit are silently discarded. + +```cpp +etl::string<10> s = "abcdefghij"; +etl::format_to_n(s.begin(), 3, "xy{}", 123); +// s == "xy1defghij" (only 3 chars written) +``` + +## 3. `etl::formatted_size` + +```cpp +template +size_t formatted_size(format_string fmt, Args&&... args); +``` + +Returns the total number of characters that `format_to` would produce, without +actually writing anything. Useful for pre-computing buffer sizes. + +```cpp +size_t n; +n = etl::formatted_size(""); // 0 +n = etl::formatted_size("{}", ""); // 0 +n = etl::formatted_size("xyz{}", 12); // 5 +n = etl::formatted_size("{}", "abc"); // 3 +``` + +## 4. `etl::print` and `etl::println` + +Declared in `etl/print.h`. + +### `etl::print` + +```cpp +template +void print(etl::format_string fmt, Args&&... args); +``` + +Formats the arguments and outputs each character by calling `etl_putchar()`. + +### `etl::println` + +```cpp +// With arguments — prints formatted text followed by '\n' +template +void println(etl::format_string fmt, Args&&... args); + +// Without arguments — prints a bare newline +void println(); +``` + +### Implementing `etl_putchar` + +`etl/print.h` declares (but does not define) the following C-linkage function: + +```cpp +extern "C" void etl_putchar(int c); +``` + +You **must** provide a definition in your project. The `int` parameter follows +the convention of the standard `putchar()` and carries a single `char` value. + +Typical implementations forward to a UART, a debug probe, `putchar`, or any +other single-character output sink: + +```cpp +// Example: forward to standard putchar +extern "C" void etl_putchar(int c) +{ + putchar(c); +} +``` + +### Example + +```cpp +etl::print("x = {}, y = {}\n", 10, 20); // "x = 10, y = 20\n" +etl::println("Hello, {}!", "world"); // "Hello, world!\n" +etl::println(); // "\n" +``` + +## 5. Format String Syntax + +A format string is ordinary text with **replacement fields** delimited by braces: + +``` +"literal text {} more text {1:>10} end" +``` + +### Replacement field grammar + +``` +replacement_field ::= '{' [arg_id] [':' format_spec] '}' +arg_id ::= integer // e.g. 0, 1, 2 … +format_spec ::= [[fill]align] [sign] ['#'] ['0'] [width] ['.' precision] ['L'] [type] +``` + +| Component | Syntax | Description | +|---|---|---| +| **Argument index** | `{0}`, `{1}`, … | Manual positional indexing. Cannot be mixed with automatic indexing. | +| **Automatic index** | `{}` | Uses the next argument in order. Cannot be mixed with manual indexing. | +| **Fill character** | any character except `{` or `}` | Used together with an alignment specifier. Default is space (` `). | +| **Alignment** | `<` left, `>` right, `^` center | Aligns the formatted value within the given *width*. | +| **Sign** | `+` always, `-` negative only (default), ` ` space for positive | Controls sign display for numeric types. | +| **`#` (alt form)** | `#` | Adds `0x`/`0X` for hex, `0b`/`0B` for binary, `0` for octal. | +| **`0` (zero-pad)** | `0` | Pads the number with leading zeros (after sign/prefix). | +| **Width** | integer, or `{}` / `{n}` | Minimum field width. Supports nested replacement fields for dynamic width. | +| **Precision** | `.` integer, or `.{}` / `.{n}` | For strings: maximum characters to output. For floats: number of decimal digits. Supports nested replacement fields. | +| **`L`** | `L` | Locale-specific flag (parsed but currently ignored). | +| **Type** | see [Presentation Types](#7-presentation-types-per-argument-kind) | Selects the output representation. | + +### Examples + +```cpp +etl::format_to(s, "{:>10}", 42); // " 42" +etl::format_to(s, "{:*^10}", 42); // "****42****" +etl::format_to(s, "{:+05d}", 67); // "+00067" +etl::format_to(s, "{:#x}", 0x3f4); // "0x3f4" +etl::format_to(s, "{:.3s}", "abcdef"); // "abc" +etl::format_to(s, "{1} {0}", 1, 2); // "2 1" +``` + +## 6. Supported Argument Types + +The core set of formattable types (matching `std::basic_format_arg`): + +| Category | Types | +|---|---| +| Boolean | `bool` | +| Character | `char` | +| Signed integer | `int`, `long long int` | +| Unsigned integer | `unsigned int`, `unsigned long long int` | +| Floating-point *(opt-in)* | `float`, `double`, `long double` — requires `ETL_USING_FORMAT_FLOATING_POINT` | +| String | `const char*`, `etl::string_view` | +| Pointer | `const void*` | + +### Implicit conversions + +Types not listed above are converted automatically before formatting: + +| Source type | Stored as | +|---|---| +| `short` | `int` | +| `unsigned short`, `uint16_t` | `unsigned int` | +| `long int` | `int` or `long long int` (platform-dependent) | +| `unsigned long int`, `size_t` | `unsigned int` or `unsigned long long int` | +| `int8_t` (`signed char`) | `char` | +| `uint8_t` (`unsigned char`) | `char` | +| `int16_t` | `int` | +| `uint32_t` | `unsigned int` | +| `int32_t` | `int` | +| `etl::string` | `etl::string_view` (lifetime of the temporary is guaranteed) | +| any pointer `T*` | `const void*` | + +## 7. Presentation Types per Argument Kind + +### Integers (`int`, `unsigned int`, `long long int`, `unsigned long long int`) + +| Type | Meaning | Example | +|---|---|---| +| `d` *(default)* | Decimal | `134` → `"134"` | +| `x` | Lowercase hexadecimal | `0x3f4` → `"3f4"` | +| `X` | Uppercase hexadecimal | `0x3f4` → `"3F4"` | +| `o` | Octal | `034` → `"34"` | +| `b` | Lowercase binary | `0b1010` → `"1010"` | +| `B` | Uppercase binary | `0b1010` → `"1010"` | +| `c` | Character (value as char) | `67` → `"C"` | + +With `#`: prefixes `0x`/`0X`, `0b`/`0B`, or leading `0` for octal. + +### Characters (`char`, `signed char`, `unsigned char`) + +| Type | Meaning | Example | +|---|---|---| +| `c` *(default)* | Character itself | `'s'` → `"s"` | +| `?` | Debug / escaped | `'\n'` → `"'\\n'"` | +| `d` | Decimal code point | `'a'` → `"97"` | +| `x` / `X` | Hex code point | `'a'` → `"61"` | + +### Booleans (`bool`) + +| Type | Meaning | Example | +|---|---|---| +| *(default)* | `false` / `true` | `true` → `"true"` | +| `s` | Same as default | `true` → `"true"` | +| `d` | `0` / `1` | `true` → `"1"` | +| `x` / `X` | Hex `0` / `1` | `true` → `"1"` | +| `o` | Octal (with `#`: `01`) | `true` → `"01"` | + +### Strings (`const char*`, `etl::string_view`, `etl::string`) + +| Type | Meaning | Example | +|---|---|---| +| `s` *(default)* | String output | `"data1"` → `"data1"` | +| `?` | Debug / escaped | `"data1\n"` → `"\"data1\\n\""` | + +Width and precision apply: width sets the minimum field width; precision (`.N`) +truncates the string to at most *N* characters. + +```cpp +etl::format_to(s, "{:>10s}", "data1"); // " data1" +etl::format_to(s, "{:.3s}", "abcdef"); // "abc" +etl::format_to(s, ".{:^8.3s}!", "data1"); // ". dat !" +``` + +### Pointers (`const void*`) + +| Type | Meaning | Example | +|---|---|---| +| `p` *(default)* | Lowercase hex with `0x` prefix | `nullptr` → `"0x0"` | +| `P` | Uppercase hex with `0X` prefix | `nullptr` → `"0X0"` | + +### Floating-point (`float`, `double`, `long double`) + +Requires `ETL_USING_FORMAT_FLOATING_POINT`. + +| Type | Meaning | Example | +|---|---|---| +| *(default)* | Shortest representation | `1.5f` → `"1.5"` | +| `e` / `E` | Scientific notation | `1.0f` → `"1.000000e+00"` | +| `f` / `F` | Fixed-point notation | `1.125f` → `"1.125000"` | +| `g` / `G` | General (fixed or scientific) | `1e10f` → `"1.000000e+10"` | +| `a` / `A` | Hexadecimal floating-point | `1.5f` → `"0x1.8p+0"` | + +`nan`, `inf` (lowercase for `e`/`f`/`g`/`a`, uppercase for `E`/`F`/`G`/`A`). + +## 8. Escape Sequences and Literal Braces + +### Literal braces + +Because `{` and `}` delimit replacement fields, they must be escaped by +doubling: + +| Input | Output | +|---|---| +| `{{` | `{` | +| `}}` | `}` | + +```cpp +etl::format_to(s, "abc{{def"); // "abc{def" +etl::format_to(s, "}}abc"); // "}abc" +``` + +### Debug / escaped presentation (`?`) + +The `?` type specifier produces a debug representation: + +- **Characters** are wrapped in single quotes with C-style escape sequences: + + | Character | Output | + |---|---| + | `\t` | `'\\t'` | + | `\n` | `'\\n'` | + | `\r` | `'\\r'` | + | `"` | `'\\\"'` | + | `'` | `'\\''` | + | `\\` | `'\\\\'` | + +- **Strings** are wrapped in double quotes with the same escape sequences: + + ```cpp + etl::format_to(s, "{:?}", "data1\n"); // "\"data1\\n\"" + ``` + +## 9. Error Handling + +Invalid format strings cause an `etl::bad_format_string_exception` (derived from +`etl::format_exception`, which is derived from `etl::exception`). + +Common error conditions: + +| Condition | Example | +|---|---| +| Missing closing brace | `"a{b"` | +| Unescaped `}` without matching `{` | `"a}b"` | +| Invalid characters inside `{}` | `"a{b}"` | +| Argument index out of range | `"{1}"` with only one argument | +| Mixing manual and automatic indexing | `"{0} {}"` | +| Invalid type specifier for the argument | `"{:d}"` on a `string_view` | +| Double colon in format spec | `"{::}"` | +| Precision on an integer | `"{:+#05.5X}"` on an `int` | + +```cpp +etl::string<100> s; +// These all throw etl::bad_format_string_exception: +etl::format_to(s, "a{b}", 1); // bad index spec +etl::format_to(s, "a{b", 1); // closing brace missing +etl::format_to(s, "a}b"); // unescaped } +etl::format_to(s, "{:d}", sv); // invalid type for string_view +``` + +> **Note:** On C++20 and later, format strings are validated at compile time +> via `consteval`. The checks cover syntax (balanced braces, valid format spec +> grammar, index bounds, no mixing of automatic and manual indexing) as well as +> type/specifier compatibility (e.g. `{:d}` is rejected for string arguments). +> A malformed format string produces a compile error whose diagnostic mentions +> `please_note_this_is_error_message_format_string_syntax_error`. +> +> On C++11–C++17, the same checks run at runtime and throw +> `etl::bad_format_string_exception`. + +## 10. Differences from `std::format` + +| Area | `std::format` (C++20/23) | ETL | +|---|---|---| +| **Output target** | Returns `std::string` | Writes through an output iterator or into `etl::istring&` — no heap allocation. | +| **`etl::istring&` overload** | Not available | `format_to(etl::istring&, ...)` automatically resizes the string. | +| **`print` / `println` output** | Writes to `FILE*` / `stdout` | Writes character-by-character via user-defined `etl_putchar(int)`. | +| **Floating-point support** | Always available | Opt-in via `ETL_USING_FORMAT_FLOATING_POINT`. | +| **User-defined formatters** | `std::formatter` specialisations | Not yet supported. | +| **Locale** | `L` flag uses `std::locale` | `L` flag is parsed but has no effect. | +| **Compile-time validation** | Enforced via `consteval` on C++20 | Enforced via `consteval` on C++20 (syntax and type/specifier compatibility); validates at run time and throws `etl::bad_format_string_exception` on C++11–C++17. | +| **`format_to_n` return type** | `std::format_to_n_result` | Returns the underlying `OutputIt` directly. | diff --git a/docs/generators.md b/docs/generators.md new file mode 100644 index 00000000..d44a38b6 --- /dev/null +++ b/docs/generators.md @@ -0,0 +1,190 @@ +# Code Generation for Pre-C++11 Support + +ETL supports C++03 (also referred to as C++98) environments where variadic +templates, `constexpr`, and other modern features are unavailable. To +provide equivalent functionality, certain headers are **generated** using +[Cog](https://nedbatchelder.com/code/cog/), a Python-based code generation +tool that embeds Python snippets inside source files. + +This document explains how the code generation system works and how to +regenerate the headers if you modify a generator template. + +--- + +## Overview + +| Directory | Contents | +|---|---| +| `include/etl/generators/` | Generator templates (`*_generator.h`) and batch scripts | +| `include/etl/private/` | Generated output (`*_cpp03.h`) committed to the repository | +| `scripts/generator_test.py` | CI script that verifies generators match committed files | + +The generator templates contain embedded Python code (delimited by `[[[cog` +and `]]]`) that produces the repetitive C++03 boilerplate. Cog processes +these templates and writes the expanded output to `include/etl/private/`. + +--- + +## Generated Headers + +The following C++03 compatibility headers are generated: + +| Generator | Output | Purpose | +|---|---|---| +| `fsm_fwd_decl_cpp03_generator.h` | `fsm_fwd_decl_cpp03.h` | FSM forward declarations | +| `fsm_friend_decl_cpp03_generator.h` | `fsm_friend_decl_cpp03.h` | FSM friend declarations | +| `fsm_cpp03_generator.h` | `fsm_cpp03.h` | Finite state machine implementation | +| `message_router_cpp03_generator.h` | `message_router_cpp03.h` | Message router | +| `message_packet_cpp03_generator.h` | `message_packet_cpp03.h` | Message packet | +| `largest_type_cpp03_generator.h` | `largest_type_cpp03.h` | Largest type metafunction | +| `largest_alignment_cpp03_generator.h` | `largest_alignment_cpp03.h` | Largest alignment metafunction | +| `largest_cpp03_generator.h` | `largest_cpp03.h` | Largest type/size utilities | +| `smallest_cpp03_generator.h` | `smallest_cpp03.h` | Smallest type/size utilities | +| `type_traits_cpp03_generator.h` | `type_traits_cpp03.h` | Type traits (`is_one_of`, etc.) | +| `type_lookup_cpp03_generator.h` | `type_lookup_cpp03.h` | Type lookup metafunction | +| `type_select_cpp03_generator.h` | `type_select_cpp03.h` | Type selection metafunction | +| `variant_pool_cpp03_generator.h` | `variant_pool_cpp03.h` | Variant pool | + +--- + +## Generator Parameters + +Cog variables control how many template parameter overloads are generated: + +| Variable | Default | Used by | +|---|---|---| +| `Handlers` | 16 | FSM and message router generators | +| `NTypes` | 16 | Type utility generators (largest, smallest, lookup, select, variant pool) | +| `IsOneOf` | 16 | Type traits generator (`is_one_of`) | + +These defaults produce overloads supporting up to 16 types or handlers, +which is sufficient for most embedded applications while keeping compile +times reasonable. + +--- + +## Prerequisites + +* **Python 3** +* **cogapp** – install via: + + ```bash + pip install cogapp + ``` + +--- + +## Regenerating Headers + +### Using the batch scripts (Windows) + +Each generator has a corresponding `.bat` file in `include/etl/generators/`: + +```bat +cd include/etl/generators +generate.bat # Regenerate all headers +generate_fsm.bat # Regenerate FSM headers only +generate_smallest.bat # Regenerate smallest_cpp03.h only +# etc. +``` + +### Manual invocation + +Run Cog directly from the `include/etl/generators/` directory: + +```bash +cd include/etl/generators + +# Example: regenerate smallest_cpp03.h +python3 -m cogapp -d -e -o../private/smallest_cpp03.h -DNTypes=16 smallest_cpp03_generator.h + +# Example: regenerate fsm_cpp03.h +python3 -m cogapp -d -e -o../private/fsm_cpp03.h -DHandlers=16 fsm_cpp03_generator.h +``` + +Cog options used: + +| Option | Meaning | +|---|---| +| `-d` | Delete the generator markers from output | +| `-e` | Warn if the input file has no generator markers | +| `-o` | Write output to the specified file | +| `-D=` | Define a Cog variable | + +### Regenerating all headers + +The `generate.bat` script regenerates every header: + +```bash +cd include/etl/generators +./generate.bat # Windows +# or run the commands manually on Linux/macOS +``` + +On Linux/macOS you can run the commands from `generate.bat` directly in +your shell (they are standard `python3 -m cogapp` invocations). + +--- + +## Verifying Generators + +After modifying a generator template, verify the output matches the +committed file: + +```bash +python3 scripts/generator_test.py +``` + +This script: + +1. Runs Cog on every `*_generator.h` file. +2. Compares each output against the corresponding file in + `include/etl/private/`. +3. Reports success or failure. + +The `generator.yml` GitHub Actions workflow runs this automatically on +every push and pull request. + +--- + +## How Generators Work + +A generator template contains standard C++ code interspersed with Cog +directives. For example, from `smallest_cpp03_generator.h`: + +```cpp +/*[[[cog +import cog +cog.outl("template " % int(NTypes)) +]]]*/ +// Generated code appears here after running Cog +/*[[[end]]]*/ +``` + +When Cog processes this file with `-DNTypes=16`, the Python code executes +and outputs the expanded template parameter list supporting 16 types. + +--- + +## Adding a New Generator + +1. Create `include/etl/generators/_cpp03_generator.h` with Cog + directives. +2. Add a corresponding entry to `generate.bat`. +3. Run `generate.bat` (or the equivalent Cog command) to produce + `include/etl/private/_cpp03.h`. +4. Commit both the generator and the generated output. +5. Verify with `python3 scripts/generator_test.py`. + +--- + +## Troubleshooting + +| Problem | Solution | +|---|---| +| `ModuleNotFoundError: No module named 'cogapp'` | Install Cog: `pip install cogapp` | +| Generator output differs from committed file | Regenerate and commit the updated output | +| Need more than 16 types/handlers | Change `-DNTypes=` or `-DHandlers=` and regenerate | diff --git a/docs/meson.md b/docs/meson.md new file mode 100644 index 00000000..3fb318d3 --- /dev/null +++ b/docs/meson.md @@ -0,0 +1,116 @@ +# Building ETL with Meson + +## Prerequisites + +- [Meson](https://mesonbuild.com/) >= 0.57.0 +- A C++17 compiler (GCC, Clang, or MSVC) +- [Ninja](https://ninja-build.org/) (default Meson backend) + +UnitTest++ is fetched automatically as a Meson subproject — no manual dependency installation is needed. + +## Quick Start + +```bash +# Configure (from the project root) +meson setup builddir + +# Build +meson compile -C builddir + +# Run tests +meson test -C builddir +``` + +## Build Options + +### ETL project options + +| Option | Type | Default | Description | +|---------------------|------|---------|-------------------------------------------------------------------| +| `use_stl` | bool | `true` | Build with STL support. When `false`, defines `ETL_NO_STL`. | +| `enable_sanitizer` | bool | `false` | Enable AddressSanitizer and UndefinedBehaviorSanitizer (GCC/Clang only). | + +### Meson built-in options + +| Option | Type | Default | Description | +|-------------|--------|----------|----------------------------------------------------------| +| `cpp_std` | string | `c++17` | C++ standard to compile with (e.g. `c++20`, `c++23`). | +| `buildtype` | string | `debug` | Build type: `plain`, `debug`, `debugoptimized`, `release`, `minsize`. | +| `werror` | bool | `false` | Treat compiler warnings as errors. | + +These are handled by Meson directly — no `get_option()` call is needed in the build files. + +### Examples + +```bash +# No STL, C++23 +meson setup builddir -Duse_stl=false -Dcpp_std=c++23 + +# Release build with sanitizers +meson setup builddir -Dbuildtype=release -Denable_sanitizer=true + +# Override the C++ standard on an existing build directory +meson configure builddir -Dcpp_std=c++20 +``` + +## Selecting a Compiler + +The compiler is chosen at configure time via environment variables: + +```bash +# GCC +CC=gcc CXX=g++ meson setup builddir + +# Clang +CC=clang CXX=clang++ meson setup builddir + +# Specific versions +CC=gcc-14 CXX=g++-14 meson setup builddir +CC=clang-18 CXX=clang++-18 meson setup builddir +``` + +To switch compilers on an existing build directory, wipe it first: + +```bash +CC=clang CXX=clang++ meson setup --wipe builddir +``` + +Or use separate directories per compiler: + +```bash +CC=gcc CXX=g++ meson setup build-gcc +CC=clang CXX=clang++ meson setup build-clang +``` + +## Running Tests + +```bash +# Run all tests +meson test -C builddir + +# Verbose output (shows individual test results) +meson test -C builddir -v + +# Run the test binary directly +./builddir/test/etl_unit_tests +``` + +## Sanitizers + +On GCC and Clang, AddressSanitizer and UndefinedBehaviorSanitizer can be enabled via the `enable_sanitizer` option: + +```bash +meson setup builddir -Denable_sanitizer=true +``` + +Note: UBSan may prevent certain `constexpr` evaluations involving function pointers from compiling (e.g. in the closure tests). This matches the CMake build, where sanitizers are also opt-in via `ETL_ENABLE_SANITIZER=ON`. + +## Using ETL as a Subproject + +ETL can be consumed as a Meson subproject. In your project's `subprojects/` directory, create an `etl.wrap` file, then use: + +```meson +etl_dep = dependency('etl', fallback: ['etl', 'etl_dep']) +``` + +When built as a subproject, the ETL test suite is not compiled. diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 00000000..c6773f6f --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,412 @@ +# Testing ETL + +This document describes how to build and run the ETL test suite locally, +inside Dev Containers, and in CI. + +## Table of Contents + +1. [Prerequisites](#prerequisites) +2. [Running Tests Locally (`test/run-tests.sh`)](#running-tests-locally) +3. [Syntax Checks (`test/run-syntax-checks.sh`)](#syntax-checks) +4. [Cross-Architecture Testing (`.devcontainer/run-tests.sh`)](#cross-architecture-testing) +5. [Dev Containers for Native Compilers](#dev-containers-for-native-compilers) +6. [CMake Options Reference](#cmake-options-reference) +7. [CI Checks (GitHub Actions)](#ci-checks-github-actions) +8. [Appveyor (Windows / MSVC)](#appveyor-windows--msvc) +9. [Code Coverage](#code-coverage) +10. [Generator Tests (`scripts/generator_test.py`)](#generator-tests) + +--- + +## Prerequisites + +* **CMake** ≥ 3.10 +* **GCC** and/or **Clang** (any version supported by the project) +* **Make** or **Ninja** (build backend) +* **Docker** (only needed for cross-architecture testing via `.devcontainer/run-tests.sh`) +* **QEMU user-mode** (installed automatically inside the cross-arch Docker images) + +The project is header-only, so there is no library to compile – the build +step compiles the test binary `etl_tests` which links against a bundled copy +of **UnitTest++**. + +--- + +## Running Tests Locally + +The main entry point for local testing is **`test/run-tests.sh`**. It +iterates over a matrix of compiler / configuration combinations, creates a +temporary `build-make` directory for each one, runs CMake + Make + CTest, +and reports coloured pass/fail output (also appended to `log.txt`). + +### Synopsis + +```bash +cd test +./run-tests.sh [Optimisation] [Threads] [Sanitizer] [Compiler] [Verbose] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ Standard | `11`, `14`, `17`, `20`, `23`, or `all` | *(required)* | +| Optimisation | `0`, `1`, `2`, `3` | `0` | +| Threads | any positive integer | `4` | +| Sanitizer | `s` (enable) / `n` (disable) | `n` (disabled) | +| Compiler | `gcc`, `clang` | all compilers | +| Verbose | `v` (enable) / `n` (disable) | `n` (disabled) | + +### Examples + +```bash +# Run all C++17 tests with GCC only, optimisation -O0, 8 threads +./run-tests.sh 17 0 8 n gcc + +# Run every standard with both compilers, sanitizers enabled, verbose +./run-tests.sh all 0 4 s "" v +``` + +### What the script does + +For every selected C++ standard the script loops over a built-in list of +configurations (STL / No STL / Force C++03 / Non-virtual messages / …) for +each selected compiler. For every combination it: + +1. Creates a fresh `build-make` directory inside the configuration's source + subdirectory. +2. Invokes `cmake` with the appropriate `-D` flags (see + [CMake Options Reference](#cmake-options-reference)). +3. Builds via `cmake --build .` (parallel level controlled by + `CMAKE_BUILD_PARALLEL_LEVEL`). +4. Runs `ctest -V`. +5. Reports success or failure and removes the build directory. + +The script exits immediately on the first compilation or test failure. + +### Test configurations exercised + +| Compiler | Configuration | +|---|---| +| GCC | STL | +| GCC | STL – Non-virtual messages | +| GCC | STL – Force C++03 | +| GCC | No STL | +| GCC | No STL – Force C++03 | +| GCC | No STL – Builtin mem functions | +| Clang | STL | +| Clang | STL – Force C++03 | +| Clang | No STL | +| Clang | No STL – Force C++03 | +| Clang | No STL – Builtin mem functions | +| GCC / Clang | Initializer list test | +| GCC / Clang | Error macros – log_errors, exceptions, log_errors_and_exceptions, assert_function | + +--- + +## Syntax Checks + +The script **`test/run-syntax-checks.sh`** performs compilation-only syntax +checks across multiple C++ standards and configurations. Unlike +`run-tests.sh`, it **does not run the test binary** – it only verifies that +the code compiles successfully. This is useful for quickly validating that +header changes do not introduce compilation errors across the supported +standard/configuration matrix. + +### Synopsis + +```bash +cd test +./run-syntax-checks.sh [Threads] [Compiler] +``` + +| Argument | Values | Default | +|---|---|---| +| C++ Standard | `03`, `11`, `14`, `17`, `20`, `23`, or `a` (all) | *(required)* | +| Threads | any positive integer | `4` | +| Compiler | `gcc`, `clang` | all compilers | + +### Examples + +```bash +# Check C++17 syntax with GCC only, using 8 threads +./run-syntax-checks.sh 17 8 gcc + +# Check all standards with both compilers +./run-syntax-checks.sh a +``` + +### What the script does + +The script operates from the `test/syntax_check` directory and iterates over +the selected C++ standard(s). For each standard and compiler combination it: + +1. Creates fresh build directories (`bgcc` / `bclang`). +2. Invokes `cmake` with the appropriate `-D` flags for the configuration. +3. Builds via `cmake --build`. +4. Reports compilation success or failure (logged to `log.txt`). + +The script exits immediately on the first compilation failure. + +### Configurations checked per standard + +For each C++ standard the following configurations are compiled: + +| Compiler | Configuration | +|---|---| +| GCC | STL | +| GCC | No STL | +| GCC | STL – Built-in traits | +| GCC | No STL – Built-in traits | +| Clang | STL | +| Clang | No STL | +| Clang | STL – Built-in traits | +| Clang | No STL – Built-in traits | + +--- + +## Cross-Architecture Testing + +**`.devcontainer/run-tests.sh`** builds and runs the test suite for +non-x86_64 architectures using Docker and QEMU user-mode emulation. It is +designed to be run **from the project root**. + +### Supported architectures + +| Argument | Target | Endianness | QEMU binary | +|---|---|---|---| +| `armhf` | ARM hard-float (32-bit) | Little | `qemu-arm-static` | +| `i386` | x86 32-bit | Little | `qemu-i386-static` | +| `powerpc` | PowerPC 32-bit | Big | `qemu-ppc` | +| `riscv64` | RISC-V 64-bit | Little | `qemu-riscv64-static` | +| `s390x` | IBM Z (64-bit) | Big | `qemu-s390x-static` | + +### Synopsis + +```bash +# From the project root +.devcontainer/run-tests.sh +``` + +### How it works + +The script has two phases controlled by a second (internal) argument: + +1. **Outside the container** (no second argument): + * Builds a Docker image from `.devcontainer//Dockerfile`. + * Starts a container, bind-mounting the project at `/workspaces/etl`. + * Re-invokes itself *inside* the container with the `inside_container` + flag. + +2. **Inside the container** (`inside_container`): + * Creates `build-` and runs CMake with the appropriate cross- + compilation toolchain file + (`.devcontainer//toolchain-.cmake`). + * Builds with `cmake --build .` using all available cores. + * Runs the test suite via `ctest --output-on-failure`. + +The toolchain files set `CMAKE_CROSSCOMPILING_EMULATOR` so that CTest can +run the binary transparently through QEMU. + +### Example + +```bash +# Build & run the armhf test suite +.devcontainer/run-tests.sh armhf +``` + +The cross-arch containers build with the following fixed settings: + +* C++23, No STL, sanitizer off, optimisation -O0. + +--- + +## Dev Containers for Native Compilers + +The `.devcontainer/` directory also provides Dev Container definitions for a +wide range of **native** (x86_64) compiler versions. These are intended for +use with **VS Code Dev Containers** or **GitHub Codespaces**. + +| Directory | Compiler | +|---|---| +| `gcc09` – `gcc15` | GCC 9 through 15 | +| `clang7` – `clang21` | Clang 7 through 21 | + +Each subdirectory contains a `devcontainer.json` that references the shared +`Dockerfile` (`.devcontainer/Dockerfile`) and passes the appropriate base +Docker image via the `BASE_IMAGE_NAME` build argument (e.g. `gcc:15`). + +The default Dev Container (`.devcontainer/devcontainer.json`) uses the +Microsoft C++ dev-container base image. + +To use one of these containers: + +1. Open the repository in VS Code. +2. **Ctrl+Shift+P → Dev Containers: Reopen in Container** and select the + desired configuration (e.g. *Gcc 15*). +3. Use `test/run-tests.sh` inside the container as described above. + +--- + +## CMake Options Reference + +When invoking CMake for the test suite (source directory is `test/`), the +following `-D` options control the build: + +| Option | Type | Description | +|---|---|---| +| `BUILD_TESTS` | `BOOL` | Must be `ON` to compile the test binary. | +| `NO_STL` | `BOOL` | Build without the C++ Standard Library. | +| `ETL_CXX_STANDARD` | `STRING` | C++ standard: `11`, `14`, `17`, `20`, `23`. | +| `ETL_OPTIMISATION` | `STRING` | Compiler optimisation flag, e.g. `-O0`. | +| `ETL_ENABLE_SANITIZER` | `BOOL` | Enable address / undefined-behaviour sanitizers. | +| `ETL_USE_TYPE_TRAITS_BUILTINS` | `BOOL` | Use compiler built-in type traits. | +| `ETL_USER_DEFINED_TYPE_TRAITS` | `BOOL` | Use user-defined type traits. | +| `ETL_FORCE_TEST_CPP03_IMPLEMENTATION` | `BOOL` | Force the C++03 code paths even on newer standards. | +| `ETL_MESSAGES_ARE_NOT_VIRTUAL` | `BOOL` | Use non-virtual message types. | +| `ETL_USE_BUILTIN_MEM_FUNCTIONS` | `BOOL` | Use built-in memory functions in No-STL mode. | +| `CMAKE_TOOLCHAIN_FILE` | `PATH` | Toolchain file for cross-compilation. | + +### Minimal manual build example + +```bash +cd test +mkdir build && cd build +cmake -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_CXX_STANDARD=20 .. +cmake --build . -j$(nproc) +ctest -V +``` + +--- + +## CI Checks (GitHub Actions) + +Every push or pull request to `master`, `development`, or `pull-request/*` +branches triggers a comprehensive set of GitHub Actions workflows defined in +`.github/workflows/`. + +### Workflow matrix + +| Workflow file | Compiler | Standard | Notes | +|---|---|---|---| +| `gcc-c++11.yml` | GCC | C++11 | STL, No STL, Force C++03 | +| `gcc-c++14.yml` | GCC | C++14 | STL, No STL, Force C++03 | +| `gcc-c++17.yml` | GCC | C++17 | STL, No STL, Force C++03 | +| `gcc-c++20.yml` | GCC | C++20 | STL, No STL, Force C++03 | +| `gcc-c++23.yml` | GCC | C++23 | STL, No STL, Force C++03 | +| `clang-c++11.yml` | Clang | C++11 | STL, No STL, Force C++03 | +| `clang-c++14.yml` | Clang | C++14 | STL, No STL, Force C++03 | +| `clang-c++17.yml` | Clang | C++17 | STL, No STL, Force C++03 | +| `clang-c++20.yml` | Clang | C++20 | STL, No STL, Force C++03 | +| `clang-c++23.yml` | Clang | C++23 | STL, No STL, Force C++03 | +| `gcc-syntax-checks.yml` | GCC | C++03 – C++23 | Compilation-only syntax checks (no tests run) | +| `clang-syntax-checks.yml` | Clang | C++03 – C++23 | Compilation-only syntax checks (no tests run) | +| `msvc.yml` | MSVC 2022 | C++17 | Windows, STL & No STL | +| `gcc-c++23-armhf.yml` | GCC cross | C++23 | armhf via QEMU | +| `gcc-c++23-i386.yml` | GCC cross | C++23 | i386 via QEMU | +| `gcc-c++23-powerpc.yml` | GCC cross | C++23 | powerpc via QEMU | +| `gcc-c++23-riscv64.yml` | GCC cross | C++23 | RISC-V 64 via QEMU | +| `gcc-c++23-s390x.yml` | GCC cross | C++23 | s390x via QEMU | +| `coverage.yml` | GCC | — | Generates lcov coverage report, deploys to GitHub Pages | +| `generator.yml` | — | — | Runs the code generator | +| `platformio-update.yml` | — | — | PlatformIO registry update | + +### Typical CI job structure + +Each compiler/standard workflow follows the same pattern: + +1. **Checkout** – `actions/checkout@v4`. +2. **Build** – set `CC`/`CXX`, call `cmake` with the appropriate `-D` flags, + then `make -j`. +3. **Run tests** – execute `./test/etl_tests -v` (or `ctest -V` for cross- + arch jobs). + +The cross-architecture CI jobs additionally install a cross-compiler +toolchain and QEMU inside a `debian:trixie` container, use the matching +toolchain file from `.devcontainer//`, and run tests via CTest (which +delegates to QEMU through `CMAKE_CROSSCOMPILING_EMULATOR`). + +### Branches tested + +* `master` +* `development` +* `pull-request/*` + +All workflows run on both `push` and `pull_request` events (types: opened, +synchronize, reopened). + +--- + +## Appveyor (Windows / MSVC) + +The `appveyor.yml` at the repository root provides additional Windows CI +using **Visual Studio 2022**. It builds the `master` branch only. + +Configurations tested: + +* Debug MSVC C++14 +* Debug MSVC C++14 – No STL +* Debug MSVC C++17 +* Debug MSVC C++17 – No STL +* Debug MSVC C++20 +* Debug MSVC C++20 – No STL + +The build uses the VS 2022 solution file at `test/vs2022/etl.vcxproj`. + +--- + +## Code Coverage + +The `coverage.yml` GitHub Actions workflow generates an **lcov** coverage +report: + +1. Runs `test/run-coverage.sh` which builds and tests with GCC coverage + flags. +2. Uploads the HTML report as a build artifact (retained for 30 days). +3. On pushes to `master`, deploys the report to **GitHub Pages**. + +To generate coverage locally: + +```bash +cd test +./run-coverage.sh +# Open test/build-coverage/coverage/index.html +``` + +--- + +## Generator Tests + +The script **`scripts/generator_test.py`** verifies that the code generators +in `include/etl/generators/` produce output matching the checked-in header +files in `include/etl/private/`. + +ETL uses [Cog](https://nedbatchelder.com/code/cog/) to generate certain +repetitive header files (e.g. `delegate.h`, `message_packet.h`). The +generator templates live in `include/etl/generators/*_generator.h` and the +generated output is committed to `include/etl/private/*.h`. This test +ensures the two stay in sync. + +### Prerequisites + +* **Python 3** +* **cogapp** – install via `pip install cogapp` + +### Synopsis + +```bash +python3 scripts/generator_test.py +``` + +### What the script does + +1. Iterates over every `*_generator.h` file in `include/etl/generators/`. +2. Runs Cog on each generator, outputting to `build/generator_tmp/`. +3. Compares each generated file against the corresponding file in + `include/etl/private/`. +4. Reports success if all files match, or failure if any differ. + +The script exits with code `0` on success and `1` on failure. + +### CI integration + +The `generator.yml` GitHub Actions workflow runs this script automatically +on pushes and pull requests to verify generator consistency. diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 63bfe13b..91252319 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -51,7 +51,7 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" -#include +#include #include #include "private/minmax_push.h" @@ -91,26 +91,6 @@ namespace etl template ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last, TCompare compare); - class algorithm_exception : public etl::exception - { - public: - - algorithm_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : exception(reason_, file_name_, line_number_) - { - } - }; - - class algorithm_error : public algorithm_exception - { - public: - - algorithm_error(string_type file_name_, numeric_type line_number_) - : algorithm_exception(ETL_ERROR_TEXT("algorithm:error", ETL_ALGORITHM_FILE_ID"A"), file_name_, line_number_) - { - } - }; - } // namespace etl //***************************************************************************** @@ -558,7 +538,8 @@ namespace etl { while (first != last) { - *first = value; + // This cast is necessary because the signedness can differ + *first = static_cast::value_type>(value); ++first; } } @@ -898,6 +879,7 @@ namespace etl { TDistance parent = (value_index - 1) / 2; +#include "etl/private/diagnostic_array_bounds_push.h" while ((value_index > top_index) && compare(first[parent], value)) { first[value_index] = ETL_MOVE(first[parent]); @@ -906,6 +888,7 @@ namespace etl } first[value_index] = ETL_MOVE(value); +#include "etl/private/diagnostic_pop.h" } // Adjust Heap Helper @@ -1358,7 +1341,9 @@ namespace etl value_type temp(ETL_MOVE(*first)); // Move the rest. +#include "etl/private/diagnostic_stringop_overread_push.h" TIterator result = etl::move(etl::next(first), last, first); +#include "etl/private/diagnostic_pop.h" // Restore the first item in its rotated position. *result = ETL_MOVE(temp); @@ -2786,7 +2771,9 @@ namespace etl d_size_type d_size = etl::distance(o_begin, o_end); min_size_type min_size = etl::min(s_size, d_size); + #include "etl/private/diagnostic_null_dereference_push.h" return etl::move(i_begin, i_begin + min_size, o_begin); + #include "etl/private/diagnostic_pop.h" } //*************************************************************************** @@ -5860,12 +5847,14 @@ namespace etl } } + #include "etl/private/diagnostic_array_bounds_push.h" // Sort the heap to produce a sorted output range for (auto heap_end = heap_size - 1; heap_end > 0; --heap_end) { etl::iter_swap(result_first, result_first + heap_end); sift_down(result_first, decltype(heap_size){0}, heap_end, comp, proj2); } + #include "etl/private/diagnostic_pop.h" return {etl::move(in_last), etl::move(r)}; } @@ -6202,6 +6191,16 @@ namespace etl I left_partition = stable_partition_impl(first, middle, etl::ref(pred), etl::ref(proj), len / 2); I right_partition = stable_partition_impl(middle, last, etl::ref(pred), etl::ref(proj), len - len / 2); + if (left_partition == middle) + { + return right_partition; + } + + if (middle == right_partition) + { + return left_partition; + } + return etl::rotate(left_partition, middle, right_partition); } }; diff --git a/include/etl/array.h b/include/etl/array.h index 2051807b..ffa3a307 100644 --- a/include/etl/array.h +++ b/include/etl/array.h @@ -35,10 +35,7 @@ SOFTWARE. #include "algorithm.h" #include "error_handler.h" #include "exception.h" -#include "functional.h" -#include "initializer_list.h" #include "iterator.h" -#include "nth_type.h" #include "parameter_type.h" #include "static_assert.h" #include "type_traits.h" diff --git a/include/etl/atomic/atomic_gcc_sync.h b/include/etl/atomic/atomic_gcc_sync.h index 087489aa..425d8707 100644 --- a/include/etl/atomic/atomic_gcc_sync.h +++ b/include/etl/atomic/atomic_gcc_sync.h @@ -341,6 +341,68 @@ namespace etl return __atomic_fetch_xor(&value, v, order); } + // Fetch max + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + // Exchange T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) { @@ -1234,6 +1296,72 @@ namespace etl return __sync_fetch_and_xor(&value, v); } + // Fetch max + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = load(order); + + while (v > old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = load(order); + + while (v < old) + { + if (compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + // Exchange T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) { diff --git a/include/etl/atomic/atomic_std.h b/include/etl/atomic/atomic_std.h index ee765a70..06fcef6c 100644 --- a/include/etl/atomic/atomic_std.h +++ b/include/etl/atomic/atomic_std.h @@ -40,11 +40,98 @@ namespace etl { //*************************************************************************** // ETL Atomic type for compilers that support std::atomic. - // etl::atomic is a simple wrapper around std::atomic. + // etl::atomic is a wrapper around std::atomic that adds fetch_max and + // fetch_min if the standard library does not yet provide them. //*************************************************************************** +#if ETL_HAS_STD_ATOMIC_MIN_MAX + // The standard library already provides fetch_max/fetch_min. template using atomic = std::atomic; +#else + template + class atomic : public std::atomic + { + using base_type = std::atomic; + + public: + + atomic() ETL_NOEXCEPT = default; + + ETL_CONSTEXPR atomic(T desired) ETL_NOEXCEPT + : base_type(desired) + { + } + + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + using base_type::operator=; + + // Fetch max + T fetch_max(T v, std::memory_order order = std::memory_order_seq_cst) + { + T old = this->load(order); + + while (v > old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_max(T v, std::memory_order order = std::memory_order_seq_cst) volatile + { + T old = this->load(order); + + while (v > old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + // Fetch min + T fetch_min(T v, std::memory_order order = std::memory_order_seq_cst) + { + T old = this->load(order); + + while (v < old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + + T fetch_min(T v, std::memory_order order = std::memory_order_seq_cst) volatile + { + T old = this->load(order); + + while (v < old) + { + if (this->compare_exchange_weak(old, v, order)) + { + break; + } + } + + return old; + } + }; +#endif using memory_order = std::memory_order; @@ -55,66 +142,66 @@ namespace etl static ETL_CONSTANT etl::memory_order memory_order_acq_rel = std::memory_order_acq_rel; static ETL_CONSTANT etl::memory_order memory_order_seq_cst = std::memory_order_seq_cst; - using atomic_bool = std::atomic; - using atomic_char = std::atomic; - using atomic_schar = std::atomic; - using atomic_uchar = std::atomic; - using atomic_short = std::atomic; - using atomic_ushort = std::atomic; - using atomic_int = std::atomic; - using atomic_uint = std::atomic; - using atomic_long = std::atomic; - using atomic_ulong = std::atomic; - using atomic_llong = std::atomic; - using atomic_ullong = std::atomic; - using atomic_wchar_t = std::atomic; + using atomic_bool = etl::atomic; + using atomic_char = etl::atomic; + using atomic_schar = etl::atomic; + using atomic_uchar = etl::atomic; + using atomic_short = etl::atomic; + using atomic_ushort = etl::atomic; + using atomic_int = etl::atomic; + using atomic_uint = etl::atomic; + using atomic_long = etl::atomic; + using atomic_ulong = etl::atomic; + using atomic_llong = etl::atomic; + using atomic_ullong = etl::atomic; + using atomic_wchar_t = etl::atomic; #if ETL_HAS_NATIVE_CHAR8_T - using atomic_char8_t = std::atomic; + using atomic_char8_t = etl::atomic; #endif #if ETL_HAS_NATIVE_CHAR16_T - using atomic_char16_t = std::atomic; + using atomic_char16_t = etl::atomic; #endif #if ETL_HAS_NATIVE_CHAR32_T - using atomic_char32_t = std::atomic; + using atomic_char32_t = etl::atomic; #endif #if ETL_USING_8BIT_TYPES - using atomic_uint8_t = std::atomic; - using atomic_int8_t = std::atomic; + using atomic_uint8_t = etl::atomic; + using atomic_int8_t = etl::atomic; #endif - using atomic_uint16_t = std::atomic; - using atomic_int16_t = std::atomic; - using atomic_uint32_t = std::atomic; - using atomic_int32_t = std::atomic; + using atomic_uint16_t = etl::atomic; + using atomic_int16_t = etl::atomic; + using atomic_uint32_t = etl::atomic; + using atomic_int32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_uint64_t = std::atomic; - using atomic_int64_t = std::atomic; + using atomic_uint64_t = etl::atomic; + using atomic_int64_t = etl::atomic; #endif - using atomic_int_least8_t = std::atomic; - using atomic_uint_least8_t = std::atomic; - using atomic_int_least16_t = std::atomic; - using atomic_uint_least16_t = std::atomic; - using atomic_int_least32_t = std::atomic; - using atomic_uint_least32_t = std::atomic; + using atomic_int_least8_t = etl::atomic; + using atomic_uint_least8_t = etl::atomic; + using atomic_int_least16_t = etl::atomic; + using atomic_uint_least16_t = etl::atomic; + using atomic_int_least32_t = etl::atomic; + using atomic_uint_least32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_int_least64_t = std::atomic; - using atomic_uint_least64_t = std::atomic; + using atomic_int_least64_t = etl::atomic; + using atomic_uint_least64_t = etl::atomic; #endif - using atomic_int_fast8_t = std::atomic; - using atomic_uint_fast8_t = std::atomic; - using atomic_int_fast16_t = std::atomic; - using atomic_uint_fast16_t = std::atomic; - using atomic_int_fast32_t = std::atomic; - using atomic_uint_fast32_t = std::atomic; + using atomic_int_fast8_t = etl::atomic; + using atomic_uint_fast8_t = etl::atomic; + using atomic_int_fast16_t = etl::atomic; + using atomic_uint_fast16_t = etl::atomic; + using atomic_int_fast32_t = etl::atomic; + using atomic_uint_fast32_t = etl::atomic; #if ETL_USING_64BIT_TYPES - using atomic_int_fast64_t = std::atomic; - using atomic_uint_fast64_t = std::atomic; + using atomic_int_fast64_t = etl::atomic; + using atomic_uint_fast64_t = etl::atomic; #endif - using atomic_intptr_t = std::atomic; - using atomic_uintptr_t = std::atomic; - using atomic_size_t = std::atomic; - using atomic_ptrdiff_t = std::atomic; - using atomic_intmax_t = std::atomic; - using atomic_uintmax_t = std::atomic; + using atomic_intptr_t = etl::atomic; + using atomic_uintptr_t = etl::atomic; + using atomic_size_t = etl::atomic; + using atomic_ptrdiff_t = etl::atomic; + using atomic_intmax_t = etl::atomic; + using atomic_uintmax_t = etl::atomic; } // namespace etl #endif diff --git a/include/etl/base64.h b/include/etl/base64.h index 4ce98b3c..03c73648 100644 --- a/include/etl/base64.h +++ b/include/etl/base64.h @@ -31,11 +31,8 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "integral_limits.h" -#include "static_assert.h" #include "type_traits.h" -#include - /************************************************************************************************************************************************************************** * See https://en.wikipedia.org/wiki/Base64 * diff --git a/include/etl/basic_format_spec.h b/include/etl/basic_format_spec.h index f80d0ec6..5c585d85 100644 --- a/include/etl/basic_format_spec.h +++ b/include/etl/basic_format_spec.h @@ -34,7 +34,6 @@ SOFTWARE. ///\ingroup string #include "platform.h" -#include "static_assert.h" #include "type_traits.h" #include "utility.h" diff --git a/include/etl/basic_string.h b/include/etl/basic_string.h index 1a38cc99..59db587a 100644 --- a/include/etl/basic_string.h +++ b/include/etl/basic_string.h @@ -39,7 +39,6 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "flags.h" -#include "functional.h" #include "integral_limits.h" #include "iterator.h" #include "memory.h" @@ -93,20 +92,6 @@ namespace etl } }; - //*************************************************************************** - ///\ingroup string - /// String empty exception. - //*************************************************************************** - class string_empty : public etl::string_exception - { - public: - - string_empty(string_type file_name_, numeric_type line_number_) - : string_exception(ETL_ERROR_TEXT("string:empty", ETL_BASIC_STRING_FILE_ID"A"), file_name_, line_number_) - { - } - }; - //*************************************************************************** ///\ingroup string /// String out of bounds exception. @@ -1481,9 +1466,7 @@ namespace etl //********************************************************************* size_type find(const_pointer s, size_type pos, size_type n) const { - size_t sz = etl::strlen(s); - - return find_impl(s, s + n, sz, pos); + return find_impl(s, s + n, n, pos); } //********************************************************************* @@ -2742,6 +2725,7 @@ namespace etl iterator>::type copy_characters(TIterator1 from, size_t n, iterator to) { +#include "etl/private/diagnostic_stringop_overflow_push.h" size_t count = 0; while (count != n) @@ -2750,6 +2734,7 @@ namespace etl ++count; } +#include "etl/private/diagnostic_pop.h" return to; } @@ -3218,8 +3203,6 @@ namespace etl #endif } // namespace etl -#undef ETL_USING_WCHAR_T_H - #include "private/minmax_pop.h" #endif diff --git a/include/etl/binary.h b/include/etl/binary.h index e7d9eec0..230fbf4a 100644 --- a/include/etl/binary.h +++ b/include/etl/binary.h @@ -1742,7 +1742,7 @@ namespace etl { count = 1U; - if ((value & 0xFFFFFFFFF0000000ULL) == 0U) + if ((value & 0xFFFFFFFF00000000ULL) == 0U) { value <<= 32U; count += 32U; @@ -1795,7 +1795,7 @@ namespace etl { typedef typename etl::make_unsigned::type unsigned_t; - return static_cast(count_trailing_ones(static_cast(value))); + return static_cast(count_leading_zeros(static_cast(value))); } #if ETL_USING_8BIT_TYPES @@ -1927,8 +1927,8 @@ namespace etl if ((value & 0xFFFF0000UL) == 0xFFFF0000UL) { - value <<= 8U; - count += 8U; + value <<= 16U; + count += 16U; } if ((value & 0xFF000000UL) == 0xFF000000UL) @@ -1988,14 +1988,14 @@ namespace etl if ((value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL) { - value <<= 8U; - count += 8U; + value <<= 32U; + count += 32U; } if ((value & 0xFFFF000000000000ULL) == 0xFFFF000000000000ULL) { - value <<= 8U; - count += 8U; + value <<= 16U; + count += 16U; } if ((value & 0xFF00000000000000ULL) == 0xFF00000000000000ULL) diff --git a/include/etl/bip_buffer_spsc_atomic.h b/include/etl/bip_buffer_spsc_atomic.h index 0901af80..fcb955da 100644 --- a/include/etl/bip_buffer_spsc_atomic.h +++ b/include/etl/bip_buffer_spsc_atomic.h @@ -51,7 +51,6 @@ SOFTWARE. #include "utility.h" #include -#include #if ETL_HAS_ATOMIC @@ -404,7 +403,7 @@ namespace etl //************************************************************************* void read_commit(const span& reserve) { - size_type rindex = etl::distance(p_buffer, reserve.data()); + size_type rindex = static_cast(etl::distance(p_buffer, reserve.data())); apply_read_reserve(rindex, reserve.size()); } @@ -438,7 +437,7 @@ namespace etl //************************************************************************* void write_commit(const span& reserve) { - size_type windex = etl::distance(p_buffer, reserve.data()); + size_type windex = static_cast(etl::distance(p_buffer, reserve.data())); apply_write_reserve(windex, reserve.size()); } diff --git a/include/etl/bresenham_line.h b/include/etl/bresenham_line.h index 02ebc49a..a2888d9d 100644 --- a/include/etl/bresenham_line.h +++ b/include/etl/bresenham_line.h @@ -33,10 +33,10 @@ SOFTWARE. #include "platform.h" #include "iterator.h" -#include "static_assert.h" #include "type_traits.h" #include "utility.h" +#include #include namespace etl diff --git a/include/etl/buffer_descriptors.h b/include/etl/buffer_descriptors.h index 100846d7..61ec7890 100644 --- a/include/etl/buffer_descriptors.h +++ b/include/etl/buffer_descriptors.h @@ -36,10 +36,9 @@ SOFTWARE. #include "array.h" #include "cyclic_value.h" #include "delegate.h" -#include "static_assert.h" #include "type_traits.h" -#include +#include #if ETL_USING_CPP11 diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 4af209ed..51dc9e92 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -40,13 +40,11 @@ SOFTWARE. #include "integral_limits.h" #include "iterator.h" #include "memory.h" -#include "nullptr.h" #include "optional.h" #include "span.h" #include "type_traits.h" -#include -#include +#include namespace etl { diff --git a/include/etl/callback_timer.h b/include/etl/callback_timer.h index 0b3da8ba..2cc94651 100644 --- a/include/etl/callback_timer.h +++ b/include/etl/callback_timer.h @@ -629,7 +629,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -758,22 +757,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -788,16 +778,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/callback_timer_atomic.h b/include/etl/callback_timer_atomic.h index 0aba1f97..98d92651 100644 --- a/include/etl/callback_timer_atomic.h +++ b/include/etl/callback_timer_atomic.h @@ -33,8 +33,6 @@ SOFTWARE. #include "algorithm.h" #include "delegate.h" #include "error_handler.h" -#include "function.h" -#include "nullptr.h" #include "placement_new.h" #include "static_assert.h" #include "timer.h" @@ -487,7 +485,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -616,22 +613,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -646,16 +634,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/callback_timer_interrupt.h b/include/etl/callback_timer_interrupt.h index 3522bd22..a67754cb 100644 --- a/include/etl/callback_timer_interrupt.h +++ b/include/etl/callback_timer_interrupt.h @@ -33,7 +33,6 @@ SOFTWARE. #include "algorithm.h" #include "delegate.h" #include "error_handler.h" -#include "nullptr.h" #include "placement_new.h" #include "static_assert.h" #include "timer.h" @@ -487,7 +486,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -616,22 +614,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -646,16 +635,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/callback_timer_locked.h b/include/etl/callback_timer_locked.h index 4c53f259..40c1161b 100644 --- a/include/etl/callback_timer_locked.h +++ b/include/etl/callback_timer_locked.h @@ -33,7 +33,6 @@ SOFTWARE. #include "algorithm.h" #include "delegate.h" #include "error_handler.h" -#include "nullptr.h" #include "placement_new.h" #include "static_assert.h" #include "timer.h" @@ -460,7 +459,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -589,22 +587,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -619,16 +608,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/chrono.h b/include/etl/chrono.h index facde8a4..b452ca4e 100644 --- a/include/etl/chrono.h +++ b/include/etl/chrono.h @@ -35,10 +35,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #include "hash.h" diff --git a/include/etl/circular_buffer.h b/include/etl/circular_buffer.h index da6877e3..4c8290c4 100644 --- a/include/etl/circular_buffer.h +++ b/include/etl/circular_buffer.h @@ -1206,7 +1206,7 @@ namespace etl { this->clear(); - for (typename etl::icircular_buffer::const_iterator itr = other.begin(); itr != other.end(); ++itr) + for (typename etl::icircular_buffer::iterator itr = other.begin(); itr != other.end(); ++itr) { this->push(etl::move(*itr)); } diff --git a/include/etl/closure.h b/include/etl/closure.h index 54b0fb36..7f11bbcf 100644 --- a/include/etl/closure.h +++ b/include/etl/closure.h @@ -33,53 +33,62 @@ SOFTWARE. #include "platform.h" #include "delegate.h" +#include "invoke.h" #include "tuple.h" #include "type_list.h" #include "utility.h" namespace etl { -#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* /// Base template for closure. + /// \tparam TSignature The callback signature. + /// \tparam TCallback The callback type, defaults to etl::delegate. //************************************************************************* - template + template > class closure; +#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* - /// Closure for binding arguments to a delegate and invoking it later. - /// Stores a delegate and its arguments, allowing deferred execution. + /// Closure for binding arguments to a callback and invoking it later. + /// Stores a callback and its arguments, allowing deferred execution. /// Arguments are stored in a tuple and can be rebound using bind(). /// Example usage: /// \code /// etl::closure c(my_delegate, 1, 2); /// c(); // Invokes my_delegate(1, 2) /// \endcode - /// \tparam TReturn The return type of the delegate. - /// \tparam TArgs The argument types of the delegate. + /// \tparam TReturn The return type of the callback. + /// \tparam TArgs The argument types of the callback. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - using delegate_type = etl::delegate; ///< The delegate type to be invoked. - using argument_types = etl::type_list; ///< The type list of arguments. + using delegate_type ETL_DEPRECATED_REASON("Use callback_type") = + TCallback; ///< The callback type to be invoked. Deprecated, use callback_type instead. + using callback_type = TCallback; ///< The callback type to be invoked. + using argument_types = etl::type_list; ///< The type list of arguments. + + static_assert(etl::is_invocable_r::value, "Callback is not invocable with the specified arguments"); + static_assert(etl::is_copy_constructible::value, "Callback type must be copy constructible"); //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. - /// \param args The arguments to bind to the delegate. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. + /// \param args The arguments to bind to the callback. //********************************************************************* - ETL_CONSTEXPR14 closure(const delegate_type& f, const TArgs... args) + ETL_CONSTEXPR14 closure(const callback_type& f, const TArgs... args) : m_f(f) , m_args(args...) { } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* ETL_CONSTEXPR14 TReturn operator()() const { @@ -131,7 +140,7 @@ namespace etl //********************************************************************* /// Execute the closure with the stored arguments. /// \tparam idx Index sequence for tuple unpacking. - /// \return The result of the delegate invocation. + /// \return The result of the callback invocation. //********************************************************************* template ETL_CONSTEXPR14 TReturn execute(etl::index_sequence) const @@ -139,43 +148,38 @@ namespace etl return m_f(etl::get(m_args)...); } - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. etl::tuple m_args; ///< The bound arguments. }; #else //************************************************************************* - /// Base template for closure. - //************************************************************************* - template - class closure; - - //************************************************************************* - /// Closure for binding one argument to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding one argument to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - /// The delegate type to be invoked. - typedef etl::delegate delegate_type; + /// The callback type to be invoked. + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its argument. - /// \param f The delegate to be invoked. - /// \param arg0 The argument to bind to the delegate. + /// Construct a closure with a callback and its argument. + /// \param f The callback to be invoked. + /// \param arg0 The argument to bind to the callback. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0) + closure(const callback_type& f, const TArg0 arg0) : m_f(f) , m_arg0(arg0) { } //********************************************************************* - /// Invoke the stored delegate with the bound argument. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound argument. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -184,30 +188,31 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; }; //************************************************************************* - /// Closure for binding two arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding two arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -215,8 +220,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -225,33 +230,34 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; }; //************************************************************************* - /// Closure for binding three arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding three arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -260,8 +266,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -270,36 +276,37 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; }; //************************************************************************* - /// Closure for binding four arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding four arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. /// \tparam TArg3 The type of the fourth argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. /// \param arg3 The fourth argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -309,8 +316,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -319,7 +326,7 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; @@ -327,31 +334,32 @@ namespace etl }; //************************************************************************* - /// Closure for binding five arguments to a delegate and invoking it later. - /// \tparam TReturn The return type of the delegate. + /// Closure for binding five arguments to a callback and invoking it later. + /// \tparam TReturn The return type of the callback. /// \tparam TArg0 The type of the first argument. /// \tparam TArg1 The type of the second argument. /// \tparam TArg2 The type of the third argument. /// \tparam TArg3 The type of the fourth argument. /// \tparam TArg4 The type of the fifth argument. + /// \tparam TCallback The callback type. //************************************************************************* - template - class closure + template + class closure { public: - typedef etl::delegate delegate_type; + typedef TCallback callback_type; //********************************************************************* - /// Construct a closure with a delegate and its arguments. - /// \param f The delegate to be invoked. + /// Construct a closure with a callback and its arguments. + /// \param f The callback to be invoked. /// \param arg0 The first argument to bind. /// \param arg1 The second argument to bind. /// \param arg2 The third argument to bind. /// \param arg3 The fourth argument to bind. /// \param arg4 The fifth argument to bind. //********************************************************************* - closure(const delegate_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3, const TArg4 arg4) + closure(const callback_type& f, const TArg0 arg0, const TArg1 arg1, const TArg2 arg2, const TArg3 arg3, const TArg4 arg4) : m_f(f) , m_arg0(arg0) , m_arg1(arg1) @@ -362,8 +370,8 @@ namespace etl } //********************************************************************* - /// Invoke the stored delegate with the bound arguments. - /// \return The result of the delegate invocation. + /// Invoke the stored callback with the bound arguments. + /// \return The result of the callback invocation. //********************************************************************* TReturn operator()() const { @@ -372,7 +380,7 @@ namespace etl private: - delegate_type m_f; ///< The delegate to invoke. + callback_type m_f; ///< The callback to invoke. TArg0 m_arg0; TArg1 m_arg1; TArg2 m_arg2; diff --git a/include/etl/concepts.h b/include/etl/concepts.h index ce5cec97..9376264b 100644 --- a/include/etl/concepts.h +++ b/include/etl/concepts.h @@ -33,13 +33,10 @@ SOFTWARE. #include "platform.h" +#include "invoke.h" #include "type_traits.h" #include "utility.h" -#if ETL_NOT_USING_CPP20 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR BELOW C++20 -#endif - #if ETL_USING_CPP20 #if ETL_USING_STL @@ -54,12 +51,31 @@ namespace etl using std::assignable_from; using std::common_reference_with; using std::common_with; + using std::constructible_from; using std::convertible_to; + using std::copy_constructible; + using std::copyable; + using std::default_initializable; using std::derived_from; + using std::destructible; + using std::equality_comparable; + using std::equivalence_relation; using std::floating_point; using std::integral; + using std::invocable; + using std::movable; + using std::move_constructible; + using std::predicate; + using std::regular; + using std::regular_invocable; + using std::relation; using std::same_as; + using std::semiregular; using std::signed_integral; + using std::strict_weak_order; + using std::swappable; + using std::swappable_with; + using std::totally_ordered; using std::unsigned_integral; #else // not ETL_USING_STL @@ -118,6 +134,112 @@ namespace etl { lhs = etl::forward(rhs) } -> etl::same_as; }; + //*************************************************************************** + template + concept invocable = etl::is_invocable_v; + + //*************************************************************************** + template + concept regular_invocable = etl::invocable; + + //*************************************************************************** + template + concept destructible = requires(T& t) { + { t.~T() } noexcept; + }; + + //*************************************************************************** + template + concept constructible_from = etl::destructible && etl::is_constructible_v; + + //*************************************************************************** + template + concept default_initializable = etl::constructible_from && requires { + T{}; + ::new T; + }; + + //*************************************************************************** + template + concept move_constructible = etl::constructible_from && etl::convertible_to; + + //*************************************************************************** + template + concept copy_constructible = + etl::move_constructible && etl::constructible_from && etl::convertible_to && etl::constructible_from + && etl::convertible_to && etl::constructible_from && etl::convertible_to; + + //*************************************************************************** + namespace private_concepts + { + template + concept boolean_testable = etl::convertible_to && requires(T&& t) { + { !etl::forward(t) } -> etl::convertible_to; + }; + } // namespace private_concepts + + //*************************************************************************** + template + concept equality_comparable = requires(const etl::remove_reference_t& a, const etl::remove_reference_t& b) { + { a == b } -> private_concepts::boolean_testable; + { a != b } -> private_concepts::boolean_testable; + }; + + //*************************************************************************** + template + concept totally_ordered = etl::equality_comparable && requires(const etl::remove_reference_t& a, const etl::remove_reference_t& b) { + { a < b } -> private_concepts::boolean_testable; + { a > b } -> private_concepts::boolean_testable; + { a <= b } -> private_concepts::boolean_testable; + { a >= b } -> private_concepts::boolean_testable; + }; + + //*************************************************************************** + template + concept swappable = requires(T& a, T& b) { etl::swap(a, b); }; + + //*************************************************************************** + template + concept swappable_with = etl::common_reference_with&, etl::remove_reference_t&> && requires(T&& t, U&& u) { + etl::swap(etl::forward(t), etl::forward(t)); + etl::swap(etl::forward(u), etl::forward(u)); + etl::swap(etl::forward(t), etl::forward(u)); + etl::swap(etl::forward(u), etl::forward(t)); + }; + + //*************************************************************************** + template + concept movable = etl::is_object_v && etl::move_constructible && etl::assignable_from && etl::swappable; + + //*************************************************************************** + template + concept copyable = etl::copy_constructible && etl::movable && etl::assignable_from && etl::assignable_from + && etl::assignable_from; + + //*************************************************************************** + template + concept semiregular = etl::copyable && etl::default_initializable; + + //*************************************************************************** + template + concept regular = etl::semiregular && etl::equality_comparable; + + //*************************************************************************** + template + concept predicate = etl::regular_invocable && private_concepts::boolean_testable >; + + //*************************************************************************** + template + concept relation = etl::predicate && etl::predicate && etl::predicate && etl::predicate; + + //*************************************************************************** + template + concept equivalence_relation = etl::relation; + + //*************************************************************************** + template + concept strict_weak_order = etl::relation; + #endif } // namespace etl #endif diff --git a/include/etl/const_map.h b/include/etl/const_map.h index aa20fb4d..f96f616b 100644 --- a/include/etl/const_map.h +++ b/include/etl/const_map.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_map const_map ///\ingroup containers @@ -528,14 +526,14 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_map(TElements...) -> const_map::first_type, typename etl::nth_type_t<0, TElements...>::second_type, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -586,16 +584,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_map_ext(const etl::span&) -> const_map_ext; template const_map_ext(const TElements (&)[Size]) -> const_map_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -659,3 +657,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_multimap.h b/include/etl/const_multimap.h index 6f5f8208..dea60ee1 100644 --- a/include/etl/const_multimap.h +++ b/include/etl/const_multimap.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_multimap const_multimap ///\ingroup containers @@ -478,14 +476,14 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multimap(TPairs...) -> const_multimap::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, sizeof...(TPairs)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -536,16 +534,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multimap_ext(const etl::span&) -> const_multimap_ext; template const_multimap_ext(const TElements (&)[Size]) -> const_multimap_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -626,3 +624,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_multiset.h b/include/etl/const_multiset.h index 1fb0bd9e..6184f9e7 100644 --- a/include/etl/const_multiset.h +++ b/include/etl/const_multiset.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_multiset const_multiset ///\ingroup containers @@ -433,13 +431,13 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multiset(TElements...) -> const_multiset, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Multiset type designed for constexpr. @@ -488,16 +486,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_multiset_ext(const etl::span&) -> const_multiset_ext; template const_multiset_ext(const TElements (&)[Size]) -> const_multiset_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -572,3 +570,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/const_set.h b/include/etl/const_set.h index e4629d71..df7f0989 100644 --- a/include/etl/const_set.h +++ b/include/etl/const_set.h @@ -33,10 +33,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #include "algorithm.h" #include "functional.h" #include "nth_type.h" @@ -45,6 +41,8 @@ SOFTWARE. #include "private/comparator_is_transparent.h" +#if ETL_USING_CPP11 + ///\defgroup const_set const_set ///\ingroup containers @@ -426,13 +424,13 @@ namespace etl value_type element_list[Size]; }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_set(TElements...) -> const_set, sizeof...(TElements)>; -#endif + #endif //********************************************************************* /// Map type designed for constexpr. @@ -481,16 +479,16 @@ namespace etl } }; - //************************************************************************* - /// Template deduction guides. - //************************************************************************* -#if ETL_USING_CPP17 + //************************************************************************* + /// Template deduction guides. + //************************************************************************* + #if ETL_USING_CPP17 template const_set_ext(const etl::span&) -> const_set_ext; template const_set_ext(const TElements (&)[Size]) -> const_set_ext; -#endif + #endif //************************************************************************* /// Equality test. @@ -548,3 +546,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/container.h b/include/etl/container.h index c020dc7d..0452d2b4 100644 --- a/include/etl/container.h +++ b/include/etl/container.h @@ -34,6 +34,4 @@ SOFTWARE. #include "platform.h" #include "iterator.h" -#include - #endif diff --git a/include/etl/cyclic_value.h b/include/etl/cyclic_value.h index d1c2f47b..c33b306b 100644 --- a/include/etl/cyclic_value.h +++ b/include/etl/cyclic_value.h @@ -38,11 +38,8 @@ SOFTWARE. #include "platform.h" #include "algorithm.h" #include "exception.h" -#include "static_assert.h" #include "type_traits.h" -#include - namespace etl { //*************************************************************************** diff --git a/include/etl/debounce.h b/include/etl/debounce.h index f554c8b9..2618d5e3 100644 --- a/include/etl/debounce.h +++ b/include/etl/debounce.h @@ -32,9 +32,6 @@ SOFTWARE. #define ETL_DEBOUNCE_INCLUDED #include "platform.h" -#include "static_assert.h" - -#include namespace etl { diff --git a/include/etl/delegate_service.h b/include/etl/delegate_service.h index 8b7ef718..6ca7b40c 100644 --- a/include/etl/delegate_service.h +++ b/include/etl/delegate_service.h @@ -34,9 +34,10 @@ SOFTWARE. #include "platform.h" #include "array.h" #include "delegate.h" -#include "nullptr.h" #include "static_assert.h" +#include + namespace etl { //*************************************************************************** diff --git a/include/etl/deque.h b/include/etl/deque.h index 888ac06a..bd9afa46 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -44,7 +44,6 @@ SOFTWARE. #include "utility.h" #include -#include #include "private/minmax_push.h" @@ -462,19 +461,6 @@ namespace etl private: - //*************************************************** - difference_type distance(difference_type firstIndex, difference_type index_) const - { - if (index_ < firstIndex) - { - return static_cast(p_deque->Buffer_Size) + index_ - firstIndex; - } - else - { - return index_ - firstIndex; - } - } - //*************************************************** iterator(difference_type index_, ideque& the_deque, pointer p_buffer_) : index(index_) @@ -619,10 +605,10 @@ namespace etl } //*************************************************** - reference operator[](size_t i) + const_reference operator[](size_t i) const { - iterator result(*this); - result += i; + const_iterator result(*this); + result += static_cast(i); return *result; } @@ -721,19 +707,6 @@ namespace etl private: - //*************************************************** - difference_type distance(difference_type firstIndex, difference_type index_) const - { - if (index_ < firstIndex) - { - return static_cast(p_deque->Buffer_Size) + index_ - firstIndex; - } - else - { - return index_ - firstIndex; - } - } - //*************************************************** const_iterator(difference_type index_, ideque& the_deque, pointer p_buffer_) : index(index_) diff --git a/include/etl/doxygen.h b/include/etl/doxygen.h index f9adce19..0251f1b6 100644 --- a/include/etl/doxygen.h +++ b/include/etl/doxygen.h @@ -27,31 +27,29 @@ SOFTWARE. ******************************************************************************/ ///\defgroup etl Embedded Template Library. -https - : // github.com/ETLCPP/etl - http - : // www.etlcpp.com +/// https://github.com/ETLCPP/etl +/// http://www.etlcpp.com - ///\defgroup containers Containers - ///\ingroup etl +///\defgroup containers Containers +///\ingroup etl - ///\defgroup utilities Utilities - /// A set of utility templates. - ///\ingroup etl +///\defgroup utilities Utilities +/// A set of utility templates. +///\ingroup etl - ///\defgroup maths Maths - /// A set of mathematical templates. - ///\ingroup etl +///\defgroup maths Maths +/// A set of mathematical templates. +///\ingroup etl - ///\defgroup patterns Patterns - /// A set of templated design patterns. - ///\ingroup etl +///\defgroup patterns Patterns +/// A set of templated design patterns. +///\ingroup etl - ///\defgroup crc CRC - /// A set of CRC calculations - ///\ingroup maths +///\defgroup crc CRC +/// A set of CRC calculations +///\ingroup maths - ///\ingroup etl - namespace etl +///\ingroup etl +namespace etl { } diff --git a/include/etl/expected.h b/include/etl/expected.h index 2bb2ca9a..655be8b1 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -206,7 +206,7 @@ namespace etl //******************************************* /// Get the error. //******************************************* - ETL_CONSTEXPR14 TError&& error() const&& ETL_NOEXCEPT + ETL_CONSTEXPR14 const TError&& error() const&& ETL_NOEXCEPT { return etl::move(error_value); } @@ -604,6 +604,38 @@ namespace etl return etl::move(etl::get(storage)); } + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) const& + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return error(); + } + } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) && + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return etl::move(error()); + } + } + //******************************************* /// Swap with another etl::expected. //******************************************* @@ -661,6 +693,22 @@ namespace etl { return etl::get(storage); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + error_type error_or(const G& default_error) const + { + if (has_value()) + { + return static_cast(default_error); + } + else + { + return error(); + } + } #endif //******************************************* @@ -725,6 +773,39 @@ namespace etl } #endif + //******************************************* + /// Returns a pointer to the value if has_value(), otherwise returns nullptr. + /// Allows expected to be used as a range of 0 or 1 elements. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 value_type* begin() ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) : ETL_NULLPTR; + } + + //******************************************* + /// Returns a pointer past the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 value_type* end() ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) + 1 : ETL_NULLPTR; + } + + //******************************************* + /// Returns a const pointer to the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 const value_type* begin() const ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) : ETL_NULLPTR; + } + + //******************************************* + /// Returns a const pointer past the value if has_value(), otherwise returns nullptr. + //******************************************* + ETL_NODISCARD ETL_CONSTEXPR14 const value_type* end() const ETL_NOEXCEPT + { + return has_value() ? &etl::get(storage) + 1 : ETL_NULLPTR; + } + #if ETL_USING_CPP11 template ::type>::type> auto transform(F&& f) & -> expected @@ -827,13 +908,12 @@ namespace etl enum { - Uninitialised, Value_Type, Error_Type }; - typedef etl::variant storage_type; - storage_type storage; + typedef etl::variant storage_type; + storage_type storage; #if ETL_USING_CPP11 template < typename F, typename TExp, typename TRet, typename TValueRef, typename = typename etl::enable_if::value>::type> @@ -1066,6 +1146,38 @@ namespace etl { return etl::move(etl::get(storage)); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) const& + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return error(); + } + } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + ETL_NODISCARD ETL_CONSTEXPR14 etl::enable_if_t::value, error_type> error_or(G&& default_error) && + { + if (has_value()) + { + return static_cast(etl::forward(default_error)); + } + else + { + return etl::move(error()); + } + } #else //******************************************* /// Returns the error @@ -1075,6 +1187,22 @@ namespace etl { return etl::get(storage); } + + //******************************************* + /// Get the error or a default value. + //******************************************* + template + error_type error_or(const G& default_error) const + { + if (has_value()) + { + return static_cast(default_error); + } + else + { + return error(); + } + } #endif //******************************************* @@ -1181,7 +1309,7 @@ namespace etl template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result::type>::type> auto transform_error(F&& f) const&& -> expected { - return transform_error_impl(etl::forward(f), *this); + return transform_error_impl(etl::forward(f), etl::move(*this)); } #endif @@ -1189,7 +1317,7 @@ namespace etl enum { - Uninitialised, + Void_Type, Error_Type }; @@ -1381,24 +1509,25 @@ namespace etl { return !(lhs == rhs); } + + //******************************************* + /// Swap etl::expected. + //******************************************* + template + ETL_CONSTEXPR14 void swap(etl::expected& lhs, etl::expected& rhs) + { + lhs.swap(rhs); + } + + //******************************************* + /// Swap etl::unexpected. + //******************************************* + template + ETL_CONSTEXPR14 void swap(etl::unexpected& lhs, etl::unexpected& rhs) + { + lhs.swap(rhs); + } + } // namespace etl -//******************************************* -/// Swap etl::expected. -//******************************************* -template -ETL_CONSTEXPR14 void swap(etl::expected& lhs, etl::expected& rhs) -{ - lhs.swap(rhs); -} - -//******************************************* -/// Swap etl::unexpected. -//******************************************* -template -ETL_CONSTEXPR14 void swap(etl::unexpected& lhs, etl::unexpected& rhs) -{ - lhs.swap(rhs); -} - #endif diff --git a/include/etl/flags.h b/include/etl/flags.h index 4fd77d89..3896458e 100644 --- a/include/etl/flags.h +++ b/include/etl/flags.h @@ -39,8 +39,6 @@ SOFTWARE. #include "type_traits.h" #include -#include -#include namespace etl { diff --git a/include/etl/flat_map.h b/include/etl/flat_map.h index 8e2cd39f..a9188642 100644 --- a/include/etl/flat_map.h +++ b/include/etl/flat_map.h @@ -100,26 +100,6 @@ namespace etl private: - //********************************************************************* - /// How to compare elements and keys. - //********************************************************************* - class compare - { - public: - - 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); - } - - key_compare comp; - }; - public: //********************************************************************* diff --git a/include/etl/fnv_1.h b/include/etl/fnv_1.h index 0ac9c5d7..69b7c5c0 100644 --- a/include/etl/fnv_1.h +++ b/include/etl/fnv_1.h @@ -34,7 +34,6 @@ SOFTWARE. #include "platform.h" #include "frame_check_sequence.h" #include "ihash.h" -#include "static_assert.h" #include "type_traits.h" #include diff --git a/include/etl/format.h b/include/etl/format.h index 72c79be0..b237caa5 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -76,17 +76,409 @@ namespace etl } }; - template - ETL_CONSTEXPR14 bool check_f(const char* fmt) + #if ETL_USING_CPP20 + namespace private_format_check { - // to be implemented later - // return fmt[0] == 0; // actual check + // Type category for compile-time type/specifier compatibility checking + enum class type_category + { + NONE, // monostate + BOOLEAN, // bool + CHAR, // char + INTEGER, // int, unsigned, long long, unsigned long long, short, etc. + FLOAT, // float, double, long double + STRING, // const char*, string_view + POINTER // const void* + }; + + // Map a type to its category. Decays and removes cv-qualifiers. + 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 + } + + // Check if a format type character is valid for a given type category. + // '\0' means no explicit type was specified (always valid — uses default presentation). + inline constexpr bool ct_check_type_spec(type_category cat, char type_char) + { + if (type_char == '\0') + { + return true; // no explicit type: always OK, uses default + } + + switch (cat) + { + case type_category::BOOLEAN: + // bool: s (as "true"/"false"), b, B, c, d, o, x, X (as integer 0/1) + return type_char == 's' || type_char == 'b' || type_char == 'B' || type_char == 'c' || type_char == 'd' || type_char == 'o' + || type_char == 'x' || type_char == 'X'; + + case type_category::CHAR: + // char: c (default), b, B, d, o, x, X (as integer), s, ? + return type_char == 'c' || type_char == '?' || type_char == 'b' || type_char == 'B' || type_char == 'd' || type_char == 'o' + || type_char == 'x' || type_char == 'X' || type_char == 's'; + + case type_category::INTEGER: + // integers: b, B, c, d, o, x, X + return type_char == 'b' || type_char == 'B' || type_char == 'c' || type_char == 'd' || type_char == 'o' || type_char == 'x' + || type_char == 'X'; + + case type_category::FLOAT: + // floats: a, A, e, E, f, F, g, G + return type_char == 'a' || type_char == 'A' || type_char == 'e' || type_char == 'E' || type_char == 'f' || type_char == 'F' + || type_char == 'g' || type_char == 'G'; + + case type_category::STRING: + // strings: s, ? + return type_char == 's' || type_char == '?'; + + case type_category::POINTER: + // pointers: p, P + return type_char == 'p' || type_char == 'P'; + + case type_category::NONE: + default: return true; // unknown/custom type: be permissive, let runtime handle it + } + } + + inline constexpr bool ct_is_digit(char c) + { + return c >= '0' && c <= '9'; + } + + // Parse an unsigned integer from fmt starting at pos. Updates pos past the digits. + // Returns the parsed number, or -1 if no digits found, or -2 on overflow. + inline constexpr int ct_parse_num(const char* fmt, int& pos) + { + if (!ct_is_digit(fmt[pos])) + { + return -1; + } + int result = 0; + while (ct_is_digit(fmt[pos])) + { + int new_result = result * 10 + (fmt[pos] - '0'); + if (new_result < result) + { + // Overflow detected + return -2; + } + result = new_result; + ++pos; + } + return result; + } + + inline constexpr bool ct_is_align(char c) + { + return c == '<' || c == '>' || c == '^'; + } + + inline constexpr bool ct_is_sign(char c) + { + return c == '+' || c == '-' || c == ' '; + } + + inline constexpr bool ct_is_type(char c) + { + // All valid type characters from the format spec + return (c == 's') || (c == '?') || (c == 'b') || (c == 'B') || (c == 'c') || (c == 'd') || (c == 'o') || (c == 'x') || (c == 'X') || (c == 'a') + || (c == 'A') || (c == 'e') || (c == 'E') || (c == 'f') || (c == 'F') || (c == 'g') || (c == 'G') || (c == 'p') || (c == 'P'); + } + + // Validate a nested replacement field like {}, {0}, {1} inside width/precision. + // pos should be at the '{'. Updates pos past the closing '}'. + // Updates auto_count / has_manual / has_auto. Returns false on error. + inline constexpr bool ct_parse_nested_replacement(const char* fmt, int& pos, int n_args, int& auto_count, bool& has_auto, bool& has_manual) + { + if (fmt[pos] != '{') + return false; + ++pos; // skip '{' + + int num = ct_parse_num(fmt, pos); + if (num == -2) + return false; // overflow + if (num >= 0) + { + // manual index + if (has_auto) + return false; // mixing + has_manual = true; + if (num >= n_args) + return false; + } + else + { + // automatic index + if (has_manual) + return false; // mixing + has_auto = true; + if (auto_count >= n_args) + return false; + ++auto_count; + } + + if (fmt[pos] != '}') + return false; + ++pos; // skip '}' + return true; + } + + // Skip/validate the format-spec portion after the colon: + // [[fill]align][sign][#][0][width][.precision][L][type] + // pos is right after ':'. Returns false on invalid spec. + // parsed_type is set to the type character found, or '\0' if none. + inline constexpr bool ct_skip_format_spec(const char* fmt, int& pos, int n_args, int& auto_count, bool& has_auto, bool& has_manual, + char& parsed_type, bool& parsed_has_precision) + { + parsed_type = '\0'; + parsed_has_precision = false; + + if (fmt[pos] == '\0' || fmt[pos] == '}') + { + return true; // empty spec is valid + } + + // fill-and-align: either [align] or [fill][align] + // Look ahead: if second char is an align char, first is fill + if (fmt[pos + 1] != '\0' && ct_is_align(fmt[pos + 1])) + { + char fill = fmt[pos]; + if (fill == '{' || fill == '}') + return false; // { and } not allowed as fill + pos += 2; // skip fill + align + } + else if (ct_is_align(fmt[pos])) + { + ++pos; // skip align only + } + + // sign + if (ct_is_sign(fmt[pos])) + { + ++pos; + } + + // '#' + if (fmt[pos] == '#') + { + ++pos; + } + + // '0' + if (fmt[pos] == '0') + { + ++pos; + } + + // width: number or nested replacement + if (ct_is_digit(fmt[pos])) + { + if (ct_parse_num(fmt, pos) == -2) + return false; // overflow + } + else if (fmt[pos] == '{') + { + if (!ct_parse_nested_replacement(fmt, pos, n_args, auto_count, has_auto, has_manual)) + { + return false; + } + } + + // precision: '.' followed by number or nested replacement + bool has_precision = false; + if (fmt[pos] == '.') + { + has_precision = true; + ++pos; + if (ct_is_digit(fmt[pos])) + { + if (ct_parse_num(fmt, pos) == -2) + return false; // overflow + } + else if (fmt[pos] == '{') + { + if (!ct_parse_nested_replacement(fmt, pos, n_args, auto_count, has_auto, has_manual)) + { + return false; + } + } + // else: '.' with no precision number/replacement — still valid (empty precision) + } + + // locale-specific: 'L' + if (fmt[pos] == 'L') + { + ++pos; + } + + // type + if (ct_is_type(fmt[pos])) + { + parsed_type = fmt[pos]; + ++pos; + } + + // After parsing the spec, we must be at '}' (the closing brace is consumed by the caller) + // Any remaining characters before '}' means invalid spec + if (fmt[pos] != '}') + { + return false; + } + + parsed_has_precision = has_precision; + + return true; + } + } // namespace private_format_check + + template + constexpr bool check_format(const char* fmt) + { + const int n_args = static_cast(sizeof...(Args)); + int pos = 0; + int auto_count = 0; + bool has_auto = false; + bool has_manual = false; + + // Build a constexpr array mapping arg index -> type category + const private_format_check::type_category arg_categories[] = { + private_format_check::get_type_category()..., + private_format_check::type_category::NONE // sentinel for zero-arg case + }; + + while (fmt[pos] != '\0') + { + char c = fmt[pos]; + ++pos; + + if (c == '{') + { + if (fmt[pos] == '{') + { + // escaped '{' + ++pos; + continue; + } + + // Start of a replacement field: [arg_id][:format_spec] + int resolved_index = -1; + int arg_index = private_format_check::ct_parse_num(fmt, pos); + if (arg_index == -2) + return false; // overflow in arg index + if (arg_index >= 0) + { + // manual index + if (has_auto) + return false; // mixing auto and manual + has_manual = true; + if (arg_index >= n_args) + return false; // index out of range + resolved_index = arg_index; + } + else + { + // automatic index + if (has_manual) + return false; // mixing auto and manual + has_auto = true; + if (auto_count >= n_args) + return false; // too many arguments + resolved_index = auto_count; + ++auto_count; + } + + char type_char = '\0'; + bool has_precision = false; + if (fmt[pos] == ':') + { + ++pos; // skip ':' + if (!private_format_check::ct_skip_format_spec(fmt, pos, n_args, auto_count, has_auto, has_manual, type_char, has_precision)) + { + return false; + } + } + + // Validate type specifier against argument type + if (resolved_index >= 0 && resolved_index < n_args) + { + if (!private_format_check::ct_check_type_spec(arg_categories[resolved_index], type_char)) + { + return false; + } + + // Precision is not allowed for integer, boolean, or pointer types + if (has_precision) + { + auto cat = arg_categories[resolved_index]; + if (cat == private_format_check::type_category::INTEGER || cat == private_format_check::type_category::BOOLEAN + || cat == private_format_check::type_category::POINTER) + { + return false; + } + // Precision is also invalid for char when presented as char (not as integer) + if (cat == private_format_check::type_category::CHAR && (type_char == '\0' || type_char == 'c' || type_char == '?')) + { + return false; + } + } + } + + if (fmt[pos] != '}') + { + return false; // missing closing brace + } + ++pos; // skip '}' + } + else if (c == '}') + { + if (fmt[pos] != '}') + { + return false; // unmatched '}' + } + ++pos; // skip second '}' + } + } - (void)fmt; return true; } - inline void please_note_this_is_error_message_1() noexcept {} + inline void please_note_this_is_error_message_format_string_syntax_error() noexcept {} + #endif // ETL_USING_CPP20 template struct basic_format_string @@ -94,20 +486,15 @@ namespace etl inline ETL_CONSTEVAL basic_format_string(const char* fmt) : _sv(fmt) { - bool format_string_ok = check_f(fmt); - - if (!format_string_ok) + #if ETL_USING_CPP20 + // Compile-time validation: check_format runs at compile time via consteval. + // In pre-C++20, runtime checks in vformat_to/parse_format_spec/etc. are sufficient. + if (!check_format(fmt)) { - // if (etl::is_constant_evaluated()) // compile time error path - //{ - // // calling a non-constexpr function in a consteval context to - // trigger a compile error please_note_this_is_error_message_1(); - // } - // else // run time error path - //{ - ETL_ASSERT_FAIL_AND_RETURN(ETL_ERROR(bad_format_string_exception)); - //} + // Calling a non-constexpr function in a consteval context triggers a compile error. + please_note_this_is_error_message_format_string_syntax_error(); } + #endif } ETL_CONSTEXPR basic_format_string(const basic_format_string& other) = default; @@ -181,7 +568,6 @@ namespace etl // automatic number generation only allowed if not already in manual mode ETL_ASSERT(manual_mode == false, ETL_ERROR(bad_format_string_exception)); automatic_mode = true; - // TODO: compile time check ETL_ASSERT(current < num_args, ETL_ERROR(bad_format_string_exception) /* not enough arguments for generated index */); return current++; } @@ -598,18 +984,6 @@ namespace etl return false; } - inline bool parse_sequence(format_parse_context& parse_ctx, etl::string_view sequence) - { - auto fmt_it = parse_ctx.begin(); - if (etl::equal(sequence.cbegin(), sequence.cend(), fmt_it)) - { - fmt_it += sequence.size(); - parse_ctx.advance_to(fmt_it); - return true; - } - return false; - } - inline bool is_align_character(char c) { return c == '<' || c == '>' || c == '^'; @@ -1039,22 +1413,27 @@ namespace etl { const size_t fractional_decimals = 6; // default - T integral; - T fractional = modf(value, &integral); - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; - if (integral < 0.0) + // Detect sign using signbit to correctly handle -0.0 + bool sign = signbit(value); + + T integral; + T fractional = modf(value, &integral); + + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1071,9 +1450,8 @@ namespace etl static const size_t exponent_decimals = 1; long long int exponent_int = 0; - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; + // Detect sign using signbit to correctly handle -0.0 + bool sign = signbit(value); T integral; T fractional = modf(value, &integral); @@ -1092,17 +1470,21 @@ namespace etl fractional = modf(value, &integral); } - if (integral < 0.0) + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(static_cast(0x10), fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(0x10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(static_cast(0x10), fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1133,9 +1515,8 @@ namespace etl static const size_t exponent_decimals = 2; long long int exponent_int = 0; - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; + // Detect sign using signbit to correctly handle -0.0 + bool sign = std::signbit(value); T integral; T fractional = modf(value, &integral); @@ -1154,17 +1535,21 @@ namespace etl fractional = modf(value, &integral); } - if (integral < 0.0) + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1186,22 +1571,27 @@ namespace etl { const size_t fractional_decimals = 6; // default - T integral; - T fractional = modf(value, &integral); - bool sign; - unsigned long long int fractional_int; - unsigned long long int integral_int; - if (integral < 0.0) + // Detect sign using signbit to correctly handle -0.0 + bool sign = std::signbit(value); + + T integral; + T fractional = modf(value, &integral); + + // Take absolute values to avoid casting negative values to unsigned + if (sign) { - sign = true; - fractional_int = static_cast(-fractional * pow(10., fractional_decimals)); - integral_int = static_cast(-integral); + fractional = -fractional; + integral = -integral; } - else + + unsigned long long int scale = int_pow(10, fractional_decimals); + unsigned long long int fractional_int = static_cast(round(fractional * scale)); + unsigned long long int integral_int = static_cast(integral); + + if (fractional_int == scale) { - sign = false; - fractional_int = static_cast(fractional * pow(10., fractional_decimals)); - integral_int = static_cast(integral); + fractional_int = 0; + ++integral_int; } private_format::format_sign(it, sign ? -1 : 0, spec); @@ -1443,6 +1833,40 @@ namespace etl fmt_context.advance_to(tmp); } + // Compute prefix/suffix padding sizes for alignment. + // default_align_start: if true, NONE defaults to left-align (START); otherwise right-align (END). + inline void compute_padding(size_t pad, spec_align_t align, bool default_align_start, size_t& prefix_size, size_t& suffix_size) + { + switch (align) + { + case spec_align_t::START: + prefix_size = 0; + suffix_size = pad; + break; + case spec_align_t::CENTER: + prefix_size = pad / 2; + suffix_size = pad - prefix_size; + break; + case spec_align_t::END: + prefix_size = pad; + suffix_size = 0; + break; + case spec_align_t::NONE: + default: + if (default_align_start) + { + prefix_size = 0; + suffix_size = pad; + } + else + { + prefix_size = pad; + suffix_size = 0; + } + break; + } + } + template typename format_context::iterator format_aligned_int(Int arg, format_context& fmt_ctx) { @@ -1451,32 +1875,13 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_num(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + compute_padding(pad, fmt_ctx.format_spec.align, false, prefix_size, suffix_size); } } @@ -1497,32 +1902,13 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_floating(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + compute_padding(pad, fmt_ctx.format_spec.align, false, prefix_size, suffix_size); } } @@ -1593,32 +1979,13 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_string_view(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + compute_padding(pad, fmt_ctx.format_spec.align, true, prefix_size, suffix_size); } } @@ -1630,99 +1997,10 @@ namespace etl return it; } - template - void format_chars(OutputIt& it, const char* arg, const format_spec_t& spec) - { - bool escaped = false; - if (spec.type.has_value()) - { - switch (spec.type.value()) - { - case 's': - // default output - break; - case '?': - // escaped string - escaped = true; - break; - default: - // invalid type for string - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } - } - size_t limit = etl::numeric_limits::max(); - if (spec.precision.has_value()) - { - limit = spec.precision.value(); - } - - if (escaped) - { - format_plain_char(it, '"'); - } - const char_type* arg_it = arg; - while (*arg_it != '\0' && limit > 0) - { - if (escaped) - { - format_escaped_char(it, *arg_it); - } - else - { - format_plain_char(it, *arg_it); - } - ++arg_it; - --limit; - } - if (escaped) - { - format_plain_char(it, '"'); - } - } - template typename format_context::iterator format_aligned_chars(const char* arg, format_context& fmt_ctx) { - size_t prefix_size = 0; - size_t suffix_size = 0; - - if (fmt_ctx.format_spec.width) - { - // calculate size - private_format::counter_iterator counter; - private_format::format_chars(counter, arg, fmt_ctx.format_spec); - - if (counter.value() < fmt_ctx.format_spec.width.value()) - { - size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } - } - } - - // actual output - OutputIt it = fmt_ctx.out(); - private_format::fill(it, prefix_size, fmt_ctx.format_spec.fill); - private_format::format_chars(it, arg, fmt_ctx.format_spec); - private_format::fill(it, suffix_size, fmt_ctx.format_spec.fill); - return it; + return format_aligned_string_view(etl::string_view(arg), fmt_ctx); } inline void check_char_spec(const format_spec_t& spec) @@ -1777,43 +2055,16 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_char(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::NONE: // default - if (!fmt_ctx.format_spec.type.has_value() || fmt_ctx.format_spec.type.value() == 'c' || fmt_ctx.format_spec.type.value() == '?') - { - prefix_size = 0; - suffix_size = pad; - } - else - { - prefix_size = pad; - suffix_size = 0; - } - break; - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + // char type defaults to left-align, integer presentation defaults to right-align + bool default_start = + !fmt_ctx.format_spec.type.has_value() || fmt_ctx.format_spec.type.value() == 'c' || fmt_ctx.format_spec.type.value() == '?'; + compute_padding(pad, fmt_ctx.format_spec.align, default_start, prefix_size, suffix_size); } } @@ -1861,32 +2112,13 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_bool(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + compute_padding(pad, fmt_ctx.format_spec.align, false, prefix_size, suffix_size); } } @@ -1930,32 +2162,13 @@ namespace etl if (fmt_ctx.format_spec.width) { - // calculate size private_format::counter_iterator counter; private_format::format_pointer(counter, arg, fmt_ctx.format_spec); if (counter.value() < fmt_ctx.format_spec.width.value()) { size_t pad = fmt_ctx.format_spec.width.value() - counter.value(); - switch (fmt_ctx.format_spec.align) - { - case private_format::spec_align_t::START: - prefix_size = 0; - suffix_size = pad; - break; - case private_format::spec_align_t::CENTER: - prefix_size = pad / 2; - suffix_size = pad - prefix_size; - break; - case private_format::spec_align_t::NONE: // default - case private_format::spec_align_t::END: - prefix_size = pad; - suffix_size = 0; - break; - default: - // invalid alignment specification - ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception)); - } + compute_padding(pad, fmt_ctx.format_spec.align, false, prefix_size, suffix_size); } } diff --git a/include/etl/forward_list.h b/include/etl/forward_list.h index 4518be05..cfba7bf9 100644 --- a/include/etl/forward_list.h +++ b/include/etl/forward_list.h @@ -116,15 +116,15 @@ namespace etl }; //*************************************************************************** - /// Unsorted exception for the list. - ///\ingroup list + /// Unsorted exception for the forward_list. + ///\ingroup forward_list //*************************************************************************** class forward_list_no_pool : public forward_list_exception { public: forward_list_no_pool(string_type file_name_, numeric_type line_number_) - : forward_list_exception(ETL_ERROR_TEXT("list:no pool", ETL_FORWARD_LIST_FILE_ID"D"), file_name_, line_number_) + : forward_list_exception(ETL_ERROR_TEXT("forward_list:no pool", ETL_FORWARD_LIST_FILE_ID"D"), file_name_, line_number_) { } }; diff --git a/include/etl/gamma.h b/include/etl/gamma.h index 4def080e..4ad83ffb 100644 --- a/include/etl/gamma.h +++ b/include/etl/gamma.h @@ -36,7 +36,6 @@ SOFTWARE. #include "type_traits.h" #include -#include namespace etl { diff --git a/include/etl/histogram.h b/include/etl/histogram.h index 195076dd..95943b76 100644 --- a/include/etl/histogram.h +++ b/include/etl/histogram.h @@ -479,7 +479,7 @@ namespace etl //********************************* const_iterator end() const { - return accumulator.begin(); + return accumulator.end(); } //********************************* @@ -487,7 +487,7 @@ namespace etl //********************************* const_iterator cend() const { - return accumulator.cbegin(); + return accumulator.cend(); } //********************************* diff --git a/include/etl/ihash.h b/include/etl/ihash.h index 10890044..08db0a3b 100644 --- a/include/etl/ihash.h +++ b/include/etl/ihash.h @@ -36,8 +36,6 @@ SOFTWARE. #include "exception.h" #include "utility.h" -#include - ///\defgroup ihash Common data for all hash type classes. ///\ingroup hash diff --git a/include/etl/index_of_type.h b/include/etl/index_of_type.h index 53128447..2d799832 100644 --- a/include/etl/index_of_type.h +++ b/include/etl/index_of_type.h @@ -31,7 +31,8 @@ SOFTWARE. #include "platform.h" #include "integral_limits.h" -#include "static_assert.h" + +#include namespace etl { diff --git a/include/etl/integral_limits.h b/include/etl/integral_limits.h index 45d7a026..cf741e30 100644 --- a/include/etl/integral_limits.h +++ b/include/etl/integral_limits.h @@ -35,7 +35,6 @@ SOFTWARE. #include "type_traits.h" #include -#include #include "private/minmax_push.h" diff --git a/include/etl/intrusive_links.h b/include/etl/intrusive_links.h index 6355ee0a..a1a9e653 100644 --- a/include/etl/intrusive_links.h +++ b/include/etl/intrusive_links.h @@ -39,7 +39,7 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" -#include +#include //***************************************************************************** // Note: @@ -890,7 +890,10 @@ namespace etl template typename etl::enable_if< etl::is_same >::value, void>::type link_clear_range(TLink* start) { - etl::link_clear_range(*start); + if (start != ETL_NULLPTR) + { + etl::link_clear_range(*start); + } } #if ETL_USING_CPP17 diff --git a/include/etl/invert.h b/include/etl/invert.h index fc1a4e50..fddcebf9 100644 --- a/include/etl/invert.h +++ b/include/etl/invert.h @@ -35,8 +35,6 @@ SOFTWARE. #include "functional.h" #include "limits.h" -#include - namespace etl { //*************************************************************************** diff --git a/include/etl/ipool.h b/include/etl/ipool.h index c71254bf..1fdd996a 100644 --- a/include/etl/ipool.h +++ b/include/etl/ipool.h @@ -37,9 +37,10 @@ SOFTWARE. #include "iterator.h" #include "memory.h" #include "placement_new.h" -#include "static_assert.h" #include "utility.h" +#include + #define ETL_POOL_CPP03_CODE 0 namespace etl @@ -644,7 +645,7 @@ namespace etl // in debug. #if ETL_IS_DEBUG_BUILD // Is the address on a valid object boundary? - bool is_valid_address = ((distance % Item_Size) == 0); + bool is_valid_address = ((static_cast(distance) % Item_Size) == 0); #else bool is_valid_address = true; #endif diff --git a/include/etl/iterator.h b/include/etl/iterator.h index 8a09e7c0..263ab5c6 100644 --- a/include/etl/iterator.h +++ b/include/etl/iterator.h @@ -958,13 +958,121 @@ namespace etl template ETL_CONSTANT bool is_random_access_iterator_concept::value; +#if ETL_USING_CPP11 + //*************************************************************************** + /// Trait to detect if a type is a container (has iterator and begin/end) + /// but is not itself an iterator. + /// Used to constrain begin()/end() free functions in C++26. + //*************************************************************************** + namespace private_iterator + { + // Check if T has iterator_category (i.e., is an iterator) + template + struct has_iterator_category : etl::false_type + { + }; + + template + struct has_iterator_category> : etl::true_type + { + }; + + // is_container: has iterator/const_iterator/begin/end but does NOT have iterator_category + template + struct is_container : etl::false_type + { + }; + + template + struct is_container< + T, etl::void_t< typename T::iterator, typename T::const_iterator, decltype(etl::declval().begin()), decltype(etl::declval().end()) >> + : etl::bool_constant::value> + { + }; + } // namespace private_iterator +#endif + #if ETL_NOT_USING_STL || ETL_CPP11_NOT_SUPPORTED + #if ETL_USING_CPP11 + + //***************************************************************************** + /// Get the 'begin' iterator. + /// Note: Contains SFINAE guard, ensuring they only participate in overload + /// resolution when TContainer actually has the corresponding member function. + /// This prevents ADL from matching these templates when std::ranges::begin + /// performs an unqualified call on etl:: iterator types. + ///\ingroup container + //***************************************************************************** + template ().begin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::iterator>::type + begin(TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().begin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + begin(const TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().cbegin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + cbegin(const TContainer& container) + { + return container.cbegin(); + } + + //***************************************************************************** + /// Get the 'end' iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().end())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::iterator>::type end(TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().end())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + end(const TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().cend())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_iterator>::type + cend(const TContainer& container) + { + return container.cend(); + } + #else + // C++03 fallback: + // - no SFINAE guards needed since std::ranges does not exist + // - no constraint needed as C++26 ADL issue doesn't apply //***************************************************************************** /// Get the 'begin' iterator. ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::iterator begin(TContainer& container) + typename TContainer::iterator begin(TContainer& container) { return container.begin(); } @@ -974,7 +1082,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_iterator begin(const TContainer& container) + typename TContainer::const_iterator begin(const TContainer& container) { return container.begin(); } @@ -984,7 +1092,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_iterator cbegin(const TContainer& container) + typename TContainer::const_iterator cbegin(const TContainer& container) { return container.cbegin(); } @@ -994,7 +1102,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::iterator end(TContainer& container) + typename TContainer::iterator end(TContainer& container) { return container.end(); } @@ -1004,7 +1112,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_iterator end(const TContainer& container) + typename TContainer::const_iterator end(const TContainer& container) { return container.end(); } @@ -1014,10 +1122,11 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_iterator cend(const TContainer& container) + typename TContainer::const_iterator cend(const TContainer& container) { return container.cend(); } + #endif //***************************************************************************** /// Get the 'begin' pointer for an array. @@ -1081,12 +1190,83 @@ namespace etl #endif #if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED + #if ETL_USING_CPP11 + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + /// Note: Contains SFINAE guard (see begin/end above for rationale). + ///\ingroup container + //***************************************************************************** + template ().rbegin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::reverse_iterator>::type + rbegin(TContainer& container) + { + return container.rbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().rbegin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + rbegin(const TContainer& container) + { + return container.rbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().crbegin())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + crbegin(const TContainer& container) + { + return container.crbegin(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().rend())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::reverse_iterator>::type + rend(TContainer& container) + { + return container.rend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().rend())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + rend(const TContainer& container) + { + return container.rend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template ().crend())> > + ETL_CONSTEXPR typename etl::enable_if::value, typename TContainer::const_reverse_iterator>::type + crend(const TContainer& container) + { + return container.crend(); + } + #else + // C++03 fallback: + // - no SFINAE guards needed since std::ranges does not exist. + // - no constraint needed as C++26 ADL issue doesn't apply //***************************************************************************** /// Get the 'begin' reverse_iterator for a container. ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::reverse_iterator rbegin(TContainer& container) + typename TContainer::reverse_iterator rbegin(TContainer& container) { return container.rbegin(); } @@ -1096,7 +1276,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_reverse_iterator rbegin(const TContainer& container) + typename TContainer::const_reverse_iterator rbegin(const TContainer& container) { return container.rbegin(); } @@ -1106,7 +1286,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_reverse_iterator crbegin(const TContainer& container) + typename TContainer::const_reverse_iterator crbegin(const TContainer& container) { return container.crbegin(); } @@ -1116,7 +1296,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::reverse_iterator rend(TContainer& container) + typename TContainer::reverse_iterator rend(TContainer& container) { return container.rend(); } @@ -1126,7 +1306,7 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_reverse_iterator rend(const TContainer& container) + typename TContainer::const_reverse_iterator rend(const TContainer& container) { return container.rend(); } @@ -1136,10 +1316,11 @@ namespace etl ///\ingroup container //***************************************************************************** template - ETL_CONSTEXPR typename TContainer::const_reverse_iterator crend(const TContainer& container) + typename TContainer::const_reverse_iterator crend(const TContainer& container) { return container.crend(); } + #endif //***************************************************************************** /// Get the 'begin' reverse_iterator for an array. diff --git a/include/etl/jenkins.h b/include/etl/jenkins.h index 682a2187..5ea72099 100644 --- a/include/etl/jenkins.h +++ b/include/etl/jenkins.h @@ -36,7 +36,6 @@ SOFTWARE. #include "frame_check_sequence.h" #include "ihash.h" #include "iterator.h" -#include "static_assert.h" #include "type_traits.h" #include diff --git a/include/etl/limiter.h b/include/etl/limiter.h index 7876582a..5b285df2 100644 --- a/include/etl/limiter.h +++ b/include/etl/limiter.h @@ -36,8 +36,6 @@ SOFTWARE. #include "functional.h" #include "type_traits.h" -#include - namespace etl { namespace private_limiter diff --git a/include/etl/limits.h b/include/etl/limits.h index 5f98fd73..c274a337 100644 --- a/include/etl/limits.h +++ b/include/etl/limits.h @@ -43,7 +43,6 @@ SOFTWARE. #include #include #include -#include #include "private/minmax_push.h" diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 032d9e29..b385565d 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -35,6 +35,8 @@ SOFTWARE. #include "span.h" #include "static_assert.h" +#if ETL_USING_CPP11 + ///\defgroup manchester manchester /// Manchester encoding and decoding ///\ingroup utilities @@ -51,13 +53,13 @@ namespace etl struct is_encodable { static const bool value = -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES etl::is_same::value || -#endif + #endif etl::is_same::value -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES || etl::is_same::value -#endif + #endif ; }; @@ -69,13 +71,13 @@ namespace etl struct is_decodable { static const bool value = -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES etl::is_same::value || -#endif + #endif etl::is_same::value -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES || etl::is_same::value -#endif + #endif ; }; @@ -91,13 +93,13 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); }; -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES template <> struct encoded { typedef uint16_t type; }; -#endif + #endif template <> struct encoded @@ -105,13 +107,13 @@ namespace etl typedef uint32_t type; }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct encoded { typedef uint64_t type; }; -#endif + #endif //************************************************************************* /// Type trait to determine the decoded type for a given encoded type. @@ -125,13 +127,13 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint8_t type; }; -#endif + #endif template <> struct decoded @@ -139,24 +141,24 @@ namespace etl typedef uint16_t type; }; -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint32_t type; }; -#endif + #endif //************************************************************************* /// Normal Manchester encoding type (no inversion). //************************************************************************* struct manchester_type_normal { -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES static const uint64_t inversion_mask = 0x0000000000000000ULL; -#else + #else static const uint32_t inversion_mask = 0x00000000UL; -#endif + #endif }; //************************************************************************* @@ -164,11 +166,11 @@ namespace etl //************************************************************************* struct manchester_type_inverted { -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL; -#else + #else static const uint32_t inversion_mask = 0xFFFFFFFFUL; -#endif + #endif }; //************************************************************************* @@ -247,11 +249,11 @@ namespace etl ETL_STATIC_ASSERT(CHAR_BIT == etl::numeric_limits::digits, "Manchester requires uint_least8_t to have the same number of bits as CHAR (CHAR_BITS)"); - //************************************************************************* - // Encoding functions - //************************************************************************* + //************************************************************************* + // Encoding functions + //************************************************************************* -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES //************************************************************************* /// Encode a 8-bit unsigned value and return 16-bit result. ///\param decoded The value to encode. @@ -273,7 +275,7 @@ namespace etl ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask))); return encoded; } -#endif + #endif //************************************************************************* /// Encode a 16-bit unsigned value and return the 32-bit result. @@ -297,7 +299,7 @@ namespace etl return encoded; } -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES //************************************************************************* /// Encode a 32-bit unsigned value and return the 64-bit result. ///\param decoded The value to encode. @@ -320,7 +322,7 @@ namespace etl encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask); return encoded; } -#endif + #endif //************************************************************************* /// Encode a span of data with the specified chunk size. @@ -350,11 +352,11 @@ namespace etl } } - //************************************************************************* - // Decoding functions - //************************************************************************* + //************************************************************************* + // Decoding functions + //************************************************************************* -#if ETL_USING_8BIT_TYPES + #if ETL_USING_8BIT_TYPES //************************************************************************* /// Decode a 16-bit value and return the 8-bit result. ///\param encoded The value to decode. @@ -373,7 +375,7 @@ namespace etl encoded = static_cast((static_cast(encoded) | (static_cast(encoded) >> 2)) & 0x0F0FU); return static_cast(static_cast(encoded) | (static_cast(encoded) >> 4U)); } -#endif + #endif //************************************************************************* /// Decode a 32-bit value and return the 16-bit result. @@ -394,7 +396,7 @@ namespace etl return static_cast(encoded | (encoded >> 8U)); } -#if ETL_USING_64BIT_TYPES + #if ETL_USING_64BIT_TYPES //************************************************************************* /// Decode a 64-bit value and return the 32-bit result. ///\param encoded The value to decode. @@ -414,7 +416,7 @@ namespace etl encoded = (encoded | (encoded >> 8)) & 0x0000FFFF0000FFFFULL; return static_cast(encoded | (encoded >> 16U)); } -#endif + #endif //************************************************************************* /// Decode a span of data using the specified chunk type. @@ -500,3 +502,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/memory.h b/include/etl/memory.h index b1456298..6bd07d61 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -42,7 +42,6 @@ SOFTWARE. #include "private/addressof.h" -#include #include #if defined(ETL_IN_UNIT_TEST) || ETL_USING_STL @@ -795,12 +794,8 @@ namespace etl template TOutputIterator uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin) { - // Move not supported. Defer to copy. - #if ETL_USING_CPP11 - return std::uninitialized_copy_n(i_begin, n, o_begin); - #else + // Move not supported. Defer to copy. return etl::uninitialized_copy_n(i_begin, n, o_begin); - #endif } //***************************************************************************** @@ -814,12 +809,8 @@ namespace etl { count += TCounter(n); - // Move not supported. Defer to copy. - #if ETL_USING_CPP11 - return std::uninitialized_copy_n(i_begin, n, o_begin); - #else + // Move not supported. Defer to copy. return etl::uninitialized_copy_n(i_begin, n, o_begin); - #endif } #endif @@ -1798,6 +1789,117 @@ namespace etl } // namespace ranges #endif +#if ETL_USING_CPP11 + //***************************************************************************** + /// Trivially relocate a range of objects. + /// This function relocates objects by copying their bytes using memmove. + /// The source objects' lifetimes are ended without calling destructors. + /// Based on C++26 P2786R13. + /// https://en.cppreference.com/w/cpp/memory/trivially_relocate + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value && !etl::is_const::value, T*>::type trivially_relocate(T* first, T* last, + T* result) + { + if (first == result) + { + return last; + } + + const size_t count = static_cast(last - first); + + if (count > 0) + { + // Use memmove to handle overlapping ranges + ::memmove(static_cast(result), static_cast(first), count * sizeof(T)); + } + + return result + count; + } + + //***************************************************************************** + /// Relocate implementation for trivially relocatable types. + /// Delegates to etl::trivially_relocate. + /// Uses SFINAE (enable_if) so that etl::trivially_relocate is never + /// instantiated for non-trivially relocatable types on pre-C++17 compilers, + /// avoiding the ill-formed instantiation that would occur with a plain + /// ETL_IF_CONSTEXPR branch. + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value, T*>::type relocate_impl(T* first, T* last, T* result) + { + return etl::trivially_relocate(first, last, result); + } + + //***************************************************************************** + /// Relocate implementation for non-trivially relocatable types. + /// Uses move construction + destroy. + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value, T*>::type relocate_impl(T* first, T* last, T* result) + { + const ptrdiff_t count = last - first; + + // Check if ranges overlap and handle accordingly + if (result < first || result >= last) + { + // No overlap or destination is after source - iterate forward + T* src = first; + T* dst = result; + while (src != last) + { + ::new (static_cast(dst)) T(etl::move(*src)); + src->~T(); + ++src; + ++dst; + } + } + else + { + // Destination overlaps with source from below - iterate backward + T* src = last; + T* dst = result + count; + while (src != first) + { + --src; + --dst; + ::new (static_cast(dst)) T(etl::move(*src)); + src->~T(); + } + } + + return result + count; + } + + //***************************************************************************** + /// Relocate a range of objects. + /// For trivially relocatable types, uses trivially_relocate via relocate_impl. + /// For other nothrow relocatable types, uses move + destroy via relocate_impl. + /// Delegates to SFINAE-guarded relocate_impl overloads instead of using + /// ETL_IF_CONSTEXPR, so that etl::trivially_relocate is never instantiated + /// for non-trivially relocatable types on pre-C++17 compilers. + /// Based on C++26 P2786R13. + /// https://en.cppreference.com/w/cpp/memory/relocate + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value && !etl::is_const::value, T*>::type relocate(T* first, T* last, T* result) + { + // Handle trivial relocation case + if (first == result || first == last) + { + return (first == result) ? last : result; + } + + // SFINAE on etl::is_trivially_relocatable selects the correct overload + // so that etl::trivially_relocate is only instantiated when valid. + return relocate_impl(first, last, result); + } +#endif + //***************************************************************************** /// Default deleter. ///\tparam T The pointed to type type. @@ -2259,47 +2361,43 @@ namespace etl pointer p; TDeleter deleter; }; -} // namespace etl -//***************************************************************************** -// Global functions for unique_ptr -//***************************************************************************** -template -bool operator==(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return lhs.get() == rhs.get(); -} + //***************************************************************************** + // Comparison operators for unique_ptr + //***************************************************************************** + template + bool operator==(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return lhs.get() == rhs.get(); + } -//********************************* -template -bool operator<(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); -} + //********************************* + template + bool operator<(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); + } -//********************************* -template -bool operator<=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return !(rhs < lhs); -} + //********************************* + template + bool operator<=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return !(rhs < lhs); + } -//********************************* -template -bool operator>(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return (rhs < lhs); -} + //********************************* + template + bool operator>(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return (rhs < lhs); + } -//********************************* -template -bool operator>=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) -{ - return !(lhs < rhs); -} - -namespace etl -{ + //********************************* + template + bool operator>=(const etl::unique_ptr& lhs, const etl::unique_ptr& rhs) + { + return !(lhs < rhs); + } //***************************************************************************** /// Default construct an item at address p. ///\ingroup memory @@ -2536,6 +2634,14 @@ namespace etl { *p++ = 0; } + + // Prevent the compiler from optimising away the volatile stores + // as dead stores (observed with GCC -O3 in C++23 mode). +#if defined(ETL_COMPILER_GCC) || defined(ETL_COMPILER_CLANG) + __asm__ __volatile__("" : : : "memory"); +#elif defined(ETL_COMPILER_MICROSOFT) + _ReadWriteBarrier(); +#endif } //***************************************************************************** diff --git a/include/etl/message.h b/include/etl/message.h index 4002023c..a21769c6 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -36,8 +36,6 @@ SOFTWARE. #include "static_assert.h" #include "type_traits.h" -#include - namespace etl { //*************************************************************************** diff --git a/include/etl/message_broker.h b/include/etl/message_broker.h index b8dc8ad8..25e54f62 100644 --- a/include/etl/message_broker.h +++ b/include/etl/message_broker.h @@ -36,8 +36,6 @@ SOFTWARE. #include "nullptr.h" #include "span.h" -#include - namespace etl { //*************************************************************************** diff --git a/include/etl/message_bus.h b/include/etl/message_bus.h index c2e7bfbc..7899b7d9 100644 --- a/include/etl/message_bus.h +++ b/include/etl/message_bus.h @@ -36,10 +36,9 @@ SOFTWARE. #include "message.h" #include "message_router.h" #include "message_types.h" -#include "nullptr.h" #include "vector.h" -#include +#include namespace etl { diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index d42eca61..fdaed2b3 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -39,8 +39,6 @@ SOFTWARE. #include "type_list.h" #include "utility.h" -#include - namespace etl { #if ETL_USING_CPP17 && !defined(ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION) diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 216b4710..e1454c4b 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -38,14 +38,12 @@ SOFTWARE. #include "message.h" #include "message_packet.h" #include "message_types.h" -#include "nullptr.h" -#include "placement_new.h" #include "shared_message.h" #include "successor.h" #include "type_list.h" #include "type_traits.h" -#include +#include namespace etl { diff --git a/include/etl/message_router_registry.h b/include/etl/message_router_registry.h index b57ac6b9..87942090 100644 --- a/include/etl/message_router_registry.h +++ b/include/etl/message_router_registry.h @@ -38,7 +38,7 @@ SOFTWARE. #include "memory.h" #include "message_router.h" -#include +#include namespace etl { diff --git a/include/etl/message_timer.h b/include/etl/message_timer.h index 378ff36f..a6d44a33 100644 --- a/include/etl/message_timer.h +++ b/include/etl/message_timer.h @@ -157,7 +157,6 @@ namespace etl list(etl::message_timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -286,22 +285,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -316,16 +306,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; etl::message_timer_data* const ptimers; }; diff --git a/include/etl/message_timer_atomic.h b/include/etl/message_timer_atomic.h index 584cc491..93e328c3 100644 --- a/include/etl/message_timer_atomic.h +++ b/include/etl/message_timer_atomic.h @@ -466,7 +466,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -595,22 +594,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -625,16 +615,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/message_timer_interrupt.h b/include/etl/message_timer_interrupt.h index acb3c344..5aaeb424 100644 --- a/include/etl/message_timer_interrupt.h +++ b/include/etl/message_timer_interrupt.h @@ -472,7 +472,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -601,22 +600,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -631,16 +621,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/message_timer_locked.h b/include/etl/message_timer_locked.h index 8826ad5e..4eb689ee 100644 --- a/include/etl/message_timer_locked.h +++ b/include/etl/message_timer_locked.h @@ -480,7 +480,6 @@ namespace etl timer_list(timer_data* ptimers_) : head(etl::timer::id::NO_TIMER) , tail(etl::timer::id::NO_TIMER) - , current(etl::timer::id::NO_TIMER) , ptimers(ptimers_) { } @@ -609,22 +608,13 @@ namespace etl //******************************* etl::timer::id::type begin() { - current = head; - return current; - } - - //******************************* - etl::timer::id::type previous(etl::timer::id::type last) - { - current = ptimers[last].previous; - return current; + return head; } //******************************* etl::timer::id::type next(etl::timer::id::type last) { - current = ptimers[last].next; - return current; + return ptimers[last].next; } //******************************* @@ -639,16 +629,14 @@ namespace etl timer.next = etl::timer::id::NO_TIMER; } - head = etl::timer::id::NO_TIMER; - tail = etl::timer::id::NO_TIMER; - current = etl::timer::id::NO_TIMER; + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; } private: etl::timer::id::type head; etl::timer::id::type tail; - etl::timer::id::type current; timer_data* const ptimers; }; diff --git a/include/etl/not_null.h b/include/etl/not_null.h index fc8366f3..25823d68 100644 --- a/include/etl/not_null.h +++ b/include/etl/not_null.h @@ -35,7 +35,6 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "memory.h" -#include "static_assert.h" #include "type_traits.h" namespace etl diff --git a/include/etl/numeric.h b/include/etl/numeric.h index 633755e5..7e740839 100644 --- a/include/etl/numeric.h +++ b/include/etl/numeric.h @@ -130,11 +130,11 @@ namespace etl { if (a > b) { - return b + (etl::distance(b, a) / 2U); + return b + (etl::distance(b, a) / 2); } else { - return a + (etl::distance(a, b) / 2U); + return a + (etl::distance(a, b) / 2); } } @@ -151,11 +151,11 @@ namespace etl { if (a > b) { - return b + (etl::distance(b, a) / 2U); + return b + (etl::distance(b, a) / 2); } else { - return a + (etl::distance(a, b) / 2U); + return a + (etl::distance(a, b) / 2); } } @@ -172,7 +172,7 @@ namespace etl || etl::is_same::iterator_category, ETL_OR_STD::bidirectional_iterator_tag>::value)), int>::type = 0) { - etl::advance(a, etl::distance(a, b) / 2U); + etl::advance(a, etl::distance(a, b) / 2); return a; } @@ -204,6 +204,284 @@ namespace etl return typecast_a(a) + (typecast_t(t) * (typecast_b(b) - typecast_a(a))); } + + //*************************************************************************** + /// Saturating addition for unsigned integers. + /// Returns x + y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type add_sat(T x, T y) ETL_NOEXCEPT + { + T result = static_cast(x + y); + // Overflow occurred if result < x + if (result < x) + { + return etl::numeric_limits::max(); + } + return result; + } + + //*************************************************************************** + /// Saturating addition for signed integers. + /// Returns x + y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type add_sat(T x, T y) ETL_NOEXCEPT + { + // Check for overflow: both operands have same sign and result has different sign + if (y > T(0)) + { + // Positive overflow check + if (x > (etl::numeric_limits::max() - y)) + { + return etl::numeric_limits::max(); + } + } + else + { + // Negative overflow check + if (x < (etl::numeric_limits::min() - y)) + { + return etl::numeric_limits::min(); + } + } + + return static_cast(x + y); + } + + //*************************************************************************** + /// Saturating subtraction for unsigned integers. + /// Returns x - y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type sub_sat(T x, T y) ETL_NOEXCEPT + { + // Underflow occurred if y > x + if (y > x) + { + return T(0); + } + return static_cast(x - y); + } + + //*************************************************************************** + /// Saturating subtraction for signed integers. + /// Returns x - y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type sub_sat(T x, T y) ETL_NOEXCEPT + { + // Check for overflow/underflow + if (y > T(0)) + { + // Subtracting positive: check for underflow + if (x < (etl::numeric_limits::min() + y)) + { + return etl::numeric_limits::min(); + } + } + else + { + // Subtracting negative (adding): check for overflow + if (x > (etl::numeric_limits::max() + y)) + { + return etl::numeric_limits::max(); + } + } + + return static_cast(x - y); + } + + //*************************************************************************** + /// Saturating multiplication for unsigned integers. + /// Returns x * y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type mul_sat(T x, T y) ETL_NOEXCEPT + { + if ((x == T(0)) || (y == T(0))) + { + return T(0); + } + + // Check for overflow: x * y > max => x > max / y + if (x > (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + + return static_cast(x * y); + } + + //*************************************************************************** + /// Saturating multiplication for signed integers. + /// Returns x * y, clamped to the range of T. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type mul_sat(T x, T y) ETL_NOEXCEPT + { + if ((x == T(0)) || (y == T(0))) + { + return T(0); + } + + // Both positive + if ((x > T(0)) && (y > T(0))) + { + if (x > (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + } + // Both negative + else if ((x < T(0)) && (y < T(0))) + { + if (x < (etl::numeric_limits::max() / y)) + { + return etl::numeric_limits::max(); + } + } + // Different signs (x positive, y negative) + else if ((x > T(0)) && (y < T(0))) + { + if (y < (etl::numeric_limits::min() / x)) + { + return etl::numeric_limits::min(); + } + } + // Different signs (x negative, y positive) + else + { + if (x < (etl::numeric_limits::min() / y)) + { + return etl::numeric_limits::min(); + } + } + + return static_cast(x * y); + } + + //*************************************************************************** + /// Saturating division for unsigned integers. + /// Returns x / y. For unsigned types, no saturation is needed. + /// \pre y != 0 (undefined behaviour if y is zero, matching C++26). + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, T>::type div_sat(T x, T y) ETL_NOEXCEPT + { + return static_cast(x / y); + } + + //*************************************************************************** + /// Saturating division for signed integers. + /// Returns x / y, clamped to the range of T. + /// The only case of overflow is min / -1. + /// \pre y != 0 (undefined behaviour if y is zero, matching C++26). + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, T>::type div_sat(T x, T y) ETL_NOEXCEPT + { + // The only overflow case: min / -1 would be max + 1 + if ((x == etl::numeric_limits::min()) && (y == T(-1))) + { + return etl::numeric_limits::max(); + } + + return static_cast(x / y); + } + + //*************************************************************************** + /// saturate_cast + /// Converts an integer value to another integer type, clamping the value + /// to the representable range of the destination type. + /// C++26 equivalent of std::saturate_cast. + /// + /// When the source value is within the range of R, returns the value as R. + /// When the source value is below R's minimum, returns numeric_limits::min(). + /// When the source value is above R's maximum, returns numeric_limits::max(). + //*************************************************************************** + + // Case 1: Both unsigned. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_unsigned::value && etl::is_unsigned::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // If sizeof(R) >= sizeof(T), all values of T fit in R. + // If sizeof(R) < sizeof(T), clamp to R's max. The comparison is safe + // because R's max fits in T when T is wider. + if ((sizeof(R) < sizeof(T)) && (value > static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } + + // Case 2: Both signed. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_signed::value && etl::is_signed::value, R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // Only need to clamp when narrowing (R is smaller than T). + // When sizeof(R) >= sizeof(T), all values of T fit in R. + if (sizeof(R) < sizeof(T)) + { + if (value > static_cast(etl::numeric_limits::max())) + { + return etl::numeric_limits::max(); + } + if (value < static_cast(etl::numeric_limits::min())) + { + return etl::numeric_limits::min(); + } + } + return static_cast(value); + } + + // Case 3: Signed source -> Unsigned destination. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_unsigned::value && etl::is_signed::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + if (value < T(0)) + { + return R(0); + } + + typedef typename etl::make_unsigned::type unsigned_t; + unsigned_t uvalue = static_cast(value); + + // Compare in unsigned domain. R's max is always representable as unsigned_t + // when sizeof(T) > sizeof(R), and when sizeof(R) >= sizeof(T) all positive + // values of T fit in R. + if ((sizeof(R) < sizeof(T)) && (uvalue > static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } + + // Case 4: Unsigned source -> Signed destination. + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && etl::is_integral::value && etl::is_signed::value && etl::is_unsigned::value, + R>::type + saturate_cast(T value) ETL_NOEXCEPT + { + // R's max is positive, so we can safely represent it as T (unsigned) when + // sizeof(T) >= sizeof(R). When sizeof(T) < sizeof(R), all values of T fit. + typedef typename etl::make_unsigned::type unsigned_r; + + if (value > static_cast(static_cast(etl::numeric_limits::max()))) + { + return etl::numeric_limits::max(); + } + return static_cast(value); + } } // namespace etl #endif diff --git a/include/etl/optional.h b/include/etl/optional.h index fc0db4f7..244aa3cb 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -127,7 +127,7 @@ namespace etl /// Constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl() + optional_impl() ETL_NOEXCEPT : storage() { } @@ -136,17 +136,18 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(etl::nullopt_t) + optional_impl(etl::nullopt_t) ETL_NOEXCEPT : storage() { } #include "private/diagnostic_uninitialized_push.h" + //*************************************************************************** /// Copy constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(const optional_impl& other) + optional_impl(const optional_impl& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { if (other.has_value()) { @@ -160,7 +161,7 @@ namespace etl /// Move constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(optional_impl&& other) + optional_impl(optional_impl&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { if (other.has_value()) { @@ -177,7 +178,7 @@ namespace etl typename etl::enable_if< etl::is_constructible::value && !etl::is_same::type, etl::in_place_t>::value && !etl::is_same::type, optional_impl>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional_impl(U&& value_) + ETL_CONSTEXPR20_STL optional_impl(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(value_)); } @@ -186,7 +187,7 @@ namespace etl /// Constructor from variadic args. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, TArgs&&... args) + ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, TArgs&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(args)...); } @@ -197,6 +198,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { storage.construct(ilist, etl::forward(args)...); } @@ -207,7 +209,7 @@ namespace etl /// Destructor. //*************************************************************************** ETL_CONSTEXPR20_STL - ~optional_impl() + ~optional_impl() ETL_NOEXCEPT { storage.destroy(); } @@ -216,7 +218,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(etl::nullopt_t) + optional_impl& operator=(etl::nullopt_t) ETL_NOEXCEPT { if (has_value()) { @@ -230,7 +232,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(const optional_impl& other) + optional_impl& operator=(const optional_impl& other) ETL_NOEXCEPT_IF(etl::is_nothrow_copy_constructible::value) { if (this != &other) { @@ -252,7 +254,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator=(optional_impl&& other) + optional_impl& operator=(optional_impl&& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { if (this != &other) { @@ -277,7 +279,7 @@ namespace etl template ::value && !etl::is_same::type, optional_impl>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) + ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(value_)); @@ -477,18 +479,18 @@ namespace etl /// Swaps this value with another. //*************************************************************************** ETL_CONSTEXPR20_STL - void swap(optional_impl& other) + void swap(optional_impl& other) ETL_NOEXCEPT_IF(etl::is_nothrow_move_constructible::value) { - optional_impl temp(*this); - *this = other; - other = temp; + optional_impl temp(ETL_MOVE(*this)); + *this = ETL_MOVE(other); + other = ETL_MOVE(temp); } //*************************************************************************** /// Reset back to invalid. //*************************************************************************** ETL_CONSTEXPR20_STL - void reset() + void reset() ETL_NOEXCEPT { storage.destroy(); } @@ -497,7 +499,7 @@ namespace etl /// //************************************************************************* ETL_CONSTEXPR20_STL - T& emplace(const optional_impl& other) + T& emplace(const optional_impl& other) { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid)); @@ -518,7 +520,7 @@ namespace etl template < typename U, typename... URest, typename etl::enable_if< !etl::is_base_of< optional_impl, typename etl::remove_cv< typename etl::remove_reference::type>::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL T& emplace(U&& first, URest&&... rest) + ETL_CONSTEXPR20_STL T& emplace(U&& first, URest&&... rest) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { storage.construct(etl::forward(first), etl::forward(rest)...); @@ -529,7 +531,7 @@ namespace etl /// Emplaces with zero arguments, i.e. default construct emplace. //************************************************************************* ETL_CONSTEXPR20_STL - T& emplace() + T& emplace() ETL_NOEXCEPT_IF(etl::is_nothrow_default_constructible::value) { storage.construct(); @@ -735,7 +737,7 @@ namespace etl //*************************************************************************** /// Constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl() + ETL_CONSTEXPR14 optional_impl() ETL_NOEXCEPT : storage() { } @@ -743,16 +745,17 @@ namespace etl //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(etl::nullopt_t) + ETL_CONSTEXPR14 optional_impl(etl::nullopt_t) ETL_NOEXCEPT : storage() { } #include "private/diagnostic_uninitialized_push.h" + //*************************************************************************** /// Copy constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(const optional_impl& other) + ETL_CONSTEXPR14 optional_impl(const optional_impl& other) ETL_NOEXCEPT { if (other.has_value()) { @@ -765,7 +768,7 @@ namespace etl //*************************************************************************** /// Move constructor. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(optional_impl&& other) + ETL_CONSTEXPR14 optional_impl(optional_impl&& other) ETL_NOEXCEPT { if (other.has_value()) { @@ -776,7 +779,7 @@ namespace etl //*************************************************************************** /// Constructor from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(const T& value_) + ETL_CONSTEXPR14 optional_impl(const T& value_) ETL_NOEXCEPT { storage.construct(value_); } @@ -784,7 +787,7 @@ namespace etl //*************************************************************************** /// Constructor from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl(T&& value_) + ETL_CONSTEXPR14 optional_impl(T&& value_) ETL_NOEXCEPT { storage.construct(etl::move(value_)); } @@ -793,7 +796,7 @@ namespace etl /// Constructor from variadic args. //*************************************************************************** template - ETL_CONSTEXPR14 optional_impl(etl::in_place_t, TArgs&&... args) + ETL_CONSTEXPR14 optional_impl(etl::in_place_t, TArgs&&... args) ETL_NOEXCEPT { storage.construct(etl::forward(args)...); } @@ -803,7 +806,7 @@ namespace etl /// Construct from initializer_list and arguments. //******************************************* template - ETL_CONSTEXPR14 optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_CONSTEXPR14 optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) ETL_NOEXCEPT { storage.construct(ilist, etl::forward(args)...); } @@ -813,7 +816,7 @@ namespace etl //*************************************************************************** /// Assignment operator from nullopt. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(etl::nullopt_t) + ETL_CONSTEXPR14 optional_impl& operator=(etl::nullopt_t) ETL_NOEXCEPT { if (has_value()) { @@ -826,7 +829,7 @@ namespace etl //*************************************************************************** /// Assignment operator from optional_impl. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(const optional_impl& other) + ETL_CONSTEXPR14 optional_impl& operator=(const optional_impl& other) ETL_NOEXCEPT { if (this != &other) { @@ -847,7 +850,7 @@ namespace etl //*************************************************************************** /// Assignment operator from optional_impl. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(optional_impl&& other) + ETL_CONSTEXPR14 optional_impl& operator=(optional_impl&& other) ETL_NOEXCEPT { if (this != &other) { @@ -868,7 +871,7 @@ namespace etl //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(const T& value_) + ETL_CONSTEXPR14 optional_impl& operator=(const T& value_) ETL_NOEXCEPT { storage.construct(value_); @@ -879,7 +882,7 @@ namespace etl //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR14 optional_impl& operator=(T&& value_) + ETL_CONSTEXPR14 optional_impl& operator=(T&& value_) ETL_NOEXCEPT { storage.construct(etl::move(value_)); @@ -1058,7 +1061,7 @@ namespace etl //*************************************************************************** /// Swaps this value with another. //*************************************************************************** - ETL_CONSTEXPR14 void swap(optional_impl& other) + ETL_CONSTEXPR14 void swap(optional_impl& other) ETL_NOEXCEPT { optional_impl temp(*this); *this = other; @@ -1068,7 +1071,7 @@ namespace etl //*************************************************************************** /// Reset back to invalid. //*************************************************************************** - ETL_CONSTEXPR14 void reset() + ETL_CONSTEXPR14 void reset() ETL_NOEXCEPT { storage.destroy(); } @@ -1077,7 +1080,7 @@ namespace etl /// //************************************************************************* ETL_CONSTEXPR20_STL - T& emplace(const optional_impl& other) + T& emplace(const optional_impl& other) { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid)); @@ -1094,7 +1097,7 @@ namespace etl ///\param args The arguments to construct with. //************************************************************************* template - ETL_CONSTEXPR14 T& emplace(TArgs&&... args) + ETL_CONSTEXPR14 T& emplace(TArgs&&... args) ETL_NOEXCEPT { storage.construct(etl::forward(args)...); @@ -1286,7 +1289,7 @@ namespace etl /// Constructor. //*************************************************************************** template - ETL_CONSTEXPR14 optional() + ETL_CONSTEXPR14 optional() ETL_NOEXCEPT : impl_t() { } @@ -1295,12 +1298,12 @@ namespace etl /// Constructor. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional() + ETL_CONSTEXPR20_STL optional() ETL_NOEXCEPT : impl_t() { } #else - optional() + optional() ETL_NOEXCEPT : impl_t() { } @@ -1311,7 +1314,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** template - ETL_CONSTEXPR14 optional(etl::nullopt_t) + ETL_CONSTEXPR14 optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } @@ -1320,7 +1323,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional(etl::nullopt_t) + ETL_CONSTEXPR20_STL optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } @@ -1328,31 +1331,15 @@ namespace etl //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** - optional(etl::nullopt_t) + optional(etl::nullopt_t) ETL_NOEXCEPT : impl_t(etl::nullopt) { } #endif #include "private/diagnostic_uninitialized_push.h" -#if ETL_USING_CPP11 - //*************************************************************************** - /// Copy constructor. - //*************************************************************************** - template - ETL_CONSTEXPR14 optional(const optional& other) - : impl_t(other) - { - } - //*************************************************************************** - /// Copy constructor. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL optional(const optional& other) - : impl_t(other) - { - } +#if ETL_USING_CPP11 #else //*************************************************************************** /// Copy constructor. @@ -1364,26 +1351,6 @@ namespace etl #endif #include "private/diagnostic_pop.h" -#if ETL_USING_CPP11 - //*************************************************************************** - /// Move constructor. - //*************************************************************************** - template - ETL_CONSTEXPR14 optional(optional&& other) - : impl_t(other) - { - } - - //*************************************************************************** - /// Move constructor. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL optional(optional&& other) - : impl_t(other) - { - } -#endif - #if ETL_USING_CPP11 //*************************************************************************** /// Converting constructor from value type. @@ -1396,7 +1363,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR14 optional(U&& value_) + ETL_CONSTEXPR14 optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::forward(value_)) { } @@ -1410,7 +1377,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && !etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional(U&& value_) + ETL_CONSTEXPR20_STL optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::forward(value_)) { } @@ -1429,7 +1396,7 @@ namespace etl /// Emplace construct from arguments. //*************************************************************************** template - ETL_CONSTEXPR14 explicit optional(etl::in_place_t, Args&&... args) + ETL_CONSTEXPR14 explicit optional(etl::in_place_t, Args&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::in_place_t{}, etl::forward(args)...) { } @@ -1438,7 +1405,7 @@ namespace etl /// Emplace construct from arguments. //*************************************************************************** template - ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, Args&&... args) + ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, Args&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) : impl_t(etl::in_place_t{}, etl::forward(args)...) { } @@ -1449,6 +1416,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR14 explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } @@ -1458,6 +1426,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } @@ -1469,7 +1438,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** template - ETL_CONSTEXPR14 optional& operator=(etl::nullopt_t) + ETL_CONSTEXPR14 optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1480,7 +1449,7 @@ namespace etl /// Assignment operator from nullopt. //*************************************************************************** template - ETL_CONSTEXPR20_STL optional& operator=(etl::nullopt_t) + ETL_CONSTEXPR20_STL optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1490,7 +1459,7 @@ namespace etl //*************************************************************************** /// Assignment operator from nullopt. //*************************************************************************** - optional& operator=(etl::nullopt_t) + optional& operator=(etl::nullopt_t) ETL_NOEXCEPT { impl_t::operator=(etl::nullopt); @@ -1499,27 +1468,6 @@ namespace etl #endif #if ETL_USING_CPP11 - //*************************************************************************** - /// Assignment operator from optional. - //*************************************************************************** - template - ETL_CONSTEXPR14 optional& operator=(const optional& other) - { - impl_t::operator=(other); - - return *this; - } - - //*************************************************************************** - /// Assignment operator from optional. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL optional& operator=(const optional& other) - { - impl_t::operator=(other); - - return *this; - } #else //*************************************************************************** /// Assignment operator from optional. @@ -1532,30 +1480,6 @@ namespace etl } #endif -#if ETL_USING_CPP11 - //*************************************************************************** - /// Move assignment operator from optional. - //*************************************************************************** - template - ETL_CONSTEXPR14 optional& operator=(optional&& other) - { - impl_t::operator=(etl::move(other)); - - return *this; - } - - //*************************************************************************** - /// Move assignment operator from optional. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL optional& operator=(optional&& other) - { - impl_t::operator=(etl::move(other)); - - return *this; - } -#endif - #if ETL_USING_CPP11 //*************************************************************************** /// Converting assignment operator from value type. @@ -1565,7 +1489,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR14 optional& operator=(U&& value_) + ETL_CONSTEXPR14 optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { impl_t::operator=(etl::forward(value_)); @@ -1580,7 +1504,7 @@ namespace etl && !etl::is_same::type, etl::nullopt_t>::value && !etl::is_pod::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL optional& operator=(U&& value_) + ETL_CONSTEXPR20_STL optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { impl_t::operator=(etl::forward(value_)); @@ -2223,6 +2147,71 @@ namespace etl #include "private/diagnostic_pop.h" +#if ETL_CPP11_SUPPORTED + //*************************************************************************** + /// Creates an optional object from `value`. + //*************************************************************************** + template + ETL_CONSTEXPR14 etl::optional::type> make_optional(T&& value) // + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::type, T&&>::value)) + { + return etl::optional::type>(etl::forward(value)); + } + template + ETL_CONSTEXPR20_STL etl::optional::type> make_optional(T&& value) // + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::type, T&&>::value)) + { + return etl::optional::type>(etl::forward(value)); + } + + //*************************************************************************** + /// Creates an optional object constructed in-place from `args...` . + /// Equivalent to `return etl::optional(etl::in_place, etl::forward(args)...);`. + /// This overload participates in overload resolution only if + /// `etl::is_constructible_v` is true. + //*************************************************************************** + template ::value, int>::type = 0, // + typename U = T, ETL_OPTIONAL_ENABLE_CPP14> + ETL_CONSTEXPR14 etl::optional make_optional(Args&&... args) // + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) + { + return etl::optional(etl::in_place_t{}, etl::forward(args)...); + } + template ::value, int>::type = 0, // + typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL> + ETL_CONSTEXPR20_STL etl::optional make_optional(Args&&... args) // + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) + { + return etl::optional(etl::in_place_t{}, etl::forward(args)...); + } + + #if ETL_HAS_INITIALIZER_LIST + //*************************************************************************** + /// Creates an optional object constructed in-place from `ilist` and `args...`. + /// Equivalent to `return etl::optional(std::in_place, ilist, std::forward(args)...);`. + /// This overload participates in overload resolution only if + /// `etl::is_constructible_v&, Args...>` is true. + //*************************************************************************** + template &, Args...>::value, int>::type = 0, // + typename U = T, ETL_OPTIONAL_ENABLE_CPP14> + ETL_CONSTEXPR14 etl::optional make_optional(std::initializer_list ilist, Args&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, Args...>::value)) + { + return etl::optional(etl::in_place_t{}, ilist, etl::forward(args)...); + } + template &, Args...>::value, int>::type = 0, // + typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL> + ETL_CONSTEXPR20_STL etl::optional make_optional(std::initializer_list ilist, Args&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, Args...>::value)) + { + return etl::optional(etl::in_place_t{}, ilist, etl::forward(args)...); + } + #endif +#else //*************************************************************************** /// Make an optional. //*************************************************************************** @@ -2231,6 +2220,7 @@ namespace etl { return etl::optional::type>(value); } +#endif //*************************************************************************** /// Template deduction guides. @@ -2239,16 +2229,17 @@ namespace etl template optional(T) -> optional; #endif -} // namespace etl -//************************************************************************* -/// Swaps the values. -//************************************************************************* -template -ETL_CONSTEXPR20_STL void swap(etl::optional& lhs, etl::optional& rhs) -{ - lhs.swap(rhs); -} + //************************************************************************* + /// Swaps the values. + //************************************************************************* + template + ETL_CONSTEXPR20_STL void swap(etl::optional& lhs, etl::optional& rhs) ETL_NOEXCEPT_FROM(lhs.swap(rhs)) + { + lhs.swap(rhs); + } + +} // namespace etl #undef ETL_OPTIONAL_ENABLE_CPP14 #undef ETL_OPTIONAL_ENABLE_CPP20_STL diff --git a/include/etl/parameter_pack.h b/include/etl/parameter_pack.h index 5dd21717..bed2949c 100644 --- a/include/etl/parameter_pack.h +++ b/include/etl/parameter_pack.h @@ -32,13 +32,9 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" -#include +#include -#if ETL_CPP11_NOT_SUPPORTED - #if !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW - #endif -#else +#if ETL_CPP11_SUPPORTED namespace etl { //*************************************************************************** diff --git a/include/etl/platform.h b/include/etl/platform.h index 43e33e6f..a7ca8305 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -499,6 +499,18 @@ SOFTWARE. #define ETL_ASSUME ETL_DO_NOTHING #endif +//************************************* +// C++26 +#if defined(__has_cpp_attribute) + #if __has_cpp_attribute(indeterminate) + #define ETL_INDETERMINATE [[indeterminate]] + #else + #define ETL_INDETERMINATE + #endif +#else + #define ETL_INDETERMINATE +#endif + //************************************* // Determine if the ETL can use char8_t type. #if ETL_NO_SMALL_CHAR_SUPPORT @@ -660,6 +672,7 @@ namespace etl static ETL_CONSTANT bool using_cpp17 = (ETL_USING_CPP17 == 1); static ETL_CONSTANT bool using_cpp20 = (ETL_USING_CPP20 == 1); static ETL_CONSTANT bool using_cpp23 = (ETL_USING_CPP23 == 1); + static ETL_CONSTANT bool using_cpp26 = (ETL_USING_CPP26 == 1); static ETL_CONSTANT bool using_gcc_compiler = (ETL_USING_GCC_COMPILER == 1); static ETL_CONSTANT bool using_microsoft_compiler = (ETL_USING_MICROSOFT_COMPILER == 1); static ETL_CONSTANT bool using_arm5_compiler = (ETL_USING_ARM5_COMPILER == 1); @@ -707,6 +720,9 @@ namespace etl static ETL_CONSTANT bool has_chrono_literals_microseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_chrono_literals_nanoseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_std_byteswap = (ETL_HAS_STD_BYTESWAP == 1); + static ETL_CONSTANT bool has_std_is_virtual_base_of = (ETL_HAS_STD_IS_VIRTUAL_BASE_OF == 1); + static ETL_CONSTANT bool has_std_trivially_relocatable = (ETL_HAS_STD_TRIVIALLY_RELOCATABLE == 1); + static ETL_CONSTANT bool has_std_atomic_min_max = (ETL_HAS_STD_ATOMIC_MIN_MAX == 1); static ETL_CONSTANT bool has_noexcept_function_type = (ETL_HAS_NOEXCEPT_FUNCTION_TYPE == 1); // Is... diff --git a/include/etl/priority_queue.h b/include/etl/priority_queue.h index e72d4908..2623fc07 100644 --- a/include/etl/priority_queue.h +++ b/include/etl/priority_queue.h @@ -439,7 +439,9 @@ namespace etl //************************************************************************* void clone(const ipriority_queue& other) { +#include "etl/private/diagnostic_uninitialized_push.h" assign(other.container.cbegin(), other.container.cend()); +#include "etl/private/diagnostic_pop.h" } #if ETL_USING_CPP11 diff --git a/include/etl/private/bitset_legacy.h b/include/etl/private/bitset_legacy.h index 7fa70ce3..8846e034 100644 --- a/include/etl/private/bitset_legacy.h +++ b/include/etl/private/bitset_legacy.h @@ -1523,16 +1523,16 @@ namespace etl { return !(lhs == rhs); } -} // namespace etl -//************************************************************************* -/// swap -//************************************************************************* -template -void swap(etl::bitset& lhs, etl::bitset& rhs) -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + void swap(etl::bitset& lhs, etl::bitset& rhs) + { + lhs.swap(rhs); + } +} // namespace etl #include "minmax_pop.h" diff --git a/include/etl/private/bitset_new.h b/include/etl/private/bitset_new.h index 89d4a0a8..e33f3b10 100644 --- a/include/etl/private/bitset_new.h +++ b/include/etl/private/bitset_new.h @@ -1078,7 +1078,7 @@ namespace etl /// Extract an value from multiple elements. //************************************************************************* template - static ETL_CONSTEXPR14 typename etl::make_unsigned::type extract_from_multiple_elements(const element_type* pbuffer, int element_index, + static ETL_CONSTEXPR14 typename etl::make_unsigned::type extract_from_multiple_elements(const element_type* pbuffer, size_t element_index, size_t active_bits_in_msb, size_t length) ETL_NOEXCEPT { typedef typename etl::make_unsigned::type unsigned_t; @@ -1133,8 +1133,8 @@ namespace etl unsigned_t value(0); - const int Msb_Element_Index = (position + length - 1) >> etl::log2::value; - const int Lsb_Element_Index = position >> etl::log2::value; + const size_t Msb_Element_Index = (position + length - 1) >> etl::log2::value; + const size_t Lsb_Element_Index = position >> etl::log2::value; // Is the value contained within one element? if (Msb_Element_Index == Lsb_Element_Index) @@ -1150,7 +1150,7 @@ namespace etl size_t active_bits_in_msb = (position + length) - (static_cast(Msb_Element_Index) * Bits_Per_Element); // Start with index of the element containing the msb. - int element_index = Msb_Element_Index; + size_t element_index = Msb_Element_Index; value = extract_from_multiple_elements(pbuffer, element_index, active_bits_in_msb, length); } @@ -1169,7 +1169,7 @@ namespace etl { typedef typename etl::make_unsigned::type unsigned_t; - const int Element_Index = (Position + Length - 1) >> etl::log2::value; + const size_t Element_Index = (Position + Length - 1) >> etl::log2::value; const unsigned_t Mask = etl::lsb_mask::value; const unsigned_t Shift = Position % Bits_Per_Element; @@ -1186,7 +1186,7 @@ namespace etl extract_from_buffer(const_pointer pbuffer) { // Start with index of the element containing the msb. - const int Msb_Element_Index = (Position + Length - 1) >> etl::log2::value; + const size_t Msb_Element_Index = (Position + Length - 1) >> etl::log2::value; // Get the number of active bits in the first element const size_t Active_Bits_In_Msb = ((Position + Length - 1) % Bits_Per_Element) + 1; @@ -2519,32 +2519,30 @@ namespace etl temp ^= rhs; return temp; } -} // namespace etl -//*************************************************************************** -/// operator != -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } -//************************************************************************* -/// swap -//************************************************************************* -template -ETL_CONSTEXPR14 void swap(etl::bitset& lhs, etl::bitset& rhs) ETL_NOEXCEPT -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + ETL_CONSTEXPR14 void swap(etl::bitset& lhs, etl::bitset& rhs) ETL_NOEXCEPT + { + lhs.swap(rhs); + } + + //*************************************************************************** + /// bitset_ext + //*************************************************************************** -//*************************************************************************** -/// bitset_ext -//*************************************************************************** -namespace etl -{ //*************************************************************************** template class bitset_ext; @@ -3396,29 +3394,26 @@ namespace etl // Pointer to the storage for the bitset. element_type* pbuffer; }; -} // namespace etl -//*************************************************************************** -/// operator != -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } -//************************************************************************* -/// swap -//************************************************************************* -template -ETL_CONSTEXPR14 void swap(etl::bitset_ext& lhs, etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - lhs.swap(rhs); -} + //************************************************************************* + /// swap + //************************************************************************* + template + ETL_CONSTEXPR14 void swap(etl::bitset_ext& lhs, etl::bitset_ext& rhs) ETL_NOEXCEPT + { + lhs.swap(rhs); + } -namespace etl -{ namespace private_bitset { //************************************************************************* @@ -3464,216 +3459,217 @@ namespace etl return true; } } // namespace private_bitset + + //*************************************************************************** + /// operator == + /// bitset + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset_ext + /// Different element types + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset compared with bitset_ext, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + const char Storage_Model = etl::bitset::Storage_Model; + const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; + + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + typedef etl::bitset_impl implementation; + + return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); + } + + //*************************************************************************** + /// operator != + /// bitset compared with bitset_ext, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext compared with bitset, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + const char Storage_Model = etl::bitset::Storage_Model; + const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; + + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + typedef etl::bitset_impl implementation; + + return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); + } + + //*************************************************************************** + /// operator != + /// bitset_ext compared with bitset, same element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset compared with bitset_ext, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset::const_span_type lhs_span = lhs.span(); + typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset compared with bitset_ext, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// operator == + /// bitset_ext compared with bitset, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + // Get a span of each type. + typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); + typename etl::bitset::const_span_type rhs_span = rhs.span(); + + // Put the bitset with the largest element type as the first argument. + if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) + { + return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); + } + else + { + return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); + } + } + + //*************************************************************************** + /// operator != + /// bitset_ext compared with bitset, different element types. + ///\ingroup bitset + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type + operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT + { + return !(lhs == rhs); + } + } // namespace etl -//*************************************************************************** -/// operator == -/// bitset -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset_ext -/// Different element types -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset_ext& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset compared with bitset_ext, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - const char Storage_Model = etl::bitset::Storage_Model; - const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; - - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - typedef etl::bitset_impl implementation; - - return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); -} - -//*************************************************************************** -/// operator != -/// bitset compared with bitset_ext, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext compared with bitset, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - const char Storage_Model = etl::bitset::Storage_Model; - const size_t Number_Of_Elements = etl::bitset::Number_Of_Elements; - - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - typedef etl::bitset_impl implementation; - - return implementation::operator_equality(lhs_span.begin(), rhs_span.begin(), Number_Of_Elements); -} - -//*************************************************************************** -/// operator != -/// bitset_ext compared with bitset, same element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 bool operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset compared with bitset_ext, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset::const_span_type lhs_span = lhs.span(); - typename etl::bitset_ext::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset compared with bitset_ext, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset& lhs, const etl::bitset_ext& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - -//*************************************************************************** -/// operator == -/// bitset_ext compared with bitset, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator==(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - // Get a span of each type. - typename etl::bitset_ext::const_span_type lhs_span = lhs.span(); - typename etl::bitset::const_span_type rhs_span = rhs.span(); - - // Put the bitset with the largest element type as the first argument. - if ETL_IF_CONSTEXPR (sizeof(TLhsElement) > sizeof(TRhsElement)) - { - return etl::private_bitset::compare_bitset_spans(lhs_span, rhs_span); - } - else - { - return etl::private_bitset::compare_bitset_spans(rhs_span, lhs_span); - } -} - -//*************************************************************************** -/// operator != -/// bitset_ext compared with bitset, different element types. -///\ingroup bitset -//*************************************************************************** -template -ETL_CONSTEXPR14 typename etl::enable_if::value, bool>::type - operator!=(const etl::bitset_ext& lhs, const etl::bitset& rhs) ETL_NOEXCEPT -{ - return !(lhs == rhs); -} - #include "minmax_pop.h" #endif diff --git a/include/etl/private/chrono/year_month_weekday.h b/include/etl/private/chrono/year_month_weekday.h index c557138a..8d7f4d52 100644 --- a/include/etl/private/chrono/year_month_weekday.h +++ b/include/etl/private/chrono/year_month_weekday.h @@ -174,11 +174,11 @@ namespace etl unsigned int target_wd = ymwd.weekday().c_encoding(); unsigned int target_index = ymwd.index(); - etl::chrono::weekday first_weekday(static_cast(sd.time_since_epoch().count())); + etl::chrono::weekday first_weekday(sd); unsigned int first_wd = first_weekday.c_encoding(); unsigned int offset = (target_wd - first_wd + 7U) % 7U; - unsigned int day_of_month = offset + (target_index - 1U) * 7U; + unsigned int day_of_month = 1U + offset + (target_index - 1U) * 7U; etl::chrono::year_month_day result(year(), month(), etl::chrono::day(day_of_month)); @@ -382,7 +382,7 @@ namespace etl { etl::chrono::year_month_day ymd(year(), month(), etl::chrono::day(d)); etl::chrono::sys_days ymd_sys_days = static_cast(ymd); - etl::chrono::weekday wd(static_cast(ymd_sys_days.time_since_epoch().count())); + etl::chrono::weekday wd(ymd_sys_days); if (wd == weekday()) { diff --git a/include/etl/private/delegate_cpp11.h b/include/etl/private/delegate_cpp11.h index 33d993e2..27b443c0 100644 --- a/include/etl/private/delegate_cpp11.h +++ b/include/etl/private/delegate_cpp11.h @@ -172,7 +172,7 @@ namespace etl //************************************************************************* // Construct from a function pointer. //************************************************************************* - delegate(function_ptr fp) ETL_NOEXCEPT + explicit delegate(function_ptr fp) ETL_NOEXCEPT { assign(fp, function_ptr_stub); } @@ -534,7 +534,14 @@ namespace etl //************************************************************************* delegate& operator=(function_ptr fp) ETL_NOEXCEPT { - assign(fp, function_ptr_stub); + if (fp == ETL_NULLPTR) + { + invocation.clear(); + } + else + { + assign(fp, function_ptr_stub); + } return *this; } @@ -559,6 +566,14 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 bool is_valid() const ETL_NOEXCEPT { + // GCC's UBSan instruments function pointer comparisons, which prevents + // constexpr evaluation. Use implicit bool conversion at compile time + // to avoid the instrumented != comparison while still checking validity. + if (etl::is_constant_evaluated()) + { + return static_cast(invocation.stub); + } + return invocation.stub != ETL_NULLPTR; } diff --git a/include/etl/private/diagnostic_sign_conversion_push.h b/include/etl/private/diagnostic_sign_conversion_push.h new file mode 100644 index 00000000..50c0532e --- /dev/null +++ b/include/etl/private/diagnostic_sign_conversion_push.h @@ -0,0 +1,44 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/* + * The header include guard has been intentionally omitted. + * This file is intended to evaluated multiple times by design. + */ + +#if defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if defined(__clang__) || defined(__llvm__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-conversion" +#endif diff --git a/include/etl/private/variant_variadic.h b/include/etl/private/variant_variadic.h index 5598f896..3a95502a 100644 --- a/include/etl/private/variant_variadic.h +++ b/include/etl/private/variant_variadic.h @@ -486,7 +486,7 @@ namespace etl /// alternative (index() is zero). //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant() + ETL_CONSTEXPR14 variant() ETL_NOEXCEPT_IF(etl::is_nothrow_default_constructible >::value) { using type = type_from_index<0U>; @@ -501,7 +501,7 @@ namespace etl //*************************************************************************** #include "diagnostic_uninitialized_push.h" template , variant>::value, int> = 0> - ETL_CONSTEXPR14 variant(T&& value) + ETL_CONSTEXPR14 variant(T&& value) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, T&&>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -518,6 +518,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -534,6 +535,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) : type_id(Index) { using type = type_from_index; @@ -552,6 +554,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, std::initializer_list init, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) : operation(operation_type< etl::remove_cvref_t, etl::is_copy_constructible >::value, etl::is_move_constructible >::value>::do_operation) , type_id(index_of_type::value) @@ -568,6 +571,7 @@ namespace etl #include "diagnostic_uninitialized_push.h" template ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t, std::initializer_list init, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) : type_id(Index) { using type = type_from_index; @@ -585,7 +589,7 @@ namespace etl ///\param other The other variant object to copy. //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(const variant& other) + ETL_CONSTEXPR14 variant(const variant& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) : operation(other.operation) , type_id(other.type_id) { @@ -605,7 +609,7 @@ namespace etl ///\param other The other variant object to copy. //*************************************************************************** #include "diagnostic_uninitialized_push.h" - ETL_CONSTEXPR14 variant(variant&& other) + ETL_CONSTEXPR14 variant(variant&& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) : operation(other.operation) , type_id(other.type_id) { @@ -623,7 +627,7 @@ namespace etl //*************************************************************************** /// Destructor. //*************************************************************************** - ~variant() + ~variant() ETL_NOEXCEPT { if (!valueless_by_exception()) { @@ -638,7 +642,7 @@ namespace etl /// Emplace by type with variadic constructor parameters. //*************************************************************************** template - T& emplace(TArgs&&... args) + T& emplace(TArgs&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { static_assert(etl::is_one_of::value, "Unsupported type"); @@ -664,6 +668,7 @@ namespace etl //*************************************************************************** template T& emplace(std::initializer_list il, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) { static_assert(etl::is_one_of::value, "Unsupported type"); @@ -689,6 +694,7 @@ namespace etl //*************************************************************************** template typename etl::variant_alternative_t >& emplace(TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) { static_assert(Index < sizeof...(TTypes), "Index out of range"); @@ -714,6 +720,7 @@ namespace etl //*************************************************************************** template typename etl::variant_alternative_t >& emplace(std::initializer_list il, TArgs&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, std::initializer_list, TArgs...>::value)) { static_assert(Index < sizeof...(TTypes), "Index out of range"); @@ -739,7 +746,7 @@ namespace etl ///\param value The value to assign. //*************************************************************************** template , variant>::value, int> = 0> - variant& operator=(T&& value) + variant& operator=(T&& value) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, T&&>::value)) { using type = etl::remove_cvref_t; @@ -762,7 +769,7 @@ namespace etl /// Assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(const variant& other) + variant& operator=(const variant& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) { if (this != &other) { @@ -791,7 +798,7 @@ namespace etl /// Assignment operator for variant type. ///\param other The variant to assign. //*************************************************************************** - variant& operator=(variant&& other) + variant& operator=(variant&& other) ETL_NOEXCEPT_IF((etl::conjunction...>::value)) { if (this != &other) { diff --git a/include/etl/profiles/cpp20.h b/include/etl/profiles/cpp20.h new file mode 100644 index 00000000..ea1fa98a --- /dev/null +++ b/include/etl/profiles/cpp20.h @@ -0,0 +1,49 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP20_INCLUDED +#define ETL_CPP20_INCLUDED + +//***************************************************************************** +// Generic C++20 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp20_no_stl.h b/include/etl/profiles/cpp20_no_stl.h new file mode 100644 index 00000000..c997cdc8 --- /dev/null +++ b/include/etl/profiles/cpp20_no_stl.h @@ -0,0 +1,50 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP20_NO_STL_INCLUDED +#define ETL_CPP20_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++20 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/cpp23.h b/include/etl/profiles/cpp23.h new file mode 100644 index 00000000..21fc36f0 --- /dev/null +++ b/include/etl/profiles/cpp23.h @@ -0,0 +1,50 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP23_INCLUDED +#define ETL_CPP23_INCLUDED + +//***************************************************************************** +// Generic C++23 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp23_no_stl.h b/include/etl/profiles/cpp23_no_stl.h new file mode 100644 index 00000000..d06a8545 --- /dev/null +++ b/include/etl/profiles/cpp23_no_stl.h @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP23_NO_STL_INCLUDED +#define ETL_CPP23_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++23 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/cpp26.h b/include/etl/profiles/cpp26.h new file mode 100644 index 00000000..8ba60ee3 --- /dev/null +++ b/include/etl/profiles/cpp26.h @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP26_INCLUDED +#define ETL_CPP26_INCLUDED + +//***************************************************************************** +// Generic C++26 +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_CPP26_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 + +#endif diff --git a/include/etl/profiles/cpp26_no_stl.h b/include/etl/profiles/cpp26_no_stl.h new file mode 100644 index 00000000..76dcf143 --- /dev/null +++ b/include/etl/profiles/cpp26_no_stl.h @@ -0,0 +1,52 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CPP26_NO_STL_INCLUDED +#define ETL_CPP26_NO_STL_INCLUDED + +//***************************************************************************** +// Generic C++26 without STL support +//***************************************************************************** + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_CPP17_SUPPORTED 1 +#define ETL_CPP20_SUPPORTED 1 +#define ETL_CPP23_SUPPORTED 1 +#define ETL_CPP26_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_NO_STL + +#endif diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index 4a303fc0..da15062a 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -41,6 +41,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE 1 #endif + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE 1 + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE 1 + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1 #endif @@ -60,7 +68,10 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED) #define ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED 1 #endif +#endif +#if defined(ETL_USE_BUILTIN_MEM_FUNCTIONS) // Set all of them to be true if not + // already defined #if !defined(ETL_USING_BUILTIN_MEMCPY) #define ETL_USING_BUILTIN_MEMCPY 1 #endif @@ -93,6 +104,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE __has_builtin(__is_constructible) #endif + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE __has_builtin(__is_nothrow_constructible) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE __has_builtin(__is_nothrow_assignable) + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE (__has_builtin(__has_trivial_constructor) || __has_builtin(__is_trivially_constructible)) #endif @@ -132,6 +151,20 @@ SOFTWARE. #if !defined(ETL_USING_BUILTIN_MEMCHR) #define ETL_USING_BUILTIN_MEMCHR __has_builtin(__builtin_memchr) #endif + + #if !defined(ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF) + #define ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF __has_builtin(__is_virtual_base_of) + #endif + + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE __has_builtin(__is_trivially_relocatable) + #endif + + // __builtin_is_cpp_trivially_relocatable replaces __is_trivially_relocatable by an + // effort of standardization for newer C++ standards + #if !defined(ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE __has_builtin(__builtin_is_cpp_trivially_relocatable) + #endif #endif // The default. Set to 0, if not already set. @@ -143,6 +176,14 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_CONSTRUCTIBLE 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE) + #define ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE 0 +#endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0 #endif @@ -183,24 +224,41 @@ SOFTWARE. #define ETL_USING_BUILTIN_MEMCHR 0 #endif +#if !defined(ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF) + #define ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF 0 +#endif + +#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE 0 +#endif + +#if !defined(ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE) + #define ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE 0 +#endif + namespace etl { namespace traits { // Documentation: https://www.etlcpp.com/etl_traits.html - static ETL_CONSTANT bool using_builtin_is_assignable = (ETL_USING_BUILTIN_IS_ASSIGNABLE == 1); - static ETL_CONSTANT bool using_builtin_is_constructible = (ETL_USING_BUILTIN_IS_CONSTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1); - static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1); - static ETL_CONSTANT bool using_builtin_underlying_type = (ETL_USING_BUILTIN_UNDERLYING_TYPE == 1); - static ETL_CONSTANT bool using_builtin_is_constant_evaluated = (ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED == 1); - static ETL_CONSTANT bool using_builtin_memcpy = (ETL_USING_BUILTIN_MEMCPY == 1); - static ETL_CONSTANT bool using_builtin_memmove = (ETL_USING_BUILTIN_MEMMOVE == 1); - static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1); - static ETL_CONSTANT bool using_builtin_memcmp = (ETL_USING_BUILTIN_MEMCMP == 1); - static ETL_CONSTANT bool using_builtin_memchr = (ETL_USING_BUILTIN_MEMCHR == 1); + static ETL_CONSTANT bool using_builtin_is_assignable = (ETL_USING_BUILTIN_IS_ASSIGNABLE == 1); + static ETL_CONSTANT bool using_builtin_is_constructible = (ETL_USING_BUILTIN_IS_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_constructible = (ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_nothrow_assignable = (ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_constructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_destructible = (ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE == 1); + static ETL_CONSTANT bool using_builtin_is_trivially_copyable = (ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE == 1); + static ETL_CONSTANT bool using_builtin_underlying_type = (ETL_USING_BUILTIN_UNDERLYING_TYPE == 1); + static ETL_CONSTANT bool using_builtin_is_constant_evaluated = (ETL_USING_BUILTIN_IS_CONSTANT_EVALUATED == 1); + static ETL_CONSTANT bool using_builtin_memcpy = (ETL_USING_BUILTIN_MEMCPY == 1); + static ETL_CONSTANT bool using_builtin_memmove = (ETL_USING_BUILTIN_MEMMOVE == 1); + static ETL_CONSTANT bool using_builtin_memset = (ETL_USING_BUILTIN_MEMSET == 1); + static ETL_CONSTANT bool using_builtin_memcmp = (ETL_USING_BUILTIN_MEMCMP == 1); + static ETL_CONSTANT bool using_builtin_memchr = (ETL_USING_BUILTIN_MEMCHR == 1); + 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); } // namespace traits } // namespace etl diff --git a/include/etl/profiles/determine_compiler_language_support.h b/include/etl/profiles/determine_compiler_language_support.h index 645bd06d..58bda6ef 100644 --- a/include/etl/profiles/determine_compiler_language_support.h +++ b/include/etl/profiles/determine_compiler_language_support.h @@ -35,6 +35,31 @@ SOFTWARE. #include "determine_compiler.h" +// Determine C++26 support +#if !defined(ETL_CPP26_SUPPORTED) + #if defined(__cplusplus) + #if defined(ETL_COMPILER_MICROSOFT) + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #elif defined(ETL_COMPILER_ARM5) + #define ETL_CPP26_SUPPORTED 0 + #elif defined(ETL_COMPILER_GCC) + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #else + #define ETL_CPP26_SUPPORTED (__cplusplus >= 202400L) + #endif + #else + #define ETL_CPP26_SUPPORTED 0 + #endif +#endif + +#if ETL_CPP26_SUPPORTED + #define ETL_CPP11_SUPPORTED 1 + #define ETL_CPP14_SUPPORTED 1 + #define ETL_CPP17_SUPPORTED 1 + #define ETL_CPP20_SUPPORTED 1 + #define ETL_CPP23_SUPPORTED 1 +#endif + // Determine C++23 support #if !defined(ETL_CPP23_SUPPORTED) #if defined(__cplusplus) @@ -162,6 +187,7 @@ SOFTWARE. #define ETL_CPP17_NOT_SUPPORTED (!ETL_CPP17_SUPPORTED) #define ETL_CPP20_NOT_SUPPORTED (!ETL_CPP20_SUPPORTED) #define ETL_CPP23_NOT_SUPPORTED (!ETL_CPP23_SUPPORTED) +#define ETL_CPP26_NOT_SUPPORTED (!ETL_CPP26_SUPPORTED) // 'Using' macros #define ETL_USING_CPP11 (ETL_CPP11_SUPPORTED == 1) @@ -169,12 +195,14 @@ SOFTWARE. #define ETL_USING_CPP17 (ETL_CPP17_SUPPORTED == 1) #define ETL_USING_CPP20 (ETL_CPP20_SUPPORTED == 1) #define ETL_USING_CPP23 (ETL_CPP23_SUPPORTED == 1) +#define ETL_USING_CPP26 (ETL_CPP26_SUPPORTED == 1) #define ETL_NOT_USING_CPP11 (ETL_CPP11_SUPPORTED == 0) #define ETL_NOT_USING_CPP14 (ETL_CPP14_SUPPORTED == 0) #define ETL_NOT_USING_CPP17 (ETL_CPP17_SUPPORTED == 0) #define ETL_NOT_USING_CPP20 (ETL_CPP20_SUPPORTED == 0) #define ETL_NOT_USING_CPP23 (ETL_CPP23_SUPPORTED == 0) +#define ETL_NOT_USING_CPP26 (ETL_CPP26_SUPPORTED == 0) #if !defined(ETL_NO_NULLPTR_SUPPORT) #define ETL_NO_NULLPTR_SUPPORT ETL_NOT_USING_CPP11 @@ -198,7 +226,9 @@ SOFTWARE. // Language standard #if !defined(ETL_LANGUAGE_STANDARD) - #if ETL_USING_CPP23 + #if ETL_USING_CPP26 + #define ETL_LANGUAGE_STANDARD 26 + #elif ETL_USING_CPP23 #define ETL_LANGUAGE_STANDARD 23 #elif ETL_USING_CPP20 #define ETL_LANGUAGE_STANDARD 20 @@ -227,10 +257,37 @@ SOFTWARE. #define ETL_HAS_STD_BYTESWAP 1 #endif #endif + + #if defined(__cpp_lib_is_virtual_base_of) + #if __cpp_lib_is_virtual_base_of != 0 + #define ETL_HAS_STD_IS_VIRTUAL_BASE_OF 1 + #endif + #endif + + #if defined(__cpp_lib_trivially_relocatable) + #if __cpp_lib_trivially_relocatable != 0 + #define ETL_HAS_STD_TRIVIALLY_RELOCATABLE 1 + #endif + #endif + + #if defined(__cpp_lib_atomic_min_max) + #if __cpp_lib_atomic_min_max != 0 + #define ETL_HAS_STD_ATOMIC_MIN_MAX 1 + #endif + #endif #endif #endif #ifndef ETL_HAS_STD_BYTESWAP #define ETL_HAS_STD_BYTESWAP 0 #endif +#ifndef ETL_HAS_STD_IS_VIRTUAL_BASE_OF + #define ETL_HAS_STD_IS_VIRTUAL_BASE_OF 0 +#endif +#ifndef ETL_HAS_STD_TRIVIALLY_RELOCATABLE + #define ETL_HAS_STD_TRIVIALLY_RELOCATABLE 0 +#endif +#ifndef ETL_HAS_STD_ATOMIC_MIN_MAX + #define ETL_HAS_STD_ATOMIC_MIN_MAX 0 +#endif #endif diff --git a/include/etl/quantize.h b/include/etl/quantize.h index b36add55..a789a380 100644 --- a/include/etl/quantize.h +++ b/include/etl/quantize.h @@ -35,8 +35,9 @@ SOFTWARE. #include "functional.h" #include "type_traits.h" +#include + ////#include -#include namespace etl { diff --git a/include/etl/queue.h b/include/etl/queue.h index 0c702507..fef81d77 100644 --- a/include/etl/queue.h +++ b/include/etl/queue.h @@ -44,7 +44,6 @@ SOFTWARE. #include "utility.h" #include -#include //***************************************************************************** ///\defgroup queue queue diff --git a/include/etl/queue_lockable.h b/include/etl/queue_lockable.h index 68934815..92daba21 100644 --- a/include/etl/queue_lockable.h +++ b/include/etl/queue_lockable.h @@ -32,7 +32,6 @@ SOFTWARE. #define ETL_QUEUE_LOCKABLE_INCLUDED #include "platform.h" -#include "function.h" #include "integral_limits.h" #include "memory.h" #include "memory_model.h" @@ -41,7 +40,6 @@ SOFTWARE. #include "utility.h" #include -#include namespace etl { diff --git a/include/etl/queue_spsc_atomic.h b/include/etl/queue_spsc_atomic.h index b14d749b..c162500f 100644 --- a/include/etl/queue_spsc_atomic.h +++ b/include/etl/queue_spsc_atomic.h @@ -41,7 +41,6 @@ SOFTWARE. #include "utility.h" #include -#include #if ETL_HAS_ATOMIC diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index e90bf1c4..b5bb79f6 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -40,7 +40,6 @@ SOFTWARE. #include "utility.h" #include -#include namespace etl { diff --git a/include/etl/queue_spsc_locked.h b/include/etl/queue_spsc_locked.h index e87454f6..2aab884a 100644 --- a/include/etl/queue_spsc_locked.h +++ b/include/etl/queue_spsc_locked.h @@ -41,7 +41,6 @@ SOFTWARE. #include "utility.h" #include -#include namespace etl { diff --git a/include/etl/ranges.h b/include/etl/ranges.h index 4e1ba4b1..5fd8b6fe 100644 --- a/include/etl/ranges.h +++ b/include/etl/ranges.h @@ -2975,7 +2975,7 @@ namespace etl iterator() = default; iterator(const_iterator_type current, const_iterator_type segment_end, bool is_end) - : _current(current) + : _current_it(current) , _segment_end(segment_end) , _is_end(is_end || (current == segment_end)) { @@ -2983,18 +2983,18 @@ namespace etl reference operator*() const { - return *_current; + return *_current_it; } pointer operator->() const { - return &(*_current); + return &(*_current_it); } iterator& operator++() { - ++_current; - if (_current == _segment_end) + ++_current_it; + if (_current_it == _segment_end) { _is_end = true; } @@ -3018,7 +3018,7 @@ namespace etl { return false; } - return _current == other._current; + return _current_it == other._current_it; } constexpr bool operator!=(const iterator& other) const @@ -3028,7 +3028,7 @@ namespace etl private: - const_iterator_type _current{}; + const_iterator_type _current_it{}; const_iterator_type _segment_end{}; bool _is_end = true; }; @@ -3379,7 +3379,7 @@ namespace etl concat_iterator(size_t index, concat_view& view, iterator_variant_type current) : _ranges_index{index} , _view(view) - , _current(current) + , _current_it(current) { } @@ -3387,7 +3387,7 @@ namespace etl constexpr reference operator*() const { - return _view.get_value(_ranges_index, _current); + return _view.get_value(_ranges_index, _current_it); } constexpr decltype(auto) operator[](difference_type pos) const @@ -3397,14 +3397,14 @@ namespace etl { for (difference_type i = 0; i < pos; ++i) { - tmp._view.advance(tmp._ranges_index, tmp._current, 1); + tmp._view.advance(tmp._ranges_index, tmp._current_it, 1); } } if (pos < 0) { for (difference_type i = 0; i < -pos; ++i) { - tmp._view.advance(tmp._ranges_index, tmp._current, -1); + tmp._view.advance(tmp._ranges_index, tmp._current_it, -1); } } return *tmp; @@ -3412,27 +3412,27 @@ namespace etl constexpr concat_iterator& operator++() { - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); return *this; } constexpr concat_iterator operator++(int) { auto result = *this; - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); return result; } constexpr concat_iterator& operator--() { - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); return *this; } constexpr concat_iterator operator--(int) { auto result = *this; - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); return result; } @@ -3440,7 +3440,7 @@ namespace etl { for (difference_type i = 0; i < n; ++i) { - _view.advance(_ranges_index, _current, 1); + _view.advance(_ranges_index, _current_it, 1); } return *this; } @@ -3449,7 +3449,7 @@ namespace etl { for (difference_type i = 0; i < n; ++i) { - _view.advance(_ranges_index, _current, -1); + _view.advance(_ranges_index, _current_it, -1); } return *this; } @@ -3457,12 +3457,12 @@ namespace etl friend constexpr bool operator==(const concat_iterator& x, etl::default_sentinel_t) { return x._ranges_index == x._view.number_of_ranges - 1 - && etl::get(x._current) == etl::get(x._view).end(); + && etl::get(x._current_it) == etl::get(x._view).end(); } friend constexpr bool operator==(const concat_iterator& x, const concat_iterator& y) { - return x._ranges_index == y._ranges_index && x._current.index() == y._current.index() && x._current == y._current; + return x._ranges_index == y._ranges_index && x._current_it.index() == y._current_it.index() && x._current_it == y._current_it; } friend constexpr bool operator!=(const concat_iterator& x, etl::default_sentinel_t) @@ -3479,7 +3479,7 @@ namespace etl size_t _ranges_index; const concat_view& _view; - iterator_variant_type _current; + iterator_variant_type _current_it; }; template @@ -3639,20 +3639,6 @@ namespace etl template concat_view(Ranges&&...) -> concat_view...>; - struct concat_range_adapter_closure : public range_adapter_closure - { - template - using target_view_type = concat_view; - - constexpr concat_range_adapter_closure() = default; - - template - constexpr auto operator()(Ranges&&... r) const - { - return concat_view(views::all(etl::forward(r))...); - } - }; - namespace views { namespace private_views @@ -5746,7 +5732,7 @@ namespace etl using iterator_category = ETL_OR_STD::forward_iterator_tag; constexpr cartesian_product_iterator(iterators_type current, iterators_type begins, iterators_type ends, bool is_end = false) - : _current(current) + : _current_it(current) , _begins(begins) , _ends(ends) , _is_end(is_end) @@ -5799,7 +5785,7 @@ namespace etl template constexpr etl::enable_if_t<(I > 0)> increment_at() { - auto& it = etl::get(_current); + auto& it = etl::get(_current_it); ++it; if (it == etl::get(_ends)) { @@ -5811,7 +5797,7 @@ namespace etl template constexpr etl::enable_if_t<(I == 0)> increment_at() { - auto& it = etl::get<0>(_current); + auto& it = etl::get<0>(_current_it); ++it; if (it == etl::get<0>(_ends)) { @@ -5822,16 +5808,16 @@ namespace etl template constexpr value_type deref(etl::index_sequence) const { - return value_type(*etl::get(_current)...); + return value_type(*etl::get(_current_it)...); } template constexpr bool all_equal(const cartesian_product_iterator& other, etl::index_sequence) const { - return ((etl::get(_current) == etl::get(other._current)) && ...); + return ((etl::get(_current_it) == etl::get(other._current_it)) && ...); } - iterators_type _current; + iterators_type _current_it; iterators_type _begins; iterators_type _ends; bool _is_end; diff --git a/include/etl/ratio.h b/include/etl/ratio.h index f4476dff..df16ecb0 100644 --- a/include/etl/ratio.h +++ b/include/etl/ratio.h @@ -37,7 +37,6 @@ SOFTWARE. #include "type_traits.h" -#include #include ///\defgroup ratio ratio @@ -161,12 +160,20 @@ namespace etl #endif //*********************************************************************** -/// Predefined ration types. +/// Predefined ratio types. //*********************************************************************** #if INT_MAX > INT32_MAX - typedef ratio<1, 1000000000000000000> atto; - typedef ratio<1, 1000000000000000> femto; - typedef ratio<1, 1000000000000> pico; + // 2022 SI prefix (10^-30) + typedef ratio<1, 1000000000000000000LL * 1000000000000LL> quecto; + // 2022 SI prefix (10^-27) + typedef ratio<1, 1000000000000000000LL * 1000000000LL> ronto; + // 10^-24 + typedef ratio<1, 1000000000000000000LL * 1000000LL> yocto; + // 10^-21 + typedef ratio<1, 1000000000000000000LL * 1000LL> zepto; + typedef ratio<1, 1000000000000000000> atto; + typedef ratio<1, 1000000000000000> femto; + typedef ratio<1, 1000000000000> pico; #endif #if (INT_MAX >= INT32_MAX) @@ -192,6 +199,14 @@ namespace etl typedef ratio<1000000000000, 1> tera; typedef ratio<1000000000000000, 1> peta; typedef ratio<1000000000000000000, 1> exa; + // 10^21 + typedef ratio<1000000000000000000LL * 1000LL, 1> zetta; + // 10^24 + typedef ratio<1000000000000000000LL * 1000000LL, 1> yotta; + // 2022 SI prefix (10^27) + typedef ratio<1000000000000000000LL * 1000000000LL, 1> ronna; + // 2022 SI prefix (10^30) + typedef ratio<1000000000000000000LL * 1000000000000LL, 1> quetta; #endif /// An approximation of Pi. diff --git a/include/etl/rescale.h b/include/etl/rescale.h index 54f8d265..fa183f22 100644 --- a/include/etl/rescale.h +++ b/include/etl/rescale.h @@ -37,7 +37,6 @@ SOFTWARE. #include "type_traits.h" // #include -#include namespace etl { diff --git a/include/etl/result.h b/include/etl/result.h index 5b5fcad8..22b5f92c 100644 --- a/include/etl/result.h +++ b/include/etl/result.h @@ -38,11 +38,7 @@ SOFTWARE. #include "optional.h" #include "variant.h" -#if ETL_CPP11_NOT_SUPPORTED - #if !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW - #endif -#else +#if ETL_CPP11_SUPPORTED namespace etl { @@ -70,7 +66,6 @@ namespace etl { } - #if ETL_CPP11_SUPPORTED //******************************************* /// Move constructor //******************************************* @@ -78,7 +73,6 @@ namespace etl : data(etl::move(other.data)) { } - #endif //******************************************* // Construct from a value @@ -104,15 +98,13 @@ namespace etl { } - //******************************************* - /// Move construct from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move construct from error + //******************************************* result(TError&& error) : data(etl::move(error)) { } - #endif //******************************************* /// Copy assign @@ -141,16 +133,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from value - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from value + //******************************************* result& operator=(TValue&& value) { data = etl::move(value); return *this; } - #endif //******************************************* /// Copy assign from error @@ -161,16 +151,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from error + //******************************************* result& operator=(TError&& error) { data = etl::move(error); return *this; } - #endif //******************************************* /// true if result contains a value @@ -223,16 +211,14 @@ namespace etl return etl::get(data); } - //******************************************* - /// Returns an rvalue reference to the error. - /// Undefined if the result does not contain an error. - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Returns an rvalue reference to the error. + /// Undefined if the result does not contain an error. + //******************************************* TError&& error() { return etl::move(etl::get(data)); } - #endif private: @@ -280,15 +266,13 @@ namespace etl { } - //******************************************* - /// Move construct from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move construct from error + //******************************************* result(TError&& error) : data(etl::move(error)) { } - #endif //******************************************* /// Copy assign from error @@ -299,16 +283,14 @@ namespace etl return *this; } - //******************************************* - /// Move assign from error - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Move assign from error + //******************************************* result& operator=(TError&& error) { data = etl::move(error); return *this; } - #endif //******************************************* /// true if result contains a value @@ -343,16 +325,14 @@ namespace etl return data.value(); } - //******************************************* - /// Returns an rvalue reference to the error. - /// Undefined if the result does not contain an error. - //******************************************* - #if ETL_CPP11_SUPPORTED + //******************************************* + /// Returns an rvalue reference to the error. + /// Undefined if the result does not contain an error. + //******************************************* TError&& error() { return etl::move(data.value()); } - #endif private: diff --git a/include/etl/rounded_integral_division.h b/include/etl/rounded_integral_division.h index b56a9dc5..26ae700c 100644 --- a/include/etl/rounded_integral_division.h +++ b/include/etl/rounded_integral_division.h @@ -36,6 +36,8 @@ SOFTWARE. #include "type_traits.h" #include "utility.h" +#if ETL_USING_CPP11 + namespace etl { namespace private_rounded_integral_division @@ -565,7 +567,7 @@ namespace etl // Work with magnitudes in unsigned form (avoids abs() overflow for // T::min()). - typedef typename std::make_unsigned::type utype; + typedef typename etl::make_unsigned::type utype; const utype abs_denominator = (denominator < 0) ? (utype(0) - utype(denominator)) : utype(denominator); const utype abs_remainder = (remainder < 0) ? (utype(0) - utype(remainder)) : utype(remainder); const utype half_denominator = abs_denominator / 2U; @@ -784,3 +786,4 @@ namespace etl } // namespace etl #endif +#endif diff --git a/include/etl/scaled_rounding.h b/include/etl/scaled_rounding.h index d09d0203..1c72a02a 100644 --- a/include/etl/scaled_rounding.h +++ b/include/etl/scaled_rounding.h @@ -33,7 +33,6 @@ SOFTWARE. #include "platform.h" #include "absolute.h" -#include "static_assert.h" #include "type_traits.h" namespace etl diff --git a/include/etl/signal.h b/include/etl/signal.h index 0f198824..3392cff6 100644 --- a/include/etl/signal.h +++ b/include/etl/signal.h @@ -35,10 +35,6 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #include "algorithm.h" diff --git a/include/etl/stack.h b/include/etl/stack.h index 24d0165d..98c18812 100644 --- a/include/etl/stack.h +++ b/include/etl/stack.h @@ -44,7 +44,6 @@ SOFTWARE. #include "utility.h" #include -#include //***************************************************************************** ///\defgroup stack stack diff --git a/include/etl/string_utilities.h b/include/etl/string_utilities.h index aa540d9c..b00cb6ba 100644 --- a/include/etl/string_utilities.h +++ b/include/etl/string_utilities.h @@ -39,7 +39,7 @@ SOFTWARE. #include "optional.h" #include -#include +#include #include "private/minmax_push.h" diff --git a/include/etl/string_view.h b/include/etl/string_view.h index 7f0162ec..1178e4c4 100644 --- a/include/etl/string_view.h +++ b/include/etl/string_view.h @@ -589,9 +589,9 @@ namespace etl return npos; } - position = etl::min(position, size()); + position = etl::min(position, size() - view.size()); - const_iterator iposition = etl::find_end(begin(), begin() + position, view.begin(), view.end()); + const_iterator iposition = etl::find_end(begin(), begin() + position + view.size(), view.begin(), view.end()); if (iposition == end()) { diff --git a/include/etl/threshold.h b/include/etl/threshold.h index 76e9c00c..f1fbf09c 100644 --- a/include/etl/threshold.h +++ b/include/etl/threshold.h @@ -36,7 +36,6 @@ SOFTWARE. #include "type_traits.h" // #include -#include namespace etl { diff --git a/include/etl/tuple.h b/include/etl/tuple.h index 31cdce5f..d3a48135 100644 --- a/include/etl/tuple.h +++ b/include/etl/tuple.h @@ -31,14 +31,11 @@ SOFTWARE. #include "platform.h" -#if ETL_NOT_USING_CPP11 && !defined(ETL_IN_UNIT_TEST) - #error NOT SUPPORTED FOR C++03 OR BELOW -#endif - #if ETL_USING_CPP11 #if ETL_USING_STL #include + #include #endif #include "functional.h" @@ -1183,7 +1180,9 @@ namespace etl namespace std { - #if ETL_NOT_USING_STL && !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000)) && defined(ETL_COMPILER_CLANG)) + #if ETL_NOT_USING_STL \ + && !((defined(ETL_DEVELOPMENT_OS_APPLE) || (ETL_COMPILER_FULL_VERSION >= 190000) && (ETL_COMPILER_FULL_VERSION < 210000)) \ + && defined(ETL_COMPILER_CLANG)) template struct tuple_size; diff --git a/include/etl/type_lookup.h b/include/etl/type_lookup.h index 19b3b6f9..cb6dc803 100644 --- a/include/etl/type_lookup.h +++ b/include/etl/type_lookup.h @@ -32,10 +32,10 @@ SOFTWARE. #include "platform.h" #include "integral_limits.h" #include "null_type.h" -#include "static_assert.h" #include "type_traits.h" -#include +#include + namespace etl { //*************************************************************************** diff --git a/include/etl/type_select.h b/include/etl/type_select.h index 7be28812..ba386d65 100644 --- a/include/etl/type_select.h +++ b/include/etl/type_select.h @@ -31,8 +31,10 @@ SOFTWARE. #include "platform.h" #include "null_type.h" -#include "static_assert.h" #include "type_traits.h" + +#include + namespace etl { #if ETL_USING_CPP11 && !defined(ETL_TYPE_SELECT_FORCE_CPP03_IMPLEMENTATION) diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 411632ff..6f3b21bd 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -499,19 +499,19 @@ namespace etl }; #if ETL_HAS_NATIVE_CHAR8_T template <> - struct is_signed : true_type + struct is_signed : false_type { }; #endif #if ETL_HAS_NATIVE_CHAR16_T template <> - struct is_signed : true_type + struct is_signed : false_type { }; #endif #if ETL_HAS_NATIVE_CHAR32_T template <> - struct is_signed : true_type + struct is_signed : false_type { }; #endif @@ -569,6 +569,24 @@ namespace etl struct is_unsigned : true_type { }; + #if ETL_HAS_NATIVE_CHAR8_T + template <> + struct is_unsigned : true_type + { + }; + #endif + #if ETL_HAS_NATIVE_CHAR16_T + template <> + struct is_unsigned : true_type + { + }; + #endif + #if ETL_HAS_NATIVE_CHAR32_T + template <> + struct is_unsigned : true_type + { + }; + #endif template struct is_unsigned : is_unsigned { @@ -649,6 +667,18 @@ namespace etl struct is_void : true_type { }; + template <> + struct is_void : true_type + { + }; + template <> + struct is_void : true_type + { + }; + template <> + struct is_void : true_type + { + }; #if ETL_USING_CPP17 template @@ -1170,6 +1200,21 @@ namespace etl inline constexpr bool is_base_of_v = is_base_of::value; #endif + //*************************************************************************** + /// is_virtual_base_of + /// Determines if TBase is a virtual base class of TDerived + #if ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : etl::bool_constant<__is_virtual_base_of(TBase, TDerived)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; + #endif + #endif + //*************************************************************************** /// add_lvalue_reference template @@ -2017,6 +2062,32 @@ namespace etl inline constexpr bool is_base_of_v = std::is_base_of_v; #endif + //*************************************************************************** + /// is_virtual_base_of + /// Determines if TBase is a virtual base class of TDerived + ///\ingroup type_traits + #if ETL_HAS_STD_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : std::is_virtual_base_of + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = std::is_virtual_base_of_v; + #endif + #elif ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + template + struct is_virtual_base_of : etl::bool_constant<__is_virtual_base_of(TBase, TDerived)> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; + #endif + #endif + //*************************************************************************** /// is_class template @@ -2594,6 +2665,41 @@ namespace etl template using is_move_assignable = std::is_move_assignable; + //********************************************* + // is_nothrow_constructible + template + using is_nothrow_constructible = std::is_nothrow_constructible; + + //********************************************* + // is_nothrow_default_constructible + template + using is_nothrow_default_constructible = std::is_nothrow_default_constructible; + + //********************************************* + // is_nothrow_copy_constructible + template + using is_nothrow_copy_constructible = std::is_nothrow_copy_constructible; + + //********************************************* + // is_nothrow_move_constructible + template + using is_nothrow_move_constructible = std::is_nothrow_move_constructible; + + //********************************************* + // is_nothrow_assignable + template + using is_nothrow_assignable = std::is_nothrow_assignable; + + //********************************************* + // is_nothrow_copy_assignable + template + using is_nothrow_copy_assignable = std::is_nothrow_copy_assignable; + + //********************************************* + // is_nothrow_move_assignable + template + using is_nothrow_move_assignable = std::is_nothrow_move_assignable; + //********************************************* // is_trivially_constructible #if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED @@ -2647,6 +2753,40 @@ namespace etl using is_trivially_copyable = etl::bool_constant::value || etl::is_pointer::value>; #endif + //********************************************* + // is_trivially_relocatable + #if ETL_HAS_STD_TRIVIALLY_RELOCATABLE && ETL_USING_STL + template + using is_trivially_relocatable = std::is_trivially_relocatable; + #elif ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + template + using is_trivially_relocatable = etl::bool_constant<__builtin_is_cpp_trivially_relocatable(T)>; + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + template + using is_trivially_relocatable = etl::bool_constant<__is_trivially_relocatable(T)>; + #else + template + using is_trivially_relocatable = etl::bool_constant::value && etl::is_trivially_destructible::value>; + #endif + + //********************************************* + // is_nothrow_relocatable + // A type is nothrow relocatable if it is trivially relocatable, or + // if it has a nothrow move constructor and nothrow destructor. + #if ETL_HAS_STD_TRIVIALLY_RELOCATABLE && ETL_USING_STL + template + using is_nothrow_relocatable = std::is_nothrow_relocatable; + #elif ETL_USING_STL + template + using is_nothrow_relocatable = etl::bool_constant< etl::is_trivially_relocatable::value + || (std::is_nothrow_move_constructible::type>::value + && std::is_nothrow_destructible::type>::value)>; + #else + // Fallback: only trivially relocatable types are known to be nothrow relocatable + template + using is_nothrow_relocatable = etl::is_trivially_relocatable; + #endif + #elif defined(ETL_USE_TYPE_TRAITS_BUILTINS) && !defined(ETL_USER_DEFINED_TYPE_TRAITS) //********************************************* @@ -2723,6 +2863,71 @@ namespace etl }; #endif + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible + { + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + static ETL_CONSTANT bool value = __is_nothrow_constructible(T, TArgs...); + #else + static ETL_CONSTANT bool value = etl::is_arithmetic::value || etl::is_pointer::value; + #endif + }; + + //********************************************* + // is_nothrow_default_constructible + template + struct is_nothrow_default_constructible : public etl::is_nothrow_constructible + { + }; + + //********************************************* + // is_nothrow_copy_constructible + template + struct is_nothrow_copy_constructible : public etl::is_nothrow_constructible::type> + { + }; + + //********************************************* + // is_nothrow_move_constructible + template + struct is_nothrow_move_constructible : public etl::is_nothrow_constructible::type> + { + }; + #endif + + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_assignable + template + struct is_nothrow_assignable + { + #if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE + static ETL_CONSTANT bool value = __is_nothrow_assignable(T, U); + #else + static ETL_CONSTANT bool value = etl::is_arithmetic::value || etl::is_pointer::value; + #endif + }; + + //********************************************* + // is_nothrow_copy_assignable + template + struct is_nothrow_copy_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_lvalue_reference::type> + { + }; + + //********************************************* + // is_nothrow_move_assignable + template + struct is_nothrow_move_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_rvalue_reference::type> + { + }; + #endif + #if ETL_USING_CPP11 //********************************************* // is_trivially_constructible @@ -2800,6 +3005,31 @@ namespace etl static ETL_CONSTANT bool value = __is_trivially_copyable(T); }; + //********************************************* + // is_trivially_relocatable + template + struct is_trivially_relocatable + { + #if ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + static ETL_CONSTANT bool value = __builtin_is_cpp_trivially_relocatable(T); + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + static ETL_CONSTANT bool value = __is_trivially_relocatable(T); + #else + static ETL_CONSTANT bool value = etl::is_trivially_copyable::value && etl::is_trivially_destructible::value; + #endif + }; + + //********************************************* + // is_nothrow_relocatable + // A type is nothrow relocatable if it is trivially relocatable, or + // if it has a nothrow move constructor and nothrow destructor. + template + struct is_nothrow_relocatable + { + // In builtins mode, conservatively use trivially_relocatable as the definition + static ETL_CONSTANT bool value = etl::is_trivially_relocatable::value; + }; + #elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS) //********************************************* @@ -2894,6 +3124,104 @@ namespace etl template struct is_move_assignable; + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible_helper; + + template + struct is_nothrow_constructible_helper : public etl::true_type + { + }; + + template + struct is_nothrow_constructible_helper; + + template + struct is_nothrow_constructible : public is_nothrow_constructible_helper::value || etl::is_pointer::value, TArgs...> + { + }; + + //********************************************* + // is_nothrow_default_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_default_constructible; + + template + struct is_nothrow_default_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_default_constructible; + + //********************************************* + // is_nothrow_copy_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_copy_constructible; + + template + struct is_nothrow_copy_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_copy_constructible; + + //********************************************* + // is_nothrow_move_constructible + template ::value || etl::is_pointer::value> + struct is_nothrow_move_constructible; + + template + struct is_nothrow_move_constructible : public etl::true_type + { + }; + + template + struct is_nothrow_move_constructible; + + //********************************************* + // is_nothrow_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_assignable; + + template + struct is_nothrow_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_assignable; + + //********************************************* + // is_nothrow_copy_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_copy_assignable; + + template + struct is_nothrow_copy_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_copy_assignable; + + //********************************************* + // is_nothrow_move_assignable + template ::value || etl::is_pointer::value> + struct is_nothrow_move_assignable; + + template + struct is_nothrow_move_assignable : public etl::true_type + { + }; + + template + struct is_nothrow_move_assignable; + #endif + //********************************************* // is_trivially_constructible template ::value || etl::is_pointer::value> @@ -2959,6 +3287,33 @@ namespace etl template struct is_trivially_copyable; + //********************************************* + // is_trivially_relocatable + template ::value || etl::is_pointer::value> + struct is_trivially_relocatable; + + template + struct is_trivially_relocatable : public etl::true_type + { + }; + + template + struct is_trivially_relocatable; + + //********************************************* + // is_nothrow_relocatable + // In user-defined mode, users must specialize for non-trivially-relocatable types + template ::value || etl::is_pointer::value> + struct is_nothrow_relocatable; + + template + struct is_nothrow_relocatable : public etl::true_type + { + }; + + template + struct is_nothrow_relocatable; + #else //********************************************* @@ -3087,6 +3442,57 @@ namespace etl }; #endif + #if ETL_USING_CPP11 + //********************************************* + // is_nothrow_constructible + template + struct is_nothrow_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_default_constructible + template + struct is_nothrow_default_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_copy_constructible + template + struct is_nothrow_copy_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_move_constructible + template + struct is_nothrow_move_constructible : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_assignable + template + struct is_nothrow_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_copy_assignable + template + struct is_nothrow_copy_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + + //********************************************* + // is_nothrow_move_assignable + template + struct is_nothrow_move_assignable : public etl::bool_constant::value || etl::is_pointer::value> + { + }; + #endif + //********************************************* // is_trivially_constructible template @@ -3126,6 +3532,27 @@ namespace etl { }; + //********************************************* + // is_trivially_relocatable + template + #if ETL_USING_BUILTIN_BUILTIN_IS_CPP_TRIVIALLY_RELOCATABLE + struct is_trivially_relocatable : public etl::bool_constant<__builtin_is_cpp_trivially_relocatable(T)> + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + struct is_trivially_relocatable : public etl::bool_constant<__is_trivially_relocatable(T)> + #else + struct is_trivially_relocatable : public etl::bool_constant::value && etl::is_trivially_destructible::value> + #endif + { + }; + + //********************************************* + // is_nothrow_relocatable + // Fallback: only trivially relocatable types are known to be nothrow relocatable + template + struct is_nothrow_relocatable : public etl::is_trivially_relocatable + { + }; + #endif template @@ -3180,6 +3607,27 @@ namespace etl template inline constexpr bool is_move_assignable_v = etl::is_move_assignable::value; + template + inline constexpr bool is_nothrow_constructible_v = etl::is_nothrow_constructible::value; + + template + inline constexpr bool is_nothrow_default_constructible_v = etl::is_nothrow_default_constructible::value; + + template + inline constexpr bool is_nothrow_copy_constructible_v = etl::is_nothrow_copy_constructible::value; + + template + inline constexpr bool is_nothrow_move_constructible_v = etl::is_nothrow_move_constructible::value; + + template + inline constexpr bool is_nothrow_assignable_v = etl::is_nothrow_assignable::value; + + template + inline constexpr bool is_nothrow_copy_assignable_v = etl::is_nothrow_copy_assignable::value; + + template + inline constexpr bool is_nothrow_move_assignable_v = etl::is_nothrow_move_assignable::value; + template inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible::value; @@ -3195,6 +3643,12 @@ namespace etl template inline constexpr bool is_trivially_copyable_v = etl::is_trivially_copyable::value; + template + inline constexpr bool is_trivially_relocatable_v = etl::is_trivially_relocatable::value; + + template + inline constexpr bool is_nothrow_relocatable_v = etl::is_nothrow_relocatable::value; + #endif #if ETL_USING_CPP11 @@ -3553,6 +4007,19 @@ namespace etl template inline constexpr bool is_function_v = etl::is_function::value; #endif + + //*************************************************************************** + /// is_object + //*************************************************************************** + template + struct is_object : etl::bool_constant::value && !etl::is_reference::value && !etl::is_void::value> + { + }; + + #if ETL_USING_CPP17 + template + inline constexpr bool is_object_v = etl::is_object::value; + #endif #endif #if ETL_USING_CPP11 diff --git a/include/etl/unordered_map.h b/include/etl/unordered_map.h index cda34d8d..69531c7d 100644 --- a/include/etl/unordered_map.h +++ b/include/etl/unordered_map.h @@ -43,7 +43,6 @@ SOFTWARE. #include "intrusive_forward_list.h" #include "iterator.h" #include "nth_type.h" -#include "nullptr.h" #include "parameter_type.h" #include "placement_new.h" #include "pool.h" diff --git a/include/etl/unordered_multimap.h b/include/etl/unordered_multimap.h index 7e26a4ca..aa330abd 100644 --- a/include/etl/unordered_multimap.h +++ b/include/etl/unordered_multimap.h @@ -42,7 +42,6 @@ SOFTWARE. #include "intrusive_forward_list.h" #include "iterator.h" #include "nth_type.h" -#include "nullptr.h" #include "parameter_type.h" #include "placement_new.h" #include "pool.h" diff --git a/include/etl/unordered_multiset.h b/include/etl/unordered_multiset.h index 30c174c5..c8b6de7a 100644 --- a/include/etl/unordered_multiset.h +++ b/include/etl/unordered_multiset.h @@ -42,7 +42,6 @@ SOFTWARE. #include "intrusive_forward_list.h" #include "iterator.h" #include "nth_type.h" -#include "nullptr.h" #include "parameter_type.h" #include "placement_new.h" #include "pool.h" diff --git a/include/etl/unordered_set.h b/include/etl/unordered_set.h index b099f0bf..66b1cfe6 100644 --- a/include/etl/unordered_set.h +++ b/include/etl/unordered_set.h @@ -42,7 +42,6 @@ SOFTWARE. #include "intrusive_forward_list.h" #include "iterator.h" #include "nth_type.h" -#include "nullptr.h" #include "parameter_type.h" #include "placement_new.h" #include "pool.h" diff --git a/include/etl/utility.h b/include/etl/utility.h index 5a77b5b5..4c7e4719 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -377,7 +377,7 @@ namespace etl inline bool operator==(const pair& a, const pair& b) { #include "private/diagnostic_float_equal_push.h" - return (a.first == b.first) && !(a.second < b.second) && !(a.second > b.second); + return (a.first == b.first) && (a.second == b.second); #include "private/diagnostic_pop.h" } diff --git a/include/etl/variant_pool.h b/include/etl/variant_pool.h index b308a80d..690a9677 100644 --- a/include/etl/variant_pool.h +++ b/include/etl/variant_pool.h @@ -35,7 +35,7 @@ SOFTWARE. #include "static_assert.h" #include "type_traits.h" -#include +#include namespace etl { diff --git a/include/etl/vector.h b/include/etl/vector.h index ba10ac79..73540e2b 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -40,7 +40,6 @@ SOFTWARE. #include "debug_count.h" #include "error_handler.h" #include "exception.h" -#include "functional.h" #include "initializer_list.h" #include "iterator.h" #include "memory.h" @@ -479,7 +478,9 @@ namespace etl { ETL_ASSERT_CHECK_PUSH_POP(size() != CAPACITY, ETL_ERROR(vector_full)); + #include "private/diagnostic_sign_conversion_push.h" ::new (p_end) T(etl::forward(args)...); + #include "private/diagnostic_pop.h" ++p_end; ETL_INCREMENT_DEBUG_COUNT; return back(); @@ -668,7 +669,9 @@ namespace etl (*position_).~T(); } + #include "private/diagnostic_sign_conversion_push.h" ::new (p) T(etl::forward(args)...); + #include "private/diagnostic_pop.h" return position_; } @@ -1014,7 +1017,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - ivector& operator=(ivector&& rhs) + ivector& operator=(ivector&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1081,7 +1084,7 @@ namespace etl //********************************************************************* /// Constructor. //********************************************************************* - ivector(T* p_buffer_, size_t MAX_SIZE) + ivector(T* p_buffer_, size_t MAX_SIZE) ETL_NOEXCEPT : vector_base(MAX_SIZE) , p_buffer(p_buffer_) , p_end(p_buffer_) @@ -1121,17 +1124,6 @@ namespace etl private: - //********************************************************************* - /// Create a new element with a default value at the back. - //********************************************************************* - void create_back() - { - etl::create_value_at(p_end); - ETL_INCREMENT_DEBUG_COUNT; - - ++p_end; - } - //********************************************************************* /// Create a new element with a value at the back //********************************************************************* @@ -1284,7 +1276,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector() + vector() ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { this->initialise(); @@ -1363,7 +1355,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector(vector&& other) + vector(vector&& other) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { if (this != &other) @@ -1384,7 +1376,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector& operator=(vector&& rhs) + vector& operator=(vector&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1409,7 +1401,7 @@ namespace etl #ifdef ETL_IVECTOR_REPAIR_ENABLE virtual #endif - ~vector() + ~vector() ETL_NOEXCEPT { this->clear(); } @@ -1466,7 +1458,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector_ext(void* buffer, size_t max_size) + vector_ext(void* buffer, size_t max_size) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(buffer), max_size) { this->initialise(); @@ -1546,7 +1538,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector_ext(vector_ext&& other, void* buffer, size_t max_size) + vector_ext(vector_ext&& other, void* buffer, size_t max_size) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) : etl::ivector(reinterpret_cast(buffer), max_size) { if (this != &other) @@ -1567,7 +1559,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector_ext& operator=(vector_ext&& rhs) + vector_ext& operator=(vector_ext&& rhs) ETL_NOEXCEPT_IF((etl::is_nothrow_move_constructible::value)) { if (&rhs != this) { @@ -1590,7 +1582,7 @@ namespace etl //************************************************************************* /// Destructor. //************************************************************************* - ~vector_ext() + ~vector_ext() ETL_NOEXCEPT { this->clear(); } @@ -1625,7 +1617,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector() + vector() ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { this->initialise(); @@ -1701,7 +1693,7 @@ namespace etl //************************************************************************* /// Move constructor. //************************************************************************* - vector(vector&& other) + vector(vector&& other) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(&buffer), MAX_SIZE) { (void)etl::ivector::operator=(etl::move(other)); @@ -1710,7 +1702,7 @@ namespace etl //************************************************************************* /// Move assignment operator. //************************************************************************* - vector& operator=(vector&& rhs) + vector& operator=(vector&& rhs) ETL_NOEXCEPT { (void)etl::ivector::operator=(etl::move(rhs)); @@ -1765,7 +1757,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - vector_ext(void* buffer, size_t max_size) + vector_ext(void* buffer, size_t max_size) ETL_NOEXCEPT : etl::ivector(reinterpret_cast(buffer), max_size) { this->initialise(); @@ -1872,7 +1864,7 @@ namespace etl //************************************************************************* /// Destructor. //************************************************************************* - ~vector_ext() + ~vector_ext() ETL_NOEXCEPT { this->clear(); } diff --git a/meson_options.txt b/meson_options.txt index 6f64d611..5845d5f3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ option('use_stl', description: 'Compiling for STL', type: 'boolean', value: true) +option('enable_sanitizer', description: 'Enable address and undefined behavior sanitizers', type: 'boolean', value: false) diff --git a/scripts/run-docker.sh b/scripts/run-docker.sh new file mode 100755 index 00000000..862cb436 --- /dev/null +++ b/scripts/run-docker.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Create docker image for development environment and enter container +# +# Run from project root directory +# + +set -e + +# Verify script is running from project root +if [ ! -d ".devcontainer" ]; then + echo "Error: This script must be run from the project root directory." >&2 + echo "The .devcontainer directory was not found." >&2 + exit 1 +fi + +docker build -t etl .devcontainer +docker run -it --rm -v "$(pwd)":/home/vscode/etl -u vscode -w /home/vscode/etl etl /bin/bash diff --git a/test/BUILD.bazel b/test/BUILD.bazel new file mode 100644 index 00000000..c5f1a4d8 --- /dev/null +++ b/test/BUILD.bazel @@ -0,0 +1,36 @@ +load("@rules_cc//cc:defs.bzl", "cc_test") + +cc_test( + name = "etl_tests", + size = "small", + srcs = glob( + [ + "*.cpp", + "*.h", + ], + exclude = [ + "maincpp03check.cpp", + ], + ), + copts = [ + "-Itest", + "-fno-omit-frame-pointer", + "-fno-common", + "-pedantic-errors", + "-Wall", + "-Wextra", + "-Werror", + "-Wfloat-equal", + "-Wshadow", + "-Wnull-dereference", + "-Wsign-conversion", + "-Wextra-semi", + "-Wno-maybe-uninitialized", + "-g", + ], + linkopts = ["-latomic"], + deps = [ + "//:etl", + "//test/UnitTest++:unittest-cpp", + ], +) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a559add4..a7e61fb9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -83,8 +83,9 @@ add_executable(etl_tests test_circular_buffer.cpp test_circular_buffer_external_buffer.cpp test_circular_iterator.cpp - test_closure.cpp - test_closure_constexpr.cpp + test_closure_with_default_delegate.cpp + test_closure_with_default_delegate_constexpr.cpp + test_closure_with_inplace_function.cpp test_compare.cpp test_concepts.cpp test_constant.cpp @@ -384,6 +385,7 @@ option(ETL_NO_STL "No STL" OFF) set(EXTRA_COMPILE_OPTIONS "" CACHE STRING "Additional compiler options") set(EXTRA_LINK_OPTIONS "" CACHE STRING "Additional linker options") set(EXTRA_LINK_LIBS "" CACHE STRING "Additional libraries to link") +set(EXTRA_TESTING_FLAGS "" CACHE STRING "Additional testing flags for ctest") if (ETL_CXX_STANDARD MATCHES "98") message(STATUS "Compiling for C++98") @@ -404,10 +406,26 @@ elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) elseif (ETL_CXX_STANDARD MATCHES "23") - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Unsupported C++ standard") + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (NO_STL OR ETL_NO_STL) @@ -523,7 +541,7 @@ if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Cla target_link_options(etl_tests PRIVATE -fsanitize=address,undefined,bounds - ) + ) endif() endif () endif () @@ -537,7 +555,7 @@ target_link_libraries(etl_tests PRIVATE UnitTestpp ${EXTRA_LINK_LIBS}) enable_testing() # Enable the 'make test' CMake target using the executable defined above -add_test(NAME etl_unit_tests COMMAND etl_tests) +add_test(NAME etl_unit_tests COMMAND etl_tests ${EXTRA_TESTING_FLAGS}) # Since ctest will only show you the results of the single executable # define a target that will output all of the failing or passing tests diff --git a/test/UnitTest++/BUILD.bazel b/test/UnitTest++/BUILD.bazel new file mode 100644 index 00000000..73d55222 --- /dev/null +++ b/test/UnitTest++/BUILD.bazel @@ -0,0 +1,20 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "unittest-cpp", + srcs = glob( + [ + "*.cpp", + "Posix/*.cpp", + ], + ), + hdrs = glob( + [ + "*.h", + "Posix/*.h", + ], + ), + includes = ["."], +) diff --git a/test/data.h b/test/data.h index 782ef92a..4aadbf67 100644 --- a/test/data.h +++ b/test/data.h @@ -201,14 +201,14 @@ public: TestDataM(TestDataM&& other) noexcept : value(std::move(other.value)) - , valid(true) + , valid(other.valid) { other.valid = false; } TestDataM(const TestDataM&& other) noexcept : value(std::move(other.value)) - , valid(true) + , valid(other.valid) { other.valid = false; } @@ -220,10 +220,13 @@ public: TestDataM& operator=(TestDataM&& other) noexcept { - value = std::move(other.value); - valid = true; + if (this != &other) + { + value = std::move(other.value); + valid = other.valid; - other.valid = false; + other.valid = false; + } return *this; } diff --git a/test/etl_error_handler/assert_function/CMakeLists.txt b/test/etl_error_handler/assert_function/CMakeLists.txt index babd03cc..f9ac1b49 100644 --- a/test/etl_error_handler/assert_function/CMakeLists.txt +++ b/test/etl_error_handler/assert_function/CMakeLists.txt @@ -34,9 +34,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") diff --git a/test/etl_error_handler/exceptions/CMakeLists.txt b/test/etl_error_handler/exceptions/CMakeLists.txt index 2da119b0..eac58405 100644 --- a/test/etl_error_handler/exceptions/CMakeLists.txt +++ b/test/etl_error_handler/exceptions/CMakeLists.txt @@ -32,9 +32,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") diff --git a/test/etl_error_handler/log_errors/CMakeLists.txt b/test/etl_error_handler/log_errors/CMakeLists.txt index 337e6546..4c96e4de 100644 --- a/test/etl_error_handler/log_errors/CMakeLists.txt +++ b/test/etl_error_handler/log_errors/CMakeLists.txt @@ -18,7 +18,7 @@ if (ETL_CXX_STANDARD MATCHES "98") message(STATUS "Compiling for C++98") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) elseif (ETL_CXX_STANDARD MATCHES "03") - message(STATUS "Compiling for C++98") + message(STATUS "Compiling for C++03") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) elseif (ETL_CXX_STANDARD MATCHES "11") message(STATUS "Compiling for C++11") @@ -32,9 +32,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") @@ -121,7 +139,3 @@ add_test(etl_error_handler_unit_tests etl_tests) # as they appear from UnitTest++ add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) - -#RSG -set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) - diff --git a/test/etl_error_handler/log_errors/test_error_handler.cpp b/test/etl_error_handler/log_errors/test_error_handler.cpp index 01381e36..61d35125 100644 --- a/test/etl_error_handler/log_errors/test_error_handler.cpp +++ b/test/etl_error_handler/log_errors/test_error_handler.cpp @@ -117,12 +117,12 @@ bool AssertFailAndReturnValue() return false; } +static ErrorLog error_log; + //***************************************************************************** int main() { - static ErrorLog error_log; - - etl::error_handler::set_callback(); + etl::error_handler::set_callback(error_log); Assert(false); Assert(true); diff --git a/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt b/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt index cad344d4..3a7100df 100644 --- a/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt +++ b/test/etl_error_handler/log_errors_and_exceptions/CMakeLists.txt @@ -33,9 +33,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() if (ETL_OPTIMISATION MATCHES "-O1") @@ -120,7 +138,3 @@ add_test(etl_error_handler_unit_tests etl_tests) # as they appear from UnitTest++ add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) - -#RSG -set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) - diff --git a/test/etl_initializer_list/CMakeLists.txt b/test/etl_initializer_list/CMakeLists.txt index f29b5515..90437cdf 100644 --- a/test/etl_initializer_list/CMakeLists.txt +++ b/test/etl_initializer_list/CMakeLists.txt @@ -48,9 +48,27 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 26) + elseif (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + else() + message(FATAL_ERROR "CMake version ${CMAKE_VERSION} is too old to support C++23 or C++26. Please upgrade to CMake 3.20 or later.") + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET etl_tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) endif() target_include_directories(etl_tests diff --git a/test/meson.build b/test/meson.build index b84a21be..8de41419 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,4 +1,3 @@ - etl_test_sources = files( 'main.cpp', 'murmurhash3.cpp', @@ -8,48 +7,91 @@ etl_test_sources = files( 'test_array_view.cpp', 'test_array_wrapper.cpp', 'test_atomic.cpp', - 'test_base64_RFC2152_decoder.cppp', - 'test_base64_RFC2152_encoder.cppp', - 'test_base64_RFC3501_decoder.cppp', - 'test_base64_RFC3501_encoder.cppp', - 'test_base64_RFC4648_decoder_with_no_padding.cppp', - 'test_base64_RFC4648_decoder_with_padding.cppp', - 'test_base64_RFC4648_encoder_with_no_padding.cppp', - 'test_base64_RFC4648_encoder_with_padding.cppp', - 'test_base64_RFC4648_URL_decoder_with_no_padding.cppp', - 'test_base64_RFC4648_URL_decoder_with_padding.cppp', - 'test_base64_RFC4648_URL_encoder_with_no_padding.cppp', + 'test_base64_RFC2152_decoder.cpp', + 'test_base64_RFC2152_encoder.cpp', + 'test_base64_RFC3501_decoder.cpp', + 'test_base64_RFC3501_encoder.cpp', + 'test_base64_RFC4648_URL_decoder_with_no_padding.cpp', + 'test_base64_RFC4648_URL_decoder_with_padding.cpp', + 'test_base64_RFC4648_URL_encoder_with_no_padding.cpp', 'test_base64_RFC4648_URL_encoder_with_padding.cpp', + 'test_base64_RFC4648_decoder_with_no_padding.cpp', + 'test_base64_RFC4648_decoder_with_padding.cpp', + 'test_base64_RFC4648_encoder_with_no_padding.cpp', + 'test_base64_RFC4648_encoder_with_padding.cpp', 'test_binary.cpp', 'test_bip_buffer_spsc_atomic.cpp', 'test_bit.cpp', - 'test_bitset_legacy.cpp', - 'test_bitset_new_default_element_type.cpp', - 'test_bitset_new_explicit_single_element_type.cpp', - 'test_bitset_new_ext_default_element_type.cpp', - 'test_bitset_new_ext_explicit_single_element_type.cpp', 'test_bit_stream.cpp', 'test_bit_stream_reader_big_endian.cpp', 'test_bit_stream_reader_little_endian.cpp', 'test_bit_stream_writer_big_endian.cpp', 'test_bit_stream_writer_little_endian.cpp', - 'test_byte.cpp', - 'test_byte_stream.cpp', + 'test_bitset_legacy.cpp', + 'test_bitset_new_comparisons.cpp', + 'test_bitset_new_default_element_type.cpp', + 'test_bitset_new_explicit_single_element_type.cpp', + 'test_bitset_new_ext_default_element_type.cpp', + 'test_bitset_new_ext_explicit_single_element_type.cpp', 'test_bloom_filter.cpp', 'test_bresenham_line.cpp', 'test_bsd_checksum.cpp', 'test_buffer_descriptors.cpp', + 'test_byte.cpp', + 'test_byte_stream.cpp', 'test_callback_service.cpp', 'test_callback_timer.cpp', 'test_callback_timer_atomic.cpp', + 'test_callback_timer_deferred_locked.cpp', 'test_callback_timer_interrupt.cpp', 'test_callback_timer_locked.cpp', + 'test_char_traits.cpp', 'test_checksum.cpp', + 'test_chrono_clocks.cpp', + 'test_chrono_day.cpp', + 'test_chrono_duration.cpp', + 'test_chrono_hh_mm_ss.cpp', + 'test_chrono_literals.cpp', + 'test_chrono_month.cpp', + 'test_chrono_month_day.cpp', + 'test_chrono_month_day_last.cpp', + 'test_chrono_month_weekday.cpp', + 'test_chrono_month_weekday_last.cpp', + 'test_chrono_operators.cpp', + 'test_chrono_time_point.cpp', + 'test_chrono_weekday.cpp', + 'test_chrono_weekday_indexed.cpp', + 'test_chrono_weekday_last.cpp', + 'test_chrono_year.cpp', + 'test_chrono_year_month.cpp', + 'test_chrono_year_month_day.cpp', + 'test_chrono_year_month_day_last.cpp', + 'test_chrono_year_month_weekday.cpp', + 'test_chrono_year_month_weekday_last.cpp', 'test_circular_buffer.cpp', 'test_circular_buffer_external_buffer.cpp', 'test_circular_iterator.cpp', + 'test_closure_with_default_delegate.cpp', + 'test_closure_with_default_delegate_constexpr.cpp', + 'test_closure_with_inplace_function.cpp', 'test_compare.cpp', - 'test_compiler_settings.cpp', + 'test_concepts.cpp', + 'test_const_map.cpp', + 'test_const_map_constexpr.cpp', + 'test_const_map_ext.cpp', + 'test_const_map_ext_constexpr.cpp', + 'test_const_multimap.cpp', + 'test_const_multimap_constexpr.cpp', + 'test_const_multimap_ext.cpp', + 'test_const_multimap_ext_constexpr.cpp', + 'test_const_multiset.cpp', + 'test_const_multiset_constexpr.cpp', + 'test_const_multiset_ext.cpp', + 'test_const_multiset_ext_constexpr.cpp', + 'test_const_set.cpp', + 'test_const_set_constexpr.cpp', + 'test_const_set_ext.cpp', + 'test_const_set_ext_constexpr.cpp', 'test_constant.cpp', 'test_container.cpp', 'test_correlation.cpp', @@ -69,9 +111,12 @@ etl_test_sources = files( 'test_crc16_en13757.cpp', 'test_crc16_genibus.cpp', 'test_crc16_kermit.cpp', + 'test_crc16_m17.cpp', 'test_crc16_maxim.cpp', 'test_crc16_mcrf4xx.cpp', 'test_crc16_modbus.cpp', + 'test_crc16_opensafety_a.cpp', + 'test_crc16_opensafety_b.cpp', 'test_crc16_profibus.cpp', 'test_crc16_riello.cpp', 'test_crc16_t10dif.cpp', @@ -90,6 +135,7 @@ etl_test_sources = files( 'test_crc32_q.cpp', 'test_crc32_xfer.cpp', 'test_crc64_ecma.cpp', + 'test_crc64_iso.cpp', 'test_crc8_ccitt.cpp', 'test_crc8_cdma2000.cpp', 'test_crc8_darc.cpp', @@ -97,21 +143,29 @@ etl_test_sources = files( 'test_crc8_ebu.cpp', 'test_crc8_icode.cpp', 'test_crc8_itu.cpp', + 'test_crc8_j1850.cpp', + 'test_crc8_j1850_zero.cpp', 'test_crc8_maxim.cpp', + 'test_crc8_nrsc5.cpp', + 'test_crc8_opensafety.cpp', 'test_crc8_rohc.cpp', 'test_crc8_wcdma.cpp', 'test_cyclic_value.cpp', 'test_debounce.cpp', 'test_delegate.cpp', 'test_delegate_cpp03.cpp', + 'test_delegate_observable.cpp', 'test_delegate_service.cpp', 'test_delegate_service_compile_time.cpp', + 'test_delegate_service_cpp03.cpp', 'test_deque.cpp', 'test_endian.cpp', 'test_enum_type.cpp', 'test_error_handler.cpp', + 'test_etl_assert.cpp', 'test_etl_traits.cpp', 'test_exception.cpp', + 'test_expected.cpp', 'test_fixed_iterator.cpp', 'test_fixed_sized_memory_block_allocator.cpp', 'test_flags.cpp', @@ -120,18 +174,24 @@ etl_test_sources = files( 'test_flat_multiset.cpp', 'test_flat_set.cpp', 'test_fnv_1.cpp', + 'test_format.cpp', 'test_format_spec.cpp', 'test_forward_list.cpp', 'test_forward_list_shared_pool.cpp', 'test_fsm.cpp', 'test_function.cpp', + 'test_function_traits.cpp', 'test_functional.cpp', 'test_gamma.cpp', 'test_hash.cpp', 'test_hfsm.cpp', + 'test_hfsm_recurse_to_inner_state_on_start.cpp', + 'test_hfsm_transition_on_enter.cpp', 'test_histogram.cpp', + 'test_index_of_type.cpp', 'test_indirect_vector.cpp', 'test_indirect_vector_external_buffer.cpp', + 'test_inplace_function.cpp', 'test_instance_count.cpp', 'test_integral_limits.cpp', 'test_intrusive_forward_list.cpp', @@ -140,7 +200,9 @@ etl_test_sources = files( 'test_intrusive_queue.cpp', 'test_intrusive_stack.cpp', 'test_invert.cpp', + 'test_invoke.cpp', 'test_io_port.cpp', + 'test_is_invocable.cpp', 'test_iterator.cpp', 'test_jenkins.cpp', 'test_largest.cpp', @@ -148,14 +210,17 @@ etl_test_sources = files( 'test_limits.cpp', 'test_list.cpp', 'test_list_shared_pool.cpp', + 'test_macros.cpp', 'test_make_string.cpp', + 'test_manchester.cpp', 'test_map.cpp', 'test_math.cpp', 'test_math_functions.cpp', 'test_mean.cpp', 'test_mem_cast.cpp', 'test_mem_cast_ptr.cpp', - 'test_memory.cpp', + 'test_memory.cpp', + 'test_message.cpp', 'test_message_broker.cpp', 'test_message_bus.cpp', 'test_message_packet.cpp', @@ -163,18 +228,23 @@ etl_test_sources = files( 'test_message_router_registry.cpp', 'test_message_timer.cpp', 'test_message_timer_atomic.cpp', - 'test_message_timer_interrupt.cpp', + 'test_message_timer_interrupt.cpp', 'test_message_timer_locked.cpp', - 'test_multimap.cpp', - 'test_multiset.cpp', 'test_multi_array.cpp', 'test_multi_range.cpp', + 'test_multi_span.cpp', 'test_multi_vector.cpp', + 'test_multimap.cpp', + 'test_multiset.cpp', 'test_murmur3.cpp', + 'test_not_null_pointer.cpp', + 'test_not_null_pointer_constexpr.cpp', + 'test_not_null_unique_pointer.cpp', 'test_nth_type.cpp', 'test_numeric.cpp', 'test_observer.cpp', 'test_optional.cpp', + 'test_overload.cpp', 'test_packet.cpp', 'test_parameter_pack.cpp', 'test_parameter_type.cpp', @@ -184,6 +254,7 @@ etl_test_sources = files( 'test_poly_span_fixed_extent.cpp', 'test_pool.cpp', 'test_pool_external_buffer.cpp', + 'test_print.cpp', 'test_priority_queue.cpp', 'test_pseudo_moving_average.cpp', 'test_quantize.cpp', @@ -200,45 +271,54 @@ etl_test_sources = files( 'test_queue_spsc_locked.cpp', 'test_queue_spsc_locked_small.cpp', 'test_random.cpp', + 'test_ranges.cpp', + 'test_ratio.cpp', 'test_reference_flat_map.cpp', 'test_reference_flat_multimap.cpp', 'test_reference_flat_multiset.cpp', 'test_reference_flat_set.cpp', 'test_rescale.cpp', + 'test_result.cpp', 'test_rms.cpp', + 'test_rounded_integral_division.cpp', 'test_scaled_rounding.cpp', 'test_set.cpp', 'test_shared_message.cpp', + 'test_signal.cpp', 'test_singleton.cpp', + 'test_singleton_base.cpp', 'test_smallest.cpp', 'test_span_dynamic_extent.cpp', 'test_span_fixed_extent.cpp', 'test_stack.cpp', 'test_standard_deviation.cpp', 'test_state_chart.cpp', - 'test_state_chart_with_data_parameter.cpp', - 'test_state_chart_with_rvalue_data_parameter.cpp', 'test_state_chart_compile_time.cpp', 'test_state_chart_compile_time_with_data_parameter.cpp', + 'test_state_chart_with_data_parameter.cpp', + 'test_state_chart_with_rvalue_data_parameter.cpp', 'test_string_char.cpp', 'test_string_char_external_buffer.cpp', 'test_string_stream.cpp', - 'test_string_u8.cpp', - 'test_string_u8_external_buffer.cpp', 'test_string_stream_u16.cpp', 'test_string_stream_u32.cpp', + 'test_string_stream_u8.cpp', 'test_string_stream_wchar_t.cpp', 'test_string_u16.cpp', 'test_string_u16_external_buffer.cpp', 'test_string_u32.cpp', 'test_string_u32_external_buffer.cpp', + 'test_string_u8.cpp', + 'test_string_u8_external_buffer.cpp', 'test_string_utilities.cpp', 'test_string_utilities_std.cpp', 'test_string_utilities_std_u16.cpp', 'test_string_utilities_std_u32.cpp', + 'test_string_utilities_std_u8.cpp', 'test_string_utilities_std_wchar_t.cpp', 'test_string_utilities_u16.cpp', 'test_string_utilities_u32.cpp', + 'test_string_utilities_u8.cpp', 'test_string_utilities_wchar_t.cpp', 'test_string_view.cpp', 'test_string_wchar_t.cpp', @@ -246,17 +326,25 @@ etl_test_sources = files( 'test_successor.cpp', 'test_task_scheduler.cpp', 'test_threshold.cpp', + 'test_to_arithmetic.cpp', + 'test_to_arithmetic_u16.cpp', + 'test_to_arithmetic_u32.cpp', + 'test_to_arithmetic_u8.cpp', + 'test_to_arithmetic_wchar_t.cpp', 'test_to_string.cpp', - 'test_to_u8string.cpp', 'test_to_u16string.cpp', 'test_to_u32string.cpp', + 'test_to_u8string.cpp', 'test_to_wstring.cpp', + 'test_tuple.cpp', 'test_type_def.cpp', + 'test_type_list.cpp', 'test_type_lookup.cpp', 'test_type_select.cpp', 'test_type_traits.cpp', 'test_unaligned_type.cpp', - 'test_unaligned_type_constexpr.cpp', + 'test_unaligned_type_ext.cpp', + 'test_uncopyable.cpp', 'test_unordered_map.cpp', 'test_unordered_multimap.cpp', 'test_unordered_multiset.cpp', @@ -265,9 +353,9 @@ etl_test_sources = files( 'test_utility.cpp', 'test_variance.cpp', 'test_variant_legacy.cpp', - 'test_variant_variadic.cpp', 'test_variant_pool.cpp', 'test_variant_pool_external_buffer.cpp', + 'test_variant_variadic.cpp', 'test_vector.cpp', 'test_vector_external_buffer.cpp', 'test_vector_non_trivial.cpp', @@ -280,24 +368,26 @@ etl_test_sources = files( compile_args = [ '-DENABLE_ETL_UNIT_TESTS', - '-DETL_DEBUG', ] link_args = [] if get_option('use_stl') compile_args += '-DETL_NO_STL=0' -elif +else compile_args += '-DETL_NO_STL=1' endif if meson.get_compiler('cpp').get_argument_syntax() == 'gcc' - compile_args += '-fsanitize=address,undefined' compile_args += '-fexceptions' compile_args += '-Wall' - compile_args += '-Wextra' + compile_args += '-Wextra' compile_args += '-Wno-non-virtual-dtor' #TODO remove and fix warning in code compile_args += '-Werror' - link_args += '-fsanitize=address,undefined' + + if get_option('enable_sanitizer') + compile_args += '-fsanitize=address,undefined' + link_args += '-fsanitize=address,undefined' + endif endif threads_dep = dependency('threads') diff --git a/test/run-coverage.sh b/test/run-coverage.sh index ef977f17..bf795262 100755 --- a/test/run-coverage.sh +++ b/test/run-coverage.sh @@ -44,7 +44,7 @@ mkdir -p "$BUILD" cd "$BUILD" || exit 1 touch total.info -for CXXSTD in 11 14 17 20 23; do +for CXXSTD in 11 14 17 20 23 26; do for NOSTL in OFF ON; do rm -rf CMakeFiles cmake -DEXTRA_COMPILE_OPTIONS="--coverage" \ @@ -58,7 +58,7 @@ for CXXSTD in 11 14 17 20 23; do -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF \ -DETL_OPTIMISATION=-O0 \ -DETL_CXX_STANDARD=$CXXSTD \ - -DETL_ENABLE_SANITIZER=Off \ + -DETL_ENABLE_SANITIZER=OFF \ -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF \ -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON .. cmake --build . @@ -76,6 +76,7 @@ for CXXSTD in 11 14 17 20 23; do done genhtml total.info --output-directory coverage --rc "genhtml_branch_coverage=1" --branch-coverage -t $COMPILER \ - --ignore-errors inconsistent + --ignore-errors inconsistent \ + --ignore-errors category cd .. diff --git a/test/run-syntax-checks.sh b/test/run-syntax-checks.sh index 18a65523..f2cc75e5 100755 --- a/test/run-syntax-checks.sh +++ b/test/run-syntax-checks.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash clear echo -e @@ -47,7 +47,7 @@ PrintHelp() echo "$HelpColour" echo "----------------------------------------------------------------------------------" echo " Syntax : ./runtests.sh " - echo " C++ Standard : a, 03, 11, 14, 17, 20 or 23 (a = All standards) " + echo " C++ Standard : a, 03, 11, 14, 17, 20, 23 or 26 (a = All standards) " echo " Threads : Number of threads to use. Default = 4 " echo " Compiler select : gcc or clang. Default All compilers " echo "----------------------------------------------------------------------------------" @@ -101,6 +101,8 @@ elif [ "$1" = "20" ]; then requested_cxx_standard="20" elif [ "$1" = "23" ]; then requested_cxx_standard="23" +elif [ "$1" = "26" ]; then + requested_cxx_standard="26" elif [ "$1" = "A" ]; then requested_cxx_standard="All" elif [ "$1" = "a" ]; then @@ -288,8 +290,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -305,8 +307,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -533,8 +535,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -550,8 +552,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -777,8 +779,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -794,8 +796,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1021,8 +1023,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1038,8 +1040,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1265,8 +1267,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1282,8 +1284,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1509,8 +1511,8 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. -cmake --build bgcc +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang if [ $? -eq 0 ]; then PassedCompilation else @@ -1526,7 +1528,30 @@ PrintHeader rm -rdf bgcc rm -rdf bclang cmake -E make_directory bgcc bclang -CC=clang CXX=clang++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +fi + +############################################################################### +if [ "$requested_cxx_standard" = "26" ] || [ "$requested_cxx_standard" = "All" ]; then +SetCxxStandard "26" + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. cmake --build bgcc if [ $? -eq 0 ]; then PassedCompilation @@ -1536,6 +1561,193 @@ else fi fi +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Force C++03" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Force C++03" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Force C++03" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Force C++03" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Built-in traits" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "gcc" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Built-in traits" +compiler=$gcc_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=gcc CXX=g++ cmake -E chdir bgcc cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bgcc +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "STL - Built-in traits" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + +if [ "$compiler_enabled" = "clang" ] || [ "$compiler_enabled" = "All compilers" ]; then +SetConfigurationName "No STL - Built-in traits" +compiler=$clang_compiler +PrintHeader +rm -rdf bgcc +rm -rdf bclang +cmake -E make_directory bgcc bclang +CC=clang CXX=clang++ cmake -E chdir bclang cmake -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=ON -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=$cxx_standard .. +cmake --build bclang +if [ $? -eq 0 ]; then + PassedCompilation +else + FailedCompilation + exit $? +fi +fi + fi ChecksCompleted diff --git a/test/run-tests.sh b/test/run-tests.sh index 06e39400..ba309963 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -2,6 +2,8 @@ shopt -s xpg_echo +set -e + clear export ASAN_OPTIONS=symbol_line=1 @@ -54,7 +56,7 @@ PrintHelp() echo "$HelpColour" echo "----------------------------------------------------------------------------------------------------------" echo " Syntax : ./run-tests.sh " - echo " C++ Standard : 11, 14, 17, 20 or 23 " + echo " C++ Standard : 11, 14, 17, 20, 23, 26 or all " echo " Optimisation : 0, 1, 2 or 3. Default = 0 " echo " Threads : Number of threads to use. Default = 4 " echo " Sanitizer : s enables sanitizer checks, n disables. Default disabled " @@ -115,15 +117,19 @@ TestsCompleted() # Set the language standard. #****************************************************************************** if [ "$1" = "11" ]; then - cxx_standard="11" + cxx_standards="11" elif [ "$1" = "14" ]; then - cxx_standard="14" + cxx_standards="14" elif [ "$1" = "17" ]; then - cxx_standard="17" + cxx_standards="17" elif [ "$1" = "20" ]; then - cxx_standard="20" + cxx_standards="20" elif [ "$1" = "23" ]; then - cxx_standard="23" + cxx_standards="23" +elif [ "$1" = "26" ]; then + cxx_standards="26" +elif [ "$1" = "all" ]; then + cxx_standards="11 14 17 20 23 26" else PrintHelp exit @@ -157,11 +163,11 @@ fi # Set the sanitizer enable. Default OFF #****************************************************************************** if [ "$4" = "s" ]; then - sanitize="On" + sanitize="ON" elif [ "$4" = "n" ]; then - sanitize="Off" + sanitize="OFF" else - sanitize="Off" + sanitize="OFF" fi #****************************************************************************** @@ -180,10 +186,10 @@ fi #****************************************************************************** if [ "$6" = "v" ]; then verbose="On" - verbose_flag="-v" + verbose_cmake_flag="-DEXTRA_TESTING_FLAGS=-v" else verbose="Off" - verbose_flag="" + verbose_cmake_flag="" fi #****************************************************************************** @@ -196,66 +202,66 @@ etl_version=$(echo $etl_version_raw | sed -e 's/\r//g') # Remove trailing \r # Get the compiler versions #****************************************************************************** -while read i ; do - CC=`echo $i | cut -d, -f1 | sed -e 's/ *$//'` - MSG=`echo $i | cut -d, -f2 | sed -e 's/ *$//'` - DIR=`echo $i | cut -d, -f3 | sed -e 's/ *$//'` - CMD=`echo $i | cut -d, -f4 | sed -e 's/ *$//'` +for cxx_standard in $cxx_standards ; do + while read i ; do + CC=`echo $i | cut -d, -f1 | sed -e 's/ *$//'` + MSG=`echo $i | cut -d, -f2 | sed -e 's/ *$//'` + DIR=`echo $i | cut -d, -f3 | sed -e 's/ *$//'` + CMD=`echo $i | cut -d, -f4 | sed -e 's/ *$//'` - if [ "$compiler_enabled" = "$CC" ] || [ "$compiler_enabled" = "All compilers" ]; then - if [ "$CC" = "gcc" ] ; then - compiler=$(g++ --version | grep g++) - else - compiler=$(clang++ --version | grep clang) + if [ "$compiler_enabled" = "$CC" ] || [ "$compiler_enabled" = "All compilers" ]; then + if [ "$CC" = "gcc" ] ; then + compiler=$(g++ --version | grep g++) + else + compiler=$(clang++ --version | grep clang) + fi + OLD_DIR=`pwd` + cd $DIR + mkdir -p build-make || exit 1 + cd build-make || exit 1 + echo "ETL Tests" > log.txt + SetConfigurationName "$MSG" + PrintHeader + $CMD + if cmake --build .; then + PassedCompilation + else + FailedCompilation + exit 1 + fi + if ctest -V; then + PassedTests + else + FailedTests + exit 1 + fi + cd .. + rm -rf build-make + cd $OLD_DIR fi - OLD_DIR=`pwd` - cd $DIR - mkdir -p build-make || exit 1 - cd build-make || exit 1 - echo "ETL Tests" > log.txt - SetConfigurationName "$MSG" - PrintHeader - $CMD - cmake --build . - if [ $? -eq 0 ]; then - PassedCompilation - else - FailedCompilation - exit $? - fi - ./etl_tests $verbose_flag - if [ $? -eq 0 ]; then - PassedTests - else - FailedTests - exit $? - fi - cd .. - rm -rf build-make - cd $OLD_DIR - fi -done <<-EOF -gcc ,STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,STL - Non-virtual messages,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=ON .. -gcc ,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -gcc ,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON .. -clang,STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF .. -clang,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON .. -gcc ,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -gcc ,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. -clang,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize .. + done <<-EOF +gcc ,STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,STL - Non-virtual messages,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=ON $verbose_cmake_flag .. +gcc ,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +gcc ,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON $verbose_cmake_flag .. +clang,STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL - Force C++03 ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=ON -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF $verbose_cmake_flag .. +clang,No STL - Builtin mem functions ,.,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize -DETL_MESSAGES_ARE_NOT_VIRTUAL=OFF -DETL_USE_BUILTIN_MEM_FUNCTIONS=ON $verbose_cmake_flag .. +gcc ,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Initializer list test ,etl_initializer_list,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +gcc ,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'log_errors' test,etl_error_handler/log_errors ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'exceptions' test,etl_error_handler/exceptions ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'log_errors and exceptions' test,etl_error_handler/log_errors_and_exceptions,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. +clang,Error macros 'assert function' test,etl_error_handler/assert_function ,cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DETL_OPTIMISATION=$opt -DETL_CXX_STANDARD=$cxx_standard -DETL_ENABLE_SANITIZER=$sanitize $verbose_cmake_flag .. EOF +done TestsCompleted diff --git a/test/syntax_check/BUILD.bazel b/test/syntax_check/BUILD.bazel new file mode 100644 index 00000000..d53fc053 --- /dev/null +++ b/test/syntax_check/BUILD.bazel @@ -0,0 +1,18 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "syntax_check", + srcs = glob( + ["*.t.cpp"], + ), + hdrs = ["etl_profile.h"], + copts = [ + "-Itest/syntax_check", + "-pedantic-errors", + "-Wall", + "-Wextra", + "-Werror", + "-Wextra-semi", + ], + deps = ["//:etl"], +) diff --git a/test/syntax_check/CMakeLists.txt b/test/syntax_check/CMakeLists.txt index 0e2627df..11f3fbe6 100644 --- a/test/syntax_check/CMakeLists.txt +++ b/test/syntax_check/CMakeLists.txt @@ -27,6 +27,10 @@ if (ETL_FORCE_TEST_CPP03_IMPLEMENTATION) add_definitions(-DETL_FORCE_TEST_CPP03_IMPLEMENTATION) endif() +# Override the compile rule to use -fsyntax-only instead of -c, +# since this project only checks syntax and doesn't produce object files. +set(CMAKE_CXX_COMPILE_OBJECT " -fsyntax-only ") + add_library(tests OBJECT) target_compile_definitions(tests PRIVATE __STDC_LIMIT_MACROS __STDC_CONSTANT_MACROS __STDC_FORMAT_MACROS) target_include_directories(tests PRIVATE "") @@ -38,7 +42,6 @@ set_target_properties(tests PROPERTIES if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") target_compile_options(tests PRIVATE - -fsyntax-only -pedantic-errors -Werror -Wextra-semi @@ -47,7 +50,6 @@ endif () if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options(tests PRIVATE - -fsyntax-only -pedantic-errors -Werror -Wextra-semi @@ -74,9 +76,25 @@ elseif (ETL_CXX_STANDARD MATCHES "17") elseif (ETL_CXX_STANDARD MATCHES "20") message(STATUS "Compiling for C++20") set_property(TARGET tests PROPERTY CXX_STANDARD 20) +elseif (ETL_CXX_STANDARD MATCHES "23") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + message(STATUS "Compiling for C++23") + set_property(TARGET tests PROPERTY CXX_STANDARD 23) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++23, falling back to C++20") + set_property(TARGET tests PROPERTY CXX_STANDARD 20) + endif() +elseif (ETL_CXX_STANDARD MATCHES "26") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + message(STATUS "Compiling for C++26") + set_property(TARGET tests PROPERTY CXX_STANDARD 26) + else() + message(STATUS "CMake version ${CMAKE_VERSION} does not support C++26, falling back to C++23") + set_property(TARGET tests PROPERTY CXX_STANDARD 23) + endif() else() - message(STATUS "Compiling for C++23") - set_property(TARGET tests PROPERTY CXX_STANDARD 23) + message(STATUS "Compiling for C++17") + set_property(TARGET tests PROPERTY CXX_STANDARD 17) endif() target_sources(tests PRIVATE @@ -115,6 +133,10 @@ target_sources(tests PRIVATE checksum.h.t.cpp chrono.h.t.cpp concepts.h.t.cpp + const_map.h.t.cpp + const_multimap.h.t.cpp + const_multiset.h.t.cpp + const_set.h.t.cpp circular_buffer.h.t.cpp circular_iterator.h.t.cpp closure.h.t.cpp @@ -163,6 +185,7 @@ target_sources(tests PRIVATE crc32_q.h.t.cpp crc32_xfer.h.t.cpp crc64_ecma.h.t.cpp + crc64_iso.h.t.cpp crc8_ccitt.h.t.cpp crc8_cdma2000.h.t.cpp crc8_darc.h.t.cpp @@ -174,6 +197,7 @@ target_sources(tests PRIVATE crc8_j1850_zero.h.t.cpp crc8_maxim.h.t.cpp crc8_opensafety.h.t.cpp + crc8_nrsc5.h.t.cpp crc8_rohc.h.t.cpp crc8_wcdma.h.t.cpp cyclic_value.h.t.cpp @@ -215,6 +239,7 @@ target_sources(tests PRIVATE histogram.h.t.cpp ihash.h.t.cpp imemory_block_allocator.h.t.cpp + index_of_type.h.t.cpp indirect_vector.h.t.cpp initializer_list.h.t.cpp inplace_function.h.t.cpp @@ -239,6 +264,7 @@ target_sources(tests PRIVATE list.h.t.cpp log.h.t.cpp macros.h.t.cpp + manchester.h.t.cpp map.h.t.cpp math.h.t.cpp math_constants.h.t.cpp @@ -284,6 +310,7 @@ target_sources(tests PRIVATE poly_span.h.t.cpp pool.h.t.cpp power.h.t.cpp + print.h.t.cpp priority_queue.h.t.cpp pseudo_moving_average.h.t.cpp quantize.h.t.cpp @@ -295,6 +322,7 @@ target_sources(tests PRIVATE queue_spsc_locked.h.t.cpp radix.h.t.cpp random.h.t.cpp + ranges.h.t.cpp ratio.h.t.cpp reference_counted_message.h.t.cpp reference_counted_message_pool.h.t.cpp @@ -306,6 +334,7 @@ target_sources(tests PRIVATE rescale.h.t.cpp result.h.t.cpp rms.h.t.cpp + rounded_integral_division.h.t.cpp scaled_rounding.h.t.cpp scheduler.h.t.cpp set.h.t.cpp @@ -337,6 +366,7 @@ target_sources(tests PRIVATE to_wstring.h.t.cpp tuple.h.t.cpp type_def.h.t.cpp + type_list.h.t.cpp type_lookup.h.t.cpp type_select.h.t.cpp type_traits.h.t.cpp diff --git a/test/syntax_check/const_map.h.t.cpp b/test/syntax_check/const_map.h.t.cpp new file mode 100644 index 00000000..db4a753c --- /dev/null +++ b/test/syntax_check/const_map.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_multimap.h.t.cpp b/test/syntax_check/const_multimap.h.t.cpp new file mode 100644 index 00000000..da38716c --- /dev/null +++ b/test/syntax_check/const_multimap.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_multiset.h.t.cpp b/test/syntax_check/const_multiset.h.t.cpp new file mode 100644 index 00000000..12b01a8a --- /dev/null +++ b/test/syntax_check/const_multiset.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/const_set.h.t.cpp b/test/syntax_check/const_set.h.t.cpp new file mode 100644 index 00000000..1b73c9af --- /dev/null +++ b/test/syntax_check/const_set.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/crc64_iso.h.t.cpp b/test/syntax_check/crc64_iso.h.t.cpp new file mode 100644 index 00000000..a78f5430 --- /dev/null +++ b/test/syntax_check/crc64_iso.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/crc8_nrsc5.h.t.cpp b/test/syntax_check/crc8_nrsc5.h.t.cpp new file mode 100644 index 00000000..4dc725dd --- /dev/null +++ b/test/syntax_check/crc8_nrsc5.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/etl_profile.h b/test/syntax_check/etl_profile.h index ed633219..deee267c 100644 --- a/test/syntax_check/etl_profile.h +++ b/test/syntax_check/etl_profile.h @@ -31,7 +31,6 @@ SOFTWARE. #define ETL_TARGET_DEVICE_GENERIC #define ETL_TARGET_OS_NONE -#define ETL_IN_UNIT_TEST #define ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK #define ETL_CALLBACK_TIMER_DISABLE_INTERRUPTS #define ETL_CALLBACK_TIMER_ENABLE_INTERRUPTS diff --git a/test/syntax_check/index_of_type.h.t.cpp b/test/syntax_check/index_of_type.h.t.cpp new file mode 100644 index 00000000..0e854960 --- /dev/null +++ b/test/syntax_check/index_of_type.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/manchester.h.t.cpp b/test/syntax_check/manchester.h.t.cpp new file mode 100644 index 00000000..4e86c4f1 --- /dev/null +++ b/test/syntax_check/manchester.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/print.h.t.cpp b/test/syntax_check/print.h.t.cpp new file mode 100644 index 00000000..4fe9432b --- /dev/null +++ b/test/syntax_check/print.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/ranges.h.t.cpp b/test/syntax_check/ranges.h.t.cpp new file mode 100644 index 00000000..41861be9 --- /dev/null +++ b/test/syntax_check/ranges.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/rounded_integral_division.h.t.cpp b/test/syntax_check/rounded_integral_division.h.t.cpp new file mode 100644 index 00000000..4c2ea104 --- /dev/null +++ b/test/syntax_check/rounded_integral_division.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/syntax_check/type_list.h.t.cpp b/test/syntax_check/type_list.h.t.cpp new file mode 100644 index 00000000..d8fd1469 --- /dev/null +++ b/test/syntax_check/type_list.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 BMW AG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index fa0f4f0e..abc5f734 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -2621,8 +2621,10 @@ namespace for (size_t i = 0UL; i <= initial_data.size(); ++i) { +#include "etl/private/diagnostic_null_dereference_push.h" std::vector data1(initial_data); std::vector data2(initial_data); +#include "etl/private/diagnostic_pop.h" auto std_result = std::rotate(data1.data(), data1.data() + i, data1.data() + data1.size()); auto etl_result = etl::rotate(data2.data(), data2.data() + i, data2.data() + data2.size()); @@ -2658,8 +2660,10 @@ namespace for (size_t i = 0UL; i <= initial_data.size(); ++i) { +#include "etl/private/diagnostic_null_dereference_push.h" std::vector data1(initial_data); std::vector data2(initial_data); +#include "etl/private/diagnostic_pop.h" auto std_result = std::rotate(data1.data(), data1.data() + i, data1.data() + data1.size()); diff --git a/test/test_atomic.cpp b/test/test_atomic.cpp index 2128332b..9870caf8 100644 --- a/test/test_atomic.cpp +++ b/test/test_atomic.cpp @@ -488,6 +488,72 @@ namespace CHECK_EQUAL(compare.fetch_xor(0x55AA55AAUL), test.fetch_xor(0x55AA55AAUL)); } + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_greater) + { + etl::atomic test(10); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(10, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_less) + { + etl::atomic test(30); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(30, old_value); + CHECK_EQUAL(30, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_max_when_new_value_is_equal) + { + etl::atomic test(20); + + int old_value = test.fetch_max(20); + + CHECK_EQUAL(20, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_less) + { + etl::atomic test(30); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(30, old_value); + CHECK_EQUAL(20, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_greater) + { + etl::atomic test(10); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(10, old_value); + CHECK_EQUAL(10, test.load()); + } + + //************************************************************************* + TEST(test_atomic_operator_fetch_min_when_new_value_is_equal) + { + etl::atomic test(20); + + int old_value = test.fetch_min(20); + + CHECK_EQUAL(20, old_value); + CHECK_EQUAL(20, test.load()); + } + //************************************************************************* TEST(test_atomic_integer_exchange) { diff --git a/test/test_binary.cpp b/test/test_binary.cpp index d2c772e6..acbdd7fa 100644 --- a/test/test_binary.cpp +++ b/test/test_binary.cpp @@ -3040,6 +3040,108 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), output.data(), expected.size()); } + + //************************************************************************* + TEST(test_count_leading_zeros_signed_32) + { + // int32_t(-1) = 0xFFFFFFFF → 0 leading zeros + CHECK_EQUAL(0, int(etl::count_leading_zeros(int32_t(-1)))); + + // int32_t(1) = 0x00000001 → 31 leading zeros + CHECK_EQUAL(31, int(etl::count_leading_zeros(int32_t(1)))); + + // int32_t(0) = 0x00000000 → 32 leading zeros + CHECK_EQUAL(32, int(etl::count_leading_zeros(int32_t(0)))); + + // int32_t(256) = 0x00000100 → 23 leading zeros + CHECK_EQUAL(23, int(etl::count_leading_zeros(int32_t(256)))); + + // Verify against unsigned version + for (int i = 0; i < 32; ++i) + { + int32_t value = int32_t(1) << i; + CHECK_EQUAL(int(etl::count_leading_zeros(uint32_t(value))), int(etl::count_leading_zeros(value))); + } + } + + //************************************************************************* + TEST(test_count_leading_zeros_signed_64) + { + CHECK_EQUAL(0, int(etl::count_leading_zeros(int64_t(-1)))); + CHECK_EQUAL(63, int(etl::count_leading_zeros(int64_t(1)))); + CHECK_EQUAL(64, int(etl::count_leading_zeros(int64_t(0)))); + + for (int i = 0; i < 64; ++i) + { + int64_t value = int64_t(1) << i; + CHECK_EQUAL(int(etl::count_leading_zeros(uint64_t(value))), int(etl::count_leading_zeros(value))); + } + } + + //************************************************************************* + TEST(test_count_leading_zeros_64_specific_values) + { + // Value that specifically triggers the upper-32-bit mask path + // Bit 35 set: 0x0000000800000000 → 28 leading zeros + CHECK_EQUAL(28, int(etl::count_leading_zeros(uint64_t(0x0000000800000000ULL)))); + // Bit 31 set: 0x0000000080000000 → 32 leading zeros + CHECK_EQUAL(32, int(etl::count_leading_zeros(uint64_t(0x0000000080000000ULL)))); + // All zeros in upper 32: 0x00000000FFFFFFFF → 32 leading zeros + CHECK_EQUAL(32, int(etl::count_leading_zeros(uint64_t(0x00000000FFFFFFFFULL)))); + // Upper half has bit: 0x0000000100000000 → 31 leading zeros + CHECK_EQUAL(31, int(etl::count_leading_zeros(uint64_t(0x0000000100000000ULL)))); + } + + //************************************************************************* + TEST(test_count_leading_ones_32_specific_values) + { + // 0xFFFF0000 → upper 16 bits set → exactly 16 leading ones + CHECK_EQUAL(16, int(etl::count_leading_ones(uint32_t(0xFFFF0000UL)))); + // 0xFFFF8000 → 17 leading ones + CHECK_EQUAL(17, int(etl::count_leading_ones(uint32_t(0xFFFF8000UL)))); + // 0xFFFFF000 → 20 leading ones + CHECK_EQUAL(20, int(etl::count_leading_ones(uint32_t(0xFFFFF000UL)))); + // 0xFFFFFF00 → 24 leading ones + CHECK_EQUAL(24, int(etl::count_leading_ones(uint32_t(0xFFFFFF00UL)))); + // 0xFFFFFFFE → 31 leading ones + CHECK_EQUAL(31, int(etl::count_leading_ones(uint32_t(0xFFFFFFFEUL)))); + // 0xFFFFFFFF → 32 leading ones + CHECK_EQUAL(32, int(etl::count_leading_ones(uint32_t(0xFFFFFFFFUL)))); + // 0x80000000 → 1 leading one + CHECK_EQUAL(1, int(etl::count_leading_ones(uint32_t(0x80000000UL)))); + + // Verify against reference for boundary values + for (uint32_t i = 0; i < 33; ++i) + { + // Create value with exactly 'i' leading ones + uint32_t value = (i == 0) ? 0U : (i == 32) ? 0xFFFFFFFFUL : ~((1UL << (32U - i)) - 1UL); + CHECK_EQUAL(int(test_leading_ones(value)), int(etl::count_leading_ones(value))); + } + } + + //************************************************************************* + TEST(test_count_leading_ones_64_specific_values) + { + // 0xFFFFFFFF00000000 → 32 leading ones + CHECK_EQUAL(32, int(etl::count_leading_ones(uint64_t(0xFFFFFFFF00000000ULL)))); + // 0xFFFFFFFFFFFF0000 → 48 leading ones + CHECK_EQUAL(48, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFF0000ULL)))); + // 0xFFFF000000000000 → 16 leading ones + CHECK_EQUAL(16, int(etl::count_leading_ones(uint64_t(0xFFFF000000000000ULL)))); + // 0xFFFFFFFFFFFFFF00 → 56 leading ones + CHECK_EQUAL(56, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFF00ULL)))); + // 0xFFFFFFFFFFFFFFFE → 63 leading ones + CHECK_EQUAL(63, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFFFEULL)))); + // 0xFFFFFFFFFFFFFFFF → 64 leading ones + CHECK_EQUAL(64, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFFFFULL)))); + + // Verify against reference for boundary values + for (uint64_t i = 0; i < 65; ++i) + { + uint64_t value = (i == 0) ? 0ULL : (i == 64) ? 0xFFFFFFFFFFFFFFFFULL : ~((1ULL << (64ULL - i)) - 1ULL); + CHECK_EQUAL(int(test_leading_ones(value)), int(etl::count_leading_ones(value))); + } + } } } // namespace diff --git a/test/test_bit_stream.cpp b/test/test_bit_stream.cpp index 2c515224..d7e1cdbc 100644 --- a/test/test_bit_stream.cpp +++ b/test/test_bit_stream.cpp @@ -869,7 +869,7 @@ namespace TEST(put_get_multiple_full_size) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085L; // 0x5AA55AA5 diff --git a/test/test_bit_stream_writer_big_endian.cpp b/test/test_bit_stream_writer_big_endian.cpp index 893a5f04..c22e66db 100644 --- a/test/test_bit_stream_writer_big_endian.cpp +++ b/test/test_bit_stream_writer_big_endian.cpp @@ -614,7 +614,7 @@ namespace TEST(test_write_multiple_full_size) { char c1 = 90; // 0x5A - char c2 = -91; // 0xA5 + char c2 = static_cast(-91); // 0xA5 unsigned short s1 = 4660; // 0x1234 unsigned short s2 = 22136; // 0x5678 int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF @@ -660,7 +660,7 @@ namespace TEST(test_write_multiple_variable_size) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits @@ -705,7 +705,7 @@ namespace Accumulator accumulator; char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660U; // 0x1234 13 bits unsigned short s2 = 22136U; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits diff --git a/test/test_bit_stream_writer_little_endian.cpp b/test/test_bit_stream_writer_little_endian.cpp index 1d6f85d5..07348253 100644 --- a/test/test_bit_stream_writer_little_endian.cpp +++ b/test/test_bit_stream_writer_little_endian.cpp @@ -702,7 +702,7 @@ namespace TEST(test_write_multiple_full_size) { char c1 = 90; // 0x5A - char c2 = -91; // 0xA5 + char c2 = static_cast(-91); // 0xA5 unsigned short s1 = 4660; // 0x1234 unsigned short s2 = 22136; // 0x5678 int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF @@ -748,7 +748,7 @@ namespace TEST(test_write_multiple_variable_size) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits @@ -791,7 +791,7 @@ namespace TEST(test_write_multiple_variable_size_with_callback) { char c1 = 90; // 0x5A 6 bits - char c2 = -91; // 0xA5 7 bits + char c2 = static_cast(-91); // 0xA5 7 bits unsigned short s1 = 4660; // 0x1234 13 bits unsigned short s2 = 22136; // 0x5678 11 bits int32_t i1 = static_cast(0x89ABCDEFU); // 0x89ABCDEF 23 bits diff --git a/test/test_bsd_checksum.cpp b/test/test_bsd_checksum.cpp index 9274b112..f95dcf12 100644 --- a/test/test_bsd_checksum.cpp +++ b/test/test_bsd_checksum.cpp @@ -50,7 +50,7 @@ namespace for (size_t i = 0UL; i < sizeof(value_type); ++i) { - uint8_t byte = static_cast((static_cast(value) >> (i * 8UL)) & 0xFFU); + uint8_t byte = static_cast((static_cast(value) >> (i * 8U)) & 0xFFU); checksum = etl::rotate_right(checksum) + byte; } } diff --git a/test/test_byte_stream.cpp b/test/test_byte_stream.cpp index 29570ac1..06b2a453 100644 --- a/test/test_byte_stream.cpp +++ b/test/test_byte_stream.cpp @@ -1026,7 +1026,7 @@ namespace TEST(write_read_multiple_big_endian) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085; // 0x5AA55AA5 @@ -1089,7 +1089,7 @@ namespace TEST(write_read_multiple_little_endian) { char c1 = 90; - char c2 = -91; + char c2 = static_cast(-91); unsigned short s1 = 23205; unsigned short s2 = 42330; int32_t i1 = 1520786085; // 0x5AA55AA5 diff --git a/test/test_chrono_year_month_weekday.cpp b/test/test_chrono_year_month_weekday.cpp index 8079d813..f0ab8500 100644 --- a/test/test_chrono_year_month_weekday.cpp +++ b/test/test_chrono_year_month_weekday.cpp @@ -117,10 +117,30 @@ namespace //************************************************************************* TEST(test_to_sys_days) { - Chrono::year_month_weekday ymwd{Chrono::year(2000), Chrono::February, Chrono::weekday_indexed(Chrono::Thursday, 1)}; - Chrono::sys_days sd = Chrono::sys_days(ymwd); + // 1st Thursday of February 2000 (Feb 3) + Chrono::year_month_weekday ymwd1{Chrono::year(2000), Chrono::February, Chrono::weekday_indexed(Chrono::Thursday, 1)}; + Chrono::sys_days sd1 = Chrono::sys_days(ymwd1); + CHECK_EQUAL(10990, sd1.time_since_epoch().count()); - CHECK_EQUAL(10990, sd.time_since_epoch().count()); + // 2nd Wednesday of March 2000 (Mar 8) + Chrono::year_month_weekday ymwd2{Chrono::year(2000), Chrono::March, Chrono::weekday_indexed(Chrono::Wednesday, 2)}; + Chrono::sys_days sd2 = Chrono::sys_days(ymwd2); + CHECK_EQUAL(11024, sd2.time_since_epoch().count()); + + // 1st Sunday of January 2000 (Jan 2) + Chrono::year_month_weekday ymwd3{Chrono::year(2000), Chrono::January, Chrono::weekday_indexed(Chrono::Sunday, 1)}; + Chrono::sys_days sd3 = Chrono::sys_days(ymwd3); + CHECK_EQUAL(10958, sd3.time_since_epoch().count()); + + // 3rd Friday of June 1985 (Jun 21) + Chrono::year_month_weekday ymwd4{Chrono::year(1985), Chrono::June, Chrono::weekday_indexed(Chrono::Friday, 3)}; + Chrono::sys_days sd4 = Chrono::sys_days(ymwd4); + CHECK_EQUAL(5650, sd4.time_since_epoch().count()); + + // 2nd Wednesday of March 2024 (Mar 13) + Chrono::year_month_weekday ymwd5{Chrono::year(2024), Chrono::March, Chrono::weekday_indexed(Chrono::Wednesday, 2)}; + Chrono::sys_days sd5 = Chrono::sys_days(ymwd5); + CHECK_EQUAL(19795, sd5.time_since_epoch().count()); } //************************************************************************* diff --git a/test/test_chrono_year_month_weekday_last.cpp b/test/test_chrono_year_month_weekday_last.cpp index 7050903f..bbe92619 100644 --- a/test/test_chrono_year_month_weekday_last.cpp +++ b/test/test_chrono_year_month_weekday_last.cpp @@ -73,7 +73,7 @@ namespace Chrono::year_month_weekday_last ymwdl{Chrono::year(2000), Chrono::February, Chrono::weekday_last(Chrono::Thursday)}; Chrono::sys_days sd = Chrono::sys_days(ymwdl); - CHECK_EQUAL(11012, sd.time_since_epoch().count()); + CHECK_EQUAL(11011, sd.time_since_epoch().count()); } //************************************************************************* diff --git a/test/test_circular_buffer.cpp b/test/test_circular_buffer.cpp index a9897e43..34452537 100644 --- a/test/test_circular_buffer.cpp +++ b/test/test_circular_buffer.cpp @@ -1072,5 +1072,30 @@ namespace CHECK(!is_equal); } + + //************************************************************************* + TEST(test_move_assignment_actually_moves) + { + DataM data; + data.push(ItemM("A")); + data.push(ItemM("B")); + data.push(ItemM("C")); + + DataM data2; + data2 = std::move(data); + + CHECK_EQUAL(3U, data2.size()); + + // If the move was correct, data2 should hold the moved-to values + CHECK_EQUAL("A", data2[0].value); + CHECK_EQUAL("B", data2[1].value); + CHECK_EQUAL("C", data2[2].value); + + // Original should be moved-from (empty strings with move-only type) + for (size_t i = 0; i < data.size(); ++i) + { + CHECK(data[i].value.empty()); + } + } } } // namespace diff --git a/test/test_closure.cpp b/test/test_closure_with_default_delegate.cpp similarity index 99% rename from test/test_closure.cpp rename to test/test_closure_with_default_delegate.cpp index 3e01ca8b..a7ef4f35 100644 --- a/test/test_closure.cpp +++ b/test/test_closure_with_default_delegate.cpp @@ -34,7 +34,7 @@ SOFTWARE. namespace { - SUITE(test_closure) + SUITE(test_closure_with_default_delegate) { int f1(int a1) { diff --git a/test/test_closure_constexpr.cpp b/test/test_closure_with_default_delegate_constexpr.cpp similarity index 99% rename from test/test_closure_constexpr.cpp rename to test/test_closure_with_default_delegate_constexpr.cpp index 73c4b68c..57dcc18d 100644 --- a/test/test_closure_constexpr.cpp +++ b/test/test_closure_with_default_delegate_constexpr.cpp @@ -34,7 +34,7 @@ SOFTWARE. namespace { - SUITE(test_closure) + SUITE(test_closure_with_default_delegate_constexpr) { static constexpr int f1(int a1) { diff --git a/test/test_closure_with_inplace_function.cpp b/test/test_closure_with_inplace_function.cpp new file mode 100644 index 00000000..cd67ffba --- /dev/null +++ b/test/test_closure_with_inplace_function.cpp @@ -0,0 +1,208 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2025 BMW AG, John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/closure.h" +#include "etl/inplace_function.h" + +#include + +namespace +{ + SUITE(test_closure_with_inplace_function) + { + int f1(int a1) + { + return a1 * 3; + } + + int f1_throwing(int) + { + throw std::runtime_error("throwing function"); + } + + void f1_void(int) {} + + int f1_ref(int& a1) + { + return a1 * 3; + } + + int f2(int a1, int a2) + { + return a1 * 3 + a2; + } + + int f3(int a1, int a2, int a3) + { + return a1 * 3 + a2 * a3; + } + + int f4(int a1, int a2, int a3, int a4) + { + return a1 * 3 + a2 * a3 + a4; + } + + int f5(int a1, int a2, int a3, int a4, int a5) + { + return a1 * 3 + a2 * a3 + a4 * a5; + } + + using f1_type = int(int); + using f1_ref_type = int(int&); + using f1_void_type = void(int); + using f2_type = int(int, int); + using f3_type = int(int, int, int); + using f4_type = int(int, int, int, int); + using f5_type = int(int, int, int, int, int); + + using ipf1_type = etl::inplace_function; + using ipf1_ref_type = etl::inplace_function; + using ipf1_void_type = etl::inplace_function; + using ipf2_type = etl::inplace_function; + using ipf3_type = etl::inplace_function; + using ipf4_type = etl::inplace_function; + using ipf5_type = etl::inplace_function; + + ipf1_type ipf1 = ipf1_type::create<&f1>(); + ipf1_type ipf1_throwing = ipf1_type::create<&f1_throwing>(); + ipf1_ref_type ipf1_ref = ipf1_ref_type::create<&f1_ref>(); + ipf1_void_type ipf1_void = ipf1_void_type::create<&f1_void>(); + ipf2_type ipf2 = ipf2_type::create<&f2>(); + ipf3_type ipf3 = ipf3_type::create<&f3>(); + ipf4_type ipf4 = ipf4_type::create<&f4>(); + ipf5_type ipf5 = ipf5_type::create<&f5>(); + + //************************************************************************* + TEST(test_1_arg) + { + etl::closure c1(ipf1, 4); + CHECK_EQUAL(12, c1()); + } + + //************************************************************************* + TEST(test_1_arg_reference) + { + int v1 = 4; + etl::closure c1_ref(ipf1_ref, v1); + CHECK_EQUAL(12, c1_ref()); + v1 = 5; + CHECK_EQUAL(15, c1_ref()); + } + + //************************************************************************* + TEST(test_1_arg_lambda) + { + auto l = [](int a) + { + return a + 11; + }; + ipf1_type ipf1_lambda(l); + + etl::closure c1_lambda(ipf1_lambda, 5); + CHECK_EQUAL(16, c1_lambda()); + } + + //************************************************************************* + TEST(test_throwing) + { + etl::closure c1(ipf1_throwing, 4); + CHECK_THROW(c1(), std::runtime_error); + } + + //************************************************************************* + TEST(test_void) + { + etl::closure c1(ipf1_void, 4); + c1(); + } + + //************************************************************************* + TEST(test_2_args) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + } + +#if ETL_USING_CPP11 && !defined(ETL_CLOSURE_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + TEST(test_2_args_bind) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + + c2.bind<0>(7); + c2.bind<1>(8); + CHECK_EQUAL(29, c2()); + } + + //************************************************************************* + TEST(test_2_args_bind_all) + { + etl::closure c2(ipf2, 4, 3); + CHECK_EQUAL(15, c2()); + + c2.bind(7, 8); + CHECK_EQUAL(29, c2()); + } +#endif + + //************************************************************************* + TEST(test_3_args) + { + etl::closure c3(ipf3, 4, 3, 2); + CHECK_EQUAL(18, c3()); + } + + //************************************************************************* + TEST(test_4_args) + { + etl::closure c4(ipf4, 4, 3, 2, 1); + CHECK_EQUAL(19, c4()); + } + + //************************************************************************* + TEST(test_5_args) + { + etl::closure c5(ipf5, 4, 3, 2, 1, 5); + CHECK_EQUAL(23, c5()); + } + + //************************************************************************* + TEST(test_bind_static_assert) + { + etl::closure c(ipf2, 1, 2); + + // Uncomment to generate static_assert errors. + // c.bind(1); // Argument count mismatch + // c.bind(1, 2, 3); // Argument count mismatch + // c.bind(1, std::string()); // Argument is not convertible + } + } +} // namespace diff --git a/test/test_concepts.cpp b/test/test_concepts.cpp index 347ec8fb..a6b03830 100644 --- a/test/test_concepts.cpp +++ b/test/test_concepts.cpp @@ -29,6 +29,7 @@ SOFTWARE. #include "unit_test_framework.h" #include +#include #include #if ETL_USING_CPP20 @@ -52,6 +53,65 @@ namespace { }; + struct NotDestructible + { + ~NotDestructible() = delete; + }; + + struct NotDefaultConstructible + { + NotDefaultConstructible(int) {} + }; + + struct NotCopyable + { + NotCopyable() = default; + NotCopyable(const NotCopyable&) = delete; + NotCopyable(NotCopyable&&) = default; + NotCopyable& operator=(const NotCopyable&) = delete; + NotCopyable& operator=(NotCopyable&&) = default; + }; + + struct NotMovable + { + NotMovable() = default; + NotMovable(const NotMovable&) = delete; + NotMovable(NotMovable&&) = delete; + NotMovable& operator=(const NotMovable&) = delete; + NotMovable& operator=(NotMovable&&) = delete; + }; + + struct NotEqualityComparable + { + }; + + struct EqualityComparableType + { + bool operator==(const EqualityComparableType&) const = default; + }; + + struct OrderedType + { + int value; + auto operator<=>(const OrderedType&) const = default; + }; + + struct BoolPredicate + { + bool operator()(int) const + { + return true; + } + }; + + struct IntRelation + { + bool operator()(int, int) const + { + return true; + } + }; + SUITE(test_concepts) { //************************************************************************* @@ -140,6 +200,183 @@ namespace static_assert(etl::assignable_from == false); static_assert(etl::assignable_from&, int> == false); } + + //************************************************************************* + TEST(test_invocable) + { + struct Functor + { + void operator()() {} + }; + struct FunctorWithArgs + { + int operator()(int, double) + { + return 0; + } + }; + + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == true); + static_assert(etl::invocable == false); + static_assert(etl::invocable == false); + } + + //************************************************************************* + TEST(test_regular_invocable) + { + struct Functor + { + void operator()() {} + }; + + static_assert(etl::regular_invocable == true); + static_assert(etl::regular_invocable == true); + static_assert(etl::regular_invocable == false); + } + + //************************************************************************* + TEST(test_destructible) + { + static_assert(etl::destructible == true); + static_assert(etl::destructible == true); + static_assert(etl::destructible == false); + } + + //************************************************************************* + TEST(test_constructible_from) + { + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == true); + static_assert(etl::constructible_from == false); + } + + //************************************************************************* + TEST(test_default_initializable) + { + static_assert(etl::default_initializable == true); + static_assert(etl::default_initializable == true); + static_assert(etl::default_initializable == false); + } + + //************************************************************************* + TEST(test_move_constructible) + { + static_assert(etl::move_constructible == true); + static_assert(etl::move_constructible == true); + static_assert(etl::move_constructible == false); + } + + //************************************************************************* + TEST(test_copy_constructible) + { + static_assert(etl::copy_constructible == true); + static_assert(etl::copy_constructible == true); + static_assert(etl::copy_constructible == false); + } + + //************************************************************************* + TEST(test_equality_comparable) + { + static_assert(etl::equality_comparable == true); + static_assert(etl::equality_comparable == true); + static_assert(etl::equality_comparable == false); + } + + //************************************************************************* + TEST(test_totally_ordered) + { + static_assert(etl::totally_ordered == true); + static_assert(etl::totally_ordered == true); + static_assert(etl::totally_ordered == false); + } + + //************************************************************************* + TEST(test_swappable) + { + static_assert(etl::swappable == true); + static_assert(etl::swappable == true); + static_assert(etl::swappable == false); + } + + //************************************************************************* + TEST(test_swappable_with) + { + // Positive cases: same-type lvalue references that are swappable + static_assert(etl::swappable_with == true); + static_assert(etl::swappable_with == true); + + // Negative cases: unrelated types (no valid swap overload) + static_assert(etl::swappable_with == false); + + // Negative case: non-movable type cannot be swapped + static_assert(etl::swappable_with == false); + } + + //************************************************************************* + TEST(test_movable) + { + static_assert(etl::movable == true); + static_assert(etl::movable == true); + static_assert(etl::movable == false); + } + + //************************************************************************* + TEST(test_copyable) + { + static_assert(etl::copyable == true); + static_assert(etl::copyable == true); + static_assert(etl::copyable == false); + } + + //************************************************************************* + TEST(test_semiregular) + { + static_assert(etl::semiregular == true); + static_assert(etl::semiregular == true); + static_assert(etl::semiregular == false); + } + + //************************************************************************* + TEST(test_regular) + { + static_assert(etl::regular == true); + static_assert(etl::regular == true); + static_assert(etl::regular == false); + } + + //************************************************************************* + TEST(test_predicate) + { + static_assert(etl::predicate == true); + static_assert(etl::predicate == true); + static_assert(etl::predicate == false); + } + + //************************************************************************* + TEST(test_relation) + { + static_assert(etl::relation == true); + static_assert(etl::relation, int, int> == true); + static_assert(etl::relation == false); + } + + //************************************************************************* + TEST(test_equivalence_relation) + { + static_assert(etl::equivalence_relation, int, int> == true); + static_assert(etl::equivalence_relation == false); + } + + //************************************************************************* + TEST(test_strict_weak_order) + { + static_assert(etl::strict_weak_order, int, int> == true); + static_assert(etl::strict_weak_order == false); + } } } // namespace #endif diff --git a/test/test_delegate.cpp b/test/test_delegate.cpp index b8445166..d57ad1f8 100644 --- a/test/test_delegate.cpp +++ b/test/test_delegate.cpp @@ -372,6 +372,27 @@ namespace CHECK_FALSE(d.is_valid()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_is_valid_after_init_empty_braces) + { + etl::delegate d = {}; + + CHECK_FALSE(d.is_valid()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_is_valid_after_assign_empty_braces) + { + auto lambda = [] { + }; + + etl::delegate d(lambda); + + CHECK_TRUE(d.is_valid()); + d = {}; + CHECK_FALSE(d.is_valid()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_free_void) { diff --git a/test/test_deque.cpp b/test/test_deque.cpp index 22abd04a..d26096d1 100644 --- a/test/test_deque.cpp +++ b/test/test_deque.cpp @@ -2272,6 +2272,29 @@ namespace CHECK(std::equal(blank_data.begin(), blank_data.end(), data.begin())); } + + //************************************************************************* + TEST(test_const_iterator_subscript) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + const DataNDC& cdata = data; + + // Access via const_iterator operator[] + DataNDC::const_iterator cit = cdata.begin(); + + // Verify operator[] returns values matching sequential access + for (size_t i = 0; i < cdata.size(); ++i) + { + CHECK(cit[i] == cdata[i]); + } + + // Verify const_iterator operator[] returns const_reference + // (This is a compile-time check - if the fix is reverted, + // the type would be non-const reference which is incorrect for const_iterator) + const NDC& ref = cit[0]; + CHECK(ref == cdata[0]); + } } } // namespace diff --git a/test/test_etl_traits.cpp b/test/test_etl_traits.cpp index 3ddb93fa..a90f073c 100644 --- a/test/test_etl_traits.cpp +++ b/test/test_etl_traits.cpp @@ -49,6 +49,7 @@ namespace CHECK_EQUAL((ETL_USING_CPP17 == 1), etl::traits::using_cpp17); CHECK_EQUAL((ETL_USING_CPP20 == 1), etl::traits::using_cpp20); CHECK_EQUAL((ETL_USING_CPP23 == 1), etl::traits::using_cpp23); + CHECK_EQUAL((ETL_USING_CPP26 == 1), etl::traits::using_cpp26); CHECK_EQUAL((ETL_USING_EXCEPTIONS == 1), etl::traits::using_exceptions); CHECK_EQUAL((ETL_USING_LIBC_WCHAR_H == 1), etl::traits::using_libc_wchar_h); CHECK_EQUAL((ETL_USING_GCC_COMPILER == 1), etl::traits::using_gcc_compiler); @@ -92,7 +93,9 @@ namespace CHECK_EQUAL(ETL_VERSION_MINOR, etl::traits::version_minor); CHECK_EQUAL(ETL_VERSION_PATCH, etl::traits::version_patch); CHECK_EQUAL(ETL_VERSION_VALUE, etl::traits::version); -#if ETL_USING_CPP23 +#if ETL_USING_CPP26 + CHECK_EQUAL(26, etl::traits::language_standard); +#elif ETL_USING_CPP23 CHECK_EQUAL(23, etl::traits::language_standard); #elif ETL_USING_CPP20 CHECK_EQUAL(20, etl::traits::language_standard); diff --git a/test/test_expected.cpp b/test/test_expected.cpp index 024ecf47..621727b2 100644 --- a/test/test_expected.cpp +++ b/test/test_expected.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "etl/expected.h" #include "etl/type_traits.h" +#include #include #include @@ -1477,5 +1478,164 @@ namespace auto with_error_type_check = check_expected_type_helper(unexpected_out); CHECK_TRUE(with_error_type_check); } + + //************************************************************************* + TEST(test_begin_end_with_value) + { + etl::expected exp(std::string("hello")); + + CHECK_TRUE(exp.begin() != exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 1); + CHECK_EQUAL(*exp.begin(), std::string("hello")); + } + + //************************************************************************* + TEST(test_begin_end_with_error) + { + etl::expected exp(etl::unexpected(Error("err"))); + + CHECK_TRUE(exp.begin() == exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 0); + } + + //************************************************************************* + TEST(test_begin_end_const_with_value) + { + const etl::expected exp(std::string("world")); + + CHECK_TRUE(exp.begin() != exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 1); + CHECK_EQUAL(*exp.begin(), std::string("world")); + } + + //************************************************************************* + TEST(test_begin_end_const_with_error) + { + const etl::expected exp(etl::unexpected(Error("err"))); + + CHECK_TRUE(exp.begin() == exp.end()); + CHECK_EQUAL(std::distance(exp.begin(), exp.end()), 0); + } + + //************************************************************************* + TEST(test_range_for_with_value) + { + etl::expected exp(42); + + int count = 0; + int sum = 0; + for (auto& v : exp) + { + ++count; + sum += v; + } + + CHECK_EQUAL(1, count); + CHECK_EQUAL(42, sum); + } + + //************************************************************************* + TEST(test_range_for_with_error) + { + etl::expected exp(etl::unexpected(Error("err"))); + + int count = 0; + for (auto& v : exp) + { + (void)v; + ++count; + } + + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_error_or_with_value) + { + etl::expected exp(42); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_with_error) + { + etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_const_with_value) + { + const etl::expected exp(42); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_const_with_error) + { + const etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_rvalue_with_value) + { + Error result = etl::expected(42).error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_rvalue_with_error) + { + Error result = etl::expected(etl::unexpected(Error("real_error"))).error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_error_or_void_value_with_value) + { + etl::expected exp; + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("default", result.e); + } + + //************************************************************************* + TEST(test_error_or_void_value_with_error) + { + etl::expected exp(etl::unexpected(Error("real_error"))); + + Error result = exp.error_or(Error("default")); + CHECK_EQUAL("real_error", result.e); + } + + //************************************************************************* + TEST(test_unexpected_error_const_rvalue_ref) + { + const etl::unexpected ue(Error("test_error")); + + // Move from const rvalue — should get const Error&& + const Error&& ref = std::move(ue).error(); + CHECK_EQUAL("test_error", ref.e); + } + + //************************************************************************* + TEST(test_transform_error_void_const_rvalue) + { + const etl::expected exp(etl::unexpected(Error("original"))); + + auto result = std::move(exp).transform_error([](const Error& e) { return Error(e.e + "_transformed"); }); + + CHECK_FALSE(result.has_value()); + CHECK_EQUAL("original_transformed", result.error().e); + } } } // namespace diff --git a/test/test_format.cpp b/test/test_format.cpp index 591d83f1..78f2e413 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -203,8 +203,8 @@ namespace etl::string<100> s; CHECK_EQUAL("1.0", test_format(s, "{}", 1.0f)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.234567f)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678f)); + CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345674f)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.2345676f)); CHECK_EQUAL("1.125", test_format(s, "{}", 1.125f)); } @@ -214,8 +214,8 @@ namespace etl::string<100> s; CHECK_EQUAL("1.0", test_format(s, "{}", 1.0)); - CHECK_EQUAL("1.234564", test_format(s, "{}", 1.234564)); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678)); + CHECK_EQUAL("1.234567", test_format(s, "{}", 1.234567499)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.234567501)); CHECK_EQUAL("1.5", test_format(s, "{}", 1.5)); } @@ -227,7 +227,7 @@ namespace CHECK_EQUAL("1.0", test_format(s, "{}", 1.0l)); auto& result = test_format(s, "{}", 1.234567l); CHECK("1.234567" == result || "1.234566" == result); - CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678l)); + CHECK_EQUAL("1.234568", test_format(s, "{}", 1.2345678l)); CHECK_EQUAL("1.25", test_format(s, "{}", 1.25l)); } @@ -261,11 +261,94 @@ namespace CHECK_EQUAL("inf", test_format(s, "{:g}", INFINITY)); CHECK_EQUAL("INF", test_format(s, "{:0.3G}", INFINITY)); CHECK_EQUAL("0x1.8p+0", test_format(s, "{:a}", 1.5f)); - CHECK_EQUAL("0X1.4CCCCCCCCCP+0", test_format(s, "{:A}", 1.3l)); + CHECK_EQUAL("0X1.4CCCCCCCCDP+0", test_format(s, "{:A}", 1.3l)); CHECK_EQUAL("0x2.49fp+4", test_format(s, "{:a}", 150000.0)); CHECK_EQUAL("0x1.92a738p-5", test_format(s, "{:a}", 0.0000015f)); CHECK_EQUAL("0x1.6345785d8ap+e", test_format(s, "{:a}", 100000000000000000.l)); } + + //************************************************************************* + TEST(test_format_negative_zero) + { + etl::string<100> s; + + // Test negative zero handling - signbit() correctly detects -0.0 + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0)); + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0f)); + CHECK_EQUAL("-0.0", test_format(s, "{}", -0.0L)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0f)); + CHECK_EQUAL("-0.000000", test_format(s, "{:f}", -0.0L)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0f)); + CHECK_EQUAL("-0.000000e+00", test_format(s, "{:e}", -0.0L)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0f)); + CHECK_EQUAL("-0x0.0p+0", test_format(s, "{:a}", -0.0L)); + } + + //************************************************************************* + // Tests for fractional rounding carry: + // When round(fractional * scale) == scale the fractional part must wrap + // to 0 and the integral part must be incremented by 1. + //************************************************************************* + TEST(test_format_floating_default_rounding_carry) + { + etl::string<100> s; + + // 1.9999999: fractional 0.9999999, round(0.9999999 * 1e6) == 1000000 + // => must carry: integral 1 -> 2, fractional -> 0 + CHECK_EQUAL("2.0", test_format(s, "{}", 1.9999999)); + CHECK_EQUAL("-2.0", test_format(s, "{}", -1.9999999)); + + // 0.9999999: integral 0, fractional rounds up => becomes 1.0 + CHECK_EQUAL("1.0", test_format(s, "{}", 0.9999999)); + + // 99.9999999: integral 99, fractional rounds up => becomes 100.0 + CHECK_EQUAL("100.0", test_format(s, "{}", 99.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_f_rounding_carry) + { + etl::string<100> s; + + // Same values using {:f} which uses format_floating_f (6 fractional decimals) + CHECK_EQUAL("2.000000", test_format(s, "{:f}", 1.9999999)); + CHECK_EQUAL("-2.000000", test_format(s, "{:f}", -1.9999999)); + CHECK_EQUAL("1.000000", test_format(s, "{:f}", 0.9999999)); + CHECK_EQUAL("100.000000", test_format(s, "{:f}", 99.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_e_rounding_carry) + { + etl::string<100> s; + + // 9.9999999: after normalization integral=9, fractional=0.9999999 + // round(0.9999999 * 1e6) == 1000000 => must carry: 10.000000e+00 + CHECK_EQUAL("10.000000e+00", test_format(s, "{:e}", 9.9999999)); + CHECK_EQUAL("-10.000000e+00", test_format(s, "{:e}", -9.9999999)); + + // 1.9999999: after normalization integral=1, fractional=0.9999999 + CHECK_EQUAL("2.000000e+00", test_format(s, "{:e}", 1.9999999)); + } + + //************************************************************************* + TEST(test_format_floating_a_rounding_carry) + { + etl::string<100> s; + + // 1.5 + (1.0 - 2^-52) * 0.5 ≈ value whose hex fractional part rounds up. + // Use a value where hex fractional is all 0xF...F and rounds up. + // 2.0 - epsilon: in hex, 0x1.FFFFFFFFFFFFFp+0 (for double) + // After modf: integral=1, fractional ≈ 0.999... + // round(fractional * 16^10) should equal 16^10 => carry + double almost_two = 1.9999999999999998; // nextafter(2.0, 0.0) or very close + auto& result = test_format(s, "{:a}", almost_two); + // After carry, integral becomes 2, fractional becomes 0 + CHECK_EQUAL("0x2.0p+0", result); + } #endif //************************************************************************* @@ -320,7 +403,9 @@ namespace CHECK_EQUAL("data1", test_format(s, "{}", sv)); CHECK_EQUAL("data1", test_format(s, "{:s}", sv)); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "{:d}", sv), etl::bad_format_string_exception); + #endif CHECK_EQUAL("data1 ", test_format(s, "{:10s}", sv)); CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", sv)); CHECK_EQUAL(" data1", test_format(s, "{:>10s}", sv)); @@ -349,7 +434,9 @@ namespace CHECK_EQUAL("data1", test_format(s, "{}", s_arg)); CHECK_EQUAL("data1", test_format(s, "{:s}", s_arg)); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "{:d}", s_arg), etl::bad_format_string_exception); + #endif CHECK_EQUAL("data1 ", test_format(s, "{:10s}", s_arg)); CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", s_arg)); CHECK_EQUAL(" data1", test_format(s, "{:>10s}", s_arg)); @@ -383,7 +470,9 @@ namespace CHECK_EQUAL("data1", test_format(s, "{}", string_t(data))); CHECK_EQUAL("data1", test_format(s, "{:s}", string_t(data))); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "{:d}", string_t(data)), etl::bad_format_string_exception); + #endif CHECK_EQUAL("data1 ", test_format(s, "{:10s}", string_t(data))); CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", string_t(data))); CHECK_EQUAL(" data1", test_format(s, "{:>10s}", string_t(data))); @@ -412,7 +501,9 @@ namespace CHECK_EQUAL("data1", test_format(s, "{}", chars)); CHECK_EQUAL("data1", test_format(s, "{:s}", chars)); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "{:d}", chars), etl::bad_format_string_exception); + #endif CHECK_EQUAL("data1 ", test_format(s, "{:10s}", chars)); CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", chars)); CHECK_EQUAL(" data1", test_format(s, "{:>10s}", chars)); @@ -557,28 +648,28 @@ namespace { etl::string<100> s; + #if !ETL_USING_CPP20 + // These are caught at compile time in C++20 (consteval), so only test at runtime for pre-C++20 CHECK_THROW(test_format(s, "a{b}", 1), etl::bad_format_string_exception); // bad format index spec - // goal: rejected at compile time on C++20, error on <= C++17 CHECK_THROW(test_format(s, "a{b"), etl::bad_format_string_exception); // closing brace missing - // goal: rejected at compile time on C++20, error on <= C++17 CHECK_THROW(test_format(s, "a{b}"), etl::bad_format_string_exception); // arg missing - // goal: rejected at compile time on C++20, error on <= C++17 CHECK_THROW(test_format(s, "a}b"), etl::bad_format_string_exception); // bad format: only escaped // }} allowed - // goal: rejected at compile time on C++20, error on <= C++17 - CHECK_EQUAL("123", test_format(s, "{:}", 123)); // valid CHECK_THROW(test_format(s, "{::}", 123), etl::bad_format_string_exception); // bad format spec CHECK_THROW(test_format(s, "{1}", 123), etl::bad_format_string_exception); // bad index + #endif + + CHECK_EQUAL("123", test_format(s, "{:}", 123)); // valid } //************************************************************************* @@ -637,7 +728,9 @@ namespace CHECK_EQUAL(" 34 ", test_format(s, "{:^5}", 34)); CHECK_EQUAL(" -65 ", test_format(s, "{:^5}", -65)); CHECK_EQUAL("34 ", test_format(s, "{:<4}", 34)); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "a{:*5}", 34), etl::bad_format_string_exception); + #endif CHECK_EQUAL("a*34**", test_format(s, "a{:*^5}", 34)); CHECK_EQUAL("a*34**", test_format(s, "a{:*^5}", static_cast(34))); CHECK_EQUAL("a***-341234567890****", test_format(s, "a{:*^20}", static_cast(-341234567890))); @@ -690,7 +783,9 @@ namespace CHECK_EQUAL("00067", test_format(s, "{:05d}", 67)); CHECK_EQUAL("+00067", test_format(s, "{:+05d}", 67)); CHECK_EQUAL("+0X00EF1", test_format(s, "{:+#05X}", 0xEF1)); + #if !ETL_USING_CPP20 CHECK_THROW(test_format(s, "{:+#05.5X}", 0xEF1), etl::bad_format_string_exception); + #endif } } } // namespace diff --git a/test/test_forward_list.cpp b/test/test_forward_list.cpp index 08337c28..3f805b7f 100644 --- a/test/test_forward_list.cpp +++ b/test/test_forward_list.cpp @@ -42,6 +42,7 @@ SOFTWARE. namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_forward_list) { const size_t SIZE = 10UL; @@ -1443,5 +1444,28 @@ namespace CHECK_EQUAL(ItemNDC("F"), *itr++); } #endif + + //************************************************************************* + TEST(test_forward_list_exception_types) + { + // Verify exception class hierarchy is correct + CHECK(true == (std::is_base_of::value)); + CHECK(true == (std::is_base_of::value)); + CHECK(true == (std::is_base_of::value)); + CHECK(true == (std::is_base_of::value)); + +#if defined(ETL_VERBOSE_ERRORS) + // When verbose errors are enabled, check the error text contains "forward_list" + etl::forward_list_full ex_full(__FILE__, __LINE__); + etl::forward_list_empty ex_empty(__FILE__, __LINE__); + + std::string full_msg(ex_full.what()); + std::string empty_msg(ex_empty.what()); + + CHECK(full_msg.find("forward_list") != std::string::npos); + CHECK(empty_msg.find("forward_list") != std::string::npos); +#endif + } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_forward_list_shared_pool.cpp b/test/test_forward_list_shared_pool.cpp index 701bfe44..996efe7a 100644 --- a/test/test_forward_list_shared_pool.cpp +++ b/test/test_forward_list_shared_pool.cpp @@ -42,6 +42,7 @@ SOFTWARE. namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_forward_list) { const size_t SIZE = 20UL; @@ -1929,4 +1930,5 @@ namespace CHECK(data3 > data1); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_hash.cpp b/test/test_hash.cpp index 73a616f8..d1acd6b1 100644 --- a/test/test_hash.cpp +++ b/test/test_hash.cpp @@ -149,7 +149,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0xEC6A8D69UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0xEC6A8D69UL, hash); + } + else + { + CHECK_EQUAL(0x5F69FD19UL, hash); + } } if (ETL_PLATFORM_64BIT) @@ -165,7 +172,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0xEC6A8D69UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0xEC6A8D69UL, hash); + } + else + { + CHECK_EQUAL(0x5F69FD19UL, hash); + } } if (ETL_PLATFORM_64BIT) @@ -177,7 +191,7 @@ namespace //************************************************************************* TEST(test_hash_float) { - size_t hash = etl::hash()((float)(1.2345)); + size_t hash = etl::hash()(1.2345f); if (ETL_PLATFORM_32BIT) { @@ -204,7 +218,14 @@ namespace if (ETL_PLATFORM_32BIT) { - CHECK_EQUAL(0x86FBF224UL, hash); + if (etl::endianness::value() == etl::endian::little) + { + CHECK_EQUAL(0x86FBF224UL, hash); + } + else + { + CHECK_EQUAL(0xD1F372DEUL, hash); + } } if (ETL_PLATFORM_64BIT) diff --git a/test/test_histogram.cpp b/test/test_histogram.cpp index 92857deb..624c0e68 100644 --- a/test/test_histogram.cpp +++ b/test/test_histogram.cpp @@ -166,7 +166,7 @@ namespace for (size_t i = 0UL; i < output1.size(); ++i) { - CHECK_EQUAL(int(output1[i]), int(histogram[i])); + CHECK_EQUAL(static_cast(output1[i]), static_cast(histogram[static_cast(i)])); } } @@ -203,7 +203,7 @@ namespace for (size_t i = 0UL; i < output1.size(); ++i) { - CHECK_EQUAL(int(output1[i]), int(histogram[i - 4])); + CHECK_EQUAL(static_cast(output1[i]), static_cast(histogram[static_cast(i) - 4])); } } @@ -332,5 +332,59 @@ namespace isEqual = std::equal(output2.begin(), output2.end(), histogram.begin()); CHECK(isEqual); } + + //************************************************************************* + TEST(test_sparse_histogram_iteration) + { + StringHistogram histogram; + + // Empty histogram: begin == end + CHECK(histogram.begin() == histogram.end()); + CHECK(histogram.cbegin() == histogram.cend()); + + // Add items + histogram.add(std::string("apple")); + histogram.add(std::string("banana")); + histogram.add(std::string("apple")); + + // Non-empty: begin != end + CHECK(histogram.begin() != histogram.end()); + CHECK(histogram.cbegin() != histogram.cend()); + + // Count elements by iterating + size_t count = 0; + for (auto it = histogram.begin(); it != histogram.end(); ++it) + { + ++count; + } + CHECK_EQUAL(2U, count); // "apple" and "banana" + + // Same with cbegin/cend + count = 0; + for (auto it = histogram.cbegin(); it != histogram.cend(); ++it) + { + ++count; + } + CHECK_EQUAL(2U, count); + + // Verify we can find the expected values + bool found_apple = false; + bool found_banana = false; + for (auto it = histogram.begin(); it != histogram.end(); ++it) + { + if (it->first == "apple") + { + CHECK_EQUAL(2, it->second); + found_apple = true; + } + if (it->first == "banana") + { + CHECK_EQUAL(1, it->second); + found_banana = true; + } + } + CHECK(found_apple); + CHECK(found_banana); + } } } // namespace diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index 33002fd7..5be470bc 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -129,6 +129,7 @@ namespace namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_intrusive_forward_list) { InitialDataNDC stable_sort_data; @@ -1379,4 +1380,5 @@ namespace CHECK_FALSE(data0.contains(compare_node2)); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_intrusive_links.cpp b/test/test_intrusive_links.cpp index c90a56c3..7bdbeb1b 100644 --- a/test/test_intrusive_links.cpp +++ b/test/test_intrusive_links.cpp @@ -1845,5 +1845,15 @@ namespace CHECK(c.etl_left == nullptr); CHECK(c.etl_right == nullptr); } + + //************************************************************************* + TEST(test_link_clear_range_bidirectional_nullptr) + { + // Passing nullptr should be a no-op, not a crash + BData* null_ptr = nullptr; + etl::link_clear_range(null_ptr); + // If we get here without crashing, the test passes + CHECK(true); + } } } // namespace diff --git a/test/test_intrusive_list.cpp b/test/test_intrusive_list.cpp index 0c352b5d..4b2f6f85 100644 --- a/test/test_intrusive_list.cpp +++ b/test/test_intrusive_list.cpp @@ -142,6 +142,7 @@ namespace namespace { +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_intrusive_list) { InitialDataNDC stable_sort_data; @@ -1648,4 +1649,5 @@ namespace CHECK_FALSE(data0.contains(compare_node2)); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index bd357435..a69bfdb5 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -1,3 +1,31 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + #include "etl/manchester.h" #include "unit_test_framework.h" diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 9513e778..e0e457c6 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -47,6 +47,64 @@ SOFTWARE. #include #include +//*************************************************************************** +/// A non-trivially-relocatable type that tracks moves and destructions. +/// Used to exercise the manual move-and-destroy path of etl::relocate. +//*************************************************************************** +struct relocatable_t +{ + int value; + bool was_moved_into; ///< true when this object was constructed via move + + static int destructor_count; + + static void reset_counts() + { + destructor_count = 0; + } + + explicit relocatable_t(int v = 0) + : value(v) + , was_moved_into(false) + { + } + + relocatable_t(relocatable_t&& other) ETL_NOEXCEPT + : value(other.value) + , was_moved_into(true) + { + other.value = -1; // mark source as moved-from + } + + ~relocatable_t() + { + ++destructor_count; + } + + // Non-copyable to make the intent clear. + relocatable_t(const relocatable_t&) = delete; + relocatable_t& operator=(const relocatable_t&) = delete; + relocatable_t& operator=(relocatable_t&&) = delete; +}; + +int relocatable_t::destructor_count = 0; + +// In configurations where etl::is_nothrow_relocatable is a class template +// (non-STL builds), we must provide an explicit specialisation so that +// etl::relocate is enabled for relocatable_t. When the STL is available the +// trait is a type alias that already evaluates to true for types with a +// nothrow move constructor and a nothrow destructor, so no specialisation is +// needed (or even possible). +#if !(ETL_USING_STL && ETL_USING_CPP11) +namespace etl +{ + template <> + struct is_nothrow_relocatable : public etl::true_type + { + }; +} // namespace etl +#endif + namespace { typedef std::string non_trivial_t; @@ -2660,5 +2718,293 @@ namespace CHECK(result == p); } #endif + +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_trivially_relocate_trivial) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Initialize source + for (size_t i = 0; i < SIZE; ++i) + { + src[i] = test_data_trivial[i]; + } + + // Relocate + trivial_t* result = etl::trivially_relocate(src, src + SIZE, dst); + + // Check result + CHECK(result == dst + SIZE); + + // Check destination values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], dst[i]); + } + } + + //************************************************************************* + TEST(test_trivially_relocate_same_location) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * SIZE]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate to same location should return last + trivial_t* result = etl::trivially_relocate(p, p + SIZE, p); + + CHECK(result == p + SIZE); + + // Values should be unchanged + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i]); + } + } + + //************************************************************************* + TEST(test_trivially_relocate_empty_range) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Relocate empty range + trivial_t* result = etl::trivially_relocate(src, src, dst); + + CHECK(result == dst); + } + + //************************************************************************* + TEST(test_trivially_relocate_overlapping_forward) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * (SIZE + 2)]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate forward (overlapping) - shift elements by 2 + trivial_t* result = etl::trivially_relocate(p, p + SIZE, p + 2); + + CHECK(result == p + SIZE + 2); + + // Check values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i + 2]); + } + } + + //************************************************************************* + TEST(test_relocate_trivial) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Initialize source + for (size_t i = 0; i < SIZE; ++i) + { + src[i] = test_data_trivial[i]; + } + + // Relocate + trivial_t* result = etl::relocate(src, src + SIZE, dst); + + // Check result + CHECK(result == dst + SIZE); + + // Check destination values + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], dst[i]); + } + } + + //************************************************************************* + TEST(test_relocate_same_location) + { + alignas(trivial_t) unsigned char buffer[sizeof(trivial_t) * SIZE]; + trivial_t* p = reinterpret_cast(buffer); + + // Initialize + for (size_t i = 0; i < SIZE; ++i) + { + p[i] = test_data_trivial[i]; + } + + // Relocate to same location should return last + trivial_t* result = etl::relocate(p, p + SIZE, p); + + CHECK(result == p + SIZE); + + // Values should be unchanged + for (size_t i = 0; i < SIZE; ++i) + { + CHECK_EQUAL(test_data_trivial[i], p[i]); + } + } + + //************************************************************************* + TEST(test_relocate_empty_range) + { + alignas(trivial_t) unsigned char src_buffer[sizeof(trivial_t) * SIZE]; + alignas(trivial_t) unsigned char dst_buffer[sizeof(trivial_t) * SIZE]; + + trivial_t* src = reinterpret_cast(src_buffer); + trivial_t* dst = reinterpret_cast(dst_buffer); + + // Relocate empty range + trivial_t* result = etl::relocate(src, src, dst); + + CHECK(result == dst); + } + + //************************************************************************* + TEST(test_relocate_non_trivial) + { + const size_t N = 5; + + alignas(relocatable_t) unsigned char src_buffer[sizeof(relocatable_t) * N]; + alignas(relocatable_t) unsigned char dst_buffer[sizeof(relocatable_t) * N]; + + relocatable_t* src = reinterpret_cast(src_buffer); + relocatable_t* dst = reinterpret_cast(dst_buffer); + + // Placement-new source objects + for (size_t i = 0; i < N; ++i) + { + ::new (static_cast(src + i)) relocatable_t(static_cast(i + 1)); + } + + relocatable_t::reset_counts(); + + // Relocate (non-trivial path: move-construct into dst, destroy src) + relocatable_t* result = etl::relocate(src, src + N, dst); + + // Returned pointer must be one-past-end of destination + CHECK(result == dst + N); + + // Destination objects were move-constructed with correct values + for (size_t i = 0; i < N; ++i) + { + CHECK_EQUAL(static_cast(i + 1), dst[i].value); + CHECK(dst[i].was_moved_into); + } + + // Destructors were called for the N source objects + CHECK_EQUAL(static_cast(N), relocatable_t::destructor_count); + + // Clean up destination objects + relocatable_t::reset_counts(); + for (size_t i = 0; i < N; ++i) + { + dst[i].~relocatable_t(); + } + } + + //************************************************************************* + TEST(test_relocate_non_trivial_same_location) + { + const size_t N = 5; + + alignas(relocatable_t) unsigned char buffer[sizeof(relocatable_t) * N]; + relocatable_t* p = reinterpret_cast(buffer); + + // Placement-new objects + for (size_t i = 0; i < N; ++i) + { + ::new (static_cast(p + i)) relocatable_t(static_cast(i + 1)); + } + + relocatable_t::reset_counts(); + + // Relocating to the same location should be a no-op (early return) + relocatable_t* result = etl::relocate(p, p + N, p); + + CHECK(result == p + N); + + // No destructors should have been called (no move-and-destroy performed) + CHECK_EQUAL(0, relocatable_t::destructor_count); + + // Values should be unchanged + for (size_t i = 0; i < N; ++i) + { + CHECK_EQUAL(static_cast(i + 1), p[i].value); + CHECK(!p[i].was_moved_into); + } + + // Clean up + relocatable_t::reset_counts(); + for (size_t i = 0; i < N; ++i) + { + p[i].~relocatable_t(); + } + } + + //************************************************************************* + TEST(test_relocate_non_trivial_empty_range) + { + alignas(relocatable_t) unsigned char src_buffer[sizeof(relocatable_t)]; + alignas(relocatable_t) unsigned char dst_buffer[sizeof(relocatable_t)]; + + relocatable_t* src = reinterpret_cast(src_buffer); + relocatable_t* dst = reinterpret_cast(dst_buffer); + + relocatable_t::reset_counts(); + + // Empty range: first == last + relocatable_t* result = etl::relocate(src, src, dst); + + CHECK(result == dst); + + // No destructors should have been called + CHECK_EQUAL(0, relocatable_t::destructor_count); + } +#endif + + //************************************************************************* + TEST(test_wipe_on_destruct) + { + struct Data : public etl::wipe_on_destruct + { + uint32_t d1; + uint32_t d2; + char d3; + }; + + alignas(Data) unsigned char buffer[sizeof(Data)] = {0}; + + // Construct a Data object in the buffer with known non-zero values. + Data* p = new (buffer) Data(); + p->d1 = 0x12345678UL; + p->d2 = 0xAABBCCDDUL; + p->d3 = char(0xEE); + + // Destroy the object; wipe_on_destruct should zero the memory. + p->~Data(); + + // Verify the memory occupied by the object has been cleared. + unsigned char zeroes[sizeof(Data)] = {0}; + CHECK(memcmp(buffer, zeroes, sizeof(Data)) == 0); + } } } // namespace diff --git a/test/test_multiset.cpp b/test/test_multiset.cpp index c040e8ac..6cf29f87 100644 --- a/test/test_multiset.cpp +++ b/test/test_multiset.cpp @@ -98,10 +98,10 @@ namespace return (lhs < rhs.k); } +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_multiset) { //************************************************************************* -#include "etl/private/diagnostic_null_dereference_push.h" template bool Check_Equal(T1 begin1, T1 end1, T2 begin2) { @@ -118,7 +118,6 @@ namespace return true; } -#include "etl/private/diagnostic_pop.h" //************************************************************************* struct SetupFixture @@ -1515,7 +1514,6 @@ namespace for (pos = data.crbegin(); pos != data.crend(); ++pos) { -#include "etl/private/diagnostic_null_dereference_push.h" if (*pos > prv) { pass = false; @@ -1523,7 +1521,6 @@ namespace } prv = *pos; -#include "etl/private/diagnostic_pop.h" } CHECK(pass); @@ -1630,4 +1627,5 @@ namespace } while (std::next_permutation(permutation.begin(), permutation.end())); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_numeric.cpp b/test/test_numeric.cpp index 1f6980bc..f7407fef 100644 --- a/test/test_numeric.cpp +++ b/test/test_numeric.cpp @@ -206,5 +206,411 @@ namespace CHECK_CLOSE(10.0, etl::lerp(10.0, 10.0, 1), 0.001); CHECK_CLOSE(10.0, etl::lerp(10, 10, 1), 0.001); } + + //************************************************************************* + TEST(test_add_sat_unsigned) + { + // Normal addition (no overflow) + CHECK_EQUAL(uint8_t(0), etl::add_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(3), etl::add_sat(uint8_t(1), uint8_t(2))); + CHECK_EQUAL(uint8_t(254), etl::add_sat(uint8_t(127), uint8_t(127))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(200), uint8_t(55))); + + // Overflow saturates to max + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(1), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(200), uint8_t(200))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(128), uint8_t(128))); + + // Identity: adding zero + CHECK_EQUAL(uint8_t(42), etl::add_sat(uint8_t(42), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::add_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(255), etl::add_sat(uint8_t(255), uint8_t(0))); + + // uint16_t + CHECK_EQUAL(uint16_t(65535), etl::add_sat(uint16_t(65535), uint16_t(1))); + CHECK_EQUAL(uint16_t(65535), etl::add_sat(uint16_t(65535), uint16_t(65535))); + CHECK_EQUAL(uint16_t(1000), etl::add_sat(uint16_t(500), uint16_t(500))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(100), etl::add_sat(uint32_t(60), uint32_t(40))); + } + + //************************************************************************* + TEST(test_add_sat_signed) + { + // Normal addition (no overflow) + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(3), etl::add_sat(int8_t(1), int8_t(2))); + CHECK_EQUAL(int8_t(-3), etl::add_sat(int8_t(-1), int8_t(-2))); + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(0), etl::add_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(126), etl::add_sat(int8_t(63), int8_t(63))); + + // Positive overflow saturates to max + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(1))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(1), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(100), int8_t(100))); + + // Negative overflow saturates to min + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(-1))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-1), int8_t(-128))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(-128))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-100), int8_t(-100))); + + // Mixed signs: no overflow possible + CHECK_EQUAL(int8_t(-1), etl::add_sat(int8_t(127), int8_t(-128))); + CHECK_EQUAL(int8_t(-1), etl::add_sat(int8_t(-128), int8_t(127))); + CHECK_EQUAL(int8_t(27), etl::add_sat(int8_t(127), int8_t(-100))); + CHECK_EQUAL(int8_t(-28), etl::add_sat(int8_t(-128), int8_t(100))); + + // Identity: adding zero + CHECK_EQUAL(int8_t(42), etl::add_sat(int8_t(42), int8_t(0))); + CHECK_EQUAL(int8_t(-42), etl::add_sat(int8_t(-42), int8_t(0))); + CHECK_EQUAL(int8_t(127), etl::add_sat(int8_t(127), int8_t(0))); + CHECK_EQUAL(int8_t(-128), etl::add_sat(int8_t(-128), int8_t(0))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::add_sat(int16_t(32767), int16_t(1))); + CHECK_EQUAL(int16_t(-32768), etl::add_sat(int16_t(-32768), int16_t(-1))); + CHECK_EQUAL(int16_t(32767), etl::add_sat(int16_t(32767), int16_t(32767))); + CHECK_EQUAL(int16_t(-32768), etl::add_sat(int16_t(-32768), int16_t(-32768))); + CHECK_EQUAL(int16_t(1000), etl::add_sat(int16_t(500), int16_t(500))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::add_sat(std::numeric_limits::min(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::add_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::add_sat(std::numeric_limits::min(), std::numeric_limits::min())); + CHECK_EQUAL(int32_t(100), etl::add_sat(int32_t(60), int32_t(40))); + } + + //************************************************************************* + TEST(test_sub_sat_unsigned) + { + // Normal subtraction (no underflow) + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(1), etl::sub_sat(uint8_t(3), uint8_t(2))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(2), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::sub_sat(uint8_t(255), uint8_t(0))); + CHECK_EQUAL(uint8_t(128), etl::sub_sat(uint8_t(255), uint8_t(127))); + + // Underflow saturates to 0 + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(1), uint8_t(2))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(100), uint8_t(200))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(127), uint8_t(255))); + + // Identity: subtracting zero + CHECK_EQUAL(uint8_t(42), etl::sub_sat(uint8_t(42), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::sub_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(255), etl::sub_sat(uint8_t(255), uint8_t(0))); + + // uint16_t + CHECK_EQUAL(uint16_t(0), etl::sub_sat(uint16_t(0), uint16_t(1))); + CHECK_EQUAL(uint16_t(0), etl::sub_sat(uint16_t(0), uint16_t(65535))); + CHECK_EQUAL(uint16_t(100), etl::sub_sat(uint16_t(500), uint16_t(400))); + + // uint32_t + CHECK_EQUAL(uint32_t(0), etl::sub_sat(uint32_t(0), uint32_t(1))); + CHECK_EQUAL(uint32_t(0), etl::sub_sat(uint32_t(0), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(1), etl::sub_sat(std::numeric_limits::max(), std::numeric_limits::max() - 1)); + CHECK_EQUAL(uint32_t(20), etl::sub_sat(uint32_t(60), uint32_t(40))); + } + + //************************************************************************* + TEST(test_sub_sat_signed) + { + // Normal subtraction (no overflow) + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(1), etl::sub_sat(int8_t(3), int8_t(2))); + CHECK_EQUAL(int8_t(-1), etl::sub_sat(int8_t(2), int8_t(3))); + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-2), etl::sub_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(2), etl::sub_sat(int8_t(1), int8_t(-1))); + + // Positive overflow: subtracting large negative from positive saturates to max + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(-1))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(1), int8_t(-127))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(-128))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(100), int8_t(-100))); + + // Negative overflow: subtracting large positive from negative saturates to min + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(1))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-1), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-100), int8_t(100))); + + // No overflow when same sign + CHECK_EQUAL(int8_t(0), etl::sub_sat(int8_t(-128), int8_t(-128))); + CHECK_EQUAL(int8_t(-1), etl::sub_sat(int8_t(-128), int8_t(-127))); + + // Identity: subtracting zero + CHECK_EQUAL(int8_t(42), etl::sub_sat(int8_t(42), int8_t(0))); + CHECK_EQUAL(int8_t(-42), etl::sub_sat(int8_t(-42), int8_t(0))); + CHECK_EQUAL(int8_t(127), etl::sub_sat(int8_t(127), int8_t(0))); + CHECK_EQUAL(int8_t(-128), etl::sub_sat(int8_t(-128), int8_t(0))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::sub_sat(int16_t(32767), int16_t(-1))); + CHECK_EQUAL(int16_t(-32768), etl::sub_sat(int16_t(-32768), int16_t(1))); + CHECK_EQUAL(int16_t(32767), etl::sub_sat(int16_t(32767), int16_t(-32768))); + CHECK_EQUAL(int16_t(-32768), etl::sub_sat(int16_t(-32768), int16_t(32767))); + CHECK_EQUAL(int16_t(100), etl::sub_sat(int16_t(500), int16_t(400))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::sub_sat(std::numeric_limits::max(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::sub_sat(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::sub_sat(std::numeric_limits::max(), std::numeric_limits::min())); + CHECK_EQUAL(std::numeric_limits::min(), etl::sub_sat(std::numeric_limits::min(), std::numeric_limits::max())); + CHECK_EQUAL(int32_t(20), etl::sub_sat(int32_t(60), int32_t(40))); + } + + //************************************************************************* + TEST(test_mul_sat_unsigned) + { + // Normal multiplication (no overflow) + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(0), uint8_t(0))); + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(0), etl::mul_sat(uint8_t(255), uint8_t(0))); + CHECK_EQUAL(uint8_t(6), etl::mul_sat(uint8_t(2), uint8_t(3))); + CHECK_EQUAL(uint8_t(1), etl::mul_sat(uint8_t(1), uint8_t(1))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(250), etl::mul_sat(uint8_t(25), uint8_t(10))); + + // Overflow saturates to max + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(2), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(255), uint8_t(255))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(128), uint8_t(3))); + CHECK_EQUAL(uint8_t(255), etl::mul_sat(uint8_t(16), uint8_t(16))); + + // uint16_t + CHECK_EQUAL(uint16_t(65535), etl::mul_sat(uint16_t(65535), uint16_t(2))); + CHECK_EQUAL(uint16_t(65535), etl::mul_sat(uint16_t(65535), uint16_t(65535))); + CHECK_EQUAL(uint16_t(10000), etl::mul_sat(uint16_t(100), uint16_t(100))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), uint32_t(2))); + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(600), etl::mul_sat(uint32_t(20), uint32_t(30))); + } + + //************************************************************************* + TEST(test_mul_sat_signed) + { + // Normal multiplication (no overflow) + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(0))); + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(127))); + CHECK_EQUAL(int8_t(0), etl::mul_sat(int8_t(0), int8_t(-128))); + CHECK_EQUAL(int8_t(6), etl::mul_sat(int8_t(2), int8_t(3))); + CHECK_EQUAL(int8_t(-6), etl::mul_sat(int8_t(2), int8_t(-3))); + CHECK_EQUAL(int8_t(-6), etl::mul_sat(int8_t(-2), int8_t(3))); + CHECK_EQUAL(int8_t(6), etl::mul_sat(int8_t(-2), int8_t(-3))); + CHECK_EQUAL(int8_t(1), etl::mul_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-1), etl::mul_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(1), etl::mul_sat(int8_t(-1), int8_t(-1))); + CHECK_EQUAL(int8_t(100), etl::mul_sat(int8_t(10), int8_t(10))); + + // Positive overflow: both positive + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(127), int8_t(2))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(2), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(127), int8_t(127))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(64), int8_t(3))); + + // Positive overflow: both negative + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-128), int8_t(-2))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-2), int8_t(-128))); + CHECK_EQUAL(int8_t(127), etl::mul_sat(int8_t(-128), int8_t(-128))); + + // Negative overflow: positive * negative + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(127), int8_t(-2))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(2), int8_t(-127))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(127), int8_t(-128))); + + // Negative overflow: negative * positive + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-128), int8_t(2))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-2), int8_t(127))); + CHECK_EQUAL(int8_t(-128), etl::mul_sat(int8_t(-128), int8_t(127))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::mul_sat(int16_t(32767), int16_t(2))); + CHECK_EQUAL(int16_t(-32768), etl::mul_sat(int16_t(32767), int16_t(-2))); + CHECK_EQUAL(int16_t(32767), etl::mul_sat(int16_t(-32768), int16_t(-2))); + CHECK_EQUAL(int16_t(-32768), etl::mul_sat(int16_t(-32768), int16_t(2))); + CHECK_EQUAL(int16_t(10000), etl::mul_sat(int16_t(100), int16_t(100))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::max(), int32_t(2))); + CHECK_EQUAL(std::numeric_limits::min(), etl::mul_sat(std::numeric_limits::max(), int32_t(-2))); + CHECK_EQUAL(std::numeric_limits::max(), etl::mul_sat(std::numeric_limits::min(), int32_t(-2))); + CHECK_EQUAL(std::numeric_limits::min(), etl::mul_sat(std::numeric_limits::min(), int32_t(2))); + CHECK_EQUAL(int32_t(600), etl::mul_sat(int32_t(20), int32_t(30))); + } + + //************************************************************************* + TEST(test_div_sat_unsigned) + { + // Normal division + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(0), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(0), uint8_t(255))); + CHECK_EQUAL(uint8_t(1), etl::div_sat(uint8_t(1), uint8_t(1))); + CHECK_EQUAL(uint8_t(3), etl::div_sat(uint8_t(6), uint8_t(2))); + CHECK_EQUAL(uint8_t(127), etl::div_sat(uint8_t(255), uint8_t(2))); + CHECK_EQUAL(uint8_t(255), etl::div_sat(uint8_t(255), uint8_t(1))); + CHECK_EQUAL(uint8_t(0), etl::div_sat(uint8_t(1), uint8_t(2))); + + // uint16_t + CHECK_EQUAL(uint16_t(32767), etl::div_sat(uint16_t(65535), uint16_t(2))); + CHECK_EQUAL(uint16_t(65535), etl::div_sat(uint16_t(65535), uint16_t(1))); + CHECK_EQUAL(uint16_t(100), etl::div_sat(uint16_t(1000), uint16_t(10))); + + // uint32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(1), etl::div_sat(std::numeric_limits::max(), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(30), etl::div_sat(uint32_t(600), uint32_t(20))); + } + + //************************************************************************* + TEST(test_div_sat_signed) + { + // Normal division + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(0), int8_t(1))); + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(0), int8_t(-1))); + CHECK_EQUAL(int8_t(1), etl::div_sat(int8_t(1), int8_t(1))); + CHECK_EQUAL(int8_t(-1), etl::div_sat(int8_t(1), int8_t(-1))); + CHECK_EQUAL(int8_t(-1), etl::div_sat(int8_t(-1), int8_t(1))); + CHECK_EQUAL(int8_t(1), etl::div_sat(int8_t(-1), int8_t(-1))); + CHECK_EQUAL(int8_t(3), etl::div_sat(int8_t(6), int8_t(2))); + CHECK_EQUAL(int8_t(-3), etl::div_sat(int8_t(6), int8_t(-2))); + CHECK_EQUAL(int8_t(-3), etl::div_sat(int8_t(-6), int8_t(2))); + CHECK_EQUAL(int8_t(3), etl::div_sat(int8_t(-6), int8_t(-2))); + CHECK_EQUAL(int8_t(127), etl::div_sat(int8_t(127), int8_t(1))); + CHECK_EQUAL(int8_t(-127), etl::div_sat(int8_t(127), int8_t(-1))); + CHECK_EQUAL(int8_t(-128), etl::div_sat(int8_t(-128), int8_t(1))); + CHECK_EQUAL(int8_t(0), etl::div_sat(int8_t(1), int8_t(2))); + + // The only overflow case: min / -1 saturates to max + CHECK_EQUAL(int8_t(127), etl::div_sat(int8_t(-128), int8_t(-1))); + + // int16_t + CHECK_EQUAL(int16_t(32767), etl::div_sat(int16_t(-32768), int16_t(-1))); + CHECK_EQUAL(int16_t(-32768), etl::div_sat(int16_t(-32768), int16_t(1))); + CHECK_EQUAL(int16_t(100), etl::div_sat(int16_t(1000), int16_t(10))); + + // int32_t + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::min(), int32_t(-1))); + CHECK_EQUAL(std::numeric_limits::min(), etl::div_sat(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(std::numeric_limits::max(), etl::div_sat(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::div_sat(std::numeric_limits::max(), std::numeric_limits::min())); + CHECK_EQUAL(int32_t(30), etl::div_sat(int32_t(600), int32_t(20))); + } + + //************************************************************************* + TEST(test_saturate_cast_unsigned_to_unsigned) + { + // Fits + CHECK_EQUAL(uint8_t(42), (etl::saturate_cast(uint16_t(42)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(uint16_t(0)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(255)))); + + // Overflow: clamp to max + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(256)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(1000)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(uint16_t(65535)))); + + // Widening (always fits) + CHECK_EQUAL(uint16_t(42), (etl::saturate_cast(uint8_t(42)))); + CHECK_EQUAL(uint16_t(255), (etl::saturate_cast(uint8_t(255)))); + } + + //************************************************************************* + TEST(test_saturate_cast_signed_to_signed) + { + // Fits + CHECK_EQUAL(int8_t(42), (etl::saturate_cast(int16_t(42)))); + CHECK_EQUAL(int8_t(-42), (etl::saturate_cast(int16_t(-42)))); + CHECK_EQUAL(int8_t(0), (etl::saturate_cast(int16_t(0)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(127)))); + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-128)))); + + // Overflow: clamp to max + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(128)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(int16_t(1000)))); + + // Underflow: clamp to min + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-129)))); + CHECK_EQUAL(int8_t(-128), (etl::saturate_cast(int16_t(-1000)))); + + // Widening (always fits) + CHECK_EQUAL(int16_t(42), (etl::saturate_cast(int8_t(42)))); + CHECK_EQUAL(int16_t(-128), (etl::saturate_cast(int8_t(-128)))); + } + + //************************************************************************* + TEST(test_saturate_cast_signed_to_unsigned) + { + // Fits + CHECK_EQUAL(uint8_t(42), (etl::saturate_cast(int16_t(42)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(0)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(255)))); + + // Negative source: clamp to 0 + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(-1)))); + CHECK_EQUAL(uint8_t(0), (etl::saturate_cast(int16_t(-1000)))); + CHECK_EQUAL(uint16_t(0), (etl::saturate_cast(int16_t(-1)))); + + // Overflow: clamp to max + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(256)))); + CHECK_EQUAL(uint8_t(255), (etl::saturate_cast(int16_t(1000)))); + } + + //************************************************************************* + TEST(test_saturate_cast_unsigned_to_signed) + { + // Fits + CHECK_EQUAL(int8_t(42), (etl::saturate_cast(uint16_t(42)))); + CHECK_EQUAL(int8_t(0), (etl::saturate_cast(uint16_t(0)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(127)))); + + // Overflow: clamp to max + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(128)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(1000)))); + CHECK_EQUAL(int8_t(127), (etl::saturate_cast(uint16_t(65535)))); + + // Widening (always fits) + CHECK_EQUAL(int16_t(255), (etl::saturate_cast(uint8_t(255)))); + CHECK_EQUAL(int16_t(0), (etl::saturate_cast(uint8_t(0)))); + } + + //************************************************************************* + TEST(test_saturate_cast_same_type) + { + // Same type, no conversion needed + CHECK_EQUAL(int32_t(42), (etl::saturate_cast(int32_t(42)))); + CHECK_EQUAL(uint32_t(42), (etl::saturate_cast(uint32_t(42)))); + CHECK_EQUAL(int32_t(-42), (etl::saturate_cast(int32_t(-42)))); + } + + //************************************************************************* + TEST(test_saturate_cast_boundary_values) + { + // int32_t max -> uint16_t + CHECK_EQUAL(uint16_t(65535), (etl::saturate_cast(int32_t(2147483647)))); + + // int32_t min -> uint16_t + CHECK_EQUAL(uint16_t(0), (etl::saturate_cast(std::numeric_limits::min()))); + + // uint32_t max -> int32_t + CHECK_EQUAL(std::numeric_limits::max(), (etl::saturate_cast(std::numeric_limits::max()))); + + // uint32_t max -> int16_t + CHECK_EQUAL(int16_t(32767), (etl::saturate_cast(std::numeric_limits::max()))); + } } } // namespace diff --git a/test/test_optional.cpp b/test/test_optional.cpp index a848b0cb..04ad9574 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -28,12 +28,15 @@ SOFTWARE. #include "unit_test_framework.h" +#include #include #include #include -#include +#include +#include #include "data.h" +#include "etl/algorithm.h" #include "etl/optional.h" #include "etl/vector.h" @@ -82,6 +85,29 @@ namespace }; #include "etl/private/diagnostic_pop.h" + struct TestIL + { + constexpr TestIL() + : a(0) + , b(0) + , c(0) + { + } + + ETL_CONSTEXPR20 TestIL(std::initializer_list il, int a_, int b_, int c_) + : a(a_) + , b(b_) + , c(c_) + { + etl::copy_n(il.begin(), std::min(il.size(), arr.size()), arr.begin()); + } + + std::array arr{}; + int a; + int b; + int c; + }; + SUITE(test_optional) { //************************************************************************* @@ -90,38 +116,38 @@ namespace etl::optional data1; etl::optional data2; - CHECK(!bool(data1)); - CHECK(!bool(data2)); + CHECK(!static_cast(data1)); + CHECK(!static_cast(data2)); CHECK(!data1.has_value()); CHECK(!data2.has_value()); data1 = Data("Hello"); - CHECK(bool(data1)); + CHECK(static_cast(data1)); CHECK(data1.has_value()); CHECK_EQUAL(Data("Hello"), data1); data1 = data2; - CHECK(!bool(data1)); - CHECK(!bool(data2)); + CHECK(!static_cast(data1)); + CHECK(!static_cast(data2)); CHECK(!data1.has_value()); CHECK(!data2.has_value()); data1 = Data("World"); data2 = data1; - CHECK(bool(data1)); - CHECK(bool(data2)); + CHECK(static_cast(data1)); + CHECK(static_cast(data2)); CHECK(data1.has_value()); CHECK(data2.has_value()); - etl::optional data3(data1); - CHECK(bool(data3)); + const etl::optional data3(data1); + CHECK(static_cast(data3)); CHECK(data3.has_value()); CHECK_EQUAL(data1, data3); etl::optional data4; data4 = Data("Hello"); data4 = etl::nullopt; - CHECK(!bool(data4)); + CHECK(!static_cast(data4)); CHECK(!data4.has_value()); } @@ -132,7 +158,7 @@ namespace constexpr etl::optional opt(etl::in_place_t{}, 1); CHECK_TRUE(opt.has_value()); - CHECK(bool(opt)); + CHECK(static_cast(opt)); CHECK_EQUAL(1, opt.value()); } #endif @@ -156,7 +182,7 @@ namespace constexpr etl::optional opt(etl::in_place_t{}, 1, 2); CHECK_TRUE(opt.has_value()); - CHECK(bool(opt)); + CHECK(static_cast(opt)); CHECK_EQUAL(1, opt.value().a); CHECK_EQUAL(2, opt.value().b); } @@ -165,34 +191,14 @@ namespace //************************************************************************* TEST(test_construct_from_initializer_list_and_arguments) { - struct S - { - S() - : vi() - , a(0) - , b(0) - { - } + etl::optional opt(etl::in_place_t{}, {10, 11, 12}, 1, 2, 3); - S(std::initializer_list il, int a_, int b_) - : vi(il) - , a(a_) - , b(b_) - { - } - - std::vector vi; - int a; - int b; - }; - - etl::optional opt(etl::in_place_t{}, {10, 11, 12}, 1, 2); - - CHECK_EQUAL(10, opt.value().vi[0]); - CHECK_EQUAL(11, opt.value().vi[1]); - CHECK_EQUAL(12, opt.value().vi[2]); + CHECK_EQUAL(10, opt.value().arr[0]); + CHECK_EQUAL(11, opt.value().arr[1]); + CHECK_EQUAL(12, opt.value().arr[2]); CHECK_EQUAL(1, opt.value().a); CHECK_EQUAL(2, opt.value().b); + CHECK_EQUAL(3, opt.value().c); } //************************************************************************* @@ -200,10 +206,10 @@ namespace { Data data("Hello"); - etl::optional opt{data}; + const etl::optional opt{data}; CHECK(opt.has_value()); - CHECK(bool(opt)); + CHECK(static_cast(opt)); CHECK_EQUAL(data, opt); } @@ -257,20 +263,89 @@ namespace } //************************************************************************* - TEST(test_moveable) + TEST(test_moveable_not_fundamental) { #include "etl/private/diagnostic_pessimizing_move_push.h" + + // Construct by moving value. etl::optional data(std::move(DataM(1))); + CHECK(data.has_value()); + CHECK(data->valid); CHECK_EQUAL(1U, data.value().value); - CHECK(bool(data)); + CHECK(static_cast(data)); - data = std::move(etl::optional(std::move(DataM(2)))); - CHECK_EQUAL(2U, data.value().value); - CHECK(bool(data)); + // Assign by moving optional. + { + etl::optional temp(DataM(2)); + data = std::move(temp); + CHECK(temp.has_value() && !temp->valid); // NOLINT "Note that a moved-from optional still contains a value (although invalid one)." + CHECK(data.has_value()); + CHECK(data->valid); + CHECK(static_cast(data)); + CHECK_EQUAL(2U, data.value().value); + } - etl::optional data2(etl::move(data)); - CHECK_EQUAL(2U, data2.value().value); - CHECK(bool(data2)); + // Construct by moving optional. + { + etl::optional data2(etl::move(data)); + CHECK(data.has_value() && !data->valid); // NOLINT "Note that a moved-from optional still contains a value (although invalid one)." + CHECK(data2.has_value()); + CHECK(data2->valid); + CHECK(static_cast(data2)); + CHECK_EQUAL(2U, data2.value().value); + } + + // Try to move construct/assign from valueless. + { + etl::optional temp; + etl::optional data2(etl::move(temp)); + CHECK(!data2.has_value()); + + data2 = etl::move(etl::optional()); + CHECK(!data2.has_value()); + } +#include "etl/private/diagnostic_pop.h" + } + + //************************************************************************* + TEST(test_moveable_fundamental) + { +#include "etl/private/diagnostic_pessimizing_move_push.h" + + // Construct by moving value. + etl::optional data(1U); + CHECK(data.has_value()); + CHECK_EQUAL(1U, data.value()); + CHECK(static_cast(data)); + + // Assign by moving optional. + { + etl::optional temp(2U); + data = std::move(temp); + CHECK(temp.has_value()); // NOLINT "Note that a moved-from optional still contains a value." + CHECK(data.has_value()); + CHECK(static_cast(data)); + CHECK_EQUAL(2U, data.value()); + } + + // Construct by moving optional. + { + etl::optional data2(etl::move(data)); + CHECK(data.has_value()); // NOLINT "Note that a moved-from optional still contains a value." + CHECK(data2.has_value()); + CHECK(static_cast(data2)); + CHECK_EQUAL(2U, data2.value()); + } + + // Try to move construct/assign from valueless. + { + etl::optional temp; + etl::optional data2(etl::move(temp)); + CHECK(!data2.has_value()); + + data2 = etl::move(etl::optional()); + CHECK(!data2.has_value()); + } #include "etl/private/diagnostic_pop.h" } @@ -280,7 +355,7 @@ namespace etl::optional data(etl::nullopt); data = 1; data = etl::nullopt; - CHECK(!bool(data)); + CHECK(!static_cast(data)); } //************************************************************************* @@ -289,7 +364,7 @@ namespace etl::optional data(etl::nullopt); data = Data("Hello"); data = etl::nullopt; - CHECK(!bool(data)); + CHECK(!static_cast(data)); } //************************************************************************* @@ -316,7 +391,7 @@ namespace CHECK_EQUAL(5, resultFT); const NonFundamentalType constNFT{"Default"}; - NonFundamentalType resultNFT = etl::optional{}.value_or(constNFT); + const NonFundamentalType resultNFT = etl::optional{}.value_or(constNFT); CHECK_EQUAL("Default", resultNFT); } @@ -338,12 +413,12 @@ namespace TEST(test_chained_value_or_github_bug_720) { - github_bug_720_bug_helper helper{}; + const github_bug_720_bug_helper helper{}; - int value1 = helper.get_valid().value_or(1); + const int value1 = helper.get_valid().value_or(1); CHECK_EQUAL(5, value1); - int value2 = helper.get_invalid().value_or(1); + const int value2 = helper.get_invalid().value_or(1); CHECK_EQUAL(1, value2); } @@ -782,11 +857,11 @@ namespace container.resize(5, Data("1")); - CHECK(bool(container[0])); - CHECK(bool(container[1])); - CHECK(bool(container[2])); - CHECK(bool(container[3])); - CHECK(bool(container[4])); + CHECK(static_cast(container[0])); + CHECK(static_cast(container[1])); + CHECK(static_cast(container[2])); + CHECK(static_cast(container[3])); + CHECK(static_cast(container[4])); } //************************************************************************* @@ -795,10 +870,10 @@ namespace // The indexed access doesn't work in Linux for some reason!!! #ifndef ETL_PLATFORM_LINUX etl::optional> container; - CHECK(!bool(container)); // + CHECK(!static_cast(container)); // container = etl::vector(); - CHECK(bool(container)); + CHECK(static_cast(container)); container.value().resize(5, Data("1")); CHECK_EQUAL(5U, container.value().size()); @@ -822,51 +897,61 @@ namespace //************************************************************************* TEST(test_swap) { - etl::optional original1(Data("1")); - etl::optional original2(Data("2")); + const etl::optional original1(Data("1")); + const etl::optional original2(Data("2")); etl::optional data1; etl::optional data2; // Both invalid. swap(data1, data2); - CHECK(!bool(data1)); - CHECK(!bool(data2)); + CHECK(!static_cast(data1)); + CHECK(!static_cast(data2)); - // Data1 valid; + // data1 is valid data1 = original1; data2 = etl::nullopt; swap(data1, data2); - CHECK(!bool(data1)); - CHECK(bool(data2)); + CHECK(!static_cast(data1)); + CHECK(static_cast(data2)); CHECK_EQUAL(data2, original1); - // Data2 valid; + // data2 is valid data1 = etl::nullopt; data2 = original2; swap(data1, data2); - CHECK(bool(data1)); - CHECK(!bool(data2)); + CHECK(static_cast(data1)); + CHECK(!static_cast(data2)); CHECK_EQUAL(data1, original2); - // Both valid; + // both are valid data1 = original1; data2 = original2; swap(data1, data2); - CHECK(bool(data1)); - CHECK(bool(data2)); + CHECK(static_cast(data1)); + CHECK(static_cast(data2)); CHECK_EQUAL(data1, original2); CHECK_EQUAL(data2, original1); } + //************************************************************************* + TEST(test_swap_moveable) + { + etl::optional data1(1U); + etl::optional data2(2U); + swap(data1, data2); + CHECK_EQUAL(2U, data1.value().value); + CHECK_EQUAL(1U, data2.value().value); + } + //************************************************************************* TEST(test_reset) { etl::optional data(Data("1")); - CHECK(bool(data)); + CHECK(static_cast(data)); data.reset(); - CHECK(!bool(data)); + CHECK(!static_cast(data)); } //************************************************************************* @@ -907,10 +992,10 @@ namespace TEST(test_optional_pod_emplace_bug_712) { - etl::optional optionalObject; // The Test: Does this compile for an object with a - // deleted default constructor? + const etl::optional optionalObject; // The Test: Does this compile for an object with a + // deleted default constructor? - // Make sure it isn't optimised away. + // Make sure it isn't optimized away. CHECK_FALSE(optionalObject.has_value()); } @@ -1079,10 +1164,10 @@ namespace TEST(range_based_for_loop_with_value) { - etl::optional opt = 4; + const etl::optional opt = 4; int sum = 0; - for (int value : opt) + for (const int value : opt) { sum += value; } @@ -1092,10 +1177,10 @@ namespace TEST(range_based_for_loop_empty) { - etl::optional opt; + const etl::optional opt; int sum = 0; - for (int value : opt) + for (const int value : opt) { sum += value; } @@ -1105,8 +1190,8 @@ namespace TEST(test_range_based_for_loop_non_trivial) { - etl::optional opt = Data("TEST"); - int count = 0; + const etl::optional opt = Data("TEST"); + int count = 0; for (const Data& value : opt) { @@ -1162,8 +1247,8 @@ namespace { // etl::optional should compile when T has deleted copy/move // constructors, as long as T is constructible from the given arguments. - Issue146_Container with_value(42); - Issue146_Container without_value; + const Issue146_Container with_value(42); + const Issue146_Container without_value; CHECK_TRUE(with_value.a.has_value()); CHECK_EQUAL(42, with_value.a->_some); @@ -1171,10 +1256,298 @@ namespace CHECK_FALSE(without_value.a.has_value()); // in_place construction should also work - etl::optional opt(etl::in_place_t{}, 99); + const etl::optional opt(etl::in_place_t{}, 99); CHECK_TRUE(opt.has_value()); CHECK_EQUAL(99, opt->_some); } #endif + + TEST(test_make_optional_1_lvalue) + { + const std::string test_value("TEST"); + Data test_data(test_value); + const etl::optional opt = etl::make_optional(test_data); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(test_value, opt.value().value); + } + + TEST(test_make_optional_1_const_value) + { + const std::string test_value("TEST"); + const Data test_data(test_value); + const etl::optional opt = etl::make_optional(test_data); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(test_data.value, opt.value().value); + } + +#if ETL_USING_CPP11 + TEST(test_make_optional_1_rvalue) + { + constexpr uint32_t test_value = 42; + DataM test_data(test_value); + const etl::optional opt = etl::make_optional(std::move(test_data)); + CHECK_TRUE(opt.has_value()); + CHECK_FALSE(test_data.valid); + CHECK_EQUAL(test_value, opt.value().value); + } +#endif + +#if ETL_USING_CPP14 + TEST(test_make_optional_1_constexpr) + { + constexpr etl::optional opt = etl::make_optional(42); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(42, opt.value()); + } +#endif + + TEST(test_make_optional_2_lvalue) + { + std::string test_value("TEST"); + const auto opt = etl::make_optional(test_value); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(test_value, opt.value().value); + } + + TEST(test_make_optional_2_rvalue) + { + const etl::optional opt = etl::make_optional(42u); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(42, opt.value().value); + } + +#if ETL_USING_CPP14 + TEST(test_make_optional_2_constexpr) + { + constexpr etl::optional opt = etl::make_optional(42); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(42, opt.value()); + } +#endif + + TEST(test_make_optional_3) + { + int test_value1(1); + const int test_value2(2); + const auto opt = etl::make_optional({10, 11, 12}, test_value1, test_value2, 3); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(10, opt->arr[0]); + CHECK_EQUAL(11, opt->arr[1]); + CHECK_EQUAL(12, opt->arr[2]); + CHECK_EQUAL(test_value1, opt->a); + CHECK_EQUAL(test_value2, opt->b); + CHECK_EQUAL(3, opt->c); + } + +#if ETL_USING_CPP20 && ETL_USING_STL + TEST(test_make_optional_3_constexpr) + { + constexpr etl::optional opt = etl::make_optional({1, 2}, 10, 20, 30); + CHECK_TRUE(opt.has_value()); + CHECK_EQUAL(1, opt->arr[0]); + CHECK_EQUAL(2, opt->arr[1]); + CHECK_EQUAL(0, opt->arr[2]); + CHECK_EQUAL(10, opt->a); + CHECK_EQUAL(20, opt->b); + CHECK_EQUAL(30, opt->c); + } +#endif + + //************************************************************************* + // Tests for noexcept properties of etl::optional + // The noexcept specs only take effect when ETL_USING_EXCEPTIONS is enabled, + // because ETL_NOEXCEPT_IF expands to nothing otherwise. + // The etl::is_nothrow_* traits only work with STL or builtins. + //************************************************************************* +#if ETL_USING_CPP11 && ETL_USING_EXCEPTIONS && (defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS))) + struct NothrowAtAll + { + NothrowAtAll() noexcept {} + NothrowAtAll(const NothrowAtAll&) noexcept {} + NothrowAtAll(NothrowAtAll&&) noexcept {} + NothrowAtAll(std::initializer_list) noexcept {} + NothrowAtAll& operator=(const NothrowAtAll&) noexcept + { + return *this; + } + NothrowAtAll& operator=(NothrowAtAll&&) noexcept + { + return *this; + } + }; + + struct ThrowingCopy + { + ThrowingCopy() noexcept {} + ThrowingCopy(const ThrowingCopy&) {} // may throw + ThrowingCopy(ThrowingCopy&&) noexcept {} + ThrowingCopy& operator=(const ThrowingCopy&) // may throw + { + return *this; + } + ThrowingCopy& operator=(ThrowingCopy&&) noexcept + { + return *this; + } + }; + + struct ThrowingMove + { + ThrowingMove() noexcept {} + ThrowingMove(const ThrowingMove&) noexcept {} + ThrowingMove(ThrowingMove&&) {} // may throw + ThrowingMove& operator=(const ThrowingMove&) noexcept + { + return *this; + } + ThrowingMove& operator=(ThrowingMove&&) // may throw + { + return *this; + } + }; + + struct ThrowingAll + { + ThrowingAll() {} // may throw + ThrowingAll(const ThrowingAll&) {} // may throw + ThrowingAll(ThrowingAll&&) {} // may throw + ThrowingAll(std::initializer_list) {} // may throw + ThrowingAll& operator=(const ThrowingAll&) // may throw + { + return *this; + } + ThrowingAll& operator=(ThrowingAll&&) // may throw + { + return *this; + } + }; + + TEST(test_optional_nothrow_copy_constructible) + { + // When T is nothrow copy constructible, optional should be too + static_assert(etl::is_nothrow_copy_constructible>::value, "optional should be nothrow copy constructible"); + static_assert(etl::is_nothrow_copy_constructible>::value, + "optional should be nothrow copy constructible"); + + // When T is NOT nothrow copy constructible, optional should not be either + static_assert(!etl::is_nothrow_copy_constructible>::value, + "optional should NOT be nothrow copy constructible"); + static_assert(!etl::is_nothrow_copy_constructible>::value, + "optional should NOT be nothrow copy constructible"); + + // ThrowingMove has nothrow copy but throwing move + static_assert(etl::is_nothrow_copy_constructible>::value, + "optional should be nothrow copy constructible"); + + CHECK(true); // Placeholder for the static_asserts above + } + + TEST(test_optional_nothrow_move_constructible) + { + // When T is nothrow move constructible, optional (and swap) should be too + static_assert(etl::is_nothrow_move_constructible>::value, "optional should be nothrow move constructible"); + static_assert(etl::is_nothrow_move_constructible>::value, + "optional should be nothrow move constructible"); + static_assert(noexcept(swap(std::declval&>(), std::declval&>())), "swap() should be nothrow"); + static_assert(noexcept(swap(std::declval&>(), std::declval&>())), + "swap() should be nothrow"); + + // When T is NOT nothrow move constructible, optional (and swap) should not be either + static_assert(!etl::is_nothrow_move_constructible>::value, + "optional should NOT be nothrow move constructible"); + static_assert(!etl::is_nothrow_move_constructible>::value, + "optional should NOT be nothrow move constructible"); + static_assert(!noexcept(swap(std::declval&>(), std::declval&>())), + "swap() should NOT be nothrow"); + static_assert(!noexcept(swap(std::declval&>(), std::declval&>())), + "swap() should NOT be nothrow"); + + // ThrowingCopy has nothrow move but throwing copy + static_assert(etl::is_nothrow_move_constructible>::value, + "optional should be nothrow move constructible"); + static_assert(noexcept(swap(std::declval&>(), std::declval&>())), + "swap() should be nothrow"); + + CHECK(true); // Placeholder for the static_asserts above + } + + TEST(test_optional_nothrow_default_constructible) + { + // Default construction of optional should always be noexcept + static_assert(etl::is_nothrow_default_constructible>::value, "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + static_assert(etl::is_nothrow_default_constructible>::value, + "optional should be nothrow default constructible"); + + CHECK(true); + } + + TEST(test_optional_nothrow_constructible_from_value) + { + // optional(U&&) should be noexcept iff T is nothrow constructible from U&& + static_assert(etl::is_nothrow_constructible, int>::value, "optional should be nothrow constructible from int"); + static_assert(etl::is_nothrow_constructible, int&&>::value, "optional should be nothrow constructible from int&&"); + + CHECK(true); + } + + TEST(test_optional_nothrow_copy_assignable) + { + // Copy assignment should propagate noexcept from T + static_assert(etl::is_nothrow_copy_assignable>::value, "optional should be nothrow copy assignable"); + static_assert(etl::is_nothrow_copy_assignable>::value, "optional should be nothrow copy assignable"); + + // ThrowingCopy has a throwing copy constructor, so copy assignment should not be noexcept + static_assert(!etl::is_nothrow_copy_assignable>::value, + "optional should NOT be nothrow copy assignable"); + + CHECK(true); + } + + TEST(test_optional_nothrow_move_assignable) + { + // Move assignment should propagate noexcept from T + static_assert(etl::is_nothrow_move_assignable>::value, "optional should be nothrow move assignable"); + static_assert(etl::is_nothrow_move_assignable>::value, "optional should be nothrow move assignable"); + + // ThrowingMove has a throwing move constructor, so move assignment should not be noexcept + static_assert(!etl::is_nothrow_move_assignable>::value, + "optional should NOT be nothrow move assignable"); + + CHECK(true); + } + + TEST(test_make_optional_nothrow) + { + // make_optional #1 + { + NothrowAtAll nothrowAtAll{}; + static_assert(noexcept(etl::make_optional(nothrowAtAll)), "make_optional(NothrowAtAll&) should be nothrow"); + static_assert(noexcept(etl::make_optional(std::move(nothrowAtAll))), "make_optional(NothrowAtAll&&) should be nothrow"); + ThrowingAll throwingAll{}; + static_assert(!noexcept(etl::make_optional(throwingAll)), "make_optional(ThrowingAll&) should NOT be nothrow"); + static_assert(!noexcept(etl::make_optional(std::move(throwingAll))), "make_optional(ThrowingAll&&) should NOT be nothrow"); + } + + // make_optional #2 + { + static_assert(noexcept(etl::make_optional()), "make_optional() should be nothrow"); + static_assert(noexcept(etl::make_optional()), "make_optional() should be nothrow"); + static_assert(!noexcept(etl::make_optional()), "make_optional() should NOT be nothrow"); + static_assert(!noexcept(etl::make_optional()), "make_optional() should NOT be nothrow"); + } + + // make_optional #3 + { + static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional(1,2,3) should be nothrow"); + static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional(1,2,3) should be nothrow"); + static_assert(!noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should NOT be nothrow"); + static_assert(!noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should NOT be nothrow"); + } + } +#endif } } // namespace diff --git a/test/test_ranges.cpp b/test/test_ranges.cpp index 0fe4c41b..3f4b4e00 100644 --- a/test/test_ranges.cpp +++ b/test/test_ranges.cpp @@ -157,6 +157,7 @@ namespace std namespace { + #include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_ranges) { //************************************************************************* @@ -3383,6 +3384,42 @@ namespace CHECK(it == ev.end()); } + //************************************************************************* + TEST(test_ranges_keys_view_alias) + { + std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; + + using range_t = etl::ranges::views::all_t; + etl::ranges::keys_view kv(etl::ranges::views::all(v)); + + auto it = kv.begin(); + CHECK_EQUAL(10, *it); + ++it; + CHECK_EQUAL(20, *it); + ++it; + CHECK_EQUAL(30, *it); + ++it; + CHECK(it == kv.end()); + } + + //************************************************************************* + TEST(test_ranges_values_view_alias) + { + std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; + + using range_t = etl::ranges::views::all_t; + etl::ranges::values_view vv(etl::ranges::views::all(v)); + + auto it = vv.begin(); + CHECK_CLOSE(1.1, *it, 0.001); + ++it; + CHECK_CLOSE(2.2, *it, 0.001); + ++it; + CHECK_CLOSE(3.3, *it, 0.001); + ++it; + CHECK(it == vv.end()); + } + //************************************************************************* TEST(test_ranges_views_keys) { @@ -5740,6 +5777,7 @@ namespace CHECK_EQUAL(30, v_out[2]); } } + #include "etl/private/diagnostic_pop.h" } // namespace #endif diff --git a/test/test_set.cpp b/test/test_set.cpp index f8f56d50..2fb624d4 100644 --- a/test/test_set.cpp +++ b/test/test_set.cpp @@ -103,10 +103,10 @@ namespace // return (lhs.k < rhs.k); // } +#include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_set) { //************************************************************************* -#include "etl/private/diagnostic_null_dereference_push.h" template bool Check_Equal(T1 begin1, T1 end1, T2 begin2) { @@ -123,7 +123,6 @@ namespace return true; } -#include "etl/private/diagnostic_pop.h" //************************************************************************* struct SetupFixture @@ -595,8 +594,8 @@ namespace for (size_t i = 0; i < MAX_SIZE; ++i) { - data_result = data.insert(i); - compare_result = compare_data.insert(i); + data_result = data.insert(static_cast(i)); + compare_result = compare_data.insert(static_cast(i)); // Check that both return successful return results CHECK_EQUAL(*data_result.first, *compare_result.first); @@ -609,8 +608,8 @@ namespace // not throw error for (size_t i = 0; i < MAX_SIZE; ++i) { - data_result = data.insert(i); - compare_result = compare_data.insert(i); + data_result = data.insert(static_cast(i)); + compare_result = compare_data.insert(static_cast(i)); // Check that both return successful return results CHECK_EQUAL(*data_result.first, *compare_result.first); @@ -1443,4 +1442,5 @@ namespace } while (std::next_permutation(permutation.begin(), permutation.end())); } } +#include "etl/private/diagnostic_pop.h" } // namespace diff --git a/test/test_string_char.cpp b/test/test_string_char.cpp index 63b84400..b8271af4 100644 --- a/test/test_string_char.cpp +++ b/test/test_string_char.cpp @@ -5475,5 +5475,32 @@ namespace CHECK(text1 == sstream_view); } #endif + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_char_pointer_n_shorter_than_strlen) + { + const value_t haystack_str[] = STR("Hello World"); + + TextSTD compare(haystack_str); + TextL text(haystack_str); + + // Haystack is "Hello World" (size 11). + // search_str is "Worldly" (strlen 7). + // We search for first 5 chars ("World") starting at pos=6. + // Old code: (6 + 7 = 13) > 11 → premature npos (BUG) + // Fixed: (6 + 5 = 11) <= 11 → proceeds to search → finds at 6 + const value_t search_str[] = STR("Worldly"); + + size_t pos_std = compare.find(search_str, 6, 5); + size_t pos_etl = text.find(search_str, 6, 5); + CHECK_EQUAL(6U, pos_std); + CHECK_EQUAL(pos_std, pos_etl); + + // pos=5 also triggers: (5 + 7 = 12) > 11 with old code + pos_std = compare.find(search_str, 5, 5); + pos_etl = text.find(search_str, 5, 5); + CHECK_EQUAL(6U, pos_std); + CHECK_EQUAL(pos_std, pos_etl); + } } } // namespace diff --git a/test/test_string_view.cpp b/test/test_string_view.cpp index 658a6fea..a9314dd2 100644 --- a/test/test_string_view.cpp +++ b/test/test_string_view.cpp @@ -877,7 +877,7 @@ namespace CHECK(2U == view.rfind(s2, 5)); CHECK(View::npos == view.rfind(s4)); - CHECK(1U == view.rfind(s3, 5, 2)); + CHECK(5U == view.rfind(s3, 5, 2)); CHECK(View::npos == view.rfind(s4, 0, 11)); } @@ -1183,5 +1183,40 @@ namespace CHECK_TRUE(u32view == u32sstream_view); } #endif + + //************************************************************************* + TEST(test_rfind_boundary_positions) + { + etl::string_view sv("abcabc"); + + // rfind "abc" with position=3: should find the second "abc" at position 3 + size_t pos = sv.rfind(etl::string_view("abc"), 3); + CHECK_EQUAL(3U, pos); + + // rfind "abc" with position=2: should find only the first "abc" at position 0 + pos = sv.rfind(etl::string_view("abc"), 2); + CHECK_EQUAL(0U, pos); + + // rfind "abc" with position=0: should find at position 0 + pos = sv.rfind(etl::string_view("abc"), 0); + CHECK_EQUAL(0U, pos); + + // rfind with npos (search entire string) + pos = sv.rfind(etl::string_view("abc")); + CHECK_EQUAL(3U, pos); + + // rfind something not found + pos = sv.rfind(etl::string_view("xyz")); + CHECK_EQUAL(etl::string_view::npos, pos); + + // Compare with std::string to verify exact behavior + std::string std_sv("abcabc"); + for (size_t p = 0; p <= std_sv.size(); ++p) + { + size_t std_pos = std_sv.rfind("abc", p); + size_t etl_pos = sv.rfind(etl::string_view("abc"), p); + CHECK_EQUAL(std_pos, etl_pos); + } + } } } // namespace diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index c49b2eda..6756d6d9 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -102,8 +102,8 @@ namespace return *this; } - Copyable(Copyable&&) = delete; - Copyable& operator=(Copyable&) = delete; + Copyable(Copyable&&) = delete; + Copyable& operator=(Copyable&&) = delete; }; //********************************************* @@ -146,8 +146,8 @@ namespace return *this; } - NotDefaultConstructible(NotDefaultConstructible&&) = delete; - NotDefaultConstructible& operator=(NotDefaultConstructible&) = delete; + NotDefaultConstructible(NotDefaultConstructible&&) = delete; + NotDefaultConstructible& operator=(NotDefaultConstructible&&) = delete; }; // A function to test etl::type_identity. @@ -344,7 +344,7 @@ using etl::is_move_constructible; //************************* template <> -struct etl::is_assignable : public etl::true_type +struct etl::is_assignable : public etl::false_type { }; @@ -364,7 +364,7 @@ struct etl::is_copy_assignable : public etl::true_type }; template <> -struct etl::is_move_assignable : public etl::true_type +struct etl::is_move_assignable : public etl::false_type { }; @@ -1007,6 +1007,64 @@ namespace CHECK((std::is_base_of::value) == (etl::is_base_of::value)); } +#if ETL_USING_BUILTIN_IS_VIRTUAL_BASE_OF + //************************************************************************* + TEST(test_is_virtual_base_of) + { + struct A + { + }; + struct B : public A // Non-virtual base + { + }; + struct C : virtual public A // Virtual base + { + }; + struct D + : public B + , virtual public A // A is both virtual and non-virtual base + { + }; + struct E : public C // A is indirect virtual base + { + }; + struct F // Unrelated class + { + }; + + // A is not a virtual base of A (same class) + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // A is NOT a virtual base of B (it's a non-virtual base) + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of C + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of D (even though it's also a non-virtual base via B) + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // A IS a virtual base of E (indirect virtual base) + CHECK_EQUAL(true, (etl::is_virtual_base_of::value)); + + // Unrelated classes + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + // Fundamental types + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + CHECK_EQUAL(false, (etl::is_virtual_base_of::value)); + + #if ETL_USING_CPP17 + // Test the _v helper + CHECK_EQUAL(false, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + CHECK_EQUAL(true, etl::is_virtual_base_of_v); + #endif + } +#endif + //************************************************************************* TEST(test_types) { @@ -1490,6 +1548,155 @@ namespace #endif } + //************************************************************************* + TEST(test_is_nothrow_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_constructible::value) == true); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == false); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + CHECK((etl::is_nothrow_constructible::value) == (std::is_nothrow_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + CHECK((etl::is_nothrow_constructible_v) == (std::is_nothrow_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_default_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_default_constructible::value) == true); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == false); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + CHECK((etl::is_nothrow_default_constructible::value) == (std::is_nothrow_default_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + CHECK((etl::is_nothrow_default_constructible_v) == (std::is_nothrow_default_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_copy_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_copy_constructible::value) == true); + CHECK((etl::is_nothrow_copy_constructible::value) == true); + CHECK((etl::is_nothrow_copy_constructible::value) == false); + CHECK((etl::is_nothrow_copy_constructible::value) == false); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + CHECK((etl::is_nothrow_copy_constructible::value) == (std::is_nothrow_copy_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + CHECK((etl::is_nothrow_copy_constructible_v) == (std::is_nothrow_copy_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_move_constructible) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == false); + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == true); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + CHECK((etl::is_nothrow_move_constructible::value) == (std::is_nothrow_move_constructible::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + CHECK((etl::is_nothrow_move_constructible_v) == (std::is_nothrow_move_constructible_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == false); + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == true); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) == (std::is_nothrow_assignable::value)); + CHECK((etl::is_nothrow_assignable::value) + == (std::is_nothrow_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK((etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + CHECK( + (etl::is_nothrow_assignable_v) == (std::is_nothrow_assignable_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_copy_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_copy_assignable::value) == true); + CHECK((etl::is_nothrow_copy_assignable::value) == true); + CHECK((etl::is_nothrow_copy_assignable::value) == false); + CHECK((etl::is_nothrow_copy_assignable::value) == false); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + CHECK((etl::is_nothrow_copy_assignable::value) == (std::is_nothrow_copy_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + CHECK((etl::is_nothrow_copy_assignable_v) == (std::is_nothrow_copy_assignable_v)); + #endif +#endif + } + + //************************************************************************* + TEST(test_is_nothrow_move_assignable) + { +#if defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS)) + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == false); + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == true); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + CHECK((etl::is_nothrow_move_assignable::value) == (std::is_nothrow_move_assignable::value)); + #if ETL_USING_CPP17 + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + CHECK((etl::is_nothrow_move_assignable_v) == (std::is_nothrow_move_assignable_v)); + #endif +#endif + } + //************************************************************************* TEST(test_is_trivially_constructible) { @@ -1574,6 +1781,110 @@ namespace #endif } + //************************************************************************* + TEST(test_is_trivially_relocatable) + { + // Trivially relocatable types (trivially copyable and trivially destructible) + // Primitive types should always be detected as trivially relocatable + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + + // POD struct should be trivially relocatable when proper detection is available + struct TrivialStruct + { + int x; + double y; + }; + + // Struct with non-trivial destructor should NOT be trivially relocatable + struct NonTrivialDestructor + { + ~NonTrivialDestructor() {} + }; + CHECK_FALSE(etl::is_trivially_relocatable::value); + + // Struct with non-trivial copy constructor should NOT be trivially relocatable + struct NonTrivialCopy + { + NonTrivialCopy() = default; + NonTrivialCopy(const NonTrivialCopy&) {} + NonTrivialCopy& operator=(const NonTrivialCopy&) = default; + }; + CHECK_FALSE(etl::is_trivially_relocatable::value); + +#if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + // These tests require STL or compiler builtins to correctly detect struct/array triviality + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); + CHECK_TRUE(etl::is_trivially_relocatable::value); +#endif + +#if ETL_USING_CPP17 + // Test the _v helper variable + CHECK_TRUE(etl::is_trivially_relocatable_v); + CHECK_TRUE(etl::is_trivially_relocatable_v); + CHECK_TRUE(etl::is_trivially_relocatable_v); + #if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + CHECK_TRUE(etl::is_trivially_relocatable_v); + #endif + CHECK_FALSE(etl::is_trivially_relocatable_v); + CHECK_FALSE(etl::is_trivially_relocatable_v); +#endif + + // Verify consistency: if a type is trivially_copyable AND trivially_destructible, + // then it should be trivially_relocatable. The reverse may not hold when compiler + // builtins provide more accurate detection than the fallback implementations. + CHECK_TRUE(!(etl::is_trivially_copyable::value && etl::is_trivially_destructible::value) + || etl::is_trivially_relocatable::value); + CHECK_TRUE(!(etl::is_trivially_copyable::value && etl::is_trivially_destructible::value) + || etl::is_trivially_relocatable::value); + // Non-trivially destructible types should never be trivially relocatable + CHECK_FALSE(etl::is_trivially_relocatable::value); + // Non-trivially copyable types should never be trivially relocatable + CHECK_FALSE(etl::is_trivially_relocatable::value); + } + + //************************************************************************* + TEST(test_is_nothrow_relocatable) + { + // Trivially relocatable types should always be nothrow relocatable + // Primitive types should always be detected correctly + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + + // POD struct should be nothrow relocatable when proper detection is available + struct TrivialStruct + { + int x; + double y; + }; + +#if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + // These tests require STL or compiler builtins to correctly detect struct/array triviality + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); + CHECK_TRUE(etl::is_nothrow_relocatable::value); +#endif + +#if ETL_USING_CPP17 + // Test the _v helper variable + CHECK_TRUE(etl::is_nothrow_relocatable_v); + CHECK_TRUE(etl::is_nothrow_relocatable_v); + CHECK_TRUE(etl::is_nothrow_relocatable_v); + #if ETL_USING_STL || ETL_USING_BUILTIN_IS_TRIVIALLY_RELOCATABLE + CHECK_TRUE(etl::is_nothrow_relocatable_v); + #endif +#endif + + // Verify consistency: nothrow_relocatable should be at least as permissive as trivially_relocatable + CHECK_TRUE(!etl::is_trivially_relocatable::value || etl::is_nothrow_relocatable::value); + CHECK_TRUE(!etl::is_trivially_relocatable::value || etl::is_nothrow_relocatable::value); + } + //************************************************************************* TEST(test_is_base_of_any) { @@ -1900,5 +2211,62 @@ namespace CHECK_FALSE((etl::is_function::value)); CHECK_FALSE((etl::is_function::value)); // pointer, not function } + + //************************************************************************* + TEST(test_is_object) + { + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + CHECK_TRUE((etl::is_object::value)); + + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + CHECK_FALSE((etl::is_object::value)); + + CHECK_TRUE((etl::is_void::value)); + CHECK_TRUE((etl::is_void::value)); + CHECK_TRUE((etl::is_void::value)); + +#if ETL_USING_CPP17 + CHECK_TRUE((etl::is_object_v)); + CHECK_TRUE((etl::is_object_v)); + CHECK_TRUE((etl::is_object_v)); + + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); + CHECK_FALSE((etl::is_object_v)); +#endif + } + + //************************************************************************* + TEST(test_is_signed_unsigned_char_types) + { +#if ETL_HAS_NATIVE_CHAR8_T + CHECK_FALSE(etl::is_signed::value); + CHECK_TRUE(etl::is_unsigned::value); +#endif + +#if ETL_HAS_NATIVE_CHAR16_T + CHECK_FALSE(etl::is_signed::value); + CHECK_TRUE(etl::is_unsigned::value); +#endif + +#if ETL_HAS_NATIVE_CHAR32_T + CHECK_FALSE(etl::is_signed::value); + CHECK_TRUE(etl::is_unsigned::value); +#endif + } } } // namespace diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 06d0d325..08cf2e75 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -1047,5 +1047,51 @@ namespace CHECK_EQUAL(expect1c, result1g); #endif } + + //************************************************************************* + TEST(test_pair_equality_uses_equality_operator) + { + // Basic equality + etl::pair p1(1, 2); + etl::pair p2(1, 2); + etl::pair p3(1, 3); + etl::pair p4(2, 2); + + CHECK_TRUE(p1 == p2); + CHECK_FALSE(p1 == p3); // different second + CHECK_FALSE(p1 == p4); // different first + + // Custom type where operator== and operator< can disagree + // The old code used !(ab), which is NOT equivalent to a==b + // for types that don't define a total order consistent with equality. + struct WeirdType + { + int value; + bool equal_flag; + + bool operator==(const WeirdType& other) const + { + return equal_flag && other.equal_flag; + } + bool operator<(const WeirdType& other) const + { + return value < other.value; + } + bool operator>(const WeirdType& other) const + { + return value > other.value; + } + }; + + WeirdType w1{1, false}; + WeirdType w2{1, false}; // same value, but equal_flag is false + + // With proper ==: w1 == w2 should be false (both equal_flags are false) + // With old !(w1w2): would be true (same value) + etl::pair pw1(0, w1); + etl::pair pw2(0, w2); + + CHECK_FALSE(pw1 == pw2); // This would FAIL with the old < > based comparison + } } } // namespace diff --git a/test/test_variant_variadic.cpp b/test/test_variant_variadic.cpp index f8b8fe5f..1a1410ba 100644 --- a/test/test_variant_variadic.cpp +++ b/test/test_variant_variadic.cpp @@ -2243,6 +2243,131 @@ namespace CHECK(etl::holds_alternative(v1)); CHECK(etl::get_if(&v1) != nullptr); } + + //************************************************************************* + // Tests for noexcept properties of etl::variant + // The noexcept specs only take effect when ETL_USING_EXCEPTIONS is enabled, + // because ETL_NOEXCEPT_IF expands to nothing otherwise. + // The etl::is_nothrow_* traits only work with STL or builtins. + //************************************************************************* + #if ETL_USING_EXCEPTIONS && (defined(ETL_USE_TYPE_TRAITS_BUILTINS) || (ETL_USING_STL && !defined(ETL_USER_DEFINED_TYPE_TRAITS))) + + struct VariantNothrowType + { + VariantNothrowType() noexcept {} + VariantNothrowType(const VariantNothrowType&) noexcept {} + VariantNothrowType(VariantNothrowType&&) noexcept {} + VariantNothrowType& operator=(const VariantNothrowType&) noexcept + { + return *this; + } + VariantNothrowType& operator=(VariantNothrowType&&) noexcept + { + return *this; + } + }; + + struct VariantThrowingCopy + { + VariantThrowingCopy() noexcept {} + VariantThrowingCopy(const VariantThrowingCopy&) {} // may throw + VariantThrowingCopy(VariantThrowingCopy&&) noexcept {} + VariantThrowingCopy& operator=(const VariantThrowingCopy&) + { + return *this; + } + VariantThrowingCopy& operator=(VariantThrowingCopy&&) noexcept + { + return *this; + } + }; + + struct VariantThrowingMove + { + VariantThrowingMove() noexcept {} + VariantThrowingMove(const VariantThrowingMove&) noexcept {} + VariantThrowingMove(VariantThrowingMove&&) {} // may throw + VariantThrowingMove& operator=(const VariantThrowingMove&) noexcept + { + return *this; + } + VariantThrowingMove& operator=(VariantThrowingMove&&) + { + return *this; + } + }; + + TEST(test_variant_nothrow_copy_constructible) + { + // variant is nothrow copy constructible only if all Ts are + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_copy_constructible::value, "variant should be nothrow copy constructible"); + + using HasThrowingCopy = etl::variant; + static_assert(!etl::is_nothrow_copy_constructible::value, + "variant should NOT be nothrow copy constructible"); + + using HasThrowingMove = etl::variant; + static_assert(etl::is_nothrow_copy_constructible::value, + "variant should be nothrow copy constructible (copy is nothrow)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_move_constructible) + { + // variant is nothrow move constructible only if all Ts are + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_move_constructible::value, "variant should be nothrow move constructible"); + + using HasThrowingMove = etl::variant; + static_assert(!etl::is_nothrow_move_constructible::value, + "variant should NOT be nothrow move constructible"); + + using HasThrowingCopy = etl::variant; + static_assert(etl::is_nothrow_move_constructible::value, + "variant should be nothrow move constructible (move is nothrow)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_default_constructible) + { + // variant default-constructs the first alternative + using NothrowFirst = etl::variant; + static_assert(etl::is_nothrow_default_constructible::value, + "variant should be nothrow default constructible (int is nothrow)"); + + using ThrowingFirst = etl::variant; + // VariantThrowingCopy has noexcept default ctor, so this should be nothrow + static_assert(etl::is_nothrow_default_constructible::value, + "variant should be nothrow default constructible (ThrowingCopy has noexcept default ctor)"); + + CHECK(true); + } + + TEST(test_variant_nothrow_copy_assignable) + { + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_copy_assignable::value, "variant should be nothrow copy assignable"); + + using HasThrowingCopy = etl::variant; + static_assert(!etl::is_nothrow_copy_assignable::value, "variant should NOT be nothrow copy assignable"); + + CHECK(true); + } + + TEST(test_variant_nothrow_move_assignable) + { + using AllNothrow = etl::variant; + static_assert(etl::is_nothrow_move_assignable::value, "variant should be nothrow move assignable"); + + using HasThrowingMove = etl::variant; + static_assert(!etl::is_nothrow_move_assignable::value, "variant should NOT be nothrow move assignable"); + + CHECK(true); + } + #endif } } // namespace diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 93ea62c4..57fee1e8 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -3541,6 +3541,7 @@ + @@ -10273,8 +10274,9 @@ - - + + + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 4921e669..8553316d 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3647,7 +3647,7 @@ Tests\Chrono - + Tests\Callbacks & Delegates @@ -3704,7 +3704,7 @@ Tests\CRC - + Tests\Callbacks & Delegates @@ -3800,6 +3800,9 @@ Tests\Strings + + Tests\Callbacks & Delegates + @@ -3979,12 +3982,6 @@ Resource Files\CI\Github - - Documentation - - - Documentation -