diff options
author | Dmitry Kobets <dmitrykobets@microsoft.com> | 2022-09-27 01:27:01 +0300 |
---|---|---|
committer | Dmitry Kobets <dmitrykobets@microsoft.com> | 2022-09-27 01:27:01 +0300 |
commit | 8840d871995e06e36ac7b2c1f3a1d1a9c447365f (patch) | |
tree | 553888391284f68e7791cc35764ff6d1a16c2c20 | |
parent | d569ed65d05791fa6589115e1bfea879c8e9c591 (diff) | |
parent | 10df83d292bf5bbdc487e57dc8c2dc8c7a01f4d1 (diff) |
Merge remote-tracking branch 'origin/main' into final_action-revision
42 files changed, 1770 insertions, 1794 deletions
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 836b444..49e8c2e 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -29,7 +29,7 @@ jobs: echo "Emulator starting" - name: Configure - run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug .. + run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/25.0.8775105/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug .. - name: Build run: cmake --build . --parallel diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 9d29bbc..0ef9fa3 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -25,11 +25,11 @@ jobs: -GXcode \
-DCMAKE_SYSTEM_NAME=iOS \
"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
- -DCMAKE_OSX_DEPLOYMENT_TARGET=8 \
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=9 \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
"-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \
- -DMACOSX_BUNDLE_BUNDLE_VERSION=3.0.1 \
- -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.0.1 \
+ -DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \
+ -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \
..
- name: Build
diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a57955c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,337 +0,0 @@ - -language: cpp -notifications: - email: false - -# Use Linux unless specified otherwise -os: linux -dist: bionic - -cache: - directories: - - ${TRAVIS_BUILD_DIR}/deps - -stages: - - name: Latest # Compiler with the latest major version - - name: Previous # Compilers with the major version Latest - 1 - - name: Validation # run other jobs - -jobs: - include: - - ########################################################################## - # Validate CMake configuration - ########################################################################## - - - name: CMake 3.1.3 - latest - stage: Validation - env: &CMAKE_VERSION_LIST - - CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3 3.1.3"' - - GSL_CXX_STANDARD: 14 - addons: # Get latest release (candidate) - apt: - sources: - - sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic main' - key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' - - sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic-rc main' - packages: - - cmake - script: - - | - cd ./build - ( set -eu - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - export CXX=clang++ - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - ) - - - name: CMake 3.2.3 - 3.17.0 - stage: Validation - os: osx - osx_image: xcode11.3 - env: - - CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3"' - script: - - | - cd ./build - ( set -eu - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - ) - - ########################################################################## - # AppleClang on OSX - ########################################################################## - - - - # Xcode 10.3 - - name: AppleClang Xcode-10.3 C++14 Debug - stage: Previous - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode10.3 # AppleClang 10.0.1 same compiler as Xcode 10.2 - - name: AppleClang Xcode-10.3 C++14 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode10.3 - - name: AppleClang Xcode-10.3 C++17 Debug - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode10.3 - - name: AppleClang Xcode-10.3 C++17 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode10.3 - - - # Xcode 11.4 - - name: AppleClang Xcode-11.4 C++17 Debug - stage: Latest - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++17 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++14 Debug - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++14 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode11.4 - - ########################################################################## - # Clang on Linux - ########################################################################## - - # Clang 9 - - name: Clang-9 C++14 Debug - stage: Previous - env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &clang9 - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' - key_url: https://apt.llvm.org/llvm-snapshot.gpg.key - packages: - - clang-9 - - name: Clang-9 C++14 Release - env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *clang9 - - name: Clang-9 C++17 Debug - env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *clang9 - - name: Clang-9 C++17 Release - env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *clang9 - - # Clang 10 - - name: Clang-10 C++14 Debug - stage: Latest - env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &clang10 - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: https://apt.llvm.org/llvm-snapshot.gpg.key - packages: - - clang-10 - - name: Clang-10 C++14 Release - env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *clang10 - - name: Clang-10 C++17 Debug - env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *clang10 - - name: Clang-10 C++17 Release - env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *clang10 - - ########################################################################## - # GCC on Linux - ########################################################################## - - # GCC 8 - - name: GCC-8 C++14 Debug - stage: Previous - env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &gcc8 - apt: - packages: g++-8 - - name: GCC-8 C++14 Release - env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *gcc8 - - name: GCC-8 C++17 Debug - env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *gcc8 - - name: GCC-8 C++17 Release - env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *gcc8 - - # GCC 9 - - name: GCC-9 C++14 Debug - stage: Latest - env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &gcc9 - apt: - sources: - - sourceline: ppa:ubuntu-toolchain-r/test - packages: - - g++-9 - - name: GCC-9 C++14 Release - env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *gcc9 - - name: GCC-9 C++17 Debug - env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *gcc9 - - name: GCC-9 C++17 Release - env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *gcc9 - -before_install: - - | - # Configuration - JOBS=2 # Travis machines have 2 cores - # Dependencies required by the CI (cached directory) - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" - - | - # Setup - mkdir -p "${DEPS_DIR:?}" && cd "${DEPS_DIR:?}" - mkdir -p ~/tools && cd ~/tools - if [[ ${TRAVIS_OS_NAME:?} == "osx" ]]; then - export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH" - fi - - | - # Helper functions - # usage: if [[ $(check_url '<url>') ]]; then ... - function check_url {( set +e - if [[ "$1" =~ 'github.com' ]]; then # check for first byte - if curl --fail --silent --output /dev/null --connect-timeout 12 --range 0-0 "$1" - then echo true; fi - else # request head - if curl --fail --silent --output /dev/null --connect-timeout 12 --head "$1" - then echo true; fi - fi - return - )} - -install: - ############################################################################ - # Install a different CMake version (or several) - ############################################################################ - - | - # Install CMake versions - ( set -euo pipefail - if [[ ${CMAKE_VERSION:-} ]]; then - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - OS="Linux"; EXT="sh" - if [[ ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]]; then - # Single entry -> default CMake version - CMAKE_DEFAULT_DIR="/usr/local" - fi - elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then OS="Darwin"; EXT="tar.gz" - else echo "CMake install not supported for this OS."; exit 1 - fi - CMAKE_INSTALLER="install-cmake.${EXT}" - fi - for VERSION in ${CMAKE_VERSION:-}; do - CMAKE_URL="https://github.com/Kitware/CMake/releases/download/v${VERSION}/cmake-${VERSION}-${OS}-x86_64.${EXT}" - if [[ $(check_url "$CMAKE_URL") ]]; then - curl -sSL ${CMAKE_URL} -o ${CMAKE_INSTALLER} - CMAKE_DIR="${CMAKE_DEFAULT_DIR:-"${HOME}/tools/cmake-${VERSION}"}" - mkdir -p ${CMAKE_DIR} - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - chmod +x ${CMAKE_INSTALLER} - sudo ./${CMAKE_INSTALLER} --prefix=${CMAKE_DIR} --skip-license - else # OSX - mkdir -p ./CMake_tmp - tar --extract --gzip --file=${CMAKE_INSTALLER} --directory=./CMake_tmp - mv ./CMake_tmp/*/CMake.app/Contents/* ${CMAKE_DIR} - fi - rm --recursive --force ./CMake_tmp ${CMAKE_INSTALLER} - else echo 'Invalid url!'; echo "Version: ${VERSION}" - fi - done - ) - if [[ ${CMAKE_VERSION:-} && "${TRAVIS_OS_NAME:?}" == "osx" && ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]] - then # Single entry -> default CMake version - export PATH=${HOME}/tools/cmake-${CMAKE_VERSION:?}/bin:$PATH - fi - CMAKE_path=("cmake") # start with installed CMake version - for VERSION in ${CMAKE_VERSION:-}; do - tmp_path="$HOME/tools/cmake-${VERSION:?}/bin/cmake" - if [[ -x "$(command -v ${tmp_path:?})" ]]; then CMAKE_path+=("${tmp_path:?}"); fi - done - function test_CMake_generate { - # $1: cmake or full path to cmake - shopt -s extglob - if [[ "$1" == "cmake" || -x "$(command -v $1)" && "$1" =~ .*cmake$ ]]; then - echo "----------------" - $1 --version - echo "Configuration = ${BUILD_TYPE:-Debug}" - $1 -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} ${CMAKE_GEN_FLAGS[@]:?} .. - rm -rf !(tests/googletest-*) - if [[ ! ${BUILD_TYPE:-} ]]; then echo "" && echo "Configuration = Release" - $1 -DCMAKE_BUILD_TYPE=Release ${CMAKE_GEN_FLAGS[@]:?} .. - rm -rf !(tests/googletest-*) - fi - else echo "Non existing command: $1" - fi - } - - | - # CMake wrapper (Trusty, Xenial & Bionic); restore default behaviour. - if [[ "${TRAVIS_OS_NAME:?}" == "linux" && - "$(lsb_release --codename)" =~ (trusty|xenial|bionic)$ ]] - then - if [[ -x $(command -v /usr/local/bin/cmake) ]]; then - function cmake { command /usr/local/bin/cmake $@; } - elif [[ -x $(command -v /usr/bin/cmake) ]]; then - function cmake { command /usr/bin/cmake $@; } - fi - fi - - ############################################################################ - # [linux]: Install the right version of libc++ - # Based on https://github.com/ldionne/hana/blob/master/.travis.yml - ############################################################################ - - | - LLVM_INSTALL=${DEPS_DIR:?}/llvm/install - # if in linux and compiler clang and llvm not installed - if [[ "${TRAVIS_OS_NAME:?}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL:?})" ]]; then - if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; - elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1"; - elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1"; - elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1"; - fi - LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" - LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" - LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" - mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi - travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm - travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx - travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi - (cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL}) - (cd llvm/build/projects/libcxx && make install -j2) - (cd llvm/build/projects/libcxxabi && make install -j2) - export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1" - export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi" - export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib" - fi - -before_script: - - | - cd "${TRAVIS_BUILD_DIR:?}" - mkdir build && cd build - if [[ ${GSL_CXX_STANDARD:-} ]]; then - CMAKE_GEN_FLAGS=("-DGSL_CXX_STANDARD=$GSL_CXX_STANDARD") - fi - CMAKE_GEN_FLAGS+=("-Wdev -Werror=dev --warn-uninitialized") - -script: - # generate build files - - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE:?} ${CMAKE_GEN_FLAGS[@]:?} - # build and run tests - - cmake --build . -- -j${JOBS} - - ctest --output-on-failure -j${JOBS} diff --git a/CMakeLists.txt b/CMakeLists.txt index b59ec7a..5e0d9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") include(guidelineSupportLibrary) project(GSL - VERSION 3.1.0 + VERSION 4.0.0 LANGUAGES CXX ) @@ -30,14 +30,14 @@ not_null | ☑ | restricts a pointer / smart po span | ☑ | a view over a contiguous sequence of memory. Based on the standardized verison of `std::span`, however `gsl::span` enforces bounds checking. See the [wiki](https://github.com/microsoft/GSL/wiki/gsl::span-and-std::span) for additional information. span_p | ☐ | spans a range starting from a pointer to the first place for which the predicate is true basic_zstring | ☑ | A pointer to a C-string (zero-terminated array) with a templated char type -zstring | ☑ | An alias to `basic_zstring` with a char type of char -czstring | ☑ | An alias to `basic_zstring` with a char type of const char -wzstring | ☑ | An alias to `basic_zstring` with a char type of wchar_t -cwzstring | ☑ | An alias to `basic_zstring` with a char type of const wchar_t -u16zstring | ☑ | An alias to `basic_zstring` with a char type of char16_t -cu16zstring | ☑ | An alias to `basic_zstring` with a char type of const char16_t -u32zstring | ☑ | An alias to `basic_zstring` with a char type of char32_t -cu32zstring | ☑ | An alias to `basic_zstring` with a char type of const char32_t +zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char +czstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char +wzstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of wchar_t +cwzstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const wchar_t +u16zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char16_t +cu16zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char16_t +u32zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char32_t +cu32zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char32_t [**2. Owners**][cg-owners] | | unique_ptr | ☑ | an alias to `std::unique_ptr` shared_ptr | ☑ | an alias to `std::shared_ptr` @@ -85,17 +85,25 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp [cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts # Quick Start -## Supported Compilers -The GSL officially supports the current and previous major release of MSVC, GCC, Clang, and XCode's Apple-Clang. -See our latest test results for the most up-to-date list of supported configurations. +## Supported Compilers / Toolsets +The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang. +Within these two major versions, we try to target the latest minor updates / revisions (although this may be affected by +delays between a toolchain's release and when it becomes widely available for use). +Below is a table showing the versions currently being tested. Compiler |Toolset Versions Currently Tested :------- |--: - XCode |11.4 & 10.3 - GCC |9 & 8 - Clang |11 & 10 - Visual Studio with MSVC | VS2017 (15.9) & VS2019 (16.4) - Visual Studio with LLVM | VS2017 (Clang 9) & VS2019 (Clang 10) + XCode | 13.2.1 & 12.5.1 + GCC | 11[^1] & 10[^2] + Clang | 12[^2] & 11[^2] + Visual Studio with MSVC | VS2022[^3] & VS2019[^4] + Visual Studio with LLVM | VS2022[^3] & VS2019[^4] + + +[^1]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). +[^2]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#language-and-runtime). +[^3]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022). +[^4]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019). --- If you successfully port GSL to another platform, we would love to hear from you! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..869fdfe --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ +<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK --> + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + +<!-- END MICROSOFT SECURITY.MD BLOCK --> diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0d1219a..ba16ee9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,65 +4,63 @@ trigger: pr: autoCancel: true -# GCC stages: - stage: GCC dependsOn: [] - variables: - - name: CC - value: gcc - - name: CXX - value: g++ jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate GCC latest' - imageName: ubuntu-20.04 - - template: ./pipelines/jobs.yml - parameters: - jobName: 'Validate GCC Previous' - imageName: ubuntu-18.04 + compiler: gcc + image: ubuntu-20.04 + compilerVersions: [ 11, 10 ] + setupfile: 'setup_gcc.yml' -# Clang - stage: Clang dependsOn: [] - variables: - - name: CC - value: clang - - name: CXX - value: clang++ jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Clang latest' - imageName: ubuntu-20.04 + compiler: clang + image: ubuntu-20.04 + compilerVersions: [ 12, 11 ] + setupfile: 'setup_clang.yml' + +- stage: Xcode + dependsOn: [] + jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Clang Previous' - imageName: ubuntu-18.04 + compiler: 'Xcode' + image: macOS-11 + compilerVersions: [ '12.5.1', '13.2.1' ] + setupfile: 'setup_apple.yml' -# MSVC -- stage: MSVC +- stage: VS_MSVC dependsOn: [] jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate MSVC latest' - imageName: windows-latest + compiler: 'VS2019 (MSVC)' + compilerVersions: [ 'default' ] + image: windows-2019 - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate MSVC Previous' - imageName: vs2017-win2016 + compiler: 'VS2022 (MSVC)' + compilerVersions: [ 'default' ] + image: windows-2022 -# Apple-Clang -- stage: Apple_Clang +- stage: VS_LLVM dependsOn: [] jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Apple-Clang latest' - imageName: macos-10.15 + compiler: 'VS2019 (LLVM)' + compilerVersions: [ 'default' ] + image: windows-2019 + extraCmakeArgs: '-T ClangCL' - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Apple-Clang Previous' - imageName: macos-10.14 + compiler: 'VS2022 (LLVM)' + compilerVersions: [ 'default' ] + image: windows-2022 + extraCmakeArgs: '-T ClangCL' diff --git a/include/gsl/algorithm b/include/gsl/algorithm index b27475d..584f5cd 100644 --- a/include/gsl/algorithm +++ b/include/gsl/algorithm @@ -17,8 +17,8 @@ #ifndef GSL_ALGORITHM_H #define GSL_ALGORITHM_H -#include <gsl/assert> // for Expects -#include <gsl/span> // for dynamic_extent, span +#include "assert" // for Expects +#include "span" // for dynamic_extent, span #include <algorithm> // for copy_n #include <cstddef> // for ptrdiff_t diff --git a/include/gsl/assert b/include/gsl/assert index 0cc54f6..a601204 100644 --- a/include/gsl/assert +++ b/include/gsl/assert @@ -22,6 +22,7 @@ // Currently terminate is a no-op in this mode, so we add termination behavior back // #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) +#define GSL_KERNEL_MODE #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #include <intrin.h> diff --git a/include/gsl/gsl b/include/gsl/gsl index adadc40..3d9e288 100644 --- a/include/gsl/gsl +++ b/include/gsl/gsl @@ -17,16 +17,16 @@ #ifndef GSL_GSL_H #define GSL_GSL_H -#include <gsl/algorithm> // copy -#include <gsl/assert> // Ensures/Expects -#include <gsl/byte> // byte -#include <gsl/pointers> // owner, not_null -#include <gsl/span> // span -#include <gsl/string_span> // zstring, string_span, zstring_builder... -#include <gsl/util> // finally()/narrow_cast()... +#include "algorithm" // copy +#include "assert" // Ensures/Expects +#include "byte" // byte +#include "pointers" // owner, not_null +#include "span" // span +#include "string_span" // zstring, string_span, zstring_builder... +#include "util" // finally()/narrow_cast()... #ifdef __cpp_exceptions -#include <gsl/narrow> // narrow() +#include "narrow" // narrow() #endif #endif // GSL_GSL_H diff --git a/include/gsl/gsl_algorithm b/include/gsl/gsl_algorithm index 9f1dd50..951679a 100644 --- a/include/gsl/gsl_algorithm +++ b/include/gsl/gsl_algorithm @@ -1,3 +1,4 @@ #pragma once
-#pragma message("This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
-#include <gsl/algorithm>
+#pragma message( \
+ "This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
+#include "algorithm"
diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index b83a772..222ce30 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -1,3 +1,3 @@ #pragma once
#pragma message("This header will soon be removed. Use <gsl/assert> instead of <gsl/gsl_assert>")
-#include <gsl/assert>
+#include "assert"
diff --git a/include/gsl/gsl_byte b/include/gsl/gsl_byte index 4f198ce..831bb2d 100644 --- a/include/gsl/gsl_byte +++ b/include/gsl/gsl_byte @@ -1,3 +1,3 @@ #pragma once
#pragma message("This header will soon be removed. Use <gsl/byte> instead of <gsl/gsl_byte>")
-#include <gsl/byte>
+#include "byte"
diff --git a/include/gsl/gsl_narrow b/include/gsl/gsl_narrow index 6c2cd10..3e3e8cf 100644 --- a/include/gsl/gsl_narrow +++ b/include/gsl/gsl_narrow @@ -1,3 +1,3 @@ #pragma once
#pragma message("This header will soon be removed. Use <gsl/narrow> instead of <gsl/gsl_narrow>")
-#include <gsl/narrow>
+#include "narrow"
diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index 6a6d77e..a7ed739 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -1,3 +1,3 @@ #pragma once
#pragma message("This header will soon be removed. Use <gsl/util> instead of <gsl/gsl_util>")
-#include <gsl/util>
+#include "util"
diff --git a/include/gsl/narrow b/include/gsl/narrow index d47d9fd..7578c8b 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -16,8 +16,9 @@ #ifndef GSL_NARROW_H
#define GSL_NARROW_H
-#include <gsl/assert> // for Expects
-#include <gsl/util> // for narrow_cast
+#include "assert" // for GSL_SUPPRESS
+#include "util" // for narrow_cast
+#include <exception> // for std::exception
namespace gsl
{
struct narrowing_error : public std::exception
@@ -26,22 +27,55 @@ struct narrowing_error : public std::exception };
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
-template <class T, class U>
+template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
-// clang-format on
+GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
+ // in the static_cast below, and that gsl::narrow should be used instead.
+ // Suppress this warning, since gsl::narrow is defined in terms of
+ // static_cast
+ // clang-format on
constexpr T narrow(U u) noexcept(false)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
- const T t = narrow_cast<T>(u);
+GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow
+GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow
+GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
+ const T t = narrow_cast<T>(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type
+ // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms
+ // that we target (i.e., no hardware trap representations are hit).
+#if defined(__clang__) || defined(__GNUC__)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
{
throw narrowing_error{};
}
+#if defined(__clang__) || defined(__GNUC__)
+ #pragma GCC diagnostic pop
+#endif
+
+ return t;
+}
+
+template <class T, class U, typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr>
+// clang-format off
+GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
+GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
+ // clang-format on
+ constexpr T narrow(U u) noexcept(false)
+{
+ const T t = narrow_cast<T>(u);
+
+ if (static_cast<U>(t) != u)
+ {
+ throw narrowing_error{};
+ }
return t;
}
diff --git a/include/gsl/pointers b/include/gsl/pointers index 2f1b15f..a0a77ac 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -17,7 +17,7 @@ #ifndef GSL_POINTERS_H #define GSL_POINTERS_H -#include <gsl/assert> // for Ensures, Expects +#include "assert" // for Ensures, Expects #include <algorithm> // for forward #include <cstddef> // for ptrdiff_t, nullptr_t, size_t @@ -34,12 +34,19 @@ namespace gsl namespace details { -template<typename T, typename = void> -struct is_comparable_to_nullptr : std::false_type {}; + template <typename T, typename = void> + struct is_comparable_to_nullptr : std::false_type + { + }; -template <typename T> -struct is_comparable_to_nullptr<T, std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>> : std::true_type {}; -} // namespace details + template <typename T> + struct is_comparable_to_nullptr< + T, + std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>> + : std::true_type + { + }; +} // namespace details // // GSL.owner: ownership pointers diff --git a/include/gsl/span b/include/gsl/span index 506eb4c..49e1502 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -17,15 +17,21 @@ #ifndef GSL_SPAN_H #define GSL_SPAN_H -#include <gsl/assert> // for Expects -#include <gsl/byte> // for byte -#include <gsl/util> // for narrow_cast +#include "assert" // for Expects +#include "byte" // for byte +#include "span_ext" // for span specialization of gsl::at and other span-related extensions +#include "util" // for narrow_cast #include <array> // for array #include <cstddef> // for ptrdiff_t, size_t, nullptr_t #include <iterator> // for reverse_iterator, distance, random_access_... +#include <memory> // for pointer_traits #include <type_traits> // for enable_if_t, declval, is_convertible, inte... +#if defined(__has_include) && __has_include(<version>) +#include <version> +#endif + #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) @@ -60,12 +66,6 @@ namespace gsl { -// [views.constants], constants -constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1); - -template <class ElementType, std::size_t Extent = dynamic_extent> -class span; - // implementation details namespace details { @@ -115,6 +115,9 @@ namespace details class span_iterator { public: +#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts)) + using iterator_concept = std::contiguous_iterator_tag; +#endif // __cpp_lib_ranges using iterator_category = std::random_access_iterator_tag; using value_type = std::remove_cv_t<Type>; using difference_type = std::ptrdiff_t; @@ -334,8 +337,26 @@ namespace details pointer begin_ = nullptr; pointer end_ = nullptr; pointer current_ = nullptr; + + template <typename Ptr> + friend struct std::pointer_traits; }; +}} // namespace gsl::details +namespace std +{ +template <class Type> +struct pointer_traits<::gsl::details::span_iterator<Type>> +{ + using pointer = ::gsl::details::span_iterator<Type>; + using element_type = Type; + using difference_type = ptrdiff_t; + + static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; } +}; +} // namespace std + +namespace gsl { namespace details { template <std::size_t Ext> class extent_type { @@ -687,14 +708,11 @@ private: template <class OtherExtentType> constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) - { - Expects(ExtentType::size() != dynamic_extent); - } + {} template <class OtherExtentType> constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { - Expects(ExtentType::size() != dynamic_extent); Expects(data || ExtentType::size() == 0); } diff --git a/include/gsl/span_ext b/include/gsl/span_ext index b7c12cf..516cc99 100644 --- a/include/gsl/span_ext +++ b/include/gsl/span_ext @@ -27,16 +27,29 @@ //
///////////////////////////////////////////////////////////////////////////////
-#include <gsl/span> // for span
-#include <gsl/util> // for narrow_cast, narrow
+#include "assert" // GSL_KERNEL_MODE
+#include "util" // for narrow_cast, narrow
-#include <algorithm> // for lexicographical_compare
-#include <cstddef> // for ptrdiff_t, size_t
+#include <cstddef> // for ptrdiff_t, size_t
#include <utility>
+#ifndef GSL_KERNEL_MODE
+#include <algorithm> // for lexicographical_compare
+#endif // GSL_KERNEL_MODE
+
namespace gsl
{
+// [span.views.constants], constants
+GSL_INLINE constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
+
+template <class ElementType, std::size_t Extent = dynamic_extent>
+class span;
+
+// std::equal and std::lexicographical_compare are not /kernel compatible
+// so all comparison operators must be removed for kernel mode.
+#ifndef GSL_KERNEL_MODE
+
// [span.comparison], span comparison operators
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
@@ -74,6 +87,8 @@ constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> return !(l < r);
}
+#endif // GSL_KERNEL_MODE
+
//
// make_span() - Utility functions for creating spans
//
diff --git a/include/gsl/string_span b/include/gsl/string_span index a76236d..397c561 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -17,9 +17,9 @@ #ifndef GSL_STRING_SPAN_H
#define GSL_STRING_SPAN_H
-#include <gsl/assert> // for Ensures, Expects
-#include <gsl/span_ext> // for operator!=, operator==, dynamic_extent
-#include <gsl/util> // for narrow_cast
+#include "assert" // for Ensures, Expects
+#include "span_ext" // for operator!=, operator==, dynamic_extent
+#include "util" // for narrow_cast
#include <algorithm> // for equal, lexicographical_compare
#include <array> // for array
@@ -59,29 +59,21 @@ namespace gsl template <typename CharT, std::size_t Extent = dynamic_extent>
using basic_zstring = CharT*;
-template <std::size_t Extent = dynamic_extent>
-using czstring = basic_zstring<const char, Extent>;
+using czstring = basic_zstring<const char, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using cwzstring = basic_zstring<const wchar_t, Extent>;
+using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using cu16zstring = basic_zstring<const char16_t, Extent>;
+using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using cu32zstring = basic_zstring<const char32_t, Extent>;
+using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using zstring = basic_zstring<char, Extent>;
+using zstring = basic_zstring<char, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using wzstring = basic_zstring<wchar_t, Extent>;
+using wzstring = basic_zstring<wchar_t, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using u16zstring = basic_zstring<char16_t, Extent>;
+using u16zstring = basic_zstring<char16_t, dynamic_extent>;
-template <std::size_t Extent = dynamic_extent>
-using u32zstring = basic_zstring<char32_t, Extent>;
+using u32zstring = basic_zstring<char32_t, dynamic_extent>;
namespace details
{
diff --git a/include/gsl/util b/include/gsl/util index 8d3f381..db6a85e 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -17,7 +17,7 @@ #ifndef GSL_UTIL_H #define GSL_UTIL_H -#include <gsl/assert> // for Expects +#include "assert" // for Expects #include <array> #include <cstddef> // for ptrdiff_t, size_t @@ -25,6 +25,13 @@ #include <type_traits> // for is_signed, integral_constant #include <utility> // for exchange, forward +#if defined(__has_include) && __has_include(<version>) +#include <version> +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +#include <span> +#endif // __cpp_lib_span >= 202002L +#endif //__has_include(<version>) + #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) @@ -38,6 +45,12 @@ #define GSL_NODISCARD #endif // defined(__cplusplus) && (__cplusplus >= 201703L) +#if defined(__cpp_inline_variables) +#define GSL_INLINE inline +#else +#define GSL_INLINE +#endif + namespace gsl { // @@ -81,8 +94,8 @@ GSL_NODISCARD auto finally(F&& f) noexcept template <class T, class U> // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute -// clang-format on -constexpr T narrow_cast(U&& u) noexcept + // clang-format on + constexpr T narrow_cast(U&& u) noexcept { return static_cast<T>(std::forward<U>(u)); } @@ -94,7 +107,7 @@ template <class T, std::size_t N> // clang-format off GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -// clang-format on + // clang-format on constexpr T& at(T (&arr)[N], const index i) { Expects(i >= 0 && i < narrow_cast<index>(N)); @@ -105,7 +118,7 @@ template <class Cont> // clang-format off GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -// clang-format on + // clang-format on constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { Expects(i >= 0 && i < narrow_cast<index>(cont.size())); @@ -116,13 +129,21 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute template <class T> // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute -// clang-format on -constexpr T at(const std::initializer_list<T> cont, const index i) + // clang-format on + constexpr T at(const std::initializer_list<T> cont, const index i) { Expects(i >= 0 && i < narrow_cast<index>(cont.size())); return *(cont.begin() + i); } +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +template <class T, size_t extent = std::dynamic_extent> +constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()]) +{ + Expects(i >= 0 && i < narrow_cast<index>(sp.size())); + return sp[gsl::narrow_cast<size_t>(i)]; +} +#endif // __cpp_lib_span >= 202002L } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) diff --git a/pipelines/jobs.yml b/pipelines/jobs.yml index dad2414..aabd3db 100644 --- a/pipelines/jobs.yml +++ b/pipelines/jobs.yml @@ -1,26 +1,43 @@ parameters:
- jobName: ''
- imageName: ''
+ CXXVersions: [ 14, 17, 20 ]
+ buildTypes: [ 'Debug', 'Release' ]
+ image: ''
+
+ compiler: ''
+ compilerVersions: ["default"] # if default value, simply uses whatever version is on the machine.
+ # the text of this default value doesn't actually matter.
+ setupfile: ''
+ extraCmakeArgs: ''
jobs:
-- job:
- displayName: ${{ parameters.imageName }}
- pool:
- vmImage: ${{ parameters.imageName }}
- strategy:
- matrix:
- 14_debug:
- GSL_CXX_STANDARD: '14'
- BUILD_TYPE: 'Debug'
- 14_release:
- GSL_CXX_STANDARD: '14'
- BUILD_TYPE: 'Release'
- 17_debug:
- GSL_CXX_STANDARD: '17'
- BUILD_TYPE: 'Debug'
- 17_release:
- GSL_CXX_STANDARD: '17'
- BUILD_TYPE: 'Release'
- continueOnError: false
- steps:
- - template: ./steps.yml
+- ${{ each compilerVersion in parameters.compilerVersions }}:
+ - ${{ each CXXVersion in parameters.CXXVersions }}:
+ - ${{ each buildType in parameters.buildTypes }}:
+ - job:
+ displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }}
+ pool:
+ vmImage: ${{ parameters.image }}
+ continueOnError: false
+
+ steps:
+ - ${{ if not(eq(parameters.setupfile, '')) }}:
+ - template: ${{ parameters.setupfile }}
+ parameters:
+ version: ${{ compilerVersion }}
+
+ - task: CMake@1
+ name: Configure
+ inputs:
+ workingDirectory: build
+ cmakeArgs: '-DGSL_CXX_STANDARD=${{ CXXVersion }} -DCMAKE_BUILD_TYPE=${{ buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ parameters.extraCmakeArgs }} .. '
+
+ - task: CMake@1
+ name: Build
+ inputs:
+ workingDirectory: build
+ cmakeArgs: '--build . '
+
+ - script: ctest . --output-on-failure --no-compress-output
+ name: CTest
+ workingDirectory: build
+ failOnStderr: true
diff --git a/pipelines/setup_apple.yml b/pipelines/setup_apple.yml new file mode 100644 index 0000000..6a256a5 --- /dev/null +++ b/pipelines/setup_apple.yml @@ -0,0 +1,9 @@ +parameters: + version: 0 + +steps: + - script: | + if [ "${{ parameters.version }}" != "default" ]; then sudo xcode-select -switch /Applications/Xcode_${{ parameters.version }}.app; fi + + displayName: "Setup Xcode Version" + failOnStderr: true diff --git a/pipelines/setup_clang.yml b/pipelines/setup_clang.yml new file mode 100644 index 0000000..58403b4 --- /dev/null +++ b/pipelines/setup_clang.yml @@ -0,0 +1,13 @@ +parameters: + version: 0 + +steps: + - script: | + echo "##vso[task.setvariable variable=CXX;]${CXX}" + echo "##vso[task.setvariable variable=CC;]${CC}" + + displayName: "Setup Clang Version" + failOnStderr: true + env: + CC: clang-${{ parameters.version }} + CXX: clang++-${{ parameters.version }} diff --git a/pipelines/setup_gcc.yml b/pipelines/setup_gcc.yml new file mode 100644 index 0000000..6480f67 --- /dev/null +++ b/pipelines/setup_gcc.yml @@ -0,0 +1,14 @@ +parameters: + version: 0 + +steps: + - script: | + echo "##vso[task.setvariable variable=CXX;]${CXX}" + echo "##vso[task.setvariable variable=CC;]${CC}" + if [ "${{ parameters.version }}" = "11" ]; then sudo apt-get install $CXX; fi + + displayName: "Setup GCC Version" + failOnStderr: true + env: + CC: gcc-${{ parameters.version }} + CXX: g++-${{ parameters.version }} diff --git a/pipelines/steps.yml b/pipelines/steps.yml index 41a7fca..e69de29 100644 --- a/pipelines/steps.yml +++ b/pipelines/steps.yml @@ -1,17 +0,0 @@ -steps:
- - task: CMake@1
- name: Configure
- inputs:
- workingDirectory: build
- cmakeArgs: '-DCMAKE_CXX_STANDARD=$(GSL_CXX_STANDARD) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -Werror=dev .. '
-
- - task: CMake@1
- name: Build
- inputs:
- workingDirectory: build
- cmakeArgs: '--build . '
-
- - script: ctest . --output-on-failure --no-compress-output
- name: CTest
- workingDirectory: build
- failOnStderr: true
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 368ce75..68e18ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,8 +9,12 @@ include(ExternalProject) # will make visual studio generated project group files set_property(GLOBAL PROPERTY USE_FOLDERS ON) +if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20) + add_compile_definitions(FORCE_STD_SPAN_TESTS=1) +endif() + if(IOS) - add_compile_definitions(GTEST_HAS_DEATH_TEST=1) + add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1) endif() pkg_search_module(GTestMain gtest_main) @@ -54,10 +58,11 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) find_package(Microsoft.GSL REQUIRED) endif() -if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) +if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17)) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) endif() +include(CheckCXXCompilerFlag) # this interface adds compile options to how the tests are run # please try to keep entries ordered =) add_library(gsl_tests_config INTERFACE) @@ -84,6 +89,7 @@ if(MSVC) # MSVC or simulating MSVC > $<$<CXX_COMPILER_ID:Clang>: -Weverything + -Wfloat-equal -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-covered-switch-default # GTest @@ -101,6 +107,10 @@ if(MSVC) # MSVC or simulating MSVC > > ) + check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) + if (WARN_RESERVED_ID) + target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier") + endif() else() target_compile_options(gsl_tests_config INTERFACE -fno-strict-aliasing @@ -113,6 +123,7 @@ else() -Wpedantic -Wshadow -Wsign-conversion + -Wfloat-equal -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>: -Weverything @@ -135,6 +146,11 @@ else() $<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>: $<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template> > + $<$<AND:$<EQUAL:${GSL_CXX_STANDARD},20>,$<OR:$<CXX_COMPILER_VERSION:11.0.0>,$<CXX_COMPILER_VERSION:10.0.0>>>: + -Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 10.0.0 + # and clang 11.0.0. (operator< is being re-written by the compiler + # as operator<=> and raising the warning) + > > $<$<CXX_COMPILER_ID:AppleClang>: $<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>: @@ -164,36 +180,27 @@ target_include_directories(gsl_tests_config SYSTEM INTERFACE googletest/googletest/include ) -set_property(TARGET PROPERTY FOLDER "GSL_tests") - -function(add_gsl_test name) - add_executable(${name} ${name}.cpp) - target_link_libraries(${name} - Microsoft.GSL::GSL - gsl_tests_config - ${GTestMain_LIBRARIES} - ) - add_test( - ${name} - ${name} - ) - # group all tests under GSL_tests - set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests") -endfunction() - -add_gsl_test(span_tests) -add_gsl_test(span_ext_tests) -add_gsl_test(span_compatibility_tests) -add_gsl_test(string_span_tests) -add_gsl_test(at_tests) -add_gsl_test(notnull_tests) -add_gsl_test(assertion_tests) -add_gsl_test(utils_tests) -add_gsl_test(owner_tests) -add_gsl_test(byte_tests) -add_gsl_test(algorithm_tests) -add_gsl_test(strict_notnull_tests) +add_executable(gsl_tests + algorithm_tests.cpp + assertion_tests.cpp + at_tests.cpp + byte_tests.cpp + notnull_tests.cpp + owner_tests.cpp + span_compatibility_tests.cpp + span_ext_tests.cpp + span_tests.cpp + strict_notnull_tests.cpp + string_span_tests.cpp + utils_tests.cpp +) +target_link_libraries(gsl_tests + Microsoft.GSL::GSL + gsl_tests_config + ${GTestMain_LIBRARIES} +) +add_test(gsl_tests gsl_tests) # No exception tests @@ -222,12 +229,17 @@ if(MSVC) # MSVC or simulating MSVC > $<$<CXX_COMPILER_ID:Clang>: -Weverything + -Wfloat-equal -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes -Wno-unknown-attributes > ) + check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) + if (WARN_RESERVED_ID) + target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier") + endif() else() target_compile_options(gsl_tests_config_noexcept INTERFACE -fno-exceptions @@ -241,6 +253,7 @@ else() -Wpedantic -Wshadow -Wsign-conversion + -Wfloat-equal $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>: -Weverything -Wno-c++98-compat @@ -268,19 +281,9 @@ else() ) endif(MSVC) -function(add_gsl_test_noexcept name) - add_executable(${name} ${name}.cpp) - target_link_libraries(${name} - Microsoft.GSL::GSL - gsl_tests_config_noexcept - ${GTestMain_LIBRARIES} - ) - add_test( - ${name} - ${name} - ) - # group all tests under GSL_tests_noexcept - set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept") -endfunction() - -add_gsl_test_noexcept(no_exception_ensure_tests) +add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp) +target_link_libraries(gsl_noexcept_tests + Microsoft.GSL::GSL + gsl_tests_config_noexcept +) +add_test(gsl_noexcept_tests gsl_noexcept_tests) diff --git a/tests/CMakeLists.txt.in b/tests/CMakeLists.txt.in index 1b10044..2535f8f 100644 --- a/tests/CMakeLists.txt.in +++ b/tests/CMakeLists.txt.in @@ -4,7 +4,7 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG 389cb68b87193358358ae87cc56d257fd0d80189 + GIT_TAG 1b18723e874b256c1e39378c6774a90701d70f7a SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 0f209ac..e369be0 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -14,23 +14,19 @@ // /////////////////////////////////////////////////////////////////////////////// -#include <gtest/gtest.h> +#include <array> // for array +#include <cstddef> // for size_t #include <gsl/algorithm> // for copy -#include <gsl/span> // for span -#include <array> // for array -#include <cstddef> // for size_t +#include <gsl/span> // for span +#include <gtest/gtest.h> -namespace -{ - static constexpr char deathstring[] = "Expected Death"; -} +#include "deathTestCommon.h" namespace gsl { struct fail_fast; } // namespace gsl -using namespace std; using namespace gsl; TEST(algorithm_tests, same_type) @@ -76,8 +72,8 @@ TEST(algorithm_tests, same_type) std::array<int, 5> src{1, 2, 3, 4, 5}; std::array<int, 10> dst{}; - const span<int> src_span(src); - const span<int, 10> dst_span(dst); + const gsl::span<int> src_span(src); + const gsl::span<int, 10> dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -204,10 +200,11 @@ TEST(algorithm_tests, incompatible_type) TEST(algorithm_tests, small_destination_span) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. small_destination_span"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); std::array<int, 12> src{1, 2, 3, 4}; std::array<int, 4> dst{}; @@ -217,9 +214,9 @@ TEST(algorithm_tests, small_destination_span) const span<int> dst_span_dyn(dst); const span<int, 4> dst_span_static(dst); - EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring); - EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring); - EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring); + EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected); + EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected); + EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected); #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index 6b5fb0b..dd3ca06 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -14,14 +14,14 @@ // /////////////////////////////////////////////////////////////////////////////// -#include <gtest/gtest.h> +#include "deathTestCommon.h" #include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects +#include <gtest/gtest.h> using namespace gsl; namespace { -static constexpr char deathstring[] = "Expected Death"; int f(int i) { @@ -39,23 +39,22 @@ int g(int i) TEST(assertion_tests, expects) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. expects"; std::abort(); }); EXPECT_TRUE(f(2) == 2); - EXPECT_DEATH(f(10), deathstring); + EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler)); } - TEST(assertion_tests, ensures) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. ensures"; std::abort(); }); EXPECT_TRUE(g(2) == 3); - EXPECT_DEATH(g(9), deathstring); + EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler)); } diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 1285139..93e6b7b 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -22,31 +22,33 @@ #include <cstddef> // for size_t #include <initializer_list> // for initializer_list #include <vector> // for vector +#if defined(__cplusplus) && __cplusplus >= 202002L +#include <span> +#endif // __cplusplus >= 202002L -namespace -{ - static constexpr char deathstring[] = "Expected Death"; -} +#include "deathTestCommon.h" TEST(at_tests, static_array) { int a[4] = {1, 2, 3, 4}; const int(&c_a)[4] = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. static_array"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, std_array) @@ -54,20 +56,22 @@ TEST(at_tests, std_array) std::array<int, 4> a = {1, 2, 3, 4}; const std::array<int, 4>& c_a = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. std_array"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, std_vector) @@ -75,41 +79,73 @@ TEST(at_tests, std_vector) std::vector<int> a = {1, 2, 3, 4}; const std::vector<int>& c_a = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. std_vector"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, InitializerList) { const std::initializer_list<int> a = {1, 2, 3, 4}; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(gsl::at(a, i) == i + 1); EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. InitializerList"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected); + EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected); +} + +#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +TEST(at_tests, std_span) +{ + std::vector<int> vec{1, 2, 3, 4, 5}; + std::span sp{vec}; + + std::vector<int> cvec{1, 2, 3, 4, 5}; + std::span csp{cvec}; + + for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i) + { + EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]); + EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]); + } + + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. std_span"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); - EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); + EXPECT_DEATH(gsl::at(sp, -1), expected); + EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected); + EXPECT_DEATH(gsl::at(csp, -1), expected); + EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected); } +#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 static constexpr bool test_constexpr() @@ -119,7 +155,8 @@ static constexpr bool test_constexpr() std::array<int, 4> a2 = {1, 2, 3, 4}; const std::array<int, 4>& c_a2 = a2; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { if (&gsl::at(a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false; // requires C++17: diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index 2a86cac..4432fc9 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -37,7 +37,9 @@ TEST(byte_tests, construction) EXPECT_TRUE(static_cast<unsigned char>(b) == 4); } + // clang-format off GSL_SUPPRESS(es.49) + // clang-format on { const byte b = byte(12); EXPECT_TRUE(static_cast<unsigned char>(b) == 12); @@ -55,7 +57,7 @@ TEST(byte_tests, construction) #if defined(__cplusplus) && (__cplusplus >= 201703L) { - const byte b { 14 }; + const byte b{14}; EXPECT_TRUE(static_cast<unsigned char>(b) == 14); } #endif @@ -122,7 +124,7 @@ TEST(byte_tests, aliasing) EXPECT_TRUE(res == i); } -} +} // namespace #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); diff --git a/tests/deathTestCommon.h b/tests/deathTestCommon.h new file mode 100644 index 0000000..7bf2423 --- /dev/null +++ b/tests/deathTestCommon.h @@ -0,0 +1,11 @@ +#pragma once
+#include <gsl/assert>
+
+constexpr char deathstring[] = "Expected Death";
+constexpr char failed_set_terminate_deathstring[] = ".*";
+
+// This prevents a failed call to set_terminate from failing the test suite.
+constexpr const char* GetExpectedDeathString(std::terminate_handler handle)
+{
+ return handle ? deathstring : failed_set_terminate_deathstring;
+}
diff --git a/tests/no_exception_ensure_tests.cpp b/tests/no_exception_ensure_tests.cpp index 2ec0ebb..5fde41c 100644 --- a/tests/no_exception_ensure_tests.cpp +++ b/tests/no_exception_ensure_tests.cpp @@ -14,8 +14,11 @@ //
///////////////////////////////////////////////////////////////////////////////
+#include <chrono>
#include <cstdlib> // for std::exit
#include <gsl/span> // for span
+#include <iostream>
+#include <thread>
int operator_subscript_no_throw() noexcept
{
@@ -42,6 +45,10 @@ void setup_termination_handler() noexcept int main() noexcept
{
+ std::cout << "Running main() from " __FILE__ "\n";
+#if defined(IOS_PROCESS_DELAY_WORKAROUND)
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+#endif
setup_termination_handler();
operator_subscript_no_throw();
return -1;
diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index b95bb01..db22c72 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -25,13 +25,9 @@ #include <string> // for basic_string, operator==, string, operator<< #include <typeinfo> // for type_info +#include "deathTestCommon.h" using namespace gsl; -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} //namespace - struct MyBase { }; @@ -64,7 +60,9 @@ struct CustomPtr template <typename T, typename U> std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -72,7 +70,9 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) template <typename T, typename U> std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -80,7 +80,9 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) template <typename T, typename U> std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -88,7 +90,9 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) template <typename T, typename U> std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -96,7 +100,9 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) template <typename T, typename U> std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -104,7 +110,9 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) template <typename T, typename U> std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" : "false"; } @@ -118,12 +126,19 @@ struct NonCopyableNonMovable NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +namespace +{ +// clang-format off +GSL_SUPPRESS(f .4) // NO-FORMAT: attribute +// clang-format on bool helper(not_null<int*> p) { return *p == 12; } -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format off +GSL_SUPPRESS(f .4) // NO-FORMAT: attribute +// clang-format on bool helper_const(not_null<const int*> p) { return *p == 12; } int* return_pointer() { return nullptr; } +} // namespace TEST(notnull_tests, TestNotNullConstructors) { @@ -142,10 +157,12 @@ TEST(notnull_tests, TestNotNullConstructors) #endif } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullConstructors"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + { // from shared pointer int i = 12; @@ -157,7 +174,7 @@ TEST(notnull_tests, TestNotNullConstructors) std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable int* pi = nullptr; - EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring); + EXPECT_DEATH((not_null<decltype(pi)>(pi)), expected); } { @@ -214,8 +231,8 @@ TEST(notnull_tests, TestNotNullConstructors) { // from returned pointer - EXPECT_DEATH(helper(return_pointer()), deathstring); - EXPECT_DEATH(helper_const(return_pointer()), deathstring); + EXPECT_DEATH(helper(return_pointer()), expected); + EXPECT_DEATH(helper_const(return_pointer()), expected); } } @@ -275,17 +292,18 @@ TEST(notnull_tests, TestNotNullCasting) TEST(notnull_tests, TestNotNullAssignment) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullAssignmentd"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); int i = 12; not_null<int*> p(&i); EXPECT_TRUE(helper(p)); int* q = nullptr; - EXPECT_DEATH(p = not_null<int*>(q), deathstring); + EXPECT_DEATH(p = not_null<int*>(q), expected); } TEST(notnull_tests, TestNotNullRawPointerComparison) @@ -434,17 +452,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction) EXPECT_TRUE(*x == 42); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { auto workaround_macro = []() { int* p1 = nullptr; const not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -452,14 +471,14 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction) const int* p1 = nullptr; const not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(not_null{p}), deathstring); - EXPECT_DEATH(helper_const(not_null{p}), deathstring); + EXPECT_DEATH(helper(not_null{p}), expected); + EXPECT_DEATH(helper_const(not_null{p}), expected); } #ifdef CONFIRM_COMPILATION_ERRORS @@ -495,10 +514,11 @@ TEST(notnull_tests, TestMakeNotNull) EXPECT_TRUE(*x == 42); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestMakeNotNull"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { const auto workaround_macro = []() { @@ -506,7 +526,7 @@ TEST(notnull_tests, TestMakeNotNull) const auto x = make_not_null(p1); EXPECT_TRUE(*x == 42); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -515,21 +535,21 @@ TEST(notnull_tests, TestMakeNotNull) const auto x = make_not_null(p1); EXPECT_TRUE(*x == 42); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(make_not_null(p)), deathstring); - EXPECT_DEATH(helper_const(make_not_null(p)), deathstring); + EXPECT_DEATH(helper(make_not_null(p)), expected); + EXPECT_DEATH(helper_const(make_not_null(p)), expected); } #ifdef CONFIRM_COMPILATION_ERRORS { - EXPECT_DEATH(make_not_null(nullptr), deathstring); - EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring); - EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring); + EXPECT_DEATH(make_not_null(nullptr), expected); + EXPECT_DEATH(helper(make_not_null(nullptr)), expected); + EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected); } #endif } diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index ca8222f..87c7cec 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -20,7 +20,7 @@ using namespace gsl; -GSL_SUPPRESS(f.23) // NO-FORMAT: attribute +GSL_SUPPRESS(f .23) // NO-FORMAT: attribute void f(int* i) { *i += 1; } TEST(owner_tests, basic_test) @@ -34,10 +34,10 @@ TEST(owner_tests, basic_test) TEST(owner_tests, check_pointer_constraint) { - #ifdef CONFIRM_COMPILATION_ERRORS +#ifdef CONFIRM_COMPILATION_ERRORS { owner<int> integerTest = 10; owner<std::shared_ptr<int>> sharedPtrTest(new int(10)); } - #endif +#endif } diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index 361db84..95d8223 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -17,7 +17,7 @@ #include <gtest/gtest.h> #include <gsl/byte> // for byte -#include <gsl/span> // for span, span_iterator, operator==, operator!= +#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <array> // for array #include <cstddef> // for ptrdiff_t @@ -55,14 +55,14 @@ void ArrayConvertibilityCheck() EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_1.size() == 3); - span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)}; + gsl::span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)}; EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_2.size() == 3); - static_assert(std::is_same<decltype(span{stl_nullptr}), span<T*, 3>>::value, + static_assert(std::is_same<decltype(gsl::span{stl_nullptr}), gsl::span<T*, 3>>::value, "std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value"); static_assert( - std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<T* const, 3>>::value, + std::is_same<decltype(gsl::span{std::as_const(stl_nullptr)}), gsl::span<T* const, 3>>::value, "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, " "3>>::value"); } diff --git a/tests/span_ext_tests.cpp b/tests/span_ext_tests.cpp index 4f07188..3d35f8f 100644 --- a/tests/span_ext_tests.cpp +++ b/tests/span_ext_tests.cpp @@ -16,27 +16,26 @@ #include <gtest/gtest.h>
+#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at
-#include <gsl/span_ext> // for operator==, operator!=, make_span
-#include <array> // for array
-#include <iostream> // for cerr
-#include <vector> // for vector
+#include <array> // for array
+#include <iostream> // for cerr
+#include <vector> // for vector
using namespace std;
using namespace gsl;
-namespace
-{
-static constexpr char deathstring[] = "Expected Death";
-} // namespace
+#include "deathTestCommon.h"
TEST(span_ext_test, make_span_from_pointer_length_constructor)
{
- std::set_terminate([] {
+ const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. from_pointer_length_constructor";
std::abort();
});
+ const auto expected = GetExpectedDeathString(terminateHandler);
+
int arr[4] = {1, 2, 3, 4};
{
@@ -49,7 +48,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor) {
int* p = nullptr;
- auto s = make_span(p, narrow_cast<span<int>::size_type>(0));
+ auto s = make_span(p, narrow_cast<gsl::span<int>::size_type>(0));
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == nullptr);
}
@@ -57,7 +56,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor) {
int* p = nullptr;
auto workaround_macro = [=]() { make_span(p, 2); };
- EXPECT_DEATH(workaround_macro(), deathstring);
+ EXPECT_DEATH(workaround_macro(), expected);
}
}
@@ -88,273 +87,275 @@ TEST(span_ext_test, make_span_from_pointer_pointer_construction) }
TEST(span_ext_test, make_span_from_array_constructor)
- {
- int arr[5] = {1, 2, 3, 4, 5};
- int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
- int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
-
- {
- const auto s = make_span(arr);
- EXPECT_TRUE(s.size() == 5);
- EXPECT_TRUE(s.data() == std::addressof(arr[0]));
- }
-
- {
- const auto s = make_span(std::addressof(arr2d[0]), 1);
- EXPECT_TRUE(s.size() == 1);
- EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
- }
-
- {
- const auto s = make_span(std::addressof(arr3d[0]), 1);
- EXPECT_TRUE(s.size() == 1);
- EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
- }
- }
-
- TEST(span_ext_test, make_span_from_dynamic_array_constructor)
- {
- double(*arr)[3][4] = new double[100][3][4];
-
- {
- auto s = make_span(&arr[0][0][0], 10);
- EXPECT_TRUE(s.size() == 10);
- EXPECT_TRUE(s.data() == &arr[0][0][0]);
- }
-
- delete[] arr;
- }
-
- TEST(span_ext_test, make_span_from_std_array_constructor)
- {
- std::array<int, 4> arr = {1, 2, 3, 4};
-
- {
- auto s = make_span(arr);
- EXPECT_TRUE(s.size() == arr.size());
- EXPECT_TRUE(s.data() == arr.data());
- }
-
- // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
- {
- span<int> s1 = make_span(arr);
-
- static span<int> s2;
- s2 = s1;
-
- #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
- __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
- // Known to be broken in gcc 6.4 and 6.5 with optimizations
- // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
- EXPECT_TRUE(s1.size() == 4);
- EXPECT_TRUE(s2.size() == 0);
- #else
- EXPECT_TRUE(s1.size() == s2.size());
- #endif
- }
- }
-
- TEST(span_ext_test, make_span_from_const_std_array_constructor)
- {
- const std::array<int, 4> arr = {1, 2, 3, 4};
-
- {
- auto s = make_span(arr);
- EXPECT_TRUE(s.size() == arr.size());
- EXPECT_TRUE(s.data() == arr.data());
- }
- }
-
- TEST(span_ext_test, make_span_from_std_array_const_constructor)
- {
- std::array<const int, 4> arr = {1, 2, 3, 4};
-
- {
- auto s = make_span(arr);
- EXPECT_TRUE(s.size() == arr.size());
- EXPECT_TRUE(s.data() == arr.data());
- }
- }
-
- TEST(span_ext_test, make_span_from_container_constructor)
- {
- std::vector<int> v = {1, 2, 3};
- const std::vector<int> cv = v;
-
- {
- auto s = make_span(v);
- EXPECT_TRUE(s.size() == v.size());
- EXPECT_TRUE(s.data() == v.data());
-
- auto cs = make_span(cv);
- EXPECT_TRUE(cs.size() == cv.size());
- EXPECT_TRUE(cs.data() == cv.data());
- }
- }
-
- TEST(span_test, interop_with_gsl_at)
- {
- int arr[5] = {1, 2, 3, 4, 5};
- span<int> s{arr};
- EXPECT_TRUE(at(s, 0) == 1);
- EXPECT_TRUE(at(s, 1) == 2);
- }
-
- TEST(span_ext_test, iterator_free_functions)
- {
- int a[] = {1, 2, 3, 4};
- span<int> s{a};
-
- EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
- EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
-
- EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
- EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
-
- EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
- EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
-
- EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
- EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
-
- EXPECT_TRUE(s.begin() == begin(s));
- EXPECT_TRUE(s.end() == end(s));
-
- EXPECT_TRUE(s.rbegin() == rbegin(s));
- EXPECT_TRUE(s.rend() == rend(s));
-
- EXPECT_TRUE(s.begin() == cbegin(s));
- EXPECT_TRUE(s.end() == cend(s));
-
- EXPECT_TRUE(s.rbegin() == crbegin(s));
- EXPECT_TRUE(s.rend() == crend(s));
- }
-
- TEST(span_ext_test, ssize_free_function)
- {
- int a[] = {1, 2, 3, 4};
- span<int> s{a};
-
- EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
- EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
- }
-
- TEST(span_ext_test, comparison_operators)
- {
- {
- span<int> s1;
- span<int> s2;
- EXPECT_TRUE(s1 == s2);
- EXPECT_FALSE(s1 != s2);
- EXPECT_FALSE(s1 < s2);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s1 >= s2);
- EXPECT_TRUE(s2 == s1);
- EXPECT_FALSE(s2 != s1);
- EXPECT_FALSE(s2 != s1);
- EXPECT_TRUE(s2 <= s1);
- EXPECT_FALSE(s2 > s1);
- EXPECT_TRUE(s2 >= s1);
- }
-
- {
- int arr[] = {2, 1};
- span<int> s1 = arr;
- span<int> s2 = arr;
-
- EXPECT_TRUE(s1 == s2);
- EXPECT_FALSE(s1 != s2);
- EXPECT_FALSE(s1 < s2);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s1 >= s2);
- EXPECT_TRUE(s2 == s1);
- EXPECT_FALSE(s2 != s1);
- EXPECT_FALSE(s2 < s1);
- EXPECT_TRUE(s2 <= s1);
- EXPECT_FALSE(s2 > s1);
- EXPECT_TRUE(s2 >= s1);
- }
-
- {
- int arr[] = {2, 1}; // bigger
-
- span<int> s1;
- span<int> s2 = arr;
-
- EXPECT_TRUE(s1 != s2);
- EXPECT_TRUE(s2 != s1);
- EXPECT_FALSE(s1 == s2);
- EXPECT_FALSE(s2 == s1);
- EXPECT_TRUE(s1 < s2);
- EXPECT_FALSE(s2 < s1);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s2 <= s1);
- EXPECT_TRUE(s2 > s1);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s2 >= s1);
- EXPECT_FALSE(s1 >= s2);
- }
-
- {
- int arr1[] = {1, 2};
- int arr2[] = {1, 2};
- span<int> s1 = arr1;
- span<int> s2 = arr2;
-
- EXPECT_TRUE(s1 == s2);
- EXPECT_FALSE(s1 != s2);
- EXPECT_FALSE(s1 < s2);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s1 >= s2);
- EXPECT_TRUE(s2 == s1);
- EXPECT_FALSE(s2 != s1);
- EXPECT_FALSE(s2 < s1);
- EXPECT_TRUE(s2 <= s1);
- EXPECT_FALSE(s2 > s1);
- EXPECT_TRUE(s2 >= s1);
- }
-
- {
- int arr[] = {1, 2, 3};
-
- span<int> s1 = {&arr[0], 2}; // shorter
- span<int> s2 = arr; // longer
-
- EXPECT_TRUE(s1 != s2);
- EXPECT_TRUE(s2 != s1);
- EXPECT_FALSE(s1 == s2);
- EXPECT_FALSE(s2 == s1);
- EXPECT_TRUE(s1 < s2);
- EXPECT_FALSE(s2 < s1);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s2 <= s1);
- EXPECT_TRUE(s2 > s1);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s2 >= s1);
- EXPECT_FALSE(s1 >= s2);
- }
-
- {
- int arr1[] = {1, 2}; // smaller
- int arr2[] = {2, 1}; // bigger
-
- span<int> s1 = arr1;
- span<int> s2 = arr2;
-
- EXPECT_TRUE(s1 != s2);
- EXPECT_TRUE(s2 != s1);
- EXPECT_FALSE(s1 == s2);
- EXPECT_FALSE(s2 == s1);
- EXPECT_TRUE(s1 < s2);
- EXPECT_FALSE(s2 < s1);
- EXPECT_TRUE(s1 <= s2);
- EXPECT_FALSE(s2 <= s1);
- EXPECT_TRUE(s2 > s1);
- EXPECT_FALSE(s1 > s2);
- EXPECT_TRUE(s2 >= s1);
- EXPECT_FALSE(s1 >= s2);
- }
- }
+{
+ int arr[5] = {1, 2, 3, 4, 5};
+ int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
+ int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+
+ {
+ const auto s = make_span(arr);
+ EXPECT_TRUE(s.size() == 5);
+ EXPECT_TRUE(s.data() == std::addressof(arr[0]));
+ }
+
+ {
+ const auto s = make_span(std::addressof(arr2d[0]), 1);
+ EXPECT_TRUE(s.size() == 1);
+ EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
+ }
+
+ {
+ const auto s = make_span(std::addressof(arr3d[0]), 1);
+ EXPECT_TRUE(s.size() == 1);
+ EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
+ }
+}
+
+TEST(span_ext_test, make_span_from_dynamic_array_constructor)
+{
+ double(*arr)[3][4] = new double[100][3][4];
+
+ {
+ auto s = make_span(&arr[0][0][0], 10);
+ EXPECT_TRUE(s.size() == 10);
+ EXPECT_TRUE(s.data() == &arr[0][0][0]);
+ }
+
+ delete[] arr;
+}
+
+TEST(span_ext_test, make_span_from_std_array_constructor)
+{
+ std::array<int, 4> arr = {1, 2, 3, 4};
+
+ {
+ auto s = make_span(arr);
+ EXPECT_TRUE(s.size() == arr.size());
+ EXPECT_TRUE(s.data() == arr.data());
+ }
+
+ // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
+ {
+ gsl::span<int> s1 = make_span(arr);
+
+ static gsl::span<int> s2;
+ s2 = s1;
+
+#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
+ __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
+ // Known to be broken in gcc 6.4 and 6.5 with optimizations
+ // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
+ EXPECT_TRUE(s1.size() == 4);
+ EXPECT_TRUE(s2.size() == 0);
+#else
+ EXPECT_TRUE(s1.size() == s2.size());
+#endif
+ }
+}
+
+TEST(span_ext_test, make_span_from_const_std_array_constructor)
+{
+ const std::array<int, 4> arr = {1, 2, 3, 4};
+
+ {
+ auto s = make_span(arr);
+ EXPECT_TRUE(s.size() == arr.size());
+ EXPECT_TRUE(s.data() == arr.data());
+ }
+}
+
+TEST(span_ext_test, make_span_from_std_array_const_constructor)
+{
+ std::array<const int, 4> arr = {1, 2, 3, 4};
+
+ {
+ auto s = make_span(arr);
+ EXPECT_TRUE(s.size() == arr.size());
+ EXPECT_TRUE(s.data() == arr.data());
+ }
+}
+
+TEST(span_ext_test, make_span_from_container_constructor)
+{
+ std::vector<int> v = {1, 2, 3};
+ const std::vector<int> cv = v;
+
+ {
+ auto s = make_span(v);
+ EXPECT_TRUE(s.size() == v.size());
+ EXPECT_TRUE(s.data() == v.data());
+
+ auto cs = make_span(cv);
+ EXPECT_TRUE(cs.size() == cv.size());
+ EXPECT_TRUE(cs.data() == cv.data());
+ }
+}
+
+TEST(span_test, interop_with_gsl_at)
+{
+ int arr[5] = {1, 2, 3, 4, 5};
+ gsl::span<int> s{arr};
+ EXPECT_TRUE(at(s, 0) == 1);
+ EXPECT_TRUE(at(s, 1) == 2);
+}
+
+TEST(span_ext_test, iterator_free_functions)
+{
+ int a[] = {1, 2, 3, 4};
+ gsl::span<int> s{a};
+
+ EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
+ EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
+
+ EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
+ EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
+
+ EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
+ EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
+
+ EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
+ EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
+
+ EXPECT_TRUE(s.begin() == begin(s));
+ EXPECT_TRUE(s.end() == end(s));
+
+ EXPECT_TRUE(s.rbegin() == rbegin(s));
+ EXPECT_TRUE(s.rend() == rend(s));
+
+ EXPECT_TRUE(s.begin() == cbegin(s));
+ EXPECT_TRUE(s.end() == cend(s));
+
+ EXPECT_TRUE(s.rbegin() == crbegin(s));
+ EXPECT_TRUE(s.rend() == crend(s));
+}
+
+TEST(span_ext_test, ssize_free_function)
+{
+ int a[] = {1, 2, 3, 4};
+ gsl::span<int> s{a};
+
+ EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
+ EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
+}
+
+#ifndef GSL_KERNEL_MODE
+TEST(span_ext_test, comparison_operators)
+{
+ {
+ gsl::span<int> s1;
+ gsl::span<int> s2;
+ EXPECT_TRUE(s1 == s2);
+ EXPECT_FALSE(s1 != s2);
+ EXPECT_FALSE(s1 < s2);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s1 >= s2);
+ EXPECT_TRUE(s2 == s1);
+ EXPECT_FALSE(s2 != s1);
+ EXPECT_FALSE(s2 != s1);
+ EXPECT_TRUE(s2 <= s1);
+ EXPECT_FALSE(s2 > s1);
+ EXPECT_TRUE(s2 >= s1);
+ }
+
+ {
+ int arr[] = {2, 1};
+ gsl::span<int> s1 = arr;
+ gsl::span<int> s2 = arr;
+
+ EXPECT_TRUE(s1 == s2);
+ EXPECT_FALSE(s1 != s2);
+ EXPECT_FALSE(s1 < s2);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s1 >= s2);
+ EXPECT_TRUE(s2 == s1);
+ EXPECT_FALSE(s2 != s1);
+ EXPECT_FALSE(s2 < s1);
+ EXPECT_TRUE(s2 <= s1);
+ EXPECT_FALSE(s2 > s1);
+ EXPECT_TRUE(s2 >= s1);
+ }
+
+ {
+ int arr[] = {2, 1}; // bigger
+
+ gsl::span<int> s1;
+ gsl::span<int> s2 = arr;
+
+ EXPECT_TRUE(s1 != s2);
+ EXPECT_TRUE(s2 != s1);
+ EXPECT_FALSE(s1 == s2);
+ EXPECT_FALSE(s2 == s1);
+ EXPECT_TRUE(s1 < s2);
+ EXPECT_FALSE(s2 < s1);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s2 <= s1);
+ EXPECT_TRUE(s2 > s1);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s2 >= s1);
+ EXPECT_FALSE(s1 >= s2);
+ }
+
+ {
+ int arr1[] = {1, 2};
+ int arr2[] = {1, 2};
+ gsl::span<int> s1 = arr1;
+ gsl::span<int> s2 = arr2;
+
+ EXPECT_TRUE(s1 == s2);
+ EXPECT_FALSE(s1 != s2);
+ EXPECT_FALSE(s1 < s2);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s1 >= s2);
+ EXPECT_TRUE(s2 == s1);
+ EXPECT_FALSE(s2 != s1);
+ EXPECT_FALSE(s2 < s1);
+ EXPECT_TRUE(s2 <= s1);
+ EXPECT_FALSE(s2 > s1);
+ EXPECT_TRUE(s2 >= s1);
+ }
+
+ {
+ int arr[] = {1, 2, 3};
+
+ gsl::span<int> s1 = {&arr[0], 2}; // shorter
+ gsl::span<int> s2 = arr; // longer
+
+ EXPECT_TRUE(s1 != s2);
+ EXPECT_TRUE(s2 != s1);
+ EXPECT_FALSE(s1 == s2);
+ EXPECT_FALSE(s2 == s1);
+ EXPECT_TRUE(s1 < s2);
+ EXPECT_FALSE(s2 < s1);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s2 <= s1);
+ EXPECT_TRUE(s2 > s1);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s2 >= s1);
+ EXPECT_FALSE(s1 >= s2);
+ }
+
+ {
+ int arr1[] = {1, 2}; // smaller
+ int arr2[] = {2, 1}; // bigger
+
+ gsl::span<int> s1 = arr1;
+ gsl::span<int> s2 = arr2;
+
+ EXPECT_TRUE(s1 != s2);
+ EXPECT_TRUE(s2 != s1);
+ EXPECT_FALSE(s1 == s2);
+ EXPECT_FALSE(s2 == s1);
+ EXPECT_TRUE(s1 < s2);
+ EXPECT_FALSE(s2 < s1);
+ EXPECT_TRUE(s1 <= s2);
+ EXPECT_FALSE(s2 <= s1);
+ EXPECT_TRUE(s2 > s1);
+ EXPECT_FALSE(s1 > s2);
+ EXPECT_TRUE(s2 >= s1);
+ EXPECT_FALSE(s1 >= s2);
+ }
+}
+#endif // GSL_KERNEL_MODE
diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index b845d07..41ac3ae 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -17,19 +17,19 @@ #include <gtest/gtest.h> #include <gsl/byte> // for byte +#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <gsl/util> // for narrow_cast, at -#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <array> // for array +#include <cstddef> // for ptrdiff_t #include <iostream> // for ptrdiff_t #include <iterator> // for reverse_iterator, operator-, operator== #include <memory> // for unique_ptr, shared_ptr, make_unique, allo... #include <regex> // for match_results, sub_match, match_results<>... -#include <cstddef> // for ptrdiff_t #include <string> // for string #include <type_traits> // for integral_constant<>::value, is_default_co... -#include <vector> // for vector #include <utility> +#include <vector> // for vector // the string_view include and macro are used in the deduction guide verification #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) @@ -40,13 +40,16 @@ #endif // __has_include(<string_view>) #endif // __has_include #endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) +#if defined(__cplusplus) && __cplusplus >= 202002L +#include <span> +#endif // __cplusplus >= 202002L + +#include "deathTestCommon.h" -using namespace std; using namespace gsl; namespace { -static constexpr char deathstring[] = "Expected Death"; struct BaseClass { @@ -111,10 +114,12 @@ TEST(span_test, size_optimization) TEST(span_test, from_nullptr_size_constructor) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. from_nullptr_size_constructor"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + { span<int> s{nullptr, narrow_cast<span<int>::size_type>(0)}; EXPECT_TRUE(s.size() == 0); @@ -128,21 +133,21 @@ TEST(span_test, from_nullptr_size_constructor) auto workaround_macro = []() { const span<int, 1> s{nullptr, narrow_cast<span<int>::size_type>(0)}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { auto workaround_macro = []() { const span<int> s{nullptr, 1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); auto const_workaround_macro = []() { const span<const int> s{nullptr, 1}; }; - EXPECT_DEATH(const_workaround_macro(), deathstring); + EXPECT_DEATH(const_workaround_macro(), expected); } { auto workaround_macro = []() { const span<int, 0> s{nullptr, 1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); auto const_workaround_macro = []() { const span<const int, 0> s{nullptr, 1}; }; - EXPECT_DEATH(const_workaround_macro(), deathstring); + EXPECT_DEATH(const_workaround_macro(), expected); } { span<int*> s{nullptr, narrow_cast<span<int>::size_type>(0)}; @@ -157,10 +162,12 @@ TEST(span_test, from_nullptr_size_constructor) TEST(span_test, from_pointer_length_constructor) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. from_pointer_length_constructor"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + int arr[4] = {1, 2, 3, 4}; { @@ -171,8 +178,7 @@ TEST(span_test, from_pointer_length_constructor) EXPECT_TRUE(s.size() == narrow_cast<std::size_t>(i)); EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); - for (int j = 0; j < i; ++j) - EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]); + for (int j = 0; j < i; ++j) EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]); } { span<int> s = {&arr[i], 4 - narrow_cast<std::size_t>(i)}; @@ -204,7 +210,7 @@ TEST(span_test, from_pointer_length_constructor) { int* p = nullptr; auto workaround_macro = [=]() { const span<int> s{p, 2}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } } @@ -242,14 +248,14 @@ TEST(span_test, from_pointer_pointer_construction) // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // int* p = nullptr; // auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} { @@ -270,897 +276,912 @@ TEST(span_test, from_pointer_pointer_construction) //{ // int* p = nullptr; // auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} } TEST(span_test, from_array_constructor) - { - int arr[5] = {1, 2, 3, 4, 5}; +{ + int arr[5] = {1, 2, 3, 4, 5}; - { - const span<int> s{arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + const span<int> s{arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == &arr[0]); + } - { - const span<int, 5> s{arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + const span<int, 5> s{arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == &arr[0]); + } - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int, 6> s{arr}; - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<int, 6> s{arr}; + } - { - span<int, 0> s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + span<int, 0> s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr[0]); + } - { - span<int> s{arr2d}; - EXPECT_TRUE(s.size() == 6); - EXPECT_TRUE(s.data() == &arr2d[0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[5] == 6); - } + { + span<int> s{arr2d}; + EXPECT_TRUE(s.size() == 6); + EXPECT_TRUE(s.data() == &arr2d[0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[5] == 6); + } - { - span<int, 0> s{arr2d}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr2d[0][0]); - } + { + span<int, 0> s{arr2d}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr2d[0][0]); + } - { - span<int, 6> s{arr2d}; - } - #endif - { - const span<int[3]> s{std::addressof(arr2d[0]), 1}; - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); - } + { + span<int, 6> s{arr2d}; + } +#endif + { + const span<int[3]> s{std::addressof(arr2d[0]), 1}; + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); + } - int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int> s{arr3d}; - EXPECT_TRUE(s.size() == 12); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[11] == 12); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<int> s{arr3d}; + EXPECT_TRUE(s.size() == 12); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[11] == 12); + } - { - span<int, 0> s{arr3d}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - } + { + span<int, 0> s{arr3d}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + } - { - span<int, 11> s{arr3d}; - } + { + span<int, 11> s{arr3d}; + } - { - span<int, 12> s{arr3d}; - EXPECT_TRUE(s.size() == 12); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[5] == 6); - } - #endif - { - const span<int[3][2]> s{std::addressof(arr3d[0]), 1}; - EXPECT_TRUE(s.size() == 1); - } + { + span<int, 12> s{arr3d}; + EXPECT_TRUE(s.size() == 12); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[5] == 6); + } +#endif + { + const span<int[3][2]> s{std::addressof(arr3d[0]), 1}; + EXPECT_TRUE(s.size() == 1); + } - AddressOverloaded ao_arr[5] = {}; + AddressOverloaded ao_arr[5] = {}; - { - const span<AddressOverloaded, 5> s{ao_arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == std::addressof(ao_arr[0])); - } - } + { + const span<AddressOverloaded, 5> s{ao_arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == std::addressof(ao_arr[0])); + } +} - TEST(span_test, from_dynamic_array_constructor) - { - double(*arr)[3][4] = new double[100][3][4]; +TEST(span_test, from_dynamic_array_constructor) +{ + double(*arr)[3][4] = new double[100][3][4]; - { - span<double> s(&arr[0][0][0], 10); - EXPECT_TRUE(s.size() == 10); - EXPECT_TRUE(s.data() == &arr[0][0][0]); - } + { + span<double> s(&arr[0][0][0], 10); + EXPECT_TRUE(s.size() == 10); + EXPECT_TRUE(s.data() == &arr[0][0][0]); + } - delete[] arr; - } + delete[] arr; +} - TEST(span_test, from_std_array_constructor) - { - std::array<int, 4> arr = {1, 2, 3, 4}; +TEST(span_test, from_std_array_constructor) +{ + std::array<int, 4> arr = {1, 2, 3, 4}; - { - span<int> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); + { + span<int> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); - span<const int> cs{arr}; - EXPECT_TRUE(cs.size() == arr.size()); - EXPECT_TRUE(cs.data() == arr.data()); - } + span<const int> cs{arr}; + EXPECT_TRUE(cs.size() == arr.size()); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span<int, 4> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); + { + span<int, 4> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); - span<const int, 4> cs{arr}; - EXPECT_TRUE(cs.size() == arr.size()); - EXPECT_TRUE(cs.data() == arr.data()); - } + span<const int, 4> cs{arr}; + EXPECT_TRUE(cs.size() == arr.size()); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - std::array<int, 0> empty_arr{}; - span<int> s{empty_arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.empty()); - } + { + std::array<int, 0> empty_arr{}; + span<int> s{empty_arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.empty()); + } - std::array<AddressOverloaded, 4> ao_arr{}; + std::array<AddressOverloaded, 4> ao_arr{}; - { - span<AddressOverloaded, 4> fs{ao_arr}; - EXPECT_TRUE(fs.size() == ao_arr.size()); - EXPECT_TRUE(ao_arr.data() == fs.data()); - } + { + span<AddressOverloaded, 4> fs{ao_arr}; + EXPECT_TRUE(fs.size() == ao_arr.size()); + EXPECT_TRUE(ao_arr.data() == fs.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int, 2> s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<int, 2> s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); - span<const int, 2> cs{arr}; - EXPECT_TRUE(cs.size() == 2); - EXPECT_TRUE(cs.data() == arr.data()); - } + span<const int, 2> cs{arr}; + EXPECT_TRUE(cs.size() == 2); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span<int, 0> s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); + { + span<int, 0> s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); - span<const int, 0> cs{arr}; - EXPECT_TRUE(cs.size() == 0); - EXPECT_TRUE(cs.data() == arr.data()); - } + span<const int, 0> cs{arr}; + EXPECT_TRUE(cs.size() == 0); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span<int, 5> s{arr}; - } + { + span<int, 5> s{arr}; + } - { - auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; - auto take_a_span = [](span<int> s) { static_cast<void>(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - #endif + { + auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; + auto take_a_span = [](span<int> s) { static_cast<void>(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +#endif - { - auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; - auto take_a_span = [](span<const int> s) { static_cast<void>(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - } + { + auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; + auto take_a_span = [](span<const int> s) { static_cast<void>(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +} - TEST(span_test, from_const_std_array_constructor) - { - const std::array<int, 4> arr = {1, 2, 3, 4}; +TEST(span_test, from_const_std_array_constructor) +{ + const std::array<int, 4> arr = {1, 2, 3, 4}; - { - span<const int> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 4> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int, 4> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - const std::array<AddressOverloaded, 4> ao_arr{}; + const std::array<AddressOverloaded, 4> ao_arr{}; - { - span<const AddressOverloaded, 4> s{ao_arr}; - EXPECT_TRUE(s.size() == ao_arr.size()); - EXPECT_TRUE(s.data() == ao_arr.data()); - } + { + span<const AddressOverloaded, 4> s{ao_arr}; + EXPECT_TRUE(s.size() == ao_arr.size()); + EXPECT_TRUE(s.data() == ao_arr.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<const int, 2> s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<const int, 2> s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 0> s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int, 0> s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 5> s{arr}; - } - #endif + { + span<const int, 5> s{arr}; + } +#endif - { - auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; }; - auto take_a_span = [](span<const int> s) { static_cast<void>(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - } + { + auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; }; + auto take_a_span = [](span<const int> s) { static_cast<void>(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +} - TEST(span_test, from_std_array_const_constructor) - { - std::array<const int, 4> arr = {1, 2, 3, 4}; +TEST(span_test, from_std_array_const_constructor) +{ + std::array<const int, 4> arr = {1, 2, 3, 4}; - { - span<const int> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 4> s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int, 4> s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<const int, 2> s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<const int, 2> s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 0> s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span<const int, 0> s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span<const int, 5> s{arr}; - } + { + span<const int, 5> s{arr}; + } - { - span<int, 4> s{arr}; - } - #endif - } + { + span<int, 4> s{arr}; + } +#endif +} - TEST(span_test, from_container_constructor) - { - std::vector<int> v = {1, 2, 3}; - const std::vector<int> cv = v; +TEST(span_test, from_container_constructor) +{ + std::vector<int> v = {1, 2, 3}; + const std::vector<int> cv = v; - { - span<int> s{v}; - EXPECT_TRUE(s.size() == v.size()); - EXPECT_TRUE(s.data() == v.data()); + { + span<int> s{v}; + EXPECT_TRUE(s.size() == v.size()); + EXPECT_TRUE(s.data() == v.data()); - span<const int> cs{v}; - EXPECT_TRUE(cs.size() == v.size()); - EXPECT_TRUE(cs.data() == v.data()); - } + span<const int> cs{v}; + EXPECT_TRUE(cs.size() == v.size()); + EXPECT_TRUE(cs.data() == v.data()); + } - std::string str = "hello"; - const std::string cstr = "hello"; + std::string str = "hello"; + const std::string cstr = "hello"; - { - #ifdef CONFIRM_COMPILATION_ERRORS - span<char> s{str}; - EXPECT_TRUE(s.size() == str.size()); + { +#ifdef CONFIRM_COMPILATION_ERRORS + span<char> s{str}; + EXPECT_TRUE(s.size() == str.size()); EXPECT_TRUE(s.data() == str.data())); - #endif +#endif span<const char> cs{str}; EXPECT_TRUE(cs.size() == str.size()); EXPECT_TRUE(cs.data() == str.data()); - } + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - span<char> s{cstr}; - #endif - span<const char> cs{cstr}; - EXPECT_TRUE(cs.size() == cstr.size()); - EXPECT_TRUE(cs.data() == cstr.data()); - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + span<char> s{cstr}; +#endif + span<const char> cs{cstr}; + EXPECT_TRUE(cs.size() == cstr.size()); + EXPECT_TRUE(cs.data() == cstr.data()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> std::vector<int> { return {}; }; - auto use_span = [](span<int> s) { static_cast<void>(s); }; - use_span(get_temp_vector()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> std::vector<int> { return {}; }; + auto use_span = [](span<int> s) { static_cast<void>(s); }; + use_span(get_temp_vector()); +#endif + } - { - auto get_temp_vector = []() -> std::vector<int> { return {}; }; - auto use_span = [](span<const int> s) { static_cast<void>(s); }; - use_span(get_temp_vector()); - } + { + auto get_temp_vector = []() -> std::vector<int> { return {}; }; + auto use_span = [](span<const int> s) { static_cast<void>(s); }; + use_span(get_temp_vector()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span<char> s) { static_cast<void>(s); }; - use_span(get_temp_string()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span<char> s) { static_cast<void>(s); }; + use_span(get_temp_string()); +#endif + } - { - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span<const char> s) { static_cast<void>(s); }; - use_span(get_temp_string()); - } + { + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span<const char> s) { static_cast<void>(s); }; + use_span(get_temp_string()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> const std::vector<int> { return {}; }; - auto use_span = [](span<const char> s) { static_cast<void>(s); }; - use_span(get_temp_vector()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> const std::vector<int> { return {}; }; + auto use_span = [](span<const char> s) { static_cast<void>(s); }; + use_span(get_temp_vector()); +#endif + } - { - auto get_temp_string = []() -> const std::string { return {}; }; - auto use_span = [](span<const char> s) { static_cast<void>(s); }; - use_span(get_temp_string()); - } + { + auto get_temp_string = []() -> const std::string { return {}; }; + auto use_span = [](span<const char> s) { static_cast<void>(s); }; + use_span(get_temp_string()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - std::map<int, int> m; - span<int> s{m}; - #endif - } - } - - TEST(span_test, from_convertible_span_constructor){{span<DerivedClass> avd; - span<const DerivedClass> avcd = avd; - static_cast<void>(avcd); - } - - { - #ifdef CONFIRM_COMPILATION_ERRORS - span<DerivedClass> avd; - span<BaseClass> avb = avd; - static_cast<void>(avb); - #endif - } - - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int> s; - span<unsigned int> s2 = s; - static_cast<void>(s2); - } - - { - span<int> s; - span<const unsigned int> s2 = s; - static_cast<void>(s2); - } - - { - span<int> s; - span<short> s2 = s; - static_cast<void>(s2); - } - #endif - } - - TEST(span_test, copy_move_and_assignment) - { - span<int> s1; - EXPECT_TRUE(s1.empty()); - - int arr[] = {3, 4, 5}; - - span<const int> s2 = arr; - EXPECT_TRUE(s2.size() == 3); - EXPECT_TRUE(s2.data() == &arr[0]); - - s2 = s1; - EXPECT_TRUE(s2.empty()); - - auto get_temp_span = [&]() -> span<int> { return {&arr[1], 2}; }; - auto use_span = [&](span<const int> s) { - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == &arr[1]); - }; use_span(get_temp_span()); - - s1 = get_temp_span(); - EXPECT_TRUE(s1.size() == 2); - EXPECT_TRUE(s1.data() == &arr[1]); - } - - TEST(span_test, first) - { - std::set_terminate([] { + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::map<int, int> m; + span<int> s{m}; +#endif + } +} + +TEST(span_test, from_convertible_span_constructor){{span<DerivedClass> avd; +span<const DerivedClass> avcd = avd; +static_cast<void>(avcd); +} + +{ +#ifdef CONFIRM_COMPILATION_ERRORS + span<DerivedClass> avd; + span<BaseClass> avb = avd; + static_cast<void>(avb); +#endif +} + +#ifdef CONFIRM_COMPILATION_ERRORS +{ + span<int> s; + span<unsigned int> s2 = s; + static_cast<void>(s2); +} + +{ + span<int> s; + span<const unsigned int> s2 = s; + static_cast<void>(s2); +} + +{ + span<int> s; + span<short> s2 = s; + static_cast<void>(s2); +} +#endif +} + +TEST(span_test, copy_move_and_assignment) +{ + span<int> s1; + EXPECT_TRUE(s1.empty()); + + int arr[] = {3, 4, 5}; + + span<const int> s2 = arr; + EXPECT_TRUE(s2.size() == 3); + EXPECT_TRUE(s2.data() == &arr[0]); + + s2 = s1; + EXPECT_TRUE(s2.empty()); + + auto get_temp_span = [&]() -> span<int> { return {&arr[1], 2}; }; + auto use_span = [&](span<const int> s) { + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == &arr[1]); + }; + use_span(get_temp_span()); + + s1 = get_temp_span(); + EXPECT_TRUE(s1.size() == 2); + EXPECT_TRUE(s1.data() == &arr[1]); +} + +TEST(span_test, first) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. first"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span<int, 5> av = arr; - EXPECT_TRUE(av.first<2>().size() == 2); - EXPECT_TRUE(av.first(2).size() == 2); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span<int, 5> av = arr; - EXPECT_TRUE(av.first<0>().size() == 0); - EXPECT_TRUE(av.first(0).size() == 0); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.first<2>().size() == 2); + EXPECT_TRUE(av.first(2).size() == 2); + } - { - span<int, 5> av = arr; - EXPECT_TRUE(av.first<5>().size() == 5); - EXPECT_TRUE(av.first(5).size() == 5); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.first<0>().size() == 0); + EXPECT_TRUE(av.first(0).size() == 0); + } - { - span<int, 5> av = arr; - #ifdef CONFIRM_COMPILATION_ERRORS - EXPECT_TRUE(av.first<6>().size() == 6); - EXPECT_TRUE(av.first<-1>().size() == -1); - #endif - EXPECT_DEATH(av.first(6).size(), deathstring); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.first<5>().size() == 5); + EXPECT_TRUE(av.first(5).size() == 5); + } - { - span<int> av; - EXPECT_TRUE(av.first<0>().size() == 0); - EXPECT_TRUE(av.first(0).size() == 0); - } - } + { + span<int, 5> av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + EXPECT_TRUE(av.first<6>().size() == 6); + EXPECT_TRUE(av.first<-1>().size() == -1); +#endif + EXPECT_DEATH(av.first(6).size(), expected); + } + + { + span<int> av; + EXPECT_TRUE(av.first<0>().size() == 0); + EXPECT_TRUE(av.first(0).size() == 0); + } +} - TEST(span_test, last) - { - std::set_terminate([] { +TEST(span_test, last) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. last"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span<int, 5> av = arr; - EXPECT_TRUE(av.last<2>().size() == 2); - EXPECT_TRUE(av.last(2).size() == 2); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span<int, 5> av = arr; - EXPECT_TRUE(av.last<0>().size() == 0); - EXPECT_TRUE(av.last(0).size() == 0); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.last<2>().size() == 2); + EXPECT_TRUE(av.last(2).size() == 2); + } - { - span<int, 5> av = arr; - EXPECT_TRUE(av.last<5>().size() == 5); - EXPECT_TRUE(av.last(5).size() == 5); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.last<0>().size() == 0); + EXPECT_TRUE(av.last(0).size() == 0); + } - { - span<int, 5> av = arr; - #ifdef CONFIRM_COMPILATION_ERRORS - EXPECT_TRUE(av.last<6>().size() == 6); - #endif - EXPECT_DEATH(av.last(6).size(), deathstring); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.last<5>().size() == 5); + EXPECT_TRUE(av.last(5).size() == 5); + } - { - span<int> av; - EXPECT_TRUE(av.last<0>().size() == 0); - EXPECT_TRUE(av.last(0).size() == 0); - } - } + { + span<int, 5> av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + EXPECT_TRUE(av.last<6>().size() == 6); +#endif + EXPECT_DEATH(av.last(6).size(), expected); + } - TEST(span_test, subspan) - { - std::set_terminate([] { + { + span<int> av; + EXPECT_TRUE(av.last<0>().size() == 0); + EXPECT_TRUE(av.last(0).size() == 0); + } +} + +TEST(span_test, subspan) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. subspan"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span<int, 5> av = arr; - EXPECT_TRUE((av.subspan<2, 2>().size()) == 2); - EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2); - EXPECT_TRUE(av.subspan(2, 2).size() == 2); - EXPECT_TRUE(av.subspan(2, 3).size() == 3); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span<int, 5> av = arr; - EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(0, 0).size() == 0); - } + { + span<int, 5> av = arr; + EXPECT_TRUE((av.subspan<2, 2>().size()) == 2); + EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2); + EXPECT_TRUE(av.subspan(2, 2).size() == 2); + EXPECT_TRUE(av.subspan(2, 3).size() == 3); + } - { - span<int, 5> av = arr; - EXPECT_TRUE((av.subspan<0, 5>().size()) == 5); - EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); - EXPECT_TRUE(av.subspan(0, 5).size() == 5); + { + span<int, 5> av = arr; + EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(0, 0).size() == 0); + } - EXPECT_DEATH(av.subspan(0, 6).size(), deathstring); - EXPECT_DEATH(av.subspan(1, 5).size(), deathstring); - } + { + span<int, 5> av = arr; + EXPECT_TRUE((av.subspan<0, 5>().size()) == 5); + EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); + EXPECT_TRUE(av.subspan(0, 5).size() == 5); - { - span<int, 5> av = arr; - EXPECT_TRUE((av.subspan<4, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(4, 0).size() == 0); - EXPECT_TRUE(av.subspan(5, 0).size() == 0); - EXPECT_DEATH(av.subspan(6, 0).size(), deathstring); - } + EXPECT_DEATH(av.subspan(0, 6).size(), expected); + EXPECT_DEATH(av.subspan(1, 5).size(), expected); + } - { - span<int, 5> av = arr; - EXPECT_TRUE(av.subspan<1>().size() == 4); - EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4); - } + { + span<int, 5> av = arr; + EXPECT_TRUE((av.subspan<4, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(4, 0).size() == 0); + EXPECT_TRUE(av.subspan(5, 0).size() == 0); + EXPECT_DEATH(av.subspan(6, 0).size(), expected); + } - { - span<int> av; - EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(0, 0).size() == 0); - EXPECT_DEATH((av.subspan<1, 0>().size()), deathstring); - } + { + span<int, 5> av = arr; + EXPECT_TRUE(av.subspan<1>().size() == 4); + EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4); + } - { - span<int> av; - EXPECT_TRUE(av.subspan(0).size() == 0); - EXPECT_DEATH(av.subspan(1).size(), deathstring); - } + { + span<int> av; + EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(0, 0).size() == 0); + EXPECT_DEATH((av.subspan<1, 0>().size()), expected); + } - { - span<int> av = arr; - EXPECT_TRUE(av.subspan(0).size() == 5); - EXPECT_TRUE(av.subspan(1).size() == 4); - EXPECT_TRUE(av.subspan(4).size() == 1); - EXPECT_TRUE(av.subspan(5).size() == 0); - EXPECT_DEATH(av.subspan(6).size(), deathstring); - const auto av2 = av.subspan(1); - for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); - } + { + span<int> av; + EXPECT_TRUE(av.subspan(0).size() == 0); + EXPECT_DEATH(av.subspan(1).size(), expected); + } - { - span<int, 5> av = arr; - EXPECT_TRUE(av.subspan(0).size() == 5); - EXPECT_TRUE(av.subspan(1).size() == 4); - EXPECT_TRUE(av.subspan(4).size() == 1); - EXPECT_TRUE(av.subspan(5).size() == 0); - EXPECT_DEATH(av.subspan(6).size(), deathstring); - const auto av2 = av.subspan(1); - for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); - } - } - - TEST(span_test, iterator_default_init) - { - span<int>::iterator it1; - span<int>::iterator it2; - EXPECT_TRUE(it1 == it2); - } - - TEST(span_test, iterator_comparisons) - { - int a[] = {1, 2, 3, 4}; - { - span<int> s = a; - span<int>::iterator it = s.begin(); - auto it2 = it + 1; - - EXPECT_TRUE(it == it); - EXPECT_TRUE(it == s.begin()); - EXPECT_TRUE(s.begin() == it); - - EXPECT_TRUE(it != it2); - EXPECT_TRUE(it2 != it); - EXPECT_TRUE(it != s.end()); - EXPECT_TRUE(it2 != s.end()); - EXPECT_TRUE(s.end() != it); - - EXPECT_TRUE(it < it2); - EXPECT_TRUE(it <= it2); - EXPECT_TRUE(it2 <= s.end()); - EXPECT_TRUE(it < s.end()); - - EXPECT_TRUE(it2 > it); - EXPECT_TRUE(it2 >= it); - EXPECT_TRUE(s.end() > it2); - EXPECT_TRUE(s.end() >= it2); - } - } + { + span<int> av = arr; + EXPECT_TRUE(av.subspan(0).size() == 5); + EXPECT_TRUE(av.subspan(1).size() == 4); + EXPECT_TRUE(av.subspan(4).size() == 1); + EXPECT_TRUE(av.subspan(5).size() == 0); + EXPECT_DEATH(av.subspan(6).size(), expected); + const auto av2 = av.subspan(1); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); + } - TEST(span_test, incomparable_iterators) - { - std::set_terminate([] { - std::cerr << "Expected Death. incomparable_iterators"; - std::abort(); - }); + { + span<int, 5> av = arr; + EXPECT_TRUE(av.subspan(0).size() == 5); + EXPECT_TRUE(av.subspan(1).size() == 4); + EXPECT_TRUE(av.subspan(4).size() == 1); + EXPECT_TRUE(av.subspan(5).size() == 0); + EXPECT_DEATH(av.subspan(6).size(), expected); + const auto av2 = av.subspan(1); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); + } +} - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 3, 4}; - { - span<int> s = a; - span<int> s2 = b; +TEST(span_test, iterator_default_init) +{ + span<int>::iterator it1; + span<int>::iterator it2; + EXPECT_TRUE(it1 == it2); +} + +TEST(span_test, iterator_comparisons) +{ + int a[] = {1, 2, 3, 4}; + { + span<int> s = a; + span<int>::iterator it = s.begin(); + auto it2 = it + 1; + + EXPECT_TRUE(it == it); + EXPECT_TRUE(it == s.begin()); + EXPECT_TRUE(s.begin() == it); + + EXPECT_TRUE(it != it2); + EXPECT_TRUE(it2 != it); + EXPECT_TRUE(it != s.end()); + EXPECT_TRUE(it2 != s.end()); + EXPECT_TRUE(s.end() != it); + + EXPECT_TRUE(it < it2); + EXPECT_TRUE(it <= it2); + EXPECT_TRUE(it2 <= s.end()); + EXPECT_TRUE(it < s.end()); + + EXPECT_TRUE(it2 > it); + EXPECT_TRUE(it2 >= it); + EXPECT_TRUE(s.end() > it2); + EXPECT_TRUE(s.end() >= it2); + } +} + +TEST(span_test, incomparable_iterators) +{ + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. incomparable_iterators"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); + + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + { + span<int> s = a; + span<int> s2 = b; #if (__cplusplus > 201402L) - EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), deathstring); - EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), expected); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), expected); #else - EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); - EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), expected); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), expected); #endif - } - } + } +} - TEST(span_test, begin_end) - { - std::set_terminate([] { +TEST(span_test, begin_end) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. begin_end"; std::abort(); }); - { - int a[] = {1, 2, 3, 4}; - span<int> s = a; + const auto expected = GetExpectedDeathString(terminateHandler); - span<int>::iterator it = s.begin(); - span<int>::iterator it2 = std::begin(s); - EXPECT_TRUE(it == it2); + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; - it = s.end(); - it2 = std::end(s); - EXPECT_TRUE(it == it2); - } + span<int>::iterator it = s.begin(); + span<int>::iterator it2 = std::begin(s); + EXPECT_TRUE(it == it2); - { - int a[] = {1, 2, 3, 4}; - span<int> s = a; - - auto it = s.begin(); - auto first = it; - EXPECT_TRUE(it == first); - EXPECT_TRUE(*it == 1); - - auto beyond = s.end(); - EXPECT_TRUE(it != beyond); - EXPECT_DEATH(*beyond, deathstring); - - EXPECT_TRUE(beyond - first == 4); - EXPECT_TRUE(first - first == 0); - EXPECT_TRUE(beyond - beyond == 0); - - ++it; - EXPECT_TRUE(it - first == 1); - EXPECT_TRUE(*it == 2); - *it = 22; - EXPECT_TRUE(*it == 22); - EXPECT_TRUE(beyond - it == 3); - - it = first; - EXPECT_TRUE(it == first); - while (it != s.end()) - { - *it = 5; - ++it; - } - - EXPECT_TRUE(it == beyond); - EXPECT_TRUE(it - beyond == 0); - - for (const auto& n : s) { EXPECT_TRUE(n == 5); } - } - } + it = s.end(); + it2 = std::end(s); + EXPECT_TRUE(it == it2); + } + + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + auto it = s.begin(); + auto first = it; + EXPECT_TRUE(it == first); + EXPECT_TRUE(*it == 1); + + auto beyond = s.end(); + EXPECT_TRUE(it != beyond); + EXPECT_DEATH(*beyond, expected); + + EXPECT_TRUE(beyond - first == 4); + EXPECT_TRUE(first - first == 0); + EXPECT_TRUE(beyond - beyond == 0); + + ++it; + EXPECT_TRUE(it - first == 1); + EXPECT_TRUE(*it == 2); + *it = 22; + EXPECT_TRUE(*it == 22); + EXPECT_TRUE(beyond - it == 3); + + it = first; + EXPECT_TRUE(it == first); + while (it != s.end()) + { + *it = 5; + ++it; + } + + EXPECT_TRUE(it == beyond); + EXPECT_TRUE(it - beyond == 0); - TEST(span_test, rbegin_rend) - { - std::set_terminate([] { + for (const auto& n : s) { EXPECT_TRUE(n == 5); } + } +} + +TEST(span_test, rbegin_rend) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. rbegin_rend"; std::abort(); }); - { - int a[] = {1, 2, 3, 4}; - span<int> s = a; + const auto expected = GetExpectedDeathString(terminateHandler); + + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; - auto it = s.rbegin(); - auto first = it; - EXPECT_TRUE(it == first); - EXPECT_TRUE(*it == 4); + auto it = s.rbegin(); + auto first = it; + EXPECT_TRUE(it == first); + EXPECT_TRUE(*it == 4); - auto beyond = s.rend(); - EXPECT_TRUE(it != beyond); + auto beyond = s.rend(); + EXPECT_TRUE(it != beyond); #if (__cplusplus > 201402L) - EXPECT_DEATH([[maybe_unused]] auto _ = *beyond , deathstring); + EXPECT_DEATH([[maybe_unused]] auto _ = *beyond, expected); #else - EXPECT_DEATH(auto _ = *beyond , deathstring); + EXPECT_DEATH(auto _ = *beyond, expected); #endif - EXPECT_TRUE(beyond - first == 4); - EXPECT_TRUE(first - first == 0); - EXPECT_TRUE(beyond - beyond == 0); - - ++it; - EXPECT_TRUE(it - s.rbegin() == 1); - EXPECT_TRUE(*it == 3); - *it = 22; - EXPECT_TRUE(*it == 22); - EXPECT_TRUE(beyond - it == 3); - - it = first; - EXPECT_TRUE(it == first); - while (it != s.rend()) - { - *it = 5; - ++it; - } - - EXPECT_TRUE(it == beyond); - EXPECT_TRUE(it - beyond == 0); - - for (const auto& n : s) { EXPECT_TRUE(n == 5); } - } - } + EXPECT_TRUE(beyond - first == 4); + EXPECT_TRUE(first - first == 0); + EXPECT_TRUE(beyond - beyond == 0); - TEST(span_test, as_bytes) - { - std::set_terminate([] { - std::cerr << "Expected Death. as_bytes"; - std::abort(); - }); + ++it; + EXPECT_TRUE(it - s.rbegin() == 1); + EXPECT_TRUE(*it == 3); + *it = 22; + EXPECT_TRUE(*it == 22); + EXPECT_TRUE(beyond - it == 3); - int a[] = {1, 2, 3, 4}; - { - const span<const int> s = a; - EXPECT_TRUE(s.size() == 4); - const span<const byte> bs = as_bytes(s); - EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } + it = first; + EXPECT_TRUE(it == first); + while (it != s.rend()) + { + *it = 5; + ++it; + } - { - span<int> s; - const auto bs = as_bytes(s); - EXPECT_TRUE(bs.size() == s.size()); - EXPECT_TRUE(bs.size() == 0); - EXPECT_TRUE(bs.size_bytes() == 0); - EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); - EXPECT_TRUE(bs.data() == nullptr); - } + EXPECT_TRUE(it == beyond); + EXPECT_TRUE(it - beyond == 0); - { - span<int> s = a; - const auto bs = as_bytes(s); - EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } + for (const auto& n : s) { EXPECT_TRUE(n == 5); } + } +} - int b[5] = {1, 2, 3, 4, 5}; - { - span<int> sp(begin(b), static_cast<size_t>(-2)); - EXPECT_DEATH((void) sp.size_bytes(), deathstring); - } - } +TEST(span_test, as_bytes) +{ + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. as_bytes"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); - TEST(span_test, as_writable_bytes) - { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; + { + const span<const int> s = a; + EXPECT_TRUE(s.size() == 4); + const span<const byte> bs = as_bytes(s); + EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - // you should not be able to get writeable bytes for const objects - span<const int> s = a; - EXPECT_TRUE(s.size() == 4); - span<const byte> bs = as_writable_bytes(s); - EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - #endif - } + { + span<int> s; + const auto bs = as_bytes(s); + EXPECT_TRUE(bs.size() == s.size()); + EXPECT_TRUE(bs.size() == 0); + EXPECT_TRUE(bs.size_bytes() == 0); + EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); + EXPECT_TRUE(bs.data() == nullptr); + } - { - span<int> s; - const auto bs = as_writable_bytes(s); - EXPECT_TRUE(bs.size() == s.size()); - EXPECT_TRUE(bs.size() == 0); - EXPECT_TRUE(bs.size_bytes() == 0); - EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); - EXPECT_TRUE(bs.data() == nullptr); - } + { + span<int> s = a; + const auto bs = as_bytes(s); + EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } - { - span<int> s = a; - const auto bs = as_writable_bytes(s); - EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } - } + int b[5] = {1, 2, 3, 4, 5}; + { + span<int> sp(std::begin(b), static_cast<size_t>(-2)); + EXPECT_DEATH((void) sp.size_bytes(), expected); + } +} + +TEST(span_test, as_writable_bytes) +{ + int a[] = {1, 2, 3, 4}; + + { +#ifdef CONFIRM_COMPILATION_ERRORS + // you should not be able to get writeable bytes for const objects + span<const int> s = a; + EXPECT_TRUE(s.size() == 4); + span<const byte> bs = as_writable_bytes(s); + EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); +#endif + } + + { + span<int> s; + const auto bs = as_writable_bytes(s); + EXPECT_TRUE(bs.size() == s.size()); + EXPECT_TRUE(bs.size() == 0); + EXPECT_TRUE(bs.size_bytes() == 0); + EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); + EXPECT_TRUE(bs.data() == nullptr); + } + + { + span<int> s = a; + const auto bs = as_writable_bytes(s); + EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } +} - TEST(span_test, fixed_size_conversions) - { - std::set_terminate([] { +TEST(span_test, fixed_size_conversions) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. fixed_size_conversions"; std::abort(); }); - int arr[] = {1, 2, 3, 4}; + const auto expected = GetExpectedDeathString(terminateHandler); - // converting to an span from an equal size array is ok - span<int, 4> s4 = arr; - EXPECT_TRUE(s4.size() == 4); + int arr[] = {1, 2, 3, 4}; - // converting to dynamic_range is always ok - { - span<int> s = s4; - EXPECT_TRUE(s.size() == s4.size()); - static_cast<void>(s); - } + // converting to an span from an equal size array is ok + span<int, 4> s4 = arr; + EXPECT_TRUE(s4.size() == 4); - // initialization or assignment to static span that REDUCES size is NOT ok - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int, 2> s = arr; - } - { - span<int, 2> s2 = s4; - static_cast<void>(s2); - } - #endif + // converting to dynamic_range is always ok + { + span<int> s = s4; + EXPECT_TRUE(s.size() == s4.size()); + static_cast<void>(s); + } - // even when done dynamically - { - /* - // this now results in a compile-time error, rather than runtime. - // There is no suitable conversion from dynamic span to fixed span. - span<int> s = arr; - auto f = [&]() { - const span<int, 2> s2 = s; - static_cast<void>(s2); - }; - EXPECT_DEATH(f(), deathstring); - */ - } +// initialization or assignment to static span that REDUCES size is NOT ok +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<int, 2> s = arr; + } + { + span<int, 2> s2 = s4; + static_cast<void>(s2); + } +#endif - // but doing so explicitly is ok + // even when done dynamically + { + /* + // this now results in a compile-time error, rather than runtime. + // There is no suitable conversion from dynamic span to fixed span. + span<int> s = arr; + auto f = [&]() { + const span<int, 2> s2 = s; + static_cast<void>(s2); + }; + EXPECT_DEATH(f(), expected); + */ + } - // you can convert statically - { - const span<int, 2> s2{&arr[0], 2}; - static_cast<void>(s2); - } - { - const span<int, 1> s1 = s4.first<1>(); - static_cast<void>(s1); - } + // but doing so explicitly is ok + + // you can convert statically + { + const span<int, 2> s2{&arr[0], 2}; + static_cast<void>(s2); + } + { + const span<int, 1> s1 = s4.first<1>(); + static_cast<void>(s1); + } /* // this is not a legal operation in std::span, so we are no longer supporting it @@ -1176,73 +1197,74 @@ TEST(span_test, from_array_constructor) } */ - // initialization or assignment to static span that requires size INCREASE is not ok. - int arr2[2] = {1, 2}; + // initialization or assignment to static span that requires size INCREASE is not ok. + int arr2[2] = {1, 2}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span<int, 4> s3 = arr2; - } - { - span<int, 2> s2 = arr2; - span<int, 4> s4a = s2; - } - #endif - { - auto f = [&]() { - const span<int, 4> _s4{arr2, 2}; - static_cast<void>(_s4); - }; - EXPECT_DEATH(f(), deathstring); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span<int, 4> s3 = arr2; + } + { + span<int, 2> s2 = arr2; + span<int, 4> s4a = s2; + } +#endif + { + auto f = [&]() { + const span<int, 4> _s4{arr2, 2}; + static_cast<void>(_s4); + }; + EXPECT_DEATH(f(), expected); + } /* - // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size span. + // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size + span. // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one span<int> av = arr2; auto f = [&]() { const span<int, 4> _s4 = av; static_cast<void>(_s4); }; - EXPECT_DEATH(f(), deathstring); + EXPECT_DEATH(f(), expected); */ - } - - TEST(span_test, interop_with_std_regex) - { - char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; - span<char> s = lat; - const auto f_it = s.begin() + 7; - - std::match_results<span<char>::iterator> match; - - std::regex_match(s.begin(), s.end(), match, std::regex(".*")); - EXPECT_TRUE(match.ready()); - EXPECT_FALSE(match.empty()); - EXPECT_TRUE(match[0].matched); - EXPECT_TRUE(match[0].first == s.begin()); - EXPECT_TRUE(match[0].second == s.end()); - - std::regex_search(s.begin(), s.end(), match, std::regex("F")); - EXPECT_TRUE(match.ready()); - EXPECT_FALSE(match.empty()); - EXPECT_TRUE(match[0].matched); - EXPECT_TRUE(match[0].first == f_it); - EXPECT_TRUE(match[0].second == (f_it + 1)); - } - - TEST(span_test, default_constructible) - { - EXPECT_TRUE((std::is_default_constructible<span<int>>::value)); - EXPECT_TRUE((std::is_default_constructible<span<int, 0>>::value)); - EXPECT_FALSE((std::is_default_constructible<span<int, 42>>::value)); - } - - TEST(span_test, std_container_ctad) - { +} + +TEST(span_test, interop_with_std_regex) +{ + char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; + span<char> s = lat; + const auto f_it = s.begin() + 7; + + std::match_results<span<char>::iterator> match; + + std::regex_match(s.begin(), s.end(), match, std::regex(".*")); + EXPECT_TRUE(match.ready()); + EXPECT_FALSE(match.empty()); + EXPECT_TRUE(match[0].matched); + EXPECT_TRUE(match[0].first == s.begin()); + EXPECT_TRUE(match[0].second == s.end()); + + std::regex_search(s.begin(), s.end(), match, std::regex("F")); + EXPECT_TRUE(match.ready()); + EXPECT_FALSE(match.empty()); + EXPECT_TRUE(match[0].matched); + EXPECT_TRUE(match[0].first == f_it); + EXPECT_TRUE(match[0].second == (f_it + 1)); +} + +TEST(span_test, default_constructible) +{ + EXPECT_TRUE((std::is_default_constructible<span<int>>::value)); + EXPECT_TRUE((std::is_default_constructible<span<int, 0>>::value)); + EXPECT_FALSE((std::is_default_constructible<span<int, 42>>::value)); +} + +TEST(span_test, std_container_ctad) +{ #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) // this test is just to verify that these compile { - std::vector<int> v{1,2,3,4}; + std::vector<int> v{1, 2, 3, 4}; gsl::span sp{v}; static_assert(std::is_same<decltype(sp), gsl::span<int>>::value); } @@ -1259,20 +1281,39 @@ TEST(span_test, from_array_constructor) } #endif #endif - } +} - TEST(span_test, front_back) - { - int arr[5] = {1,2,3,4,5}; +TEST(span_test, front_back) +{ + int arr[5] = {1, 2, 3, 4, 5}; span<int> s{arr}; EXPECT_TRUE(s.front() == 1); EXPECT_TRUE(s.back() == 5); - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. front_back"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + span<int> s2; - EXPECT_DEATH(s2.front(), deathstring); - EXPECT_DEATH(s2.back(), deathstring); - } + EXPECT_DEATH(s2.front(), expected); + EXPECT_DEATH(s2.back(), expected); +} + +#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +TEST(span_test, std_span) +{ + // make sure std::span can be constructed from gsl::span + int arr[5] = {1, 2, 3, 4, 5}; + gsl::span<int> gsl_span{arr}; +#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts)) + EXPECT_TRUE(std::to_address(gsl_span.begin()) == gsl_span.data()); + EXPECT_TRUE(std::to_address(gsl_span.end()) == gsl_span.data() + gsl_span.size()); +#endif // __cpp_lib_ranges + + std::span<int> std_span = gsl_span; + EXPECT_TRUE(std_span.data() == gsl_span.data()); + EXPECT_TRUE(std_span.size() == gsl_span.size()); +} +#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L diff --git a/tests/strict_notnull_tests.cpp b/tests/strict_notnull_tests.cpp index 3cf6911..7edef43 100644 --- a/tests/strict_notnull_tests.cpp +++ b/tests/strict_notnull_tests.cpp @@ -14,30 +14,40 @@ // /////////////////////////////////////////////////////////////////////////////// +#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gtest/gtest.h> -#include <gsl/pointers> // for not_null, operator<, operator<=, operator> -namespace gsl -{ -struct fail_fast; -} // namespace gsl +#include "deathTestCommon.h" using namespace gsl; -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +namespace +{ +// clang-format off +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool helper(not_null<int*> p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool helper_const(not_null<const int*> p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool strict_helper(strict_not_null<int*> p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; } +#ifdef CONFIRM_COMPILATION_ERRORS int* return_pointer() { return nullptr; } const int* return_pointer_const() { return nullptr; } +#endif +} // namespace TEST(strict_notnull_tests, TestStrictNotNull) { @@ -123,17 +133,14 @@ TEST(strict_notnull_tests, TestStrictNotNull) } #if defined(__cplusplus) && (__cplusplus >= 201703L) -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { int i = 42; @@ -161,7 +168,7 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) int* p1 = nullptr; const strict_not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -169,14 +176,14 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) const int* p1 = nullptr; const strict_not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(strict_not_null{p}), deathstring); - EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring); + EXPECT_DEATH(helper(strict_not_null{p}), expected); + EXPECT_DEATH(helper_const(strict_not_null{p}), expected); } #ifdef CONFIRM_COMPILATION_ERRORS diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 3c919d0..45a67d9 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -16,7 +16,7 @@ #include <gtest/gtest.h> -#include <gsl/assert> // for Expects, fail_fast (ptr only) +#include <gsl/assert> // for Expects, fail_fast (ptr only) #include <gsl/pointers> // for owner #include <gsl/span> // for span, dynamic_extent #include <gsl/string_span> // for basic_string_span, operator==, ensure_z @@ -28,13 +28,10 @@ #include <type_traits> // for remove_reference<>::type #include <vector> // for vector, allocator -using namespace std; +#include "deathTestCommon.h" + using namespace gsl; -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} // Generic string functions namespace generic @@ -76,8 +73,7 @@ T create() template <class T> void use(basic_string_span<T, gsl::dynamic_extent>) -{ -} +{} #endif czstring_span<> CreateTempName(string_span<> span) @@ -85,7 +81,8 @@ czstring_span<> CreateTempName(string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = 't'; span[1] = 'm'; span[2] = 'p'; @@ -102,7 +99,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = L't'; span[1] = L'm'; span[2] = L'p'; @@ -119,7 +117,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = u't'; span[1] = u'm'; span[2] = u'p'; @@ -136,7 +135,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = U't'; span[1] = U'm'; span[2] = U'p'; @@ -950,10 +950,11 @@ TEST(string_span_tests, Conversion) TEST(string_span_tests, zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -973,7 +974,7 @@ TEST(string_span_tests, zstring) buf[0] = 'a'; auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -981,8 +982,9 @@ TEST(string_span_tests, zstring) char buf[10]; auto name = CreateTempName({buf, 10}); - if (!name.empty()) { - czstring<> str = name.assume_z(); + if (!name.empty()) + { + czstring str = name.assume_z(); EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(*(str + 3) == '\0'); } @@ -991,10 +993,11 @@ TEST(string_span_tests, zstring) TEST(string_span_tests, wzstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. wzstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1014,7 +1017,7 @@ TEST(string_span_tests, wzstring) buf[0] = L'a'; const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1022,8 +1025,9 @@ TEST(string_span_tests, wzstring) wchar_t buf[10]; const auto name = CreateTempNameW({buf, 10}); - if (!name.empty()) { - cwzstring<> str = name.assume_z(); + if (!name.empty()) + { + cwzstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } @@ -1032,10 +1036,11 @@ TEST(string_span_tests, wzstring) TEST(string_span_tests, u16zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. u16zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1055,7 +1060,7 @@ TEST(string_span_tests, u16zstring) buf[0] = u'a'; const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1063,8 +1068,9 @@ TEST(string_span_tests, u16zstring) char16_t buf[10]; const auto name = CreateTempNameU16({buf, 10}); - if (!name.empty()) { - cu16zstring<> str = name.assume_z(); + if (!name.empty()) + { + cu16zstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } @@ -1073,10 +1079,11 @@ TEST(string_span_tests, u16zstring) TEST(string_span_tests, u32zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. u31zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1096,7 +1103,7 @@ TEST(string_span_tests, u32zstring) buf[0] = u'a'; const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1104,8 +1111,9 @@ TEST(string_span_tests, u32zstring) char32_t buf[10]; const auto name = CreateTempNameU32({buf, 10}); - if (!name.empty()) { - cu32zstring<> str = name.assume_z(); + if (!name.empty()) + { + cu32zstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 74dc990..715073f 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -16,14 +16,15 @@ #include <gtest/gtest.h> -#include <gsl/util> // finally, narrow_cast -#include <gsl/narrow> // for narrow, narrowing_error #include <algorithm> // for move +#include <complex> +#include <cstddef> // for std::ptrdiff_t #include <functional> // for reference_wrapper, _Bind_helper<>::type +#include <gsl/narrow> // for narrow, narrowing_error +#include <gsl/util> // finally, narrow_cast #include <limits> // for numeric_limits #include <stdint.h> // for uint32_t, int32_t #include <type_traits> // for is_same -#include <cstddef> // for std::ptrdiff_t using namespace gsl; @@ -32,8 +33,7 @@ namespace void f(int& i) { i += 1; } static int j = 0; void g() { j += 1; } -} - +} // namespace TEST(utils_tests, sanity_check_for_gsl_index_typedef) { @@ -123,6 +123,7 @@ TEST(utils_tests, narrow_cast) EXPECT_TRUE(uc == 44); } +#ifndef GSL_KERNEL_MODE TEST(utils_tests, narrow) { int n = 120; @@ -144,4 +145,11 @@ TEST(utils_tests, narrow) n = -42; EXPECT_THROW(narrow<unsigned>(n), narrowing_error); + + EXPECT_TRUE( + narrow<std::complex<float>>(std::complex<double>(4, 2)) == std::complex<float>(4, 2)); + EXPECT_THROW(narrow<std::complex<float>>(std::complex<double>(4.2)), narrowing_error); + + EXPECT_TRUE(narrow<int>(float(1)) == 1); } +#endif // GSL_KERNEL_MODE |