diff --git a/.drone.jsonnet b/.drone.jsonnet new file mode 100644 index 00000000..a2c30dcd --- /dev/null +++ b/.drone.jsonnet @@ -0,0 +1,420 @@ +# Copyright 2022, 2023 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +local library = "crypt"; + +local triggers = +{ + branch: [ "master", "develop", "feature/*" ] +}; + +local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' }; +local asan = { ASAN: '1' }; + +local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "linux", + arch: arch + }, + steps: + [ + { + name: "everything", + image: image, + privileged: true, + environment: environment, + commands: + [ + 'set -e', + 'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -', + ] + + (if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) + + (if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) + + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "exec", + trigger: triggers, + platform: { + "os": "darwin", + "arch": arch + }, + node: { + "os": osx_version + }, + steps: [ + { + name: "everything", + environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" }, + commands: + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local windows_pipeline(name, image, environment, arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "windows", + arch: arch + }, + "steps": + [ + { + name: "everything", + image: image, + environment: environment, + commands: + [ + 'cmd /C .drone\\\\drone.bat ' + library, + ] + } + ] +}; + +[ + + linux_pipeline( + "Linux 18.04 GCC 8 32/64", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' }, + "g++-8-multilib", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 20.04 GCC 9* ARM64", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' }, + arch="arm64", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* ARM64 - ASAN", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' } + asan, + arch="arm64", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* S390x", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' }, + arch="s390x", + ), + + linux_pipeline( + "Linux 20.04 GCC 10 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' }, + "g++-10-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 11* 32/64", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 03", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 11", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 14", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '14', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 17", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 20", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 2b", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 64 ASAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '64' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 32/64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32,64', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 GNU 32/64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32,64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 32", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '64', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 GNU 32", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 GNU 64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 03", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 11", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 14", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '14', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 17", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 03", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 11", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 14", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '14', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 17", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 Clang 6.0", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' }, + "clang-6.0", + ), + + linux_pipeline( + "Linux 20.04 Clang 7", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' }, + "clang-7", + ), + + linux_pipeline( + "Linux 20.04 Clang 8", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' }, + "clang-8", + ), + + linux_pipeline( + "Linux 20.04 Clang 9", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' }, + "clang-9", + ), + + linux_pipeline( + "Linux 20.04 Clang 10", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' }, + "clang-10", + ), + + linux_pipeline( + "Linux 20.04 Clang 11", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' }, + "clang-11", + ), + + linux_pipeline( + "Linux 20.04 Clang 12", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' }, + "clang-12", + ), + + linux_pipeline( + "Linux 22.04 Clang 13", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' }, + "clang-13", + ), + + linux_pipeline( + "Linux 22.04 Clang 14 UBSAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan, + "clang-14", + ), + + linux_pipeline( + "Linux 22.04 Clang 14 ASAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + asan, + "clang-14", + ), + + linux_pipeline( + "Linux 22.04 Clang 15", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' }, + "clang-15", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"], + ), + + linux_pipeline( + "Linux 22.04 Clang 16", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '03,11,14,17,20,2b' }, + "clang-16", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main"], + ), + + linux_pipeline( + "Linux 24.04 Clang 17", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '03,11,14,17,20,2b' }, + "clang-17", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main"], + ), + + linux_pipeline( + "Linux 24.04 Clang 18", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '03,11,14,17,20,2b' }, + "clang-18", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main"], + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 UBSAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 ASAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + windows_pipeline( + "Windows VS2019 msvc-14.2", + "cppalliance/dronevs2019", + { TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' }, + ), + + windows_pipeline( + "Windows VS2022 msvc-14.3", + "cppalliance/dronevs2022:1", + { TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' }, + ), +] diff --git a/.drone/drone.bat b/.drone/drone.bat new file mode 100644 index 00000000..2b56e63c --- /dev/null +++ b/.drone/drone.bat @@ -0,0 +1,25 @@ +@REM Copyright 2022 Peter Dimov +@REM Distributed under the Boost Software License, Version 1.0. +@REM https://www.boost.org/LICENSE_1_0.txt + +@ECHO ON + +set LIBRARY=%1 +set DRONE_BUILD_DIR=%CD% + +echo $env:DRONE_STAGE_MACHINE + +set BOOST_BRANCH=develop +if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master +cd .. +git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\ +python tools/boostdep/depinst/depinst.py -I example %LIBRARY% +cmd /c bootstrap +b2 -d0 headers + +if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% +if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% +b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker diff --git a/.drone/drone.sh b/.drone/drone.sh new file mode 100755 index 00000000..5a546959 --- /dev/null +++ b/.drone/drone.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Copyright 2022 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +set -ex +export PATH=~/.local/bin:/usr/local/bin:$PATH +uname -a +echo $DRONE_STAGE_MACHINE + +DRONE_BUILD_DIR=$(pwd) + +BOOST_BRANCH=develop +if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi + +cd .. +git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +mkdir -p libs/$LIBRARY +cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY +python tools/boostdep/depinst/depinst.py -I example $LIBRARY +./bootstrap.sh +./b2 -d0 headers + +if [[ $(uname) == "Linux" ]]; then + echo 0 | sudo tee /proc/sys/kernel/randomize_va_space +fi + +echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam +./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${CXXFLAGS:+cxxflags=$CXXFLAGS} ${CXXSTDDIALECT:+cxxstd-dialect=$CXXSTDDIALECT} ${LINKFLAGS:+linkflags=$LINKFLAGS} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..66ba35dd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,798 @@ +# Copyright 2021-2022 Andrey Semashev +# Copyright 2023 Matt Borland +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: CI + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +concurrency: + group: ${{format('{0}:{1}', github.repository, github.ref)}} + cancel-in-progress: true + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + - toolset: gcc-7 + cxxstd: "03,11,14,17" + address_model: 32,64 + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-7-multilib + - toolset: gcc-8 + cxxstd: "03,11,14,17,2a" + address_model: 32,64 + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-8-multilib + - toolset: gcc-9 + cxxstd: "03,11,14,17,2a" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-9-multilib + - toolset: gcc-9 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,2a-gnu" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-9-multilib + - toolset: gcc-10 + cxxstd: "03,11,14,17,20" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-10-multilib + - toolset: gcc-11 + cxxstd: "03,11,14,17,20,23" + address_model: 32,64 + os: ubuntu-22.04 + install: + - g++-11-multilib + - toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: 32,64 + os: ubuntu-22.04 + install: + - g++-12-multilib + # Disabled for now. 22.04 dropped support and 24.04 has internal errors + #- toolset: gcc-13 + # cxxstd: "03,11,14,17,20,23" + # address_model: 32,64 + # os: ubuntu-24.04 + # install: + # - g++-13-multilib + # cxxflags: -Wno-uninitialized + - toolset: gcc-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + address_model: "32" + os: ubuntu-22.04 + install: + - g++-12-multilib + - toolset: gcc-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + address_model: "64" + os: ubuntu-22.04 + install: + - g++-12-multilib + - name: 32-bit UBSAN + toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: "32" + ubsan: 1 + os: ubuntu-22.04 + install: + - g++-12-multilib + - name: 64-bit UBSAN + toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: "64" + ubsan: 1 + os: ubuntu-22.04 + install: + - g++-12-multilib + + # Linux, clang + - toolset: clang + compiler: clang++-6.0 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-6.0 + - toolset: clang + compiler: clang++-7 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-7 + # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode + - toolset: clang + compiler: clang++-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-8 + - g++-7 + gcc_toolchain: 7 + - toolset: clang + compiler: clang++-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-20.04 + install: + - clang-9 + - toolset: clang + compiler: clang++-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-10 + - toolset: clang + compiler: clang++-11 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-11 + - toolset: clang + compiler: clang++-12 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-13 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-14 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20" + os: ubuntu-22.04 + install: + - clang-15 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-15 + - libc++-15-dev + - libc++abi-15-dev + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + - toolset: clang + compiler: clang++-16 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-16 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-17 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-17 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - name: UBSAN + toolset: clang + compiler: clang++-14 + cxxstd: "03,11,14,17,20,2b" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + ubsan: 1 + os: ubuntu-22.04 + install: + - clang-14 + - libc++-14-dev + - libc++abi-14-dev + + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-15 + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-13 + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-14 + + timeout-minutes: 180 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake + fi + fi + git config --global pack.threads 0 + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: | + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + echo "Adding key: $key" + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}" "link=static,shared") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + if [ -n "${{matrix.address_model}}" ] + then + B2_ARGS+=("address-model=${{matrix.address_model}}") + fi + B2_ARGS+=("libs/$LIBRARY/test") + ./b2 "${B2_ARGS[@]}" cxxflags="-Wall -Wextra -Werror" + + windows: + strategy: + fail-fast: false + matrix: + include: + - toolset: msvc-14.2 + cxxstd: "14,17,20,latest" + addrmd: "32" + os: windows-2019 + # B2 does not work with MSVC 17.10. Once it's updated we can re-enable these tests + # Still covered in drone + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "32" + os: windows-2022 + - toolset: msvc-14.2 + cxxstd: "14,17,20,latest" + addrmd: "64" + os: windows-2019 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "64" + os: windows-2022 + #- toolset: clang-win + # cxxstd: "14,17,latest" + # addrmd: "32" + # os: windows-2022 + #- toolset: clang-win + # cxxstd: "14,17,latest" + # addrmd: "64" + # os: windows-2022 + - toolset: gcc + cxxstd: "03,11,14,17,2a" + addrmd: "64" + os: windows-2019 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Setup Boost + shell: cmd + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + cmd /c bootstrap + b2 -d0 headers + + - name: Run tests + shell: cmd + run: | + cd ../boost-root + b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release link=static,shared embed-manifest-via=linker + + posix-cmake-subdir: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-15 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Use library with add_subdirectory + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test + mkdir __build__ && cd __build__ + cmake .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-install: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-15 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local .. + + - name: Install + run: | + cd ../boost-root/__build__ + cmake --build . --target install + + - name: Use the installed library + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__ + cmake -DCMAKE_INSTALL_PREFIX=~/.local .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-test: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-15 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON .. + + - name: Build tests + run: | + cd ../boost-root/__build__ + cmake --build . --target tests + + - name: Run tests + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error + + MSYS2: + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + include: + - { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' } + - { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' } + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup MSYS2 environment + uses: msys2/setup-msys2@v2 + with: + msystem: ${{matrix.sys}} + update: true + install: git python + pacboy: gcc:p cmake:p ninja:p + + - name: Fetch Boost.CI + uses: actions/checkout@v3 + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + - name: Get CI scripts folder + run: | + # Copy ci folder if not testing Boost.CI + [[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci . + rm -rf boost-ci-cloned + + - name: Setup Boost + env: + B2_COMPILER: ${{matrix.compiler}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_SANITIZE: ${{matrix.sanitize}} + B2_STDLIB: ${{matrix.stdlib}} + run: ci/github/install.sh + + - name: Run tests + run: ci/build.sh + + intel: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + compiler: [ intel ] + standard: [ c++20 ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + + - name: Intel Apt repository + timeout-minutes: 1 + run: | + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo apt-get update + - name: Install Intel oneAPI compilers + timeout-minutes: 5 + run: sudo apt-get install -y intel-oneapi-compiler-fortran intel-oneapi-compiler-dpcpp-cpp + + - name: Setup Intel oneAPI environment + run: | + source /opt/intel/oneapi/setvars.sh + printenv >> $GITHUB_ENV + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON .. + + - name: Build tests + run: | + cd ../boost-root/__build__ + cmake --build . --target tests + + - name: Run tests + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000..00694bab --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,76 @@ +# ------------------------------------------------------------------------------ +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ------------------------------------------------------------------------------ + +name: codecov +on: + push: + branches: + - master + - develop + - feature/** + pull_request: + types: [opened, synchronize, reopened] +jobs: + gcc-gcov-native: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + standard: [ c++20 ] + compiler: [ g++ ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: update-tools + run: | + sudo apt install lcov locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + + - name: clone-submods-bootstrap-headers-boost-develop + run: | + git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root + cd ../boost-root + git submodule update --init tools + git submodule update --init libs/assert + git submodule update --init libs/config + git submodule update --init libs/core + git submodule update --init libs/math + git submodule update --init libs/multiprecision + git submodule update --init libs/predef + git submodule update --init libs/static_assert + git submodule update --init libs/test + git submodule update --init libs/uuid + git submodule update --init libs/throw_exception + git submodule update --init libs/type_traits + ./bootstrap.sh + ./b2 headers + - name: gcc-gcov-native + run: | + cd test/cover + echo "build and run gcov/lcov/genhtml" + echo "make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" + echo + make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} + echo + echo "make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" + echo + make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} + echo + - name: upload-codecov + uses: codecov/codecov-action@v4 + with: + plugin: gcov + file: ${{ runner.workspace }}/crypt/test/cover/coverage.info + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + verbose: false diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 00000000..4487018f --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,289 @@ +# Copyright 2021-2022 Andrey Semashev +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Fuzz + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + + # Linux, clang + # https://llvm.org/docs/LibFuzzer.html#fuzzer-usage + - toolset: clang + compiler: clang++-12 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-13 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-14 + cxxstd: "14-gnu,17-gnu,20-gnu" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-15 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-16 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-16 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-17 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-17 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + + + timeout-minutes: 60 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake + fi + fi + git config --global pack.threads 0 + - uses: actions/checkout@v4 + + - name: Install packages + if: matrix.install + run: | + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + echo "Adding key: $key" + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root/libs/$LIBRARY/fuzzing + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}" "link=static,shared") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + if [ -n "${{matrix.address_model}}" ] + then + B2_ARGS+=("address-model=${{matrix.address_model}}") + fi + ../../../b2 "${B2_ARGS[@]}" diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml new file mode 100644 index 00000000..08bbfdc7 --- /dev/null +++ b/.github/workflows/qemu.yml @@ -0,0 +1,206 @@ +# Copyright 2020-2021 Peter Dimov +# Copyright 2021 Andrey Semashev +# Copyright 2021 Alexander Grund +# Copyright 2022 James E. King III +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) +--- +name: qemu + +on: + pull_request: + push: + branches: + - master + - develop + - bugfix/** + - feature/** + - fix/** + - pr/** + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + B2_CI_VERSION: 1 + B2_VARIANT: release + B2_LINK: static + LCOV_BRANCH_COVERAGE: 0 + CODECOV_NAME: Github Actions + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + # multiarch testing + - { name: PPC64LE-GCC, multiarch: yes, + compiler: gcc, cxxstd: '14', os: ubuntu-22.04, ccache: no, distro: alpine, edition: edge, arch: ppc64le } + - { name: PPC64LE-Clang, multiarch: yes, + compiler: clang, cxxstd: '14', os: ubuntu-22.04, ccache: no, distro: alpine, edition: edge, arch: ppc64le } + + + timeout-minutes: 360 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + env: {B2_USE_CCACHE: 1} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ]; then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common curl + # Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80 + curl -sSL --retry ${NET_RETRY_COUNT:-5} 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xE1DD270288B4E6030699E45FA1715D88E1DF1F24' | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/git-core_ubuntu_ppa.gpg + for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + osver=$(lsb_release -sr | cut -f1 -d.) + pkgs="g++ git" + # Ubuntu 22+ has only Python 3 in the repos + if [ -n "$osver" ] && [ "$osver" -ge "22" ]; then + pkgs+=" python-is-python3 libpython3-dev" + else + pkgs+=" python libpython-dev" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + fi + # For jobs not compatible with ccache, use "ccache: no" in the matrix + if [[ "${{ matrix.ccache }}" == "no" ]]; then + echo "B2_USE_CCACHE=0" >> $GITHUB_ENV + fi + git config --global pack.threads 0 + if [[ "${{matrix.container}}" == "ubuntu:16.04" ]] || [[ "${{matrix.container}}" == "ubuntu:18.04" ]]; then + # Ubuntu 16/18 can't run Node 20, so stick to older actions: https://github.com/actions/checkout/issues/1590 + echo "GHA_USE_NODE_20=false" >> $GITHUB_ENV + echo "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true" >> $GITHUB_ENV + else + echo "GHA_USE_NODE_20=true" >> $GITHUB_ENV + fi + + - uses: actions/checkout@v3 + if: env.GHA_USE_NODE_20 == 'false' + with: + # For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary' + fetch-depth: ${{ matrix.coverage && '0' || '1' }} + - uses: actions/checkout@v4 + if: env.GHA_USE_NODE_20 == 'true' + with: + # For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary' + fetch-depth: ${{ matrix.coverage && '0' || '1' }} + + - name: Cache ccache + uses: actions/cache@v3 + if: env.B2_USE_CCACHE && env.GHA_USE_NODE_20 == 'false' + with: + path: ~/.ccache + key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} + restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + + - name: Cache ccache + uses: actions/cache@v4 + if: env.B2_USE_CCACHE && env.GHA_USE_NODE_20 == 'true' + with: + path: ~/.ccache + key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} + restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + + - name: Fetch Boost.CI + uses: actions/checkout@v3 + if: env.GHA_USE_NODE_20 == 'false' + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + + - name: Fetch Boost.CI + uses: actions/checkout@v4 + if: env.GHA_USE_NODE_20 == 'true' + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + + - name: Get CI scripts folder + run: | + # Copy ci folder if not testing Boost.CI + [[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci . + rm -rf boost-ci-cloned + + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}}) + SOURCES=(${{join(matrix.sources, ' ')}}) + # Add this by default + SOURCE_KEYS+=('http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1E9377A2BA9EF27F') + SOURCES+=(ppa:ubuntu-toolchain-r/test) + + ci/add-apt-keys.sh "${SOURCE_KEYS[@]}" + # Initial update before adding sources required to get e.g. keys + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + ci/add-apt-repositories.sh "${SOURCES[@]}" + + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [[ -z "${{matrix.install}}" ]]; then + pkgs="${{matrix.compiler}}" + pkgs="${pkgs/gcc-/g++-}" + else + pkgs="${{matrix.install}}" + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs + + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=$GCC_TOOLCHAIN_ROOT" >> $GITHUB_ENV + if ! command -v dpkg-architecture; then + apt-get install -y dpkg-dev + fi + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + + - name: Setup multiarch + if: matrix.multiarch + env: + BDDE_DISTRO: ${{matrix.distro}} + BDDE_EDITION: ${{matrix.edition}} + BDDE_ARCH: ${{matrix.arch}} + run: ci/github/setup_bdde.sh + + - name: Setup Boost + env: + B2_ADDRESS_MODEL: ${{matrix.address-model}} + B2_COMPILER: ${{matrix.compiler}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_SANITIZE: ${{matrix.sanitize}} + B2_STDLIB: ${{matrix.stdlib}} + # More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys. + # B2_DEFINES: 'BOOST_DECIMAL_QEMU_TEST' + # Variables set here (to non-empty) will override the top-level environment variables, e.g. + # B2_VARIANT: ${{matrix.variant}} + # Set the (B2) target(s) to build, defaults to the test folder of the current library + # Can alternatively be done like this in the build step or in the build command of the build step, e.g. `run: B2_TARGETS=libs/$SELF/doc ci/build.sh` + # B2_TARGETS: libs/foo/test//bar + run: source ci/github/install.sh + + - name: Run tests + if: '!matrix.coverity' + run: ci/build.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..f9ef54f3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated by `boostdep --cmake crypt` +# Copyright 2020, 2021 Peter Dimov +# Copyright 2023 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(boost_crypt VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +add_library(boost_crypt INTERFACE) + +add_library(Boost::crypt ALIAS boost_crypt) + +target_include_directories(boost_crypt INTERFACE include) + +target_compile_features(boost_crypt INTERFACE cxx_std_14) + +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + + include(GNUInstallDirs) + install(DIRECTORY "include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +endif() diff --git a/build.jam b/build.jam new file mode 100644 index 00000000..2095c983 --- /dev/null +++ b/build.jam @@ -0,0 +1,19 @@ +# Copyright Matt Borland 2024 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +require-b2 5.2 ; + +project /boost/crypt + : common-requirements + include + ; + +explicit + [ alias boost_core ] + [ alias all : boost_crypt test ] + ; + +call-if : boost-library crypt + ; diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000..ff8f3817 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +/pdf/ +/html/ diff --git a/doc/Jamfile b/doc/Jamfile new file mode 100644 index 00000000..65f87059 --- /dev/null +++ b/doc/Jamfile @@ -0,0 +1,25 @@ +# Copyright 2017, 2018 Peter Dimov +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +import asciidoctor ; + +html crypt.html : crypt.adoc + : /boost/boostlook//boostlook + crypt-docinfo-footer.html + ; + +install html_ : crypt.html : html ; + +pdf crypt.pdf : crypt.adoc ; +explicit crypt.pdf ; + +install pdf_ : crypt.pdf : pdf ; +explicit pdf_ ; + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease : html_ ; +explicit boostrelease ; diff --git a/doc/crypt-docinfo-footer.html b/doc/crypt-docinfo-footer.html new file mode 100644 index 00000000..622aa5fa --- /dev/null +++ b/doc/crypt-docinfo-footer.html @@ -0,0 +1,6 @@ + diff --git a/doc/crypt.adoc b/doc/crypt.adoc new file mode 100644 index 00000000..093e4827 --- /dev/null +++ b/doc/crypt.adoc @@ -0,0 +1,30 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + += Crypt: A Modern Cryptographic Module in C++14 +:toc: left +:toclevels: 4 +:idprefix: +:listing-caption: Code Example +:docinfo: private-footer +:source-highlighter: rouge +:source-language: c++ + +:leveloffset: +1 + +include::crypt/overview.adoc[] + +include::crypt/api_reference.adoc[] + +include::crypt/md5.adoc[] + +include::crypt/config.adoc[] + +include::crypt/reference.adoc[] + +include::crypt/copyright.adoc[] + +:leveloffset: -1 diff --git a/doc/crypt/api_reference.adoc b/doc/crypt/api_reference.adoc new file mode 100644 index 00000000..f4bb7751 --- /dev/null +++ b/doc/crypt/api_reference.adoc @@ -0,0 +1,30 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#api_reference] += API Reference +:idprefix: api_ref_ + +== Types + +- <> + +== Structures and Classes + +- <> +- <> + +== Enums + +- None + +== Constants + +- None + +== Macros + +See: <> diff --git a/doc/crypt/array.adoc b/doc/crypt/array.adoc new file mode 100644 index 00000000..3353bcd6 --- /dev/null +++ b/doc/crypt/array.adoc @@ -0,0 +1,70 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#array] +:idprefix: array_ + +In order for this lab to use `` in a `constexpr` environment we would need to support C+\+17. +Additionally, CUDA environments do not directly support `std::array`. +For these reasons we reimplement `` in our namespace that both supports both C++14 and CUDA. +It is *IMPLICITLY* convertible to `std::array` for convenience. + +[source, c++] +---- +template +class array +{ +public: + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using const_iterator = const T*; + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + + T elements[N]; + + // Iterators + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() const noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto cbegin() const noexcept -> const_iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto end() noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto end() const noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto cend() const noexcept -> const_iterator; + + // Sizing + BOOST_CRYPT_GPU_ENABLED constexpr auto size() const noexcept -> size_type; + BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() const noexcept -> size_type; + + // Accessors + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) noexcept; + + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) const noexcept; + + // For at instead of throwing on out of range return the last element since throwing doesn't work on device + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) noexcept -> reference; + + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) const noexcept -> const_reference; + + BOOST_CRYPT_GPU_ENABLED constexpr auto front() noexcept -> reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto front() const noexcept -> const_reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() noexcept -> reference { return elements[N - 1]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } + + BOOST_CRYPT_GPU_ENABLED constexpr auto data() noexcept -> pointer { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto data() const noexcept -> const_pointer { return elements; } + + BOOST_CRYPT_GPU_ENABLED constexpr auto fill(const value_type& v) -> void; + + BOOST_CRYPT_GPU_ENABLED constexpr auto swap(array& a); + + // Conversion + constexpr operator std::array() noexcept; +}; +---- diff --git a/doc/crypt/config.adoc b/doc/crypt/config.adoc new file mode 100644 index 00000000..f252c371 --- /dev/null +++ b/doc/crypt/config.adoc @@ -0,0 +1,19 @@ +//// +Copyright 2023 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#configuration] += Configuration Macros +:idprefix: config_ + +== User Configurable Macros + +The following configuration macros are available: + +- None at this time + +== Automatic Configuration Macros + +- `BOOST_CRYPT_HAS_STRING_VIEW`: This is defined when compiling with at least C++17 and your standard library has a complete implementation of ``. diff --git a/doc/crypt/copyright.adoc b/doc/crypt/copyright.adoc new file mode 100644 index 00000000..f884e9ce --- /dev/null +++ b/doc/crypt/copyright.adoc @@ -0,0 +1,12 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#copyright] += Copyright and License +:idprefix: license_ + +This documentation is copyright 2024 Matt Borland and Chris Kormanyos and is distributed under +the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0]. diff --git a/doc/crypt/md5.adoc b/doc/crypt/md5.adoc new file mode 100644 index 00000000..63b20fa0 --- /dev/null +++ b/doc/crypt/md5.adoc @@ -0,0 +1,115 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#md5] +:idprefix: md5_ + += MD5 + +This library supports MD5 as described in https://www.ietf.org/rfc/rfc1321.txt[RFC 1321]. +There is a wide range of acceptable inputs for the base md5 function: + +== Hashing Functions + +[source, c++] +---- +namespace boost { +namespace crypt { + +uisng return_type = boost::crypt::array; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const unsigned char* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const unsigned char* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, size_t len) noexcept -> return_type; + +inline auto md5(const std::string& str) noexcept -> return_type; + +inline auto md5(const std::u16string& str) noexcept -> return_type; + +inline auto md5(const std::u32string& str) noexcept -> return_type; + +inline auto md5(const std::wstring& str) noexcept -> return_type; + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW + +inline auto md5(std::string_view str) noexcept -> return_type; + +inline auto md5(std::u16string_view str) noexcept -> return_type; + +inline auto md5(std::u32string_view str) noexcept -> return_type; + +inline auto md5(std::wstring_view str) noexcept -> return_type; + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + +} //namespace crypt +} //namespace boost +---- + +== File Hashing Functions + +We also have the ability to scan files and return the MD5 value: + +[source, c++] +---- +namespace boost { +namespace crypt { + +uisng return_type = boost::crypt::array; + +inline auto md5_file(const char* filepath) noexcept -> return_type; + +inline auto md5_file(const std::string& filepath) noexcept -> return_type; + +inline auto md5_file(std::string_view filepath) noexcept -> return_type; + +} // namespace crypt +} // namespace boost +---- + +== Hashing Object + +[#md5_hasher] +Lastly, there is also the ability to create a MD5 hashing object and feed it bytes as the user parses them. +This class does not use any dynamic memory allocation. + +[source, c++] +---- +namespace boost { +namespace crypt { + +class md5_hasher +{ + init(); + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept -> void; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, size_t byte_count) noexcept -> void; + + constexpr auto get_digest() noexcept -> boost::crypt::array; +}; + +} // namespace crypt +} // namespace boost +---- diff --git a/doc/crypt/overview.adoc b/doc/crypt/overview.adoc new file mode 100644 index 00000000..1fab53d8 --- /dev/null +++ b/doc/crypt/overview.adoc @@ -0,0 +1,70 @@ +//// +Copyright 2023 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#overview] += Overview +:idprefix: overview_ + +== Description + +Boost.Decimal is an implementation of https://standards.ieee.org/ieee/754/6210/[IEEE 754] and https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2849.pdf[ISO/IEC DTR 24733] Decimal Floating Point numbers. +The library is header-only, has no dependencies, and requires C++14. + +== Motivation + +Current C++ floating point types store the significand (often incorrectly referred to as the mantissa) as binary digits. +Famously this leads to representation errors: https://0.30000000000000004.com. +Decimal floating point numbers avoid this issue by storing the significand in base-10 (decimal). +The other major difference between binary and decimal floating point types is that the latter allows for multiple representations of the same number. +For example 1e5 could also be stored as 0.1e6, 0.01e7, so on and so forth. +These are referred to as cohorts which binary does not have as there is only one way to represent each number in binary floating point. + +== Use Cases + +The use case for Decimal Floating Point numbers is where rounding errors are significantly impactful such as finance. +In applications where integer or fixed-point arithmetic are used to combat this issue Decimal Floating Point numbers can provide a significantly greater range of values. +For example, while a fixed-point representation that allocates 8 decimal digits and 2 decimal places can represent the numbers 123456.78, 8765.43, 123.00, and so on, a floating-point representation with 8 decimal digits could also represent 1.2345678, 1234567.8, 0.000012345678, 12345678000000000, and so on. + +== Supported Compilers + +Boost.Decimal is tested natively on Ubuntu (x86_64, s390x, and aarch64), macOS (x86_64, and Apple Silicon), and Windows (x32 and x64); +as well as emulated PPC64LE and STM32 using QEMU with the following compilers: + +* GCC 7 and later +* Clang 6 and later +* Visual Studio 2017 and later +* Intel OneAPI DPC++ + +Tested on https://github.com/cppalliance/decimal/actions[Github Actions] and https://drone.cpp.al/cppalliance/decimal[Drone]. +Coverage can be found on https://app.codecov.io/gh/cppalliance/decimal[Codecov]. + +== Basic Usage + +[source, c++] +---- +#include +#include +#include + +int main() +{ + using namespace boost::decimal; + + // Outputs 0.30000000000000004 + std::cout << std::setprecision(17) << 0.1 + 0.2; + + // Construct the two decimal values + constexpr decimal64 a {1, -1}; // 1e-1 or 0.1 + constexpr decimal64 b {2, -1}; // 2e-1 or 0.2 + + // Outputs 0.30000000000000000 + std::cout << a + b << std::endl; + + return 0; +} + +---- + diff --git a/doc/crypt/reference.adoc b/doc/crypt/reference.adoc new file mode 100644 index 00000000..87d49fc4 --- /dev/null +++ b/doc/crypt/reference.adoc @@ -0,0 +1,15 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#reference] += References +:idprefix: ref_ + +The following books, papers and blog posts serve as the basis for the algorithms used in the library: + +:linkattrs: + +- Ronald L. Rivest, https://www.ietf.org/rfc/rfc1321.txt[RFC 1321: The MD5 Message-Digest Algorithm], 1992 diff --git a/fuzzing/.gitignore b/fuzzing/.gitignore new file mode 100644 index 00000000..38846572 --- /dev/null +++ b/fuzzing/.gitignore @@ -0,0 +1,7 @@ +cmin/ +out/ +oldcorpus/ +seedcorpus/ +corpus.tar +out*/ +fuzz-*.log diff --git a/fuzzing/Jamfile b/fuzzing/Jamfile new file mode 100644 index 00000000..4739898a --- /dev/null +++ b/fuzzing/Jamfile @@ -0,0 +1,66 @@ +# +# Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# Copyright (c) 2024 Matt Borland +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import common ; +import regex ; + +local all_fuzzers = [ regex.replace-list + [ glob "fuzz_*.cpp" ] : ".cpp" : "" +] ; + +for local fuzzer in $(all_fuzzers) +{ + # These two fuzzers are the most complex ones. The rest are really + # simple, so less time is enough + local fuzz_time = 30 ; + + # Create the output corpus directories + make /tmp/corpus/$(fuzzer) : : common.MkDir ; + make /tmp/mincorpus/$(fuzzer) : : common.MkDir ; + + # Build the fuzzer + exe $(fuzzer) + : + $(fuzzer).cpp + : requirements + on + speed + on + norecover + -fsanitize=fuzzer + -fsanitize=fuzzer + ; + + # Make sure that any old crashes are run without problems + local old_crashes = [ glob-tree-ex old_crashes/$(fuzzer) : * ] ; + if $(old_crashes) + { + run $(fuzzer) + : target-name $(fuzzer)-old-crashes + : input-files [ SORT $(old_crashes) ] + ; + } + + # Run the fuzzer for a short while + run $(fuzzer) + : "seedcorpus/$(fuzzer) -max_total_time=$(fuzz_time)" + : target-name $(fuzzer)-fuzzing + : requirements + /tmp/corpus/$(fuzzer) + ; + + # Minimize the corpus + run $(fuzzer) + : "/tmp/mincorpus/$(fuzzer) /tmp/corpus/$(fuzzer) -merge=1" + : target-name $(fuzzer)-minimize-corpus + : requirements + $(fuzzer)-fuzzing + /tmp/corpus/$(fuzzer) + /tmp/mincorpus/$(fuzzer) + ; +} diff --git a/fuzzing/fuzz_md5.cpp b/fuzzing/fuzz_md5.cpp new file mode 100644 index 00000000..584ccce4 --- /dev/null +++ b/fuzzing/fuzz_md5.cpp @@ -0,0 +1,33 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::md5(c_data_str); + boost::crypt::md5(c_data, size); + boost::crypt::md5(data, size); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + std::string_view view {c_data_str}; + boost::crypt::md5(view); + #endif + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/seedcorpus/fuzz_md5/md5.txt b/fuzzing/seedcorpus/fuzz_md5/md5.txt new file mode 100644 index 00000000..48e3b98c --- /dev/null +++ b/fuzzing/seedcorpus/fuzz_md5/md5.txt @@ -0,0 +1,18 @@ +"The quick brown fox jumps over the lazy dog" +"The quick brown fox jumps over the lazy dog." +"" +"aB3$x9Yz" +"12345" +"!@#$%^&*()" +"FuzzTest123" +" " +"Lorem ipsum dolor sit amet" +"a" +"9876543210" +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +"ñÑáéíóúÁÉÍÓÚ" +"\n\r\t" +"0" +"ThisIsAVeryLongStringWithNoSpacesOrPunctuationToTestEdgeCases" +"" +"SELECT * FROM users;" diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp new file mode 100644 index 00000000..3458e127 --- /dev/null +++ b/include/boost/crypt/hash/md5.hpp @@ -0,0 +1,644 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// See: https://www.ietf.org/rfc/rfc1321.txt + +#ifndef BOOST_CRYPT_HASH_MD5_HPP +#define BOOST_CRYPT_HASH_MD5_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#include +#include +#endif + +namespace boost { +namespace crypt { + +class md5_hasher +{ +private: + boost::crypt::uint32_t a0_ {0x67452301}; + boost::crypt::uint32_t b0_ {0xefcdab89}; + boost::crypt::uint32_t c0_ {0x98badcfe}; + boost::crypt::uint32_t d0_ {0x10325476}; + + boost::crypt::size_t low_ {}; + boost::crypt::size_t high_ {}; + + boost::crypt::array buffer_ {}; + boost::crypt::array blocks_ {}; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_update(ForwardIter data, boost::crypt::size_t size) noexcept; + + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_convert_buffer_to_blocks() noexcept; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept; + + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_body() noexcept -> void; + +public: + BOOST_CRYPT_GPU_ENABLED constexpr auto init() noexcept -> void; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t); + + template ::value_type) == 1, bool> = true> + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + + template ::value_type) == 2, bool> = true> + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + + template ::value_type) == 4, bool> = true> + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + + BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> boost::crypt::array; +}; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::init() noexcept -> void +{ + a0_ = 0x67452301U; + b0_ = 0xefcdab89U; + c0_ = 0x98badcfeU; + d0_ = 0x10325476U; + + low_ = 0U; + high_ = 0U; + + buffer_.fill(static_cast(0)); + blocks_.fill(0U); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_convert_buffer_to_blocks() noexcept +{ + boost::crypt::size_t buffer_index {}; + for (auto& block : blocks_) + { + block = static_cast( + static_cast(buffer_[buffer_index]) | + (static_cast(buffer_[buffer_index + 1U]) << 8U) | + (static_cast(buffer_[buffer_index + 2U]) << 16U) | + (static_cast(buffer_[buffer_index + 3U]) << 24U) + ); + + buffer_index += 4U; + } +} + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept +{ + for (boost::crypt::size_t i {}; i < size; ++i) + { + BOOST_CRYPT_ASSERT(offset + i < buffer_.size()); + buffer_[offset + i] = static_cast(*(data + static_cast(i))); + } +} + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept +{ + const auto input_bits {size << 3U}; // Convert size to bits + const auto old_low {low_}; + low_ += input_bits; + if (low_ < old_low) + { + // This should never happen as it indicates size_t roll over + ++high_; // LCOV_EXCL_LINE + } + high_ += size >> 29U; + + auto used {(old_low >> 3U) & 0x3F}; // Number of bytes used in buffer + + if (used) + { + auto available = 64U - used; + if (size < available) + { + md5_copy_data(data, used, size); + return; + } + + md5_copy_data(data, used, available); + md5_convert_buffer_to_blocks(); + md5_body(); + data += static_cast(available); + size -= available; + } + + while (size >= 64U) + { + md5_copy_data(data, 0U, 64U); + md5_convert_buffer_to_blocks(); + md5_body(); + data += 64U; + size -= 64U; + } + + if (size > 0) + { + md5_copy_data(data, 0U, size); + } +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest() noexcept -> boost::crypt::array +{ + boost::crypt::array digest {}; + auto used {(low_ >> 3U) & 0x3F}; // Number of bytes used in buffer + buffer_[used++] = 0x80; + auto available {buffer_.size() - used}; + + if (available < 8U) + { + fill_array(buffer_.begin() + used, buffer_.end(), static_cast(0)); + md5_convert_buffer_to_blocks(); + md5_body(); + used = 0; + buffer_.fill(0); + } + else + { + fill_array(buffer_.begin() + used, buffer_.end() - 8, static_cast(0)); + } + + const auto total_bits {(static_cast(high_) << 32) | low_}; + + // Append the length in bits as a 64-bit little-endian integer + buffer_[56] = static_cast(total_bits & 0xFF); + buffer_[57] = static_cast((total_bits >> 8) & 0xFF); + buffer_[58] = static_cast((total_bits >> 16) & 0xFF); + buffer_[59] = static_cast((total_bits >> 24) & 0xFF); + buffer_[60] = static_cast((total_bits >> 32) & 0xFF); + buffer_[61] = static_cast((total_bits >> 40) & 0xFF); + buffer_[62] = static_cast((total_bits >> 48) & 0xFF); + buffer_[63] = static_cast((total_bits >> 56) & 0xFF); + + md5_convert_buffer_to_blocks(); + md5_body(); + + for (boost::crypt::size_t i = 0; i < 4; ++i) + { + const auto value {(i == 0 ? a0_ : (i == 1 ? b0_ : (i == 2 ? c0_ : d0_)))}; + digest[i*4] = static_cast(value & 0xFF); + digest[i*4 + 1] = static_cast((value >> 8U) & 0xFF); + digest[i*4 + 2] = static_cast((value >> 16U) & 0xFF); + digest[i*4 + 3] = static_cast((value >> 24U) & 0xFF); + } + + return digest; +} + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t) +{ + const auto value {static_cast(byte)}; + md5_update(&value, 1UL); +} + +template ::value_type) == 1, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +{ + md5_update(buffer, byte_count); +} + +template ::value_type) == 2, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +{ + #ifndef BOOST_CRYPT_HAS_CUDA + + const auto* char_ptr {reinterpret_cast(std::addressof(*buffer))}; + const auto* data {reinterpret_cast(char_ptr)}; + md5_update(data, byte_count * 2U); + + #else + + const auto* data {reinterpret_cast(buffer)}; + md5_update(data, byte_count * 2U); + + #endif +} + +template ::value_type) == 4, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +{ + #ifndef BOOST_CRYPT_HAS_CUDA + + const auto* char_ptr {reinterpret_cast(std::addressof(*buffer))}; + const auto* data {reinterpret_cast(char_ptr)}; + md5_update(data, byte_count * 4U); + + #else + + const auto* data {reinterpret_cast(buffer)}; + md5_update(data, byte_count * 4U); + + #endif +} + +// See: Applied Cryptography - Bruce Schneier +// Section 18.5 +namespace md5_body_detail { + +BOOST_CRYPT_GPU_ENABLED constexpr auto F(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return (x & y) | ((~x) & z); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto G(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return (x & z) | (y & (~z)); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto H(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return x ^ y ^ z; +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto I(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return y ^ (x | (~z)); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto FF(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + F(b, c, d) + Mj + ti), si); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto GG(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + G(b, c, d) + Mj + ti), si); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto HH(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + H(b, c, d) + Mj + ti), si); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto II(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + I(b, c, d) + Mj + ti), si); +} + +} // md5_body_detail + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void +{ + using namespace md5_body_detail; + + boost::crypt::uint32_t a {a0_}; + boost::crypt::uint32_t b {b0_}; + boost::crypt::uint32_t c {c0_}; + boost::crypt::uint32_t d {d0_}; + + // Round 1 + FF(a, b, c, d, blocks_[0], 7, 0xd76aa478); + FF(d, a, b, c, blocks_[1], 12, 0xe8c7b756); + FF(c, d, a, b, blocks_[2], 17, 0x242070db); + FF(b, c, d, a, blocks_[3], 22, 0xc1bdceee); + FF(a, b, c, d, blocks_[4], 7, 0xf57c0faf); + FF(d, a, b, c, blocks_[5], 12, 0x4787c62a); + FF(c, d, a, b, blocks_[6], 17, 0xa8304613); + FF(b, c, d, a, blocks_[7], 22, 0xfd469501); + FF(a, b, c, d, blocks_[8], 7, 0x698098d8); + FF(d, a, b, c, blocks_[9], 12, 0x8b44f7af); + FF(c, d, a, b, blocks_[10], 17, 0xffff5bb1); + FF(b, c, d, a, blocks_[11], 22, 0x895cd7be); + FF(a, b, c, d, blocks_[12], 7, 0x6b901122); + FF(d, a, b, c, blocks_[13], 12, 0xfd987193); + FF(c, d, a, b, blocks_[14], 17, 0xa679438e); + FF(b, c, d, a, blocks_[15], 22, 0x49b40821); + + // Round 2 + GG(a, b, c, d, blocks_[1], 5, 0xf61e2562); + GG(d, a, b, c, blocks_[6], 9, 0xc040b340); + GG(c, d, a, b, blocks_[11], 14, 0x265e5a51); + GG(b, c, d, a, blocks_[0], 20, 0xe9b6c7aa); + GG(a, b, c, d, blocks_[5], 5, 0xd62f105d); + GG(d, a, b, c, blocks_[10], 9, 0x02441453); + GG(c, d, a, b, blocks_[15], 14, 0xd8a1e681); + GG(b, c, d, a, blocks_[4], 20, 0xe7d3fbc8); + GG(a, b, c, d, blocks_[9], 5, 0x21e1cde6); + GG(d, a, b, c, blocks_[14], 9, 0xc33707d6); + GG(c, d, a, b, blocks_[3], 14, 0xf4d50d87); + GG(b, c, d, a, blocks_[8], 20, 0x455a14ed); + GG(a, b, c, d, blocks_[13], 5, 0xa9e3e905); + GG(d, a, b, c, blocks_[2], 9, 0xfcefa3f8); + GG(c, d, a, b, blocks_[7], 14, 0x676f02d9); + GG(b, c, d, a, blocks_[12], 20, 0x8d2a4c8a); + + // Round 3 + HH(a, b, c, d, blocks_[5], 4, 0xfffa3942); + HH(d, a, b, c, blocks_[8], 11, 0x8771f681); + HH(c, d, a, b, blocks_[11], 16, 0x6d9d6122); + HH(b, c, d, a, blocks_[14], 23, 0xfde5380c); + HH(a, b, c, d, blocks_[1], 4, 0xa4beea44); + HH(d, a, b, c, blocks_[4], 11, 0x4bdecfa9); + HH(c, d, a, b, blocks_[7], 16, 0xf6bb4b60); + HH(b, c, d, a, blocks_[10], 23, 0xbebfbc70); + HH(a, b, c, d, blocks_[13], 4, 0x289b7ec6); + HH(d, a, b, c, blocks_[0], 11, 0xeaa127fa); + HH(c, d, a, b, blocks_[3], 16, 0xd4ef3085); + HH(b, c, d, a, blocks_[6], 23, 0x04881d05); + HH(a, b, c, d, blocks_[9], 4, 0xd9d4d039); + HH(d, a, b, c, blocks_[12], 11, 0xe6db99e5); + HH(c, d, a, b, blocks_[15], 16, 0x1fa27cf8); + HH(b, c, d, a, blocks_[2], 23, 0xc4ac5665); + + // Round 4 + II(a, b, c, d, blocks_[0], 6, 0xf4292244); + II(d, a, b, c, blocks_[7], 10, 0x432aff97); + II(c, d, a, b, blocks_[14], 15, 0xab9423a7); + II(b, c, d, a, blocks_[5], 21, 0xfc93a039); + II(a, b, c, d, blocks_[12], 6, 0x655b59c3); + II(d, a, b, c, blocks_[3], 10, 0x8f0ccc92); + II(c, d, a, b, blocks_[10], 15, 0xffeff47d); + II(b, c, d, a, blocks_[1], 21, 0x85845dd1); + II(a, b, c, d, blocks_[8], 6, 0x6fa87e4f); + II(d, a, b, c, blocks_[15], 10, 0xfe2ce6e0); + II(c, d, a, b, blocks_[6], 15, 0xa3014314); + II(b, c, d, a, blocks_[13], 21, 0x4e0811a1); + II(a, b, c, d, blocks_[4], 6, 0xf7537e82); + II(d, a, b, c, blocks_[11], 10, 0xbd3af235); + II(c, d, a, b, blocks_[2], 15, 0x2ad7d2bb); + II(b, c, d, a, blocks_[9], 21, 0xeb86d391); + + a0_ += a; + b0_ += b; + c0_ += c; + d0_ += d; +} + +namespace detail { + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(T begin, T end) noexcept -> boost::crypt::array +{ + if (end < begin) + { + return boost::crypt::array {}; + } + else if (end == begin) + { + return boost::crypt::array { + 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e + }; + } + + boost::crypt::md5_hasher hasher; + hasher.process_bytes(begin, static_cast(end - begin)); + auto result {hasher.get_digest()}; + + return result; +} + +} // Namespace detail + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +// On some platforms wchar_t is 16 bits and others it's 32 +// Since we check sizeof() the underlying with SFINAE in the actual implementation this is handled transparently +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +// ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- + +#ifndef BOOST_CRYPT_HAS_CUDA + +inline auto md5(const std::string& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::u16string& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::u32string& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::wstring& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW + +inline auto md5(std::string_view str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(std::u16string_view str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(std::u32string_view str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(std::wstring_view str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + +// ---- CUDA also does not have the ability to consume files ----- + +namespace detail { + +template +auto md5_file_impl(utility::file_reader& reader) noexcept -> boost::crypt::array +{ + md5_hasher hasher; + while (!reader.eof()) + { + const auto buffer_iter {reader.read_next_block()}; + const auto len {reader.get_bytes_read()}; + hasher.process_bytes(buffer_iter, len); + } + + return hasher.get_digest(); +} + +} // namespace detail + +inline auto md5_file(const std::string& filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +inline auto md5_file(const char* filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW + +inline auto md5_file(std::string_view filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + +#endif // BOOST_CRYPT_HAS_CUDA + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HASH_MD5_HPP diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp new file mode 100644 index 00000000..f13b1ddf --- /dev/null +++ b/include/boost/crypt/utility/array.hpp @@ -0,0 +1,129 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +#ifndef BOOST_CRYPT_UTILITIES_ARRAY_HPP +#define BOOST_CRYPT_UTILITIES_ARRAY_HPP + +#include +#include +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +template +class array +{ +public: + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using const_iterator = const T*; + using size_type = boost::crypt::size_t; + using difference_type = boost::crypt::ptrdiff_t; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + + T elements[N]; + + // Iterators + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() noexcept -> iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() const noexcept -> iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto cbegin() const noexcept -> const_iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto end() noexcept -> iterator { return elements + N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto end() const noexcept -> iterator { return elements + N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto cend() const noexcept -> const_iterator { return elements + N; } + + // Sizing + BOOST_CRYPT_GPU_ENABLED constexpr auto size() const noexcept -> size_type { return N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() const noexcept -> size_type { return N; } + + // Accessors + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) noexcept -> reference + { + BOOST_CRYPT_ASSERT(n < N); + return elements[n]; + } + + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) const noexcept -> const_reference + { + BOOST_CRYPT_ASSERT(n < N); + return elements[n]; + } + + // For at instead of throwing on out of range return the last element since throwing doesn't work on device + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) noexcept -> reference + { + if (n >= N) + { + return elements[N - 1U]; + } + return elements[n]; + } + + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) const noexcept -> const_reference + { + if (n >= N) + { + return elements[N - 1U]; + } + return elements[n]; + } + + // Front and back + BOOST_CRYPT_GPU_ENABLED constexpr auto front() noexcept -> reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto front() const noexcept -> const_reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() noexcept -> reference { return elements[N - 1]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } + + BOOST_CRYPT_GPU_ENABLED constexpr auto data() noexcept -> pointer { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto data() const noexcept -> const_pointer { return elements; } + + // Fill and swap + BOOST_CRYPT_GPU_ENABLED constexpr auto fill(const value_type& v) -> void + { + for (size_type i {}; i < N; ++i) + { + elements[i] = v; + } + } + + BOOST_CRYPT_GPU_ENABLED constexpr auto swap(array& a) + { + const auto temp {a}; + a = *this; + *this = temp; + } + + constexpr operator std::array() noexcept + { + std::array new_array{}; + for (boost::crypt::size_t i {}; i < N; ++i) + { + new_array[i] = elements[i]; + } + + return new_array; + } +}; + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto fill_array(ForwardIter first, ForwardIter last, T value) +{ + while (first != last) + { + *first++ = static_cast(value); + } +} + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_UTILITIES_ARRAY_HPP diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp new file mode 100644 index 00000000..b0d679f7 --- /dev/null +++ b/include/boost/crypt/utility/bit.hpp @@ -0,0 +1,105 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_BIT_HPP +#define BOOST_CRYPT_UTILITY_BIT_HPP + +#include +#include +#include +#include + +namespace boost { +namespace crypt { +namespace detail { + +// Forward decls +template ::value, bool> = true> +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept; +template ::value, bool> = true> +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept; + +template ::value, bool> = true> +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept; +template ::value, bool> = true> +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept; + +// Only works for unsigned s so we can optimize away the call to rotr +template ::value, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept +{ + constexpr auto N {boost::crypt::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + + return (x << r) | (x >> (N - r)); +} + +template ::value, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept +{ + constexpr auto N {boost::crypt::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + else if (r < 0) + { + return rotr(x, -r); + } + + return (x << r) | (x >> (N - r)); +} + +template ::value, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept +{ + constexpr auto N {boost::crypt::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + + return (x >> r) | (x << (N - r)); +} + +template ::value, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept +{ + constexpr auto N {boost::crypt::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + else if (r < 0) + { + return rotl(x, -r); + } + + return (x >> r) | (x << (N - r)); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto swap_endian(const boost::crypt::uint32_t val) -> boost::crypt::uint32_t +{ + return ((val & 0xFF000000) >> 24U) | + ((val & 0x00FF0000) >> 8U) | + ((val & 0x0000FF00) << 8U) | + ((val & 0x000000FF) << 24U); +} + +} // namespace detail +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_BIT_HPP diff --git a/include/boost/crypt/utility/byte.hpp b/include/boost/crypt/utility/byte.hpp new file mode 100644 index 00000000..cf392988 --- /dev/null +++ b/include/boost/crypt/utility/byte.hpp @@ -0,0 +1,109 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_BYTE_HPP +#define BOOST_CRYPT_UTILITY_BYTE_HPP + +#include +#include +#include + +namespace boost { +namespace crypt { + +class byte +{ +private: + boost::crypt::uint8_t bits_; + +public: + constexpr byte() noexcept : bits_ {} {} + explicit constexpr byte(boost::crypt::uint8_t bits) noexcept : bits_ {bits} {} + + template + constexpr auto to_integer() noexcept + BOOST_CRYPT_REQUIRES(boost::crypt::is_integral_v, IntegerType) + { + return static_cast(bits_); + } + + template + constexpr auto operator<<(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte) + { + return byte{bits_ << shift}; + } + + template + constexpr auto operator>>(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte) + { + return byte{bits_ >> shift}; + } + + constexpr auto operator|(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ | rhs.bits_)}; + } + + constexpr auto operator&(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ & rhs.bits_)}; + } + + constexpr auto operator^(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ ^ rhs.bits_)}; + } + + constexpr auto operator~() const noexcept -> byte + { + return byte{static_cast(~bits_)}; + } + + template + constexpr auto operator<<=(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte&) + { + bits_ <<= shift; + return *this; + } + + template + constexpr auto operator >>=(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte&) + { + bits_ >>= shift; + return *this; + } + + constexpr auto operator|(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ | rhs.bits_); + return *this; + } + + constexpr auto operator&(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ & rhs.bits_); + return *this; + } + + constexpr auto operator^(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ ^ rhs.bits_); + return *this; + } + + constexpr auto operator~() noexcept -> byte& + { + bits_ = static_cast(~bits_); + return *this; + } +}; + +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_BYTE_HPP diff --git a/include/boost/crypt/utility/concepts.hpp b/include/boost/crypt/utility/concepts.hpp new file mode 100644 index 00000000..47037ea9 --- /dev/null +++ b/include/boost/crypt/utility/concepts.hpp @@ -0,0 +1,124 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_CONCEPTS_HPP +#define BOOST_CRYPT_UTILITY_CONCEPTS_HPP + +#include + +// GCC-11 yields internal compiler errors when using the concepts + +/* +./boost/decimal/detail/concepts.hpp:239:80: note: in definition of macro 'BOOST_CRYPT_REQUIRES_RETURN' + 239 | #define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> ReturnType requires X + | ^ +0xe3223b internal_error(char const*, ...) + ???:0 +0xf56ed4 duplicate_decls(tree_node*, tree_node*, bool, bool) + ???:0 +0xf60a2b pushdecl_namespace_level(tree_node*, bool) + ???:0 +0x10801ca push_template_decl(tree_node*, bool) + ???:0 +0x1527ec1 do_friend(tree_node*, tree_node*, tree_node*, tree_node*, overload_flags, bool) + ???:0 +0xfc4e1e grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**) + ???:0 +0x100dcf4 grokfield(cp_declarator const*, cp_decl_specifier_seq*, tree_node*, bool, tree_node*, tree_node*) + ???:0 +0x149dce3 c_parse_file() + ???:0 +0x148d4de c_common_parse_file() + ???:0 +*/ +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_MATH_DISABLE_CONCEPTS) &&\ + (!defined(__GNUC__) || __GNUC__ != 11) + +#if __has_include() + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace boost::crypt::concepts { + +template +concept integral = boost::crypt::is_integral_v; + +template +concept signed_integral = integral && boost::crypt::is_signed_v; + +template +concept unsigned_integral = integral && boost::crypt::is_unsigned_v; + +template +concept real = boost::crypt::is_floating_point_v; + +} // boost::crypt::concepts + +#define BOOST_CRYPT_HAS_CONCEPTS 1 + +#define BOOST_CRYPT_INTEGRAL boost::crypt::concepts::integral +#define BOOST_CRYPT_SIGNED_INTEGRAL boost::crypt::concepts::signed_integral +#define BOOST_CRYPT_UNSIGNED_INTEGRAL boost::crypt::concepts::unsigned_integral +#define BOOST_CRYPT_REAL boost::crypt::concepts::real + +#define BOOST_CRYPT_REQUIRES(X, T) -> T requires X +#define BOOST_CRYPT_REQUIRES_TWO(X1, T1, X2, T2) -> detail::promote_args_t requires X1 && X2 +#define BOOST_CRYPT_REQUIRES_TWO_RETURN(X1, T1, X2, T2, ReturnType) -> ReturnType requires X1 && X2 +#define BOOST_CRYPT_REQUIRES_THREE(X1, T1, X2, T2, X3, T3) -> detail::promote_args_t requires X1 && X2 && X3 +#define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> ReturnType requires X +#define BOOST_CRYPT_REQUIRES_CONVERSION(T1, T2) -> void requires boost::crypt::is_convertible_v + +#endif // Has +#endif // C++20 + +// If concepts are unavailable replace them with typename for compatibility + +#ifndef BOOST_CRYPT_INTEGRAL +# define BOOST_CRYPT_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_SIGNED_INTEGRAL +# define BOOST_CRYPT_SIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_UNSIGNED_INTEGRAL +# define BOOST_CRYPT_UNSIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_REAL +# define BOOST_CRYPT_REAL typename +#endif +#ifndef BOOST_CRYPT_REQUIRES +# define BOOST_CRYPT_REQUIRES(X, T) -> boost::crypt::enable_if_t, T> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_TWO +# define BOOST_CRYPT_REQUIRES_TWO(X1, T1, X2, T2) -> boost::crypt::enable_if_t && X2, detail::promote_args_t> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_TWO_RETURN +# define BOOST_CRYPT_REQUIRES_TWO_RETURN(X1, T1, X2, T2, ReturnType) -> boost::crypt::enable_if_t && X2, ReturnType> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_THREE +# define BOOST_CRYPT_REQUIRES_THREE(X1, T1, X2, T2, X3, T3) -> boost::crypt::enable_if_t && X2 && X3, detail::promote_args_t> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_RETURN +# define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> boost::crypt::enable_if_t, ReturnType> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_CONVERSION +# define BOOST_CRYPT_REQUIRES_CONVERSION(T1, T2) -> boost::crypt::enable_if_t, void> +#endif + +#endif //BOOST_CRYPT_UTILITY_CONCEPTS_HPP diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp new file mode 100644 index 00000000..07e0f940 --- /dev/null +++ b/include/boost/crypt/utility/config.hpp @@ -0,0 +1,83 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_DETAIL_CONFIG_HPP +#define BOOST_CRYPT_DETAIL_CONFIG_HPP + +#ifdef __CUDACC__ +# ifndef BOOST_CRYPT_HAS_CUDA +# define BOOST_CRYPT_HAS_CUDA +# endif +# define BOOST_CRYPT_GPU_ENABLED __host__ __device__ +# define BOOST_CRYPT_GPU_HOST_ENABLED __host__ +# define BOOST_CRYPT_GPU_DEVICE_ENABLED __device__ +#endif + +#ifdef __CUDACC_RTC__ +# ifndef BOOST_CRYPT_HAS_CUDA +# define BOOST_CRYPT_HAS_CUDA +# endif +# define BOOST_CRYPT_HAS_NVRTC +# define BOOST_CRYPT_GPU_ENABLED __host__ __device__ +# define BOOST_CRYPT_GPU_HOST_ENABLED __host__ +# define BOOST_CRYPT_GPU_DEVICE_ENABLED __device__ +#endif + +#ifndef BOOST_CRYPT_GPU_ENABLED +# define BOOST_CRYPT_GPU_ENABLED +#endif + +#ifndef BOOST_CRYPT_GPU_HOST_ENABLED +# define BOOST_CRYPT_GPU_HOST_ENABLED +#endif + +#ifndef BOOST_CRYPT_GPU_DEVICE_ENABLED +# define BOOST_CRYPT_GPU_DEVICE_ENABLED +#endif + +// ---- Constexpr arrays ----- +#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L +# define BOOST_CRYPT_CONSTEXPR_ARRAY inline constexpr +# define BOOST_CRYPT_DEVICE_ARRAY inline constexpr +# define BOOST_CRYPT_INLINE_CONSTEXPR inline constexpr +#elif defined(BOOST_CRYPT_ENABLE_CUDA) +# define BOOST_CYPRT_CONSTEXPR_ARRAY static constexpr +# define BOOST_CRYPT_DEVICE_ARRAY __constant__ +# define BOOST_CRYPT_INLINE_CONSTEXPR static constexpr +#else +# define BOOST_CRYPT_CONSTEXPR_ARRAY static constexpr +# define BOOST_CRYPT_DEVICE_ARRAY static constexpr +# define BOOST_CRYPT_INLINE_CONSTEXPR static constexpr +#endif +// ---- Constexpr arrays ----- + +// ----- Assertions ----- +#include +#define BOOST_CRYPT_ASSERT(x) assert(x) +#define BOOST_CRYPT_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) +// ----- Assertions ----- + +// ----- Has CXX something ----- +// C++17 +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# if __has_include() +# include +# if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L +# define BOOST_CRYPT_HAS_STRING_VIEW +# endif +# endif +#endif +// ----- Has CXX something ----- + +// ----- Unreachable ----- +#if defined(__GNUC__) || defined(__clang__) +# define BOOST_CRYPT_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +# define BOOST_CRYPT_UNREACHABLE __assume(0) +#else +# define BOOST_CRYPT_UNREACHABLE std::abort() +#endif +// ----- Unreachable ----- + +#endif //BOOST_CRYPT_DETAIL_CONFIG_HPP diff --git a/include/boost/crypt/utility/cstddef.hpp b/include/boost/crypt/utility/cstddef.hpp new file mode 100644 index 00000000..3fb2a1c8 --- /dev/null +++ b/include/boost/crypt/utility/cstddef.hpp @@ -0,0 +1,44 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CRYPT_TOOLS_CSTDDEF +#define BOOST_CRYPT_TOOLS_CSTDDEF + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +namespace boost { +namespace crypt { + +using size_t = unsigned long; +using ptrdiff_t = long; +using nullptr_t = void; +using std::max_align_t = double; + + +} // namespace crypt +} // namespace boost + +#else // No cude + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +using std::size_t; +using std::ptrdiff_t; +using std::nullptr_t; +using std::max_align_t; + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HAS_CUDA + +#endif //BOOST_CSTDDEF_HPP diff --git a/include/boost/crypt/utility/cstdint.hpp b/include/boost/crypt/utility/cstdint.hpp new file mode 100644 index 00000000..12f512ab --- /dev/null +++ b/include/boost/crypt/utility/cstdint.hpp @@ -0,0 +1,104 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CRYPT_TOOLS_CSTDINT +#define BOOST_CRYPT_TOOLS_CSTDINT + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +#include + +namespace boost { +namespace crypt { + +using cuda::std::int8_t; +using cuda::std::int16_t; +using cuda::std::int32_t; +using cuda::std::int64_t; + +using cuda::std::int_fast8_t; +using cuda::std::int_fast16_t; +using cuda::std::int_fast32_t; +using cuda::std::int_fast64_t; + +using cuda::std::int_least8_t; +using cuda::std::int_least16_t; +using cuda::std::int_least32_t; +using cuda::std::int_least64_t; + +using cuda::std::intmax_t; +using cuda::std::intptr_t; + +using cuda::std::uint8_t; +using cuda::std::uint16_t; +using cuda::std::uint32_t; +using cuda::std::uint64_t; + +using cuda::std::uint_fast8_t; +using cuda::std::uint_fast16_t; +using cuda::std::uint_fast32_t; +using cuda::std::uint_fast64_t; + +using cuda::std::uint_least8_t; +using cuda::std::uint_least16_t; +using cuda::std::uint_least32_t; +using cuda::std::uint_least64_t; + +using cuda::std::uintmax_t; +using cuda::std::uintptr_t; + +#else + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +using std::int8_t; +using std::int16_t; +using std::int32_t; +using std::int64_t; + +using std::int_fast8_t; +using std::int_fast16_t; +using std::int_fast32_t; +using std::int_fast64_t; + +using std::int_least8_t; +using std::int_least16_t; +using std::int_least32_t; +using std::int_least64_t; + +using std::intmax_t; +using std::intptr_t; + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; + +using std::uint_fast8_t; +using std::uint_fast16_t; +using std::uint_fast32_t; +using std::uint_fast64_t; + +using std::uint_least8_t; +using std::uint_least16_t; +using std::uint_least32_t; +using std::uint_least64_t; + +using std::uintmax_t; +using std::uintptr_t; + +#endif + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_TOOLS_CSTDINT diff --git a/include/boost/crypt/utility/file.hpp b/include/boost/crypt/utility/file.hpp new file mode 100644 index 00000000..fdf7f27a --- /dev/null +++ b/include/boost/crypt/utility/file.hpp @@ -0,0 +1,86 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_FILE_HPP +#define BOOST_CRYPT_UTILITY_FILE_HPP + +#include +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#include +#include +#include +#endif + +namespace boost { +namespace crypt { +namespace utility { + +template +class file_reader +{ +private: + std::ifstream fd; + std::array buffer_ {}; + +public: + explicit file_reader(const std::string& filename) : fd(filename, std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file: " + filename); + } + } + + explicit file_reader(const char* filename) : fd(filename, std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file"); + } + } + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + explicit file_reader(std::string_view filename) : fd(filename.data(), std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file"); + } + } + #endif + + auto read_next_block() + { + fd.read(reinterpret_cast(buffer_.data()), block_size); + return buffer_.begin(); + } + + auto get_bytes_read() const -> std::size_t + { + return static_cast(fd.gcount()); + } + + auto eof() const -> bool + { + return fd.eof(); + } + + ~file_reader() + { + if (fd.is_open()) + { + fd.close(); + } + } +}; + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_FILE_HPP diff --git a/include/boost/crypt/utility/iterator.hpp b/include/boost/crypt/utility/iterator.hpp new file mode 100644 index 00000000..8b287640 --- /dev/null +++ b/include/boost/crypt/utility/iterator.hpp @@ -0,0 +1,48 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITES_ITERATOR_HPP +#define BOOST_CRYPT_UTILITES_ITERATOR_HPP + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +#include + +namespace boost { +namespace crypt { + +template +struct iterator_traits : public cuda::std::iterator_traits {}; + +template +struct iterator_traits : public cuda::std::iterator_traits {}; + +} // namespace crypt +} // namespace boost + +#else + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { +namespace utility { + +template +struct iterator_traits : public std::iterator_traits {}; + +template +struct iterator_traits : public std::iterator_traits {}; + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HAS_CUDA + +#endif //BOOST_CRYPT_UTILITES_ITERATOR_HPP diff --git a/include/boost/crypt/utility/limits.hpp b/include/boost/crypt/utility/limits.hpp new file mode 100644 index 00000000..a09a8bce --- /dev/null +++ b/include/boost/crypt/utility/limits.hpp @@ -0,0 +1,888 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Regular use of std::numeric_limits functions can not be used on +// GPU platforms like CUDA since they are missing the __device__ marker +// and libcu++ does not provide something analogous. +// Rather than using giant if else blocks make our own version of numeric limits +// +// On the CUDA NVRTC platform we use a best attempt at emulating the functions +// and values since we do not have any macros to go off of. +// Use the values as found on GCC 11.4 RHEL 9.4 x64 + +#ifndef BOOST_CRYPT_UTILITY_LIMITS_HPP +#define BOOST_CRYPT_UTILITY_LIMITS_HPP + +#include + +#if !defined(BOOST_CRYPT_HAS_NVRTC) && !defined(BOOST_CRYPT_BUILD_MODULE) + +#include +#include +#include +#include + +#endif + +namespace boost { +namespace crypt { + +template +struct numeric_limits +#ifndef BOOST_CRYPT_HAS_NVRTC + : public std::numeric_limits {}; +#else +{}; +#endif + +#if defined(BOOST_CRYPT_HAS_CUDA) && !defined(BOOST_CRYPT_HAS_NVRTC) + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr float (min) () { return FLT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr float (max) () { return FLT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr float lowest () { return -FLT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr float epsilon () { return FLT_EPSILON; } + BOOST_CRYPT_GPU_ENABLED static constexpr float round_error () { return 0.5F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float infinity () { return static_cast(INFINITY); } + BOOST_CRYPT_GPU_ENABLED static constexpr float quiet_NaN () { return static_cast(NAN); } + BOOST_CRYPT_GPU_ENABLED static constexpr float signaling_NaN () + { + #ifdef FLT_SNAN + return FLT_SNAN; + #else + return static_cast(NAN); + #endif + } + BOOST_CRYPT_GPU_ENABLED static constexpr float denorm_min () { return FLT_TRUE_MIN; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr double (min) () { return DBL_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr double (max) () { return DBL_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr double lowest () { return -DBL_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr double epsilon () { return DBL_EPSILON; } + BOOST_CRYPT_GPU_ENABLED static constexpr double round_error () { return 0.5; } + BOOST_CRYPT_GPU_ENABLED static constexpr double infinity () { return static_cast(INFINITY); } + BOOST_CRYPT_GPU_ENABLED static constexpr double quiet_NaN () { return static_cast(NAN); } + BOOST_CRYPT_GPU_ENABLED static constexpr double signaling_NaN () + { + #ifdef DBL_SNAN + return DBL_SNAN; + #else + return static_cast(NAN); + #endif + } + BOOST_CRYPT_GPU_ENABLED static constexpr double denorm_min () { return DBL_TRUE_MIN; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr short (min) () { return SHRT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr short (max) () { return SHRT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr short lowest () { return SHRT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (max) () { return USHRT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr int (min) () { return INT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr int (max) () { return INT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr int lowest () { return INT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (max) () { return UINT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long (min) () { return LONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long (max) () { return LONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr long lowest () { return LONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (max) () { return ULONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long long (min) () { return LLONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long (max) () { return LLONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long lowest () { return LLONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (max) () { return ULLONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr bool (min) () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool (max) () { return true; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool lowest () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool epsilon () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool round_error () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool infinity () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool quiet_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool signaling_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool denorm_min () { return false; } +}; + +#elif defined(BOOST_CRYPT_HAS_NVRTC) // Pure NVRTC support - Removes rounding style and approximates the traits + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 24; + static constexpr int digits10 = 6; + static constexpr int max_digits10 = 9; + static constexpr int radix = 2; + static constexpr int min_exponent = -125; + static constexpr int min_exponent10 = -37; + static constexpr int max_exponent = 128; + static constexpr int max_exponent10 = 38; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr float (min) () { return 1.17549435e-38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float (max) () { return 3.40282347e+38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float lowest () { return -3.40282347e+38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float epsilon () { return 1.1920929e-07; } + BOOST_CRYPT_GPU_ENABLED static constexpr float round_error () { return 0.5F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float infinity () { return __int_as_float(0x7f800000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float quiet_NaN () { return __int_as_float(0x7fc00000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float signaling_NaN () { return __int_as_float(0x7fa00000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float denorm_min () { return 1.4013e-45F; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 53; + static constexpr int digits10 = 15; + static constexpr int max_digits10 = 21; + static constexpr int radix = 2; + static constexpr int min_exponent = -1021; + static constexpr int min_exponent10 = -307; + static constexpr int max_exponent = 1024; + static constexpr int max_exponent10 = 308; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr double (min) () { return 2.2250738585072014e-308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double (max) () { return 1.7976931348623157e+308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double lowest () { return -1.7976931348623157e+308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double epsilon () { return 2.2204460492503131e-16; } + BOOST_CRYPT_GPU_ENABLED static constexpr double round_error () { return 0.5; } + BOOST_CRYPT_GPU_ENABLED static constexpr double infinity () { return __longlong_as_double(0x7ff0000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double quiet_NaN () { return __longlong_as_double(0x7ff8000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double signaling_NaN () { return __longlong_as_double(0x7ff4000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double denorm_min () { return 4.9406564584124654e-324; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 15; + static constexpr int digits10 = 4; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr short (min) () { return -32768; } + BOOST_CRYPT_GPU_ENABLED static constexpr short (max) () { return 32767; } + BOOST_CRYPT_GPU_ENABLED static constexpr short lowest () { return -32768; } + BOOST_CRYPT_GPU_ENABLED static constexpr short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 16; + static constexpr int digits10 = 4; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (max) () { return 65535U; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 31; + static constexpr int digits10 = 9; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr int (min) () { return -2147483648; } + BOOST_CRYPT_GPU_ENABLED static constexpr int (max) () { return 2147483647; } + BOOST_CRYPT_GPU_ENABLED static constexpr int lowest () { return -2147483648; } + BOOST_CRYPT_GPU_ENABLED static constexpr int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 32; + static constexpr int digits10 = 9; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (max) () { return 4294967295U; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 63; + static constexpr int digits10 = 18; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long (min) () { return -9223372036854775808L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long (max) () { return 9223372036854775807L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long lowest () { return -9223372036854775808L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 64; + static constexpr int digits10 = 19; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (max) () { return 18446744073709551615UL; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 63; + static constexpr int digits10 = 18; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long long (min) () { return -9223372036854775808LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long (max) () { return 9223372036854775807LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long lowest () { return -9223372036854775808LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 64; + static constexpr int digits10 = 19; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (max) () { return 18446744073709551615UL; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 1; + static constexpr int digits10 = 0; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr bool (min) () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool (max) () { return true; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool lowest () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool epsilon () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool round_error () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool infinity () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool quiet_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool signaling_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool denorm_min () { return false; } +}; + +#endif // BOOST_CRYPT_HAS_CUDA + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_UTILITY_LIMITS_HPP diff --git a/include/boost/crypt/utility/strlen.hpp b/include/boost/crypt/utility/strlen.hpp new file mode 100644 index 00000000..6f6e3856 --- /dev/null +++ b/include/boost/crypt/utility/strlen.hpp @@ -0,0 +1,30 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_STRLEN_HPP +#define BOOST_CRYPT_UTILITY_STRLEN_HPP + +#include + +namespace boost { +namespace crypt { +namespace utility { + +template +BOOST_CRYPT_GPU_ENABLED constexpr auto strlen(ForwardIter str) noexcept -> boost::crypt::size_t +{ + boost::crypt::size_t len {}; + while (*(str + len) != static_cast('\0')) + { + ++len; + } + + return len; +} + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_STRLEN_HPP diff --git a/include/boost/crypt/utility/type_traits.hpp b/include/boost/crypt/utility/type_traits.hpp new file mode 100644 index 00000000..7d689822 --- /dev/null +++ b/include/boost/crypt/utility/type_traits.hpp @@ -0,0 +1,499 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Regular use of is not compatible with CUDA +// Adds aliases to unify the support +// Also adds convience overloads like is_same_v so we don't have to wait for C++17 + +#ifndef BOOST_CRYPT_UTILITY_TYPE_TRAITS +#define BOOST_CRYPT_UTILITY_TYPE_TRAITS + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +#include + +namespace boost { +namespace crypt { + +// Helper classes +using cuda::std::integral_constant; +using cuda::std::true_type; +using cuda::std::false_type; + +// Primary type categories +using cuda::std::is_void; +using cuda::std::is_null_pointer; +using cuda::std::is_integral; +using cuda::std::is_floating_point; +using cuda::std::is_array; +using cuda::std::is_enum; +using cuda::std::is_union; +using cuda::std::is_class; +using cuda::std::is_function; +using cuda::std::is_pointer; +using cuda::std::is_lvalue_reference; +using cuda::std::is_rvalue_reference; +using cuda::std::is_member_object_pointer; +using cuda::std::is_member_function_pointer; + +// Composite Type Categories +using cuda::std::is_fundamental; +using cuda::std::is_arithmetic; +using cuda::std::is_scalar; +using cuda::std::is_object; +using cuda::std::is_compound; +using cuda::std::is_reference; +using cuda::std::is_member_pointer; + +// Type properties +using cuda::std::is_const; +using cuda::std::is_volatile; +using cuda::std::is_trivial; +using cuda::std::is_trivially_copyable; +using cuda::std::is_standard_layout; +using cuda::std::is_empty; +using cuda::std::is_polymorphic; +using cuda::std::is_abstract; +using cuda::std::is_final; +using cuda::std::is_signed; +using cuda::std::is_unsigned; + +// Supported Operations +using cuda::std::is_constructible; +using cuda::std::is_trivially_constructible; +using cuda::std::is_nothrow_constructible; + +using cuda::std::is_default_constructible; +using cuda::std::is_trivially_default_constructible; +using cuda::std::is_nothrow_default_constructible; + +using cuda::std::is_copy_constructible; +using cuda::std::is_trivially_copy_constructible; +using cuda::std::is_nothrow_copy_constructible; + +using cuda::std::is_move_constructible; +using cuda::std::is_trivially_move_constructible; +using cuda::std::is_nothrow_move_constructible; + +using cuda::std::is_assignable; +using cuda::std::is_trivially_assignable; +using cuda::std::is_nothrow_assignable; + +using cuda::std::is_copy_assignable; +using cuda::std::is_trivially_copy_assignable; +using cuda::std::is_nothrow_copy_assignable; + +using cuda::std::is_move_assignable; +using cuda::std::is_trivially_move_assignable; +using cuda::std::is_nothrow_move_assignable; + +using cuda::std::is_destructible; +using cuda::std::is_trivially_destructible; +using cuda::std::is_nothrow_destructible; + +using cuda::std::has_virtual_destructor; + +// Property Queries +using cuda::std::alignment_of; +using cuda::std::rank; +using cuda::std::extent; + +// Type Relationships +using cuda::std::is_same; +using cuda::std::is_base_of; +using cuda::std::is_convertible; + +// Const-volatility specifiers +using cuda::std::remove_cv; +using cuda::std::remove_cv_t; +using cuda::std::remove_const; +using cuda::std::remove_const_t; +using cuda::std::remove_volatile; +using cuda::std::remove_volatile_t; +using cuda::std::add_cv; +using cuda::std::add_cv_t; +using cuda::std::add_const; +using cuda::std::add_const_t; +using cuda::std::add_volatile; +using cuda::std::add_volatile_t; + +// References +using cuda::std::remove_reference; +using cuda::std::remove_reference_t; +using cuda::std::add_lvalue_reference; +using cuda::std::add_lvalue_reference_t; +using cuda::std::add_rvalue_reference; +using cuda::std::add_rvalue_reference_t; + +// Pointers +using cuda::std::remove_pointer; +using cuda::std::remove_pointer_t; +using cuda::std::add_pointer; +using cuda::std::add_pointer_t; + +// Sign Modifiers +using cuda::std::make_signed; +using cuda::std::make_signed_t; +using cuda::std::make_unsigned; +using cuda::std::make_unsigned_t; + +// Arrays +using cuda::std::remove_extent; +using cuda::std::remove_extent_t; +using cuda::std::remove_all_extents; +using cuda::std::remove_all_extents_t; + +// Misc transformations +using cuda::std::decay; +using cuda::std::decay_t; +using cuda::std::enable_if; +using cuda::std::enable_if_t; +using cuda::std::conditional; +using cuda::std::conditional_t; +using cuda::std::common_type; +using cuda::std::common_type_t; +using cuda::std::underlying_type; +using cuda::std::underlying_type_t; + +#else // STD versions + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +// Helper classes +using std::integral_constant; +using std::true_type; +using std::false_type; + +// Primary type categories +using std::is_void; +using std::is_null_pointer; +using std::is_integral; +using std::is_floating_point; +using std::is_array; +using std::is_enum; +using std::is_union; +using std::is_class; +using std::is_function; +using std::is_pointer; +using std::is_lvalue_reference; +using std::is_rvalue_reference; +using std::is_member_object_pointer; +using std::is_member_function_pointer; + +// Composite Type Categories +using std::is_fundamental; +using std::is_arithmetic; +using std::is_scalar; +using std::is_object; +using std::is_compound; +using std::is_reference; +using std::is_member_pointer; + +// Type properties +using std::is_const; +using std::is_volatile; +using std::is_trivial; +using std::is_trivially_copyable; +using std::is_standard_layout; +using std::is_empty; +using std::is_polymorphic; +using std::is_abstract; +using std::is_final; +using std::is_signed; +using std::is_unsigned; + +// Supported Operations +using std::is_constructible; +using std::is_trivially_constructible; +using std::is_nothrow_constructible; + +using std::is_default_constructible; +using std::is_trivially_default_constructible; +using std::is_nothrow_default_constructible; + +using std::is_copy_constructible; +using std::is_trivially_copy_constructible; +using std::is_nothrow_copy_constructible; + +using std::is_move_constructible; +using std::is_trivially_move_constructible; +using std::is_nothrow_move_constructible; + +using std::is_assignable; +using std::is_trivially_assignable; +using std::is_nothrow_assignable; + +using std::is_copy_assignable; +using std::is_trivially_copy_assignable; +using std::is_nothrow_copy_assignable; + +using std::is_move_assignable; +using std::is_trivially_move_assignable; +using std::is_nothrow_move_assignable; + +using std::is_destructible; +using std::is_trivially_destructible; +using std::is_nothrow_destructible; + +using std::has_virtual_destructor; + +// Property Queries +using std::alignment_of; +using std::rank; +using std::extent; + +// Type Relationships +using std::is_same; +using std::is_base_of; +using std::is_convertible; + +// Const-volatility specifiers +using std::remove_cv; +using std::remove_cv_t; +using std::remove_const; +using std::remove_const_t; +using std::remove_volatile; +using std::remove_volatile_t; +using std::add_cv; +using std::add_cv_t; +using std::add_const; +using std::add_const_t; +using std::add_volatile; +using std::add_volatile_t; + +// References +using std::remove_reference; +using std::remove_reference_t; +using std::add_lvalue_reference; +using std::add_lvalue_reference_t; +using std::add_rvalue_reference; +using std::add_rvalue_reference_t; + +// Pointers +using std::remove_pointer; +using std::remove_pointer_t; +using std::add_pointer; +using std::add_pointer_t; + +// Sign Modifiers +using std::make_signed; +using std::make_signed_t; +using std::make_unsigned; +using std::make_unsigned_t; + +// Arrays +using std::remove_extent; +using std::remove_extent_t; +using std::remove_all_extents; +using std::remove_all_extents_t; + +// Misc transformations +using std::decay; +using std::decay_t; +using std::enable_if; +using std::enable_if_t; +using std::conditional; +using std::conditional_t; +using std::common_type; +using std::common_type_t; +using std::underlying_type; +using std::underlying_type_t; + +#endif + +template +using bool_constant = boost::crypt::integral_constant; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_void_v = boost::crypt::is_void::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_null_pointer_v = boost::crypt::is_null_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_integral_v = boost::crypt::is_integral::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_floating_point_v = boost::crypt::is_floating_point::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_array_v = boost::crypt::is_array::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_enum_v = boost::crypt::is_enum::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_union_v = boost::crypt::is_union::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_class_v = boost::crypt::is_class::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_function_v = boost::crypt::is_function::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_pointer_v = boost::crypt::is_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_lvalue_reference_v = boost::crypt::is_lvalue_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_rvalue_reference_v = boost::crypt::is_rvalue_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_object_pointer_v = boost::crypt::is_member_object_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_function_pointer_v = boost::crypt::is_member_function_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_fundamental_v = boost::crypt::is_fundamental::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_arithmetic_v = boost::crypt::is_arithmetic::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_scalar_v = boost::crypt::is_scalar::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_object_v = boost::crypt::is_object::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_compound_v = boost::crypt::is_compound::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_reference_v = boost::crypt::is_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_pointer_v = boost::crypt::is_member_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_const_v = boost::crypt::is_const::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_volatile_v = boost::crypt::is_volatile::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivial_v = boost::crypt::is_trivial::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copyable_v = boost::crypt::is_trivially_copyable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_standard_layout_v = boost::crypt::is_standard_layout::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_empty_v = boost::crypt::is_empty::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_polymorphic_v = boost::crypt::is_polymorphic::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_abstract_v = boost::crypt::is_abstract::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_final_v = boost::crypt::is_final::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_signed_v = boost::crypt::is_signed::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_unsigned_v = boost::crypt::is_unsigned::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_constructible_v = boost::crypt::is_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_constructible_v = boost::crypt::is_trivially_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_constructible_v = boost::crypt::is_nothrow_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_default_constructible_v = boost::crypt::is_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_default_constructible_v = boost::crypt::is_trivially_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_default_constructible_v = boost::crypt::is_nothrow_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_copy_constructible_v = boost::crypt::is_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copy_constructible_v = boost::crypt::is_trivially_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_copy_constructible_v = boost::crypt::is_nothrow_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_move_constructible_v = boost::crypt::is_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_move_constructible_v = boost::crypt::is_trivially_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_move_constructible_v = boost::crypt::is_nothrow_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_assignable_v = boost::crypt::is_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_assignable_v = boost::crypt::is_trivially_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_assignable_v = boost::crypt::is_nothrow_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_copy_assignable_v = boost::crypt::is_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copy_assignable_v = boost::crypt::is_trivially_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_copy_assignable_v = boost::crypt::is_nothrow_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_move_assignable_v = boost::crypt::is_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_move_assignable_v = boost::crypt::is_trivially_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_move_assignable_v = boost::crypt::is_nothrow_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_destructible_v = boost::crypt::is_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_destructible_v = boost::crypt::is_trivially_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_destructible_v = boost::crypt::is_nothrow_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool has_virtual_destructor_v = boost::crypt::has_virtual_destructor::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_same_v = boost::crypt::is_same::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_base_of_v = boost::crypt::is_base_of::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_convertible_v = boost::crypt::is_convertible::value; + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_UTILITY_TYPE_TRAITS diff --git a/meta/libraries.json b/meta/libraries.json new file mode 100644 index 00000000..b01c225e --- /dev/null +++ b/meta/libraries.json @@ -0,0 +1,17 @@ +{ + "key": "crypt", + "name": "Crypt", + "authors": [ + "Matt Borland", + "Christopher Kormanyos" + ], + "maintainers": [ + "Matt Borland ", + "Christopher Kormanyos " + ], + "description": "A module of cryptographic utilities.", + "category": [ + "Math and numerics" + ], + "cxxstd": "14" +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..60767959 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2018, 2019 Peter Dimov +# Copyright 2023 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) + +if(HAVE_BOOST_TEST) + + boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::crypt Boost::core Boost::uuid) + +endif() diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 00000000..37a5fd33 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,47 @@ +# Copyright 2023 - 2024 Matt Borland +# Copyright 2023 - 2024 Christopher Kormanyos +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +require-b2 5.0.1 ; +import-search /boost/config/checks ; +import config : requires ; +import modules ; +import testing ; + +project : requirements + + /boost/uuid//boost_uuid + + gcc:-Wall + gcc:-Wextra + + # Clang-Cl gives errors that are incorrect or irrelevant (e.g. C++98 compat) + #clang:-Wall + #clang:-Wextra + + msvc:all + + # Additional flags by request + gcc:-Wsign-conversion + gcc:-Wconversion + gcc:-Wundef + gcc:-Wold-style-cast + #gcc:-Wduplicated-branches + gcc:-Wfloat-equal + + clang:-Wsign-conversion + clang:-Wconversion + clang:-Wundef + clang:-Wold-style-cast + clang:-Wfloat-equal + + msvc:on + clang:on + gcc:on + + [ requires cxx14_decltype_auto cxx14_generic_lambdas cxx14_return_type_deduction cxx14_variable_templates cxx14_constexpr ] + ; + +run quick.cpp ; +run test_md5.cpp ; diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt new file mode 100644 index 00000000..d8597268 --- /dev/null +++ b/test/cmake_install_test/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2018, 2019 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5...3.16) + +project(cmake_install_test LANGUAGES CXX) + +find_package(boost_crypt REQUIRED) + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::crypt) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt new file mode 100644 index 00000000..0ac83cf8 --- /dev/null +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright 2018, 2019 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5...3.20) + +project(cmake_subdir_test LANGUAGES CXX) + +add_subdirectory(../.. boostorg/crypt) + +set(deps + +# Primary dependencies + +assert +config +core + +# Secondary dependencies + +static_assert +throw_exception +) + +foreach(dep IN LISTS deps) + + add_subdirectory(../../../${dep} boostorg/${dep}) + +endforeach() + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::crypt) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cover/make_gcov_01_generic.gmk b/test/cover/make_gcov_01_generic.gmk new file mode 100644 index 00000000..14a4b8ce --- /dev/null +++ b/test/cover/make_gcov_01_generic.gmk @@ -0,0 +1,103 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +# cd /mnt/c/ChrisGitRepos/cppalliance/crypt/test/cover +# make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ +# make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ + +all: gcov + +PATH_MAKE = $(CURDIR) +PATH_SRC = $(PATH_MAKE)/../../test +PATH_BIN = $(PATH_MAKE)/bin +PATH_OBJ = $(PATH_MAKE)/obj + +CAT = cat +GNUECHO = echo +LS = ls +MKDIR = mkdir +GCOV = gcov +LCOV = lcov +GENHTML = genhtml +RM = rm + +include make_gcov_02_files.gmk +include make_gcov_03_flags.gmk + +FILES_ALL = $(FILES_PRJ) +FILES_EXE = $(addprefix $(PATH_BIN)/, $(notdir $(addsuffix .exe, $(FILES_ALL)))) + +# ----------------------------------------------------------------------------- +# VPATH definition: VPATH is required for make to find the source files. +# ----------------------------------------------------------------------------- +VPATH := $(sort $(dir $(FILES_ALL))) + + +# ----------------------------------------------------------------------------- +# Executable file: +# ----------------------------------------------------------------------------- + +.PHONY: objects +objects: $(FILES_EXE) + @$(GNUECHO) + @$(GNUECHO) +++ compile source to object then link and execute + + +# ----------------------------------------------------------------------------- +# Main dependency: +# Compile all files and link them. +# Run gcov and get results. +# (See also https://github.com/codecov/example-cpp11-cmake) +# ----------------------------------------------------------------------------- + +.PHONY: gcov +gcov: objects + @$(GNUECHO) + @$(GNUECHO) +++ running gcov + @$(GCOV) $(GCOV_FLAGS) $(addsuffix .cpp,$(FILES_PRJ)) + @$(GNUECHO) + @$(GNUECHO) +++ running lcov + @$(LCOV) $(LCOV_BRANCH) -c --directory obj --output-file coverage_unfiltered.info + @$(LCOV) $(LCOV_BRANCH) --remove coverage_unfiltered.info $(LCOV_REMOVES) --output-file coverage.info + @$(GNUECHO) + @$(GNUECHO) +++ running genhtml + @$(GENHTML) coverage.info $(LCOV_BRANCH) --demangle-cpp --output-directory $(PATH_BIN)/report + +# ----------------------------------------------------------------------------- +# Clean temporary files. +# ----------------------------------------------------------------------------- + +.PHONY: clean +clean: + @$(GNUECHO) + @$(GNUECHO) +++ cleaning output directories + @-$(RM) -rf $(PATH_BIN)* || uname -r + @-$(RM) -rf $(PATH_OBJ)* || uname -r + @-$(RM) -f *.gcov || uname -r + @-$(RM) -f coverage* || uname -r + @$(GNUECHO) + + +# ----------------------------------------------------------------------------- +# Prepare the gcov build. +# ----------------------------------------------------------------------------- + +.PHONY: prepare +prepare: clean + @$(GNUECHO) + @$(GNUECHO) +++ creating output directories + @-$(MKDIR) -p $(PATH_BIN) + @-$(MKDIR) -p $(PATH_OBJ) + @$(GNUECHO) + @$(GNUECHO) +++ print gcov version + @$(GCOV) --version + @$(GNUECHO) + @$(GNUECHO) +++ print include paths + @$(GNUECHO) $(C_INCLUDES) + +include make_gcov_04_rules.gmk diff --git a/test/cover/make_gcov_02_files.gmk b/test/cover/make_gcov_02_files.gmk new file mode 100644 index 00000000..36213b9b --- /dev/null +++ b/test/cover/make_gcov_02_files.gmk @@ -0,0 +1,21 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +FILES_PRJ := $(basename $(wildcard $(PATH_SRC)/*.cpp)) + +FILES_EXCLUDE := $(PATH_SRC)/concepts_test.cpp \ + $(PATH_SRC)/link_1.cpp \ + $(PATH_SRC)/link_2.cpp \ + $(PATH_SRC)/link_3.cpp \ + $(PATH_SRC)/test_bad_evaluation_method.cpp \ + $(PATH_SRC)/test_explicit_floats.cpp \ + $(PATH_SRC)/test_from_chars.cpp + +FILES_EXCLUDE := $(basename $(FILES_EXCLUDE)) + +FILES_PRJ := $(filter-out $(FILES_EXCLUDE),$(FILES_PRJ)) diff --git a/test/cover/make_gcov_03_flags.gmk b/test/cover/make_gcov_03_flags.gmk new file mode 100644 index 00000000..7605ad96 --- /dev/null +++ b/test/cover/make_gcov_03_flags.gmk @@ -0,0 +1,73 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023. +# Copyright Christopher Kormanyos 2023. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +CC = g++ +STD = c++20 +ALL_COV = 0 + +ifneq ($(MY_BOOST_ROOT),) +BOOST_ROOT_FOR_GCOV := $(MY_BOOST_ROOT) +endif + +ifneq ($(MY_CC),) +CC := $(MY_CC) +endif + +ifneq ($(MY_STD),) +STD := $(MY_STD) +endif + +ifneq ($(MY_ALL_COV),) +ALL_COV := $(MY_ALL_COV) +endif + +CXXFLAGS = -march=native \ + -mtune=native \ + -O1 \ + -Wextra \ + -Wall \ + -fno-inline-functions \ + -fprofile-arcs \ + -ftest-coverage + +C_DEFINES = + +C_INCLUDES = $(PATH_SRC) \ + $(PATH_SRC)/../include \ + $(BOOST_ROOT_FOR_GCOV) + +C_DEFINES :=$(addprefix -D,$(C_DEFINES)) +C_INCLUDES :=$(addprefix -I,$(C_INCLUDES)) + +GCOV_FLAGS = --object-directory obj \ + --demangled-names + + +# ----------------------------------------------------------------------------- +# All gcov flags: The GCOV_FLAGS below are equivalent to -abcfu +# ----------------------------------------------------------------------------- + +ifneq ($(ALL_COV),0) +GCOV_FLAGS := $(GCOV_FLAGS) \ + --all-blocks \ + --branch-counts \ + --branch-probabilities \ + --function-summaries \ + --unconditional-branches +endif + +LCOV_BRANCH = + +ifneq ($(ALL_COV),0) +LCOV_BRANCH := --rc lcov_branch_coverage=1 +endif + +LCOV_REMOVES = '*/test/mini_to_chars.hpp' \ + '*$(MY_BOOST_ROOT)*' \ + '*/boost-root/*' \ + '/usr/*' diff --git a/test/cover/make_gcov_04_rules.gmk b/test/cover/make_gcov_04_rules.gmk new file mode 100644 index 00000000..05dc73a1 --- /dev/null +++ b/test/cover/make_gcov_04_rules.gmk @@ -0,0 +1,22 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023. +# Copyright Christopher Kormanyos 2023. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# special flags (on pattern rule) for compilation of files needing threads +# Note: Each file with threads must be specifically, manually listed here. +# Note: TBD: We can/will use a similar method for libquadmath needs. +# ----------------------------------------------------------------------------- +$(PATH_BIN)/test_frexp_ldexp.exe : $(CXXFLAGS) += -pthread -lpthread + + +# ----------------------------------------------------------------------------- +# pattern rule for compilation of cpp-files +# ----------------------------------------------------------------------------- +$(PATH_BIN)/%.exe : %.cpp + @-$(GNUECHO) +++ compile and link and execute: $(notdir $<) to $(notdir $(PATH_BIN)/$(basename $(@F)).exe) + @-$(CC) $(CXXFLAGS) -x c++ -c $(C_INCLUDES) $(C_DEFINES) $< -o $(PATH_OBJ)/$(basename $(@F)).o && $(CC) $(CXXFLAGS) $(PATH_OBJ)/$(basename $(@F)).o -o $(PATH_BIN)/$(basename $(@F)).exe && $(PATH_BIN)/$(basename $(@F)).exe diff --git a/test/generate_random_strings.hpp b/test/generate_random_strings.hpp new file mode 100644 index 00000000..c85f0ff8 --- /dev/null +++ b/test/generate_random_strings.hpp @@ -0,0 +1,100 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS +#define BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS + +#include +#include +#include +#include + +namespace boost { +namespace crypt { + +inline void generate_random_string(char* str, std::size_t length) +{ + + const char charset[] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = sizeof(charset) - 1; + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = '\0'; +} + +inline void generate_random_string(char16_t* str, std::size_t length) +{ + const char16_t charset[] = u"0123456789" + u"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + u"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + +inline void generate_random_string(char32_t* str, std::size_t length) +{ + const char32_t charset[] = U"0123456789" + U"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + U"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + +inline void generate_random_string(wchar_t* str, std::size_t length) +{ + const wchar_t charset[] = L"0123456789" + L"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + L"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + +} // Namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS diff --git a/test/quick.cpp b/test/quick.cpp new file mode 100644 index 00000000..ca796b7b --- /dev/null +++ b/test/quick.cpp @@ -0,0 +1,10 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +auto main() -> int +{ + return 0; +} diff --git a/test/test_file_1.txt b/test/test_file_1.txt new file mode 100644 index 00000000..2fe6575e --- /dev/null +++ b/test/test_file_1.txt @@ -0,0 +1 @@ +The quick brown fox jumps over the lazy dog. diff --git a/test/test_file_2.txt b/test/test_file_2.txt new file mode 100644 index 00000000..45bb78df --- /dev/null +++ b/test/test_file_2.txt @@ -0,0 +1,9 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras leo purus, faucibus id risus pulvinar, condimentum molestie justo. Nulla sit amet pulvinar magna. In at quam id leo scelerisque posuere. Nullam porttitor auctor vestibulum. Nullam ac velit orci. Quisque semper hendrerit tortor, eu vulputate mauris vestibulum eget. Quisque nunc neque, posuere ut tortor a, suscipit tristique diam. Maecenas nec elit turpis. Nullam sapien enim, rhoncus et aliquet id, accumsan ac justo. Maecenas eu diam eget lorem vehicula lacinia eget sit amet orci. Ut lobortis magna arcu, pharetra lacinia est lobortis ut. Nam sagittis ex et magna maximus volutpat. Praesent lacinia felis neque. Vestibulum velit nisl, ullamcorper eu hendrerit eget, aliquet vitae ante. Mauris scelerisque blandit felis sed pharetra. + +Etiam a sapien at arcu cursus malesuada. Mauris ut quam velit. Praesent rutrum, neque ut vehicula hendrerit, lorem libero malesuada neque, sed sodales turpis lorem fermentum erat. Vestibulum in eleifend erat, nec blandit libero. Etiam aliquam lacus sit amet nisl cursus, ut consequat orci dignissim. Proin varius lectus augue, a euismod quam euismod at. Nullam augue sapien, finibus viverra ante ac, ultricies eleifend ipsum. Mauris ullamcorper eros nulla, sed porta nulla imperdiet sed. Sed ac massa dui. Pellentesque tellus ligula, posuere quis enim hendrerit, suscipit eleifend felis. Vivamus consectetur feugiat orci a faucibus. Morbi tristique, ex sit amet mollis laoreet, ligula ligula tempor lorem, sed posuere nisl sem at nunc. Morbi a sodales justo. Sed efficitur nibh vitae turpis aliquam semper nec in urna. + +In neque nisl, malesuada eu tristique non, euismod a diam. Sed mattis scelerisque consectetur. Sed in molestie libero, quis porta felis. Curabitur vel augue mauris. Aliquam dignissim facilisis bibendum. Vestibulum ut dignissim metus, ut fermentum elit. Etiam eu arcu id massa tristique semper. Ut lobortis neque eget hendrerit pretium. Nulla congue justo nec nibh cursus mattis. Morbi libero urna, sagittis ac risus vel, rutrum finibus purus. + +Nam mattis fringilla justo eget pretium. Vivamus quis facilisis tortor. Aenean blandit elit eu mollis lacinia. Cras orci odio, aliquet eget lacus ac, feugiat lacinia magna. Pellentesque vel urna congue metus faucibus accumsan. Donec ac tortor feugiat nibh maximus imperdiet non id lectus. Duis commodo, purus eu suscipit porttitor, lorem purus faucibus enim, ac ultricies nulla massa vitae magna. Vestibulum maximus enim ante, quis lacinia magna molestie nec. Donec eleifend sapien at risus iaculis rhoncus. Phasellus sit amet urna pulvinar, commodo mi ut, feugiat sapien. Nullam id felis nec turpis commodo laoreet. + +Vivamus quis felis pretium, bibendum turpis vitae, maximus nulla. Phasellus a elit id erat lacinia lacinia. Nunc in feugiat libero. Morbi sodales quam eget sem egestas varius ut quis orci. In hac habitasse platea dictumst. Sed sollicitudin vestibulum faucibus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam rhoncus nulla elit, id egestas arcu posuere vulputate. Nullam sit amet leo iaculis, viverra nisi nec, efficitur nisi. Fusce nec dui ultricies, ultricies est ac, pretium est. diff --git a/test/test_md5.cpp b/test/test_md5.cpp new file mode 100644 index 00000000..fb9ae419 --- /dev/null +++ b/test/test_md5.cpp @@ -0,0 +1,449 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include "generate_random_strings.hpp" + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconversion" +# pragma clang diagnostic ignored "-Wold-style-cast" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#include + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +auto get_boost_uuid_result(const char* str, size_t length) +{ + unsigned char digest[16]; + boost::uuids::detail::md5 hasher; + hasher.process_bytes(str, length); + hasher.get_digest(digest); + + std::array return_array {}; + for (std::size_t i {}; i < 16U; ++i) + { + return_array[i] = digest[i]; + } + + return return_array; +} + +constexpr std::array>, 15> test_values = +{ + // // Start with the sample hashes from wiki + std::make_tuple("The quick brown fox jumps over the lazy dog", + std::array{0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6}), + std::make_tuple("The quick brown fox jumps over the lazy dog.", + std::array{0xe4, 0xd9, 0x09, 0xc2, 0x90, 0xd0, 0xfb, 0x1c, 0xa0, 0x68, 0xff, 0xad, 0xdf, 0x22, 0xcb, 0xd0}), + std::make_tuple("", + std::array{0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e}), + std::make_tuple("ddcc8542894a27456bbeb43f51f38764c32f72ae", + std::array{0x3b, 0x34, 0x0f, 0x00, 0x97, 0x31, 0x2e, 0xc8, 0x2f, 0xa4, 0xda, 0x0d, 0x7d, 0xa5, 0x30, 0x02}), + std::make_tuple("webmin1980", + std::array{0xb7, 0x8a, 0xae, 0x35, 0x67, 0x09, 0xf8, 0xc3, 0x11, 0x18, 0xea, 0x61, 0x39, 0x80, 0x95, 0x4b}), + std::make_tuple("$2y$10$EQAmcJw0cg.rt.6..SJ2bulFhDo0eWtuMhkfDMPGsNdap4xrOY61K", + std::array{0x40, 0xbb, 0xe6, 0x64, 0x4e, 0xfd, 0x93, 0x54, 0x07, 0x8d, 0x8c, 0x70, 0xfb, 0x6c, 0x9f, 0x42}), + std::make_tuple("pkirsanov", + std::array{0x87, 0x93, 0xce, 0x04, 0xf0, 0xc5, 0xf1, 0xe8, 0xed, 0x1e, 0x0c, 0x78, 0xf2, 0x49, 0xfe, 0x1b}), + std::make_tuple("Eleanor", + std::array{0xd3, 0x7e, 0x43, 0x17, 0x49, 0x05, 0xde, 0x70, 0xfb, 0xb5, 0xb0, 0x38, 0xd7, 0x24, 0x7f, 0x57}), + std::make_tuple("The Whirlpool Galaxy is about 88% the size of the Milky Way, with a diameter of 76,900 light-years", + std::array{0xd5, 0xdf, 0xd7, 0xb4, 0x12, 0x35, 0xab, 0xc7, 0xa9, 0xa3, 0x20, 0x5b, 0x68, 0x96, 0xf3, 0x4d}), + + // From the RFC + std::make_tuple("a", + std::array{0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61}), + std::make_tuple("abc", + std::array{0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72}), + std::make_tuple("message digest", + std::array{0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0}), + std::make_tuple("abcdefghijklmnopqrstuvwxyz", + std::array{0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b}), + std::make_tuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + std::array{0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f}), + std::make_tuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", + std::array{0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a}), +}; + +void basic_tests() +{ + for (const auto& test_value : test_values) + { + const auto message_result {boost::crypt::md5(std::get<0>(test_value))}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } +} + +void string_test() +{ + for (const auto& test_value : test_values) + { + const std::string string_message {std::get<0>(test_value)}; + const auto message_result {boost::crypt::md5(string_message)}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } +} + +void string_view_test() +{ + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + for (const auto& test_value : test_values) + { + const std::string string_message {std::get<0>(test_value)}; + const std::string_view string_view_message {string_message}; + const auto message_result {boost::crypt::md5(string_view_message)}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } + #endif +} + +void bad_input() +{ + const auto null_message {boost::crypt::md5(static_cast(nullptr))}; + BOOST_TEST_EQ(null_message[0], 0x0); + BOOST_TEST_EQ(null_message[1], 0x0); + BOOST_TEST_EQ(null_message[2], 0x0); + BOOST_TEST_EQ(null_message[3], 0x0); + + const auto null_message_len {boost::crypt::md5(static_cast(nullptr), 100)}; + BOOST_TEST_EQ(null_message_len[0], 0x0); + BOOST_TEST_EQ(null_message_len[1], 0x0); + BOOST_TEST_EQ(null_message_len[2], 0x0); + BOOST_TEST_EQ(null_message_len[3], 0x0); + + const auto unsigned_null_message {boost::crypt::md5(static_cast(nullptr))}; + BOOST_TEST_EQ(unsigned_null_message[0], 0x0); + BOOST_TEST_EQ(unsigned_null_message[1], 0x0); + BOOST_TEST_EQ(unsigned_null_message[2], 0x0); + BOOST_TEST_EQ(unsigned_null_message[3], 0x0); + + const auto unsigned_null_message_len {boost::crypt::md5(static_cast(nullptr), 100)}; + BOOST_TEST_EQ(unsigned_null_message_len[0], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[1], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[2], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[3], 0x0); + + std::string test_str {"Test string"}; + const auto reveresed_input {boost::crypt::detail::md5(test_str.end(), test_str.begin())}; + BOOST_TEST_EQ(reveresed_input[0], 0x0); + BOOST_TEST_EQ(reveresed_input[1], 0x0); + BOOST_TEST_EQ(reveresed_input[2], 0x0); + BOOST_TEST_EQ(reveresed_input[3], 0x0); +} + +void test_class() +{ + boost::crypt::md5_hasher hasher; + + for (const auto& test_value : test_values) + { + const auto msg {std::get<0>(test_value)}; + hasher.process_bytes(msg, std::strlen(msg)); + const auto message_result {hasher.get_digest()}; + + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + + hasher.init(); + } +} + +template +void test_random_values() +{ + constexpr std::size_t max_str_len {65535U}; + std::mt19937_64 rng(42); + std::uniform_int_distribution str_len(1, max_str_len - 1); + + char* str {new char[max_str_len]}; + + for (std::size_t i {}; i < 1024; ++i) + { + std::memset(str, '\0', max_str_len); + const std::size_t current_str_len {str_len(rng)}; + boost::crypt::generate_random_string(str, current_str_len); + const auto uuid_res {get_boost_uuid_result(str, current_str_len)}; + + // boost::crypt::array is implicitly convertible to std::array + const std::array crypt_res = boost::crypt::md5(str, current_str_len); + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(uuid_res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with string: " << str << std::endl; + break; + // LCOV_EXCL_STOP + } + } + } + + delete[] str; +} + +template +void test_random_piecewise_values() +{ + constexpr std::size_t max_str_len {65535U}; + std::mt19937_64 rng(42); + std::uniform_int_distribution str_len(1, max_str_len - 1); + + char* str {new char[max_str_len]}; + char* str_2 {new char[max_str_len]}; + + for (std::size_t i {}; i < 1024; ++i) + { + boost::uuids::detail::md5 boost_hasher; + boost::crypt::md5_hasher md5_hasher; + + std::memset(str, '\0', max_str_len); + std::memset(str_2, '\0', max_str_len); + + const std::size_t current_str_len {str_len(rng)}; + boost::crypt::generate_random_string(str, current_str_len); + boost::crypt::generate_random_string(str_2, current_str_len); + + boost_hasher.process_bytes(str, current_str_len); + boost_hasher.process_bytes(str_2, current_str_len); + boost_hasher.process_byte(52); // "4" + unsigned char digest[16]; + boost_hasher.get_digest(digest); + + std::array uuid_res {}; + for (std::size_t j {}; j < 16U; ++j) + { + uuid_res[j] = digest[j]; + } + + md5_hasher.process_bytes(str, current_str_len); + md5_hasher.process_bytes(str_2, current_str_len); + md5_hasher.process_byte(52); // "4" + const auto crypt_res {md5_hasher.get_digest()}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(uuid_res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with string: " << str << std::endl; + break; + // LCOV_EXCL_STOP + } + } + } + + delete[] str; + delete[] str_2; +} + +template +void test_file(T filename, const std::array& res) +{ + const auto crypt_res {boost::crypt::md5_file(filename)}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with file: " << filename << std::endl; + break; + // LCOV_EXCL_STOP + } + } +} + +template +void test_invalid_file(T filename) +{ + constexpr std::array res{}; + + const auto crypt_res {boost::crypt::md5_file(filename)}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with file: " << filename << std::endl; + break; + // LCOV_EXCL_STOP + } + } +} + +void files_test() +{ + // Based off where we are testing from (test vs boost_root) we need to adjust our filepath + const char* filename; + const char* filename_2; + + // Boost-root + std::ifstream fd("libs/crypt/test/test_file_1.txt", std::ios::binary | std::ios::in); + filename = "libs/crypt/test/test_file_1.txt"; + filename_2 = "libs/crypt/test/test_file_2.txt"; + + // LCOV_EXCL_START + if (!fd.is_open()) + { + // Local test directory or IDE + std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in); + filename = "test_file_1.txt"; + filename_2 = "test_file_2.txt"; + + if (!fd2.is_open()) + { + // test/cover + std::ifstream fd3("../test_file_1.txt", std::ios::binary | std::ios::in); + filename = "../test_file_1.txt"; + filename_2 = "../test_file_2.txt"; + + if (!fd3.is_open()) + { + std::cerr << "Test not run due to file system issues" << std::endl; + return; + } + else + { + fd3.close(); + } + } + else + { + fd2.close(); + } + } + else + { + fd.close(); + } + // LCOV_EXCL_STOP + + // On macOS 15 + // md5 test_file_1.txt + // MD5 (test_file_1.txt) = 0d7006cd055e94cf614587e1d2ae0c8e + constexpr std::array res{0x0d, 0x70, 0x06, 0xcd, 0x05, 0x5e, 0x94, 0xcf, + 0x61, 0x45, 0x87, 0xe1, 0xd2, 0xae, 0x0c, 0x8e}; + + test_file(filename, res); + + const std::string str_filename {filename}; + test_file(str_filename, res); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + const std::string_view str_view_filename {str_filename}; + test_file(str_view_filename, res); + #endif + + const auto invalid_filename = "broken.bin"; + test_invalid_file(invalid_filename); + + const std::string str_invalid_filename {invalid_filename}; + test_invalid_file(str_invalid_filename); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + const std::string_view str_view_invalid_filename {str_invalid_filename}; + test_invalid_file(str_view_invalid_filename); + #endif + + // On macOS 15 + // md5 test_file_2.txt + // MD5 (test_file_2.txt) = 530e67fa4b01e3ccaee8eca9916a814c + constexpr std::array res_2{0x53, 0x0e, 0x67, 0xfa, 0x4b, 0x01, 0xe3, 0xcc, + 0xae, 0xe8, 0xec, 0xa9, 0x91, 0x6a, 0x81, 0x4c}; + + test_file(filename_2, res_2); +} + +int main() +{ + basic_tests(); + string_test(); + string_test(); + string_view_test(); + + bad_input(); + + test_class(); + + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); + + // The Windows file system returns a different result than on UNIX platforms + #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) + files_test(); + #endif + + return boost::report_errors(); +}