Merge remote-tracking branch 'origin/main' into final_action-revision

This commit is contained in:
Dmitry Kobets 2022-09-26 15:27:01 -07:00
commit 8840d87199
42 changed files with 1696 additions and 1720 deletions

View File

@ -29,7 +29,7 @@ jobs:
echo "Emulator starting" echo "Emulator starting"
- name: Configure - 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 - name: Build
run: cmake --build . --parallel run: cmake --build . --parallel

View File

@ -25,11 +25,11 @@ jobs:
-GXcode \ -GXcode \
-DCMAKE_SYSTEM_NAME=iOS \ -DCMAKE_SYSTEM_NAME=iOS \
"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=8 \ -DCMAKE_OSX_DEPLOYMENT_TARGET=9 \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \ -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
"-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \ "-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \
-DMACOSX_BUNDLE_BUNDLE_VERSION=3.0.1 \ -DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \
-DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.0.1 \ -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \
.. ..
- name: Build - name: Build

View File

@ -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}

View File

@ -4,7 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(guidelineSupportLibrary) include(guidelineSupportLibrary)
project(GSL project(GSL
VERSION 3.1.0 VERSION 4.0.0
LANGUAGES CXX LANGUAGES CXX
) )

View File

@ -30,14 +30,14 @@ not_null | &#x2611; | restricts a pointer / smart po
span | &#x2611; | 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 | &#x2611; | 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 | &#x2610; | spans a range starting from a pointer to the first place for which the predicate is true span_p | &#x2610; | spans a range starting from a pointer to the first place for which the predicate is true
basic_zstring | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type basic_zstring | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type
zstring | &#x2611; | An alias to `basic_zstring` with a char type of char zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char
czstring | &#x2611; | An alias to `basic_zstring` with a char type of const char czstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char
wzstring | &#x2611; | An alias to `basic_zstring` with a char type of wchar_t wzstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of wchar_t
cwzstring | &#x2611; | An alias to `basic_zstring` with a char type of const wchar_t cwzstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const wchar_t
u16zstring | &#x2611; | An alias to `basic_zstring` with a char type of char16_t u16zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char16_t
cu16zstring | &#x2611; | An alias to `basic_zstring` with a char type of const char16_t cu16zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char16_t
u32zstring | &#x2611; | An alias to `basic_zstring` with a char type of char32_t u32zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char32_t
cu32zstring | &#x2611; | An alias to `basic_zstring` with a char type of const char32_t cu32zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char32_t
[**2. Owners**][cg-owners] | | [**2. Owners**][cg-owners] | |
unique_ptr | &#x2611; | an alias to `std::unique_ptr` unique_ptr | &#x2611; | an alias to `std::unique_ptr`
shared_ptr | &#x2611; | an alias to `std::shared_ptr` shared_ptr | &#x2611; | 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 [cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts
# Quick Start # Quick Start
## Supported Compilers ## Supported Compilers / Toolsets
The GSL officially supports the current and previous major release of MSVC, GCC, Clang, and XCode's Apple-Clang. The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang.
See our latest test results for the most up-to-date list of supported configurations. 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 Compiler |Toolset Versions Currently Tested
:------- |--: :------- |--:
XCode |11.4 & 10.3 XCode | 13.2.1 & 12.5.1
GCC |9 & 8 GCC | 11[^1] & 10[^2]
Clang |11 & 10 Clang | 12[^2] & 11[^2]
Visual Studio with MSVC | VS2017 (15.9) & VS2019 (16.4) Visual Studio with MSVC | VS2022[^3] & VS2019[^4]
Visual Studio with LLVM | VS2017 (Clang 9) & VS2019 (Clang 10) 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! If you successfully port GSL to another platform, we would love to hear from you!

41
SECURITY.md Normal file
View File

@ -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 -->

View File

@ -4,65 +4,63 @@ trigger:
pr: pr:
autoCancel: true autoCancel: true
# GCC
stages: stages:
- stage: GCC - stage: GCC
dependsOn: [] dependsOn: []
variables:
- name: CC
value: gcc
- name: CXX
value: g++
jobs: jobs:
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate GCC latest' compiler: gcc
imageName: ubuntu-20.04 image: ubuntu-20.04
- template: ./pipelines/jobs.yml compilerVersions: [ 11, 10 ]
parameters: setupfile: 'setup_gcc.yml'
jobName: 'Validate GCC Previous'
imageName: ubuntu-18.04
# Clang
- stage: Clang - stage: Clang
dependsOn: [] dependsOn: []
variables:
- name: CC
value: clang
- name: CXX
value: clang++
jobs: jobs:
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate Clang latest' compiler: clang
imageName: ubuntu-20.04 image: ubuntu-20.04
- template: ./pipelines/jobs.yml compilerVersions: [ 12, 11 ]
parameters: setupfile: 'setup_clang.yml'
jobName: 'Validate Clang Previous'
imageName: ubuntu-18.04
# MSVC - stage: Xcode
- stage: MSVC
dependsOn: [] dependsOn: []
jobs: jobs:
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate MSVC latest' compiler: 'Xcode'
imageName: windows-latest image: macOS-11
- template: ./pipelines/jobs.yml compilerVersions: [ '12.5.1', '13.2.1' ]
parameters: setupfile: 'setup_apple.yml'
jobName: 'Validate MSVC Previous'
imageName: vs2017-win2016
# Apple-Clang - stage: VS_MSVC
- stage: Apple_Clang
dependsOn: [] dependsOn: []
jobs: jobs:
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate Apple-Clang latest' compiler: 'VS2019 (MSVC)'
imageName: macos-10.15 compilerVersions: [ 'default' ]
image: windows-2019
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate Apple-Clang Previous' compiler: 'VS2022 (MSVC)'
imageName: macos-10.14 compilerVersions: [ 'default' ]
image: windows-2022
- stage: VS_LLVM
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2019 (LLVM)'
compilerVersions: [ 'default' ]
image: windows-2019
extraCmakeArgs: '-T ClangCL'
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2022 (LLVM)'
compilerVersions: [ 'default' ]
image: windows-2022
extraCmakeArgs: '-T ClangCL'

View File

@ -17,8 +17,8 @@
#ifndef GSL_ALGORITHM_H #ifndef GSL_ALGORITHM_H
#define GSL_ALGORITHM_H #define GSL_ALGORITHM_H
#include <gsl/assert> // for Expects #include "assert" // for Expects
#include <gsl/span> // for dynamic_extent, span #include "span" // for dynamic_extent, span
#include <algorithm> // for copy_n #include <algorithm> // for copy_n
#include <cstddef> // for ptrdiff_t #include <cstddef> // for ptrdiff_t

View File

@ -22,6 +22,7 @@
// Currently terminate is a no-op in this mode, so we add termination behavior back // 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)) #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
#define GSL_KERNEL_MODE
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
#include <intrin.h> #include <intrin.h>

View File

@ -17,16 +17,16 @@
#ifndef GSL_GSL_H #ifndef GSL_GSL_H
#define GSL_GSL_H #define GSL_GSL_H
#include <gsl/algorithm> // copy #include "algorithm" // copy
#include <gsl/assert> // Ensures/Expects #include "assert" // Ensures/Expects
#include <gsl/byte> // byte #include "byte" // byte
#include <gsl/pointers> // owner, not_null #include "pointers" // owner, not_null
#include <gsl/span> // span #include "span" // span
#include <gsl/string_span> // zstring, string_span, zstring_builder... #include "string_span" // zstring, string_span, zstring_builder...
#include <gsl/util> // finally()/narrow_cast()... #include "util" // finally()/narrow_cast()...
#ifdef __cpp_exceptions #ifdef __cpp_exceptions
#include <gsl/narrow> // narrow() #include "narrow" // narrow()
#endif #endif
#endif // GSL_GSL_H #endif // GSL_GSL_H

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>") #pragma message( \
#include <gsl/algorithm> "This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
#include "algorithm"

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/assert> instead of <gsl/gsl_assert>") #pragma message("This header will soon be removed. Use <gsl/assert> instead of <gsl/gsl_assert>")
#include <gsl/assert> #include "assert"

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/byte> instead of <gsl/gsl_byte>") #pragma message("This header will soon be removed. Use <gsl/byte> instead of <gsl/gsl_byte>")
#include <gsl/byte> #include "byte"

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/narrow> instead of <gsl/gsl_narrow>") #pragma message("This header will soon be removed. Use <gsl/narrow> instead of <gsl/gsl_narrow>")
#include <gsl/narrow> #include "narrow"

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/util> instead of <gsl/gsl_util>") #pragma message("This header will soon be removed. Use <gsl/util> instead of <gsl/gsl_util>")
#include <gsl/util> #include "util"

View File

@ -16,8 +16,9 @@
#ifndef GSL_NARROW_H #ifndef GSL_NARROW_H
#define GSL_NARROW_H #define GSL_NARROW_H
#include <gsl/assert> // for Expects #include "assert" // for GSL_SUPPRESS
#include <gsl/util> // for narrow_cast #include "util" // for narrow_cast
#include <exception> // for std::exception
namespace gsl namespace gsl
{ {
struct narrowing_error : public std::exception struct narrowing_error : public std::exception
@ -26,19 +27,52 @@ struct narrowing_error : public std::exception
}; };
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value // 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 // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) 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 T narrow(U u) noexcept(false)
{ {
constexpr const bool is_different_signedness = constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value); (std::is_signed<T>::value != std::is_signed<U>::value);
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); const T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{})))) if (static_cast<U>(t) != u)
{ {
throw narrowing_error{}; throw narrowing_error{};
} }

View File

@ -17,7 +17,7 @@
#ifndef GSL_POINTERS_H #ifndef GSL_POINTERS_H
#define GSL_POINTERS_H #define GSL_POINTERS_H
#include <gsl/assert> // for Ensures, Expects #include "assert" // for Ensures, Expects
#include <algorithm> // for forward #include <algorithm> // for forward
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t #include <cstddef> // for ptrdiff_t, nullptr_t, size_t
@ -34,11 +34,18 @@ namespace gsl
namespace details namespace details
{ {
template<typename T, typename = void> template <typename T, typename = void>
struct is_comparable_to_nullptr : std::false_type {}; struct is_comparable_to_nullptr : std::false_type
{
};
template <typename T> 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 {}; 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 } // namespace details
// //

View File

@ -17,15 +17,21 @@
#ifndef GSL_SPAN_H #ifndef GSL_SPAN_H
#define GSL_SPAN_H #define GSL_SPAN_H
#include <gsl/assert> // for Expects #include "assert" // for Expects
#include <gsl/byte> // for byte #include "byte" // for byte
#include <gsl/util> // for narrow_cast #include "span_ext" // for span specialization of gsl::at and other span-related extensions
#include "util" // for narrow_cast
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
#include <iterator> // for reverse_iterator, distance, random_access_... #include <iterator> // for reverse_iterator, distance, random_access_...
#include <memory> // for pointer_traits
#include <type_traits> // for enable_if_t, declval, is_convertible, inte... #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__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
@ -60,12 +66,6 @@
namespace gsl 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 // implementation details
namespace details namespace details
{ {
@ -115,6 +115,9 @@ namespace details
class span_iterator class span_iterator
{ {
public: 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 iterator_category = std::random_access_iterator_tag;
using value_type = std::remove_cv_t<Type>; using value_type = std::remove_cv_t<Type>;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
@ -334,8 +337,26 @@ namespace details
pointer begin_ = nullptr; pointer begin_ = nullptr;
pointer end_ = nullptr; pointer end_ = nullptr;
pointer current_ = 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> template <std::size_t Ext>
class extent_type class extent_type
{ {
@ -687,14 +708,11 @@ private:
template <class OtherExtentType> template <class OtherExtentType>
constexpr storage_type(KnownNotNull data, OtherExtentType ext) constexpr storage_type(KnownNotNull data, OtherExtentType ext)
: ExtentType(ext), data_(data.p) : ExtentType(ext), data_(data.p)
{ {}
Expects(ExtentType::size() != dynamic_extent);
}
template <class OtherExtentType> template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
{ {
Expects(ExtentType::size() != dynamic_extent);
Expects(data || ExtentType::size() == 0); Expects(data || ExtentType::size() == 0);
} }

View File

@ -27,16 +27,29 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gsl/span> // for span #include "assert" // GSL_KERNEL_MODE
#include <gsl/util> // for narrow_cast, narrow #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> #include <utility>
#ifndef GSL_KERNEL_MODE
#include <algorithm> // for lexicographical_compare
#endif // GSL_KERNEL_MODE
namespace gsl 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 // [span.comparison], span comparison operators
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent> template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r) 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); return !(l < r);
} }
#endif // GSL_KERNEL_MODE
// //
// make_span() - Utility functions for creating spans // make_span() - Utility functions for creating spans
// //

View File

@ -17,9 +17,9 @@
#ifndef GSL_STRING_SPAN_H #ifndef GSL_STRING_SPAN_H
#define GSL_STRING_SPAN_H #define GSL_STRING_SPAN_H
#include <gsl/assert> // for Ensures, Expects #include "assert" // for Ensures, Expects
#include <gsl/span_ext> // for operator!=, operator==, dynamic_extent #include "span_ext" // for operator!=, operator==, dynamic_extent
#include <gsl/util> // for narrow_cast #include "util" // for narrow_cast
#include <algorithm> // for equal, lexicographical_compare #include <algorithm> // for equal, lexicographical_compare
#include <array> // for array #include <array> // for array
@ -59,29 +59,21 @@ namespace gsl
template <typename CharT, std::size_t Extent = dynamic_extent> template <typename CharT, std::size_t Extent = dynamic_extent>
using basic_zstring = CharT*; using basic_zstring = CharT*;
template <std::size_t Extent = dynamic_extent> using czstring = basic_zstring<const char, dynamic_extent>;
using czstring = basic_zstring<const char, Extent>;
template <std::size_t Extent = dynamic_extent> using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
using cwzstring = basic_zstring<const wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent> using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
using cu16zstring = basic_zstring<const char16_t, Extent>;
template <std::size_t Extent = dynamic_extent> using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
using cu32zstring = basic_zstring<const char32_t, Extent>;
template <std::size_t Extent = dynamic_extent> using zstring = basic_zstring<char, dynamic_extent>;
using zstring = basic_zstring<char, Extent>;
template <std::size_t Extent = dynamic_extent> using wzstring = basic_zstring<wchar_t, dynamic_extent>;
using wzstring = basic_zstring<wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent> using u16zstring = basic_zstring<char16_t, dynamic_extent>;
using u16zstring = basic_zstring<char16_t, Extent>;
template <std::size_t Extent = dynamic_extent> using u32zstring = basic_zstring<char32_t, dynamic_extent>;
using u32zstring = basic_zstring<char32_t, Extent>;
namespace details namespace details
{ {

View File

@ -17,7 +17,7 @@
#ifndef GSL_UTIL_H #ifndef GSL_UTIL_H
#define GSL_UTIL_H #define GSL_UTIL_H
#include <gsl/assert> // for Expects #include "assert" // for Expects
#include <array> #include <array>
#include <cstddef> // for ptrdiff_t, size_t #include <cstddef> // for ptrdiff_t, size_t
@ -25,6 +25,13 @@
#include <type_traits> // for is_signed, integral_constant #include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward #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__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
@ -38,6 +45,12 @@
#define GSL_NODISCARD #define GSL_NODISCARD
#endif // defined(__cplusplus) && (__cplusplus >= 201703L) #endif // defined(__cplusplus) && (__cplusplus >= 201703L)
#if defined(__cpp_inline_variables)
#define GSL_INLINE inline
#else
#define GSL_INLINE
#endif
namespace gsl namespace gsl
{ {
// //
@ -81,8 +94,8 @@ GSL_NODISCARD auto finally(F&& f) noexcept
template <class T, class U> template <class T, class U>
// clang-format off // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr T narrow_cast(U&& u) noexcept constexpr T narrow_cast(U&& u) noexcept
{ {
return static_cast<T>(std::forward<U>(u)); return static_cast<T>(std::forward<U>(u));
} }
@ -94,7 +107,7 @@ template <class T, std::size_t N>
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // 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) constexpr T& at(T (&arr)[N], const index i)
{ {
Expects(i >= 0 && i < narrow_cast<index>(N)); Expects(i >= 0 && i < narrow_cast<index>(N));
@ -105,7 +118,7 @@ template <class Cont>
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // 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()]) constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
{ {
Expects(i >= 0 && i < narrow_cast<index>(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> template <class T>
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr T at(const std::initializer_list<T> cont, const index i) constexpr T at(const std::initializer_list<T> cont, const index i)
{ {
Expects(i >= 0 && i < narrow_cast<index>(cont.size())); Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
return *(cont.begin() + i); 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 } // namespace gsl
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)

View File

@ -1,26 +1,43 @@
parameters: parameters:
jobName: '' CXXVersions: [ 14, 17, 20 ]
imageName: '' 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: jobs:
- job: - ${{ each compilerVersion in parameters.compilerVersions }}:
displayName: ${{ parameters.imageName }} - ${{ each CXXVersion in parameters.CXXVersions }}:
- ${{ each buildType in parameters.buildTypes }}:
- job:
displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }}
pool: pool:
vmImage: ${{ parameters.imageName }} vmImage: ${{ parameters.image }}
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 continueOnError: false
steps: steps:
- template: ./steps.yml - ${{ 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

View File

@ -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

13
pipelines/setup_clang.yml Normal file
View File

@ -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 }}

14
pipelines/setup_gcc.yml Normal file
View File

@ -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 }}

View File

@ -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

View File

@ -9,8 +9,12 @@ include(ExternalProject)
# will make visual studio generated project group files # will make visual studio generated project group files
set_property(GLOBAL PROPERTY USE_FOLDERS ON) 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) if(IOS)
add_compile_definitions(GTEST_HAS_DEATH_TEST=1) add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1)
endif() endif()
pkg_search_module(GTestMain gtest_main) pkg_search_module(GTestMain gtest_main)
@ -54,10 +58,11 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
find_package(Microsoft.GSL REQUIRED) find_package(Microsoft.GSL REQUIRED)
endif() 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-) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-)
endif() endif()
include(CheckCXXCompilerFlag)
# this interface adds compile options to how the tests are run # this interface adds compile options to how the tests are run
# please try to keep entries ordered =) # please try to keep entries ordered =)
add_library(gsl_tests_config INTERFACE) add_library(gsl_tests_config INTERFACE)
@ -84,6 +89,7 @@ if(MSVC) # MSVC or simulating MSVC
> >
$<$<CXX_COMPILER_ID:Clang>: $<$<CXX_COMPILER_ID:Clang>:
-Weverything -Weverything
-Wfloat-equal
-Wno-c++98-compat -Wno-c++98-compat
-Wno-c++98-compat-pedantic -Wno-c++98-compat-pedantic
-Wno-covered-switch-default # GTest -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() else()
target_compile_options(gsl_tests_config INTERFACE target_compile_options(gsl_tests_config INTERFACE
-fno-strict-aliasing -fno-strict-aliasing
@ -113,6 +123,7 @@ else()
-Wpedantic -Wpedantic
-Wshadow -Wshadow
-Wsign-conversion -Wsign-conversion
-Wfloat-equal
-Wno-deprecated-declarations # Allow tests for [[deprecated]] elements -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>: $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Weverything -Weverything
@ -135,6 +146,11 @@ else()
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>: $<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
$<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template> $<$<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>: $<$<CXX_COMPILER_ID:AppleClang>:
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>: $<$<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 googletest/googletest/include
) )
set_property(TARGET PROPERTY FOLDER "GSL_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
)
function(add_gsl_test name) target_link_libraries(gsl_tests
add_executable(${name} ${name}.cpp)
target_link_libraries(${name}
Microsoft.GSL::GSL Microsoft.GSL::GSL
gsl_tests_config gsl_tests_config
${GTestMain_LIBRARIES} ${GTestMain_LIBRARIES}
) )
add_test( add_test(gsl_tests gsl_tests)
${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)
# No exception tests # No exception tests
@ -222,12 +229,17 @@ if(MSVC) # MSVC or simulating MSVC
> >
$<$<CXX_COMPILER_ID:Clang>: $<$<CXX_COMPILER_ID:Clang>:
-Weverything -Weverything
-Wfloat-equal
-Wno-c++98-compat -Wno-c++98-compat
-Wno-c++98-compat-pedantic -Wno-c++98-compat-pedantic
-Wno-missing-prototypes -Wno-missing-prototypes
-Wno-unknown-attributes -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() else()
target_compile_options(gsl_tests_config_noexcept INTERFACE target_compile_options(gsl_tests_config_noexcept INTERFACE
-fno-exceptions -fno-exceptions
@ -241,6 +253,7 @@ else()
-Wpedantic -Wpedantic
-Wshadow -Wshadow
-Wsign-conversion -Wsign-conversion
-Wfloat-equal
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>: $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Weverything -Weverything
-Wno-c++98-compat -Wno-c++98-compat
@ -268,19 +281,9 @@ else()
) )
endif(MSVC) endif(MSVC)
function(add_gsl_test_noexcept name) add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp)
add_executable(${name} ${name}.cpp) target_link_libraries(gsl_noexcept_tests
target_link_libraries(${name}
Microsoft.GSL::GSL Microsoft.GSL::GSL
gsl_tests_config_noexcept gsl_tests_config_noexcept
${GTestMain_LIBRARIES} )
) add_test(gsl_noexcept_tests gsl_noexcept_tests)
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)

View File

@ -4,7 +4,7 @@ project(googletest-download NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(googletest ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 389cb68b87193358358ae87cc56d257fd0d80189 GIT_TAG 1b18723e874b256c1e39378c6774a90701d70f7a
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""

View File

@ -14,23 +14,19 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h>
#include <gsl/algorithm> // for copy
#include <gsl/span> // for span
#include <array> // for array #include <array> // for array
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <gsl/algorithm> // for copy
#include <gsl/span> // for span
#include <gtest/gtest.h>
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl namespace gsl
{ {
struct fail_fast; struct fail_fast;
} // namespace gsl } // namespace gsl
using namespace std;
using namespace gsl; using namespace gsl;
TEST(algorithm_tests, same_type) 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, 5> src{1, 2, 3, 4, 5};
std::array<int, 10> dst{}; std::array<int, 10> dst{};
const span<int> src_span(src); const gsl::span<int> src_span(src);
const span<int, 10> dst_span(dst); const gsl::span<int, 10> dst_span(dst);
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
@ -204,10 +200,11 @@ TEST(algorithm_tests, incompatible_type)
TEST(algorithm_tests, small_destination_span) TEST(algorithm_tests, small_destination_span)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. small_destination_span"; std::cerr << "Expected Death. small_destination_span";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
std::array<int, 12> src{1, 2, 3, 4}; std::array<int, 12> src{1, 2, 3, 4};
std::array<int, 4> dst{}; 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> dst_span_dyn(dst);
const span<int, 4> dst_span_static(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_dyn), expected);
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring); EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring); EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

View File

@ -14,14 +14,14 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h> #include "deathTestCommon.h"
#include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects #include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects
#include <gtest/gtest.h>
using namespace gsl; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
int f(int i) int f(int i)
{ {
@ -39,23 +39,22 @@ int g(int i)
TEST(assertion_tests, expects) TEST(assertion_tests, expects)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. expects"; std::cerr << "Expected Death. expects";
std::abort(); std::abort();
}); });
EXPECT_TRUE(f(2) == 2); EXPECT_TRUE(f(2) == 2);
EXPECT_DEATH(f(10), deathstring); EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
} }
TEST(assertion_tests, ensures) TEST(assertion_tests, ensures)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. ensures"; std::cerr << "Expected Death. ensures";
std::abort(); std::abort();
}); });
EXPECT_TRUE(g(2) == 3); EXPECT_TRUE(g(2) == 3);
EXPECT_DEATH(g(9), deathstring); EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
} }

View File

@ -22,31 +22,33 @@
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <initializer_list> // for initializer_list #include <initializer_list> // for initializer_list
#include <vector> // for vector #include <vector> // for vector
#if defined(__cplusplus) && __cplusplus >= 202002L
#include <span>
#endif // __cplusplus >= 202002L
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(at_tests, static_array) TEST(at_tests, static_array)
{ {
int a[4] = {1, 2, 3, 4}; int a[4] = {1, 2, 3, 4};
const int(&c_a)[4] = a; 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(a, i) == &a[i]);
EXPECT_TRUE(&gsl::at(c_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::cerr << "Expected Death. static_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_array) TEST(at_tests, std_array)
@ -54,20 +56,22 @@ TEST(at_tests, std_array)
std::array<int, 4> a = {1, 2, 3, 4}; std::array<int, 4> a = {1, 2, 3, 4};
const std::array<int, 4>& c_a = a; 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(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_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::cerr << "Expected Death. std_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_vector) TEST(at_tests, std_vector)
@ -75,42 +79,74 @@ TEST(at_tests, std_vector)
std::vector<int> a = {1, 2, 3, 4}; std::vector<int> a = {1, 2, 3, 4};
const std::vector<int>& c_a = a; 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(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_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::cerr << "Expected Death. std_vector";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, InitializerList) TEST(at_tests, InitializerList)
{ {
const std::initializer_list<int> a = {1, 2, 3, 4}; 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(a, i) == i + 1);
EXPECT_TRUE(gsl::at({1, 2, 3, 4}, 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::cerr << "Expected Death. InitializerList";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); 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(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 #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
static constexpr bool test_constexpr() static constexpr bool test_constexpr()
{ {
@ -119,7 +155,8 @@ static constexpr bool test_constexpr()
std::array<int, 4> a2 = {1, 2, 3, 4}; std::array<int, 4> a2 = {1, 2, 3, 4};
const std::array<int, 4>& c_a2 = a2; 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(a1, i) != &a1[i]) return false;
if (&gsl::at(c_a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false;
// requires C++17: // requires C++17:

View File

@ -37,7 +37,9 @@ TEST(byte_tests, construction)
EXPECT_TRUE(static_cast<unsigned char>(b) == 4); EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
} }
// clang-format off
GSL_SUPPRESS(es.49) GSL_SUPPRESS(es.49)
// clang-format on
{ {
const byte b = byte(12); const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12); EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
@ -55,7 +57,7 @@ TEST(byte_tests, construction)
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
{ {
const byte b { 14 }; const byte b{14};
EXPECT_TRUE(static_cast<unsigned char>(b) == 14); EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
} }
#endif #endif
@ -122,7 +124,7 @@ TEST(byte_tests, aliasing)
EXPECT_TRUE(res == i); EXPECT_TRUE(res == i);
} }
} } // namespace
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

11
tests/deathTestCommon.h Normal file
View File

@ -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;
}

View File

@ -14,8 +14,11 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <chrono>
#include <cstdlib> // for std::exit #include <cstdlib> // for std::exit
#include <gsl/span> // for span #include <gsl/span> // for span
#include <iostream>
#include <thread>
int operator_subscript_no_throw() noexcept int operator_subscript_no_throw() noexcept
{ {
@ -42,6 +45,10 @@ void setup_termination_handler() noexcept
int main() 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(); setup_termination_handler();
operator_subscript_no_throw(); operator_subscript_no_throw();
return -1; return -1;

View File

@ -25,13 +25,9 @@
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
} //namespace
struct MyBase struct MyBase
{ {
}; };
@ -64,7 +60,9 @@ struct CustomPtr
template <typename T, typename U> template <typename T, typename U>
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -72,7 +70,9 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -80,7 +80,9 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -88,7 +90,9 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -96,7 +100,9 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -104,7 +110,9 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -118,12 +126,19 @@ struct NonCopyableNonMovable
NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; 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; } 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; } bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
} // namespace
TEST(notnull_tests, TestNotNullConstructors) TEST(notnull_tests, TestNotNullConstructors)
{ {
@ -142,10 +157,12 @@ TEST(notnull_tests, TestNotNullConstructors)
#endif #endif
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructors"; std::cerr << "Expected Death. TestNotNullConstructors";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
// from shared pointer // from shared pointer
int i = 12; int i = 12;
@ -157,7 +174,7 @@ TEST(notnull_tests, TestNotNullConstructors)
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr; 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 // from returned pointer
EXPECT_DEATH(helper(return_pointer()), deathstring); EXPECT_DEATH(helper(return_pointer()), expected);
EXPECT_DEATH(helper_const(return_pointer()), deathstring); EXPECT_DEATH(helper_const(return_pointer()), expected);
} }
} }
@ -275,17 +292,18 @@ TEST(notnull_tests, TestNotNullCasting)
TEST(notnull_tests, TestNotNullAssignment) TEST(notnull_tests, TestNotNullAssignment)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullAssignmentd"; std::cerr << "Expected Death. TestNotNullAssignmentd";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int i = 12; int i = 12;
not_null<int*> p(&i); not_null<int*> p(&i);
EXPECT_TRUE(helper(p)); EXPECT_TRUE(helper(p));
int* q = nullptr; int* q = nullptr;
EXPECT_DEATH(p = not_null<int*>(q), deathstring); EXPECT_DEATH(p = not_null<int*>(q), expected);
} }
TEST(notnull_tests, TestNotNullRawPointerComparison) TEST(notnull_tests, TestNotNullRawPointerComparison)
@ -434,17 +452,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
auto workaround_macro = []() { auto workaround_macro = []() {
int* p1 = nullptr; int* p1 = nullptr;
const not_null x{p1}; 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 int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(not_null{p}), deathstring); EXPECT_DEATH(helper(not_null{p}), expected);
EXPECT_DEATH(helper_const(not_null{p}), deathstring); EXPECT_DEATH(helper_const(not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -495,10 +514,11 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull"; std::cerr << "Expected Death. TestMakeNotNull";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
const auto workaround_macro = []() { const auto workaround_macro = []() {
@ -506,7 +526,7 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); 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); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(make_not_null(p)), deathstring); EXPECT_DEATH(helper(make_not_null(p)), expected);
EXPECT_DEATH(helper_const(make_not_null(p)), deathstring); EXPECT_DEATH(helper_const(make_not_null(p)), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
EXPECT_DEATH(make_not_null(nullptr), deathstring); EXPECT_DEATH(make_not_null(nullptr), expected);
EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
} }
#endif #endif
} }

View File

@ -20,7 +20,7 @@
using namespace gsl; using namespace gsl;
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute GSL_SUPPRESS(f .23) // NO-FORMAT: attribute
void f(int* i) { *i += 1; } void f(int* i) { *i += 1; }
TEST(owner_tests, basic_test) TEST(owner_tests, basic_test)
@ -34,10 +34,10 @@ TEST(owner_tests, basic_test)
TEST(owner_tests, check_pointer_constraint) TEST(owner_tests, check_pointer_constraint)
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
owner<int> integerTest = 10; owner<int> integerTest = 10;
owner<std::shared_ptr<int>> sharedPtrTest(new int(10)); owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
} }
#endif #endif
} }

View File

@ -55,14 +55,14 @@ void ArrayConvertibilityCheck()
EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
EXPECT_TRUE(sp_const_nullptr_1.size() == 3); 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.data() == stl_nullptr.data());
EXPECT_TRUE(sp_const_nullptr_2.size() == 3); 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"); "std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
static_assert( 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, " "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
"3>>::value"); "3>>::value");
} }

View File

@ -16,8 +16,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at #include <gsl/util> // for narrow_cast, at
#include <gsl/span_ext> // for operator==, operator!=, make_span
#include <array> // for array #include <array> // for array
#include <iostream> // for cerr #include <iostream> // for cerr
@ -26,17 +26,16 @@
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
} // namespace
TEST(span_ext_test, make_span_from_pointer_length_constructor) 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::cerr << "Expected Death. from_pointer_length_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; int arr[4] = {1, 2, 3, 4};
{ {
@ -49,7 +48,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
int* p = nullptr; 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.size() == 0);
EXPECT_TRUE(s.data() == nullptr); EXPECT_TRUE(s.data() == nullptr);
} }
@ -57,7 +56,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
int* p = nullptr; int* p = nullptr;
auto workaround_macro = [=]() { make_span(p, 2); }; auto workaround_macro = [=]() { make_span(p, 2); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
} }
@ -88,7 +87,7 @@ TEST(span_ext_test, make_span_from_pointer_pointer_construction)
} }
TEST(span_ext_test, make_span_from_array_constructor) TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; 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}; int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
@ -110,10 +109,10 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
} }
} }
TEST(span_ext_test, make_span_from_dynamic_array_constructor) TEST(span_ext_test, make_span_from_dynamic_array_constructor)
{ {
double(*arr)[3][4] = new double[100][3][4]; double(*arr)[3][4] = new double[100][3][4];
{ {
@ -123,10 +122,10 @@ TEST(span_ext_test, make_span_from_array_constructor)
} }
delete[] arr; delete[] arr;
} }
TEST(span_ext_test, make_span_from_std_array_constructor) TEST(span_ext_test, make_span_from_std_array_constructor)
{ {
std::array<int, 4> arr = {1, 2, 3, 4}; std::array<int, 4> arr = {1, 2, 3, 4};
{ {
@ -137,25 +136,25 @@ TEST(span_ext_test, make_span_from_array_constructor)
// 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 // 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); gsl::span<int> s1 = make_span(arr);
static span<int> s2; static gsl::span<int> s2;
s2 = s1; s2 = s1;
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
// Known to be broken in gcc 6.4 and 6.5 with optimizations // 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 // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
EXPECT_TRUE(s1.size() == 4); EXPECT_TRUE(s1.size() == 4);
EXPECT_TRUE(s2.size() == 0); EXPECT_TRUE(s2.size() == 0);
#else #else
EXPECT_TRUE(s1.size() == s2.size()); EXPECT_TRUE(s1.size() == s2.size());
#endif #endif
}
} }
}
TEST(span_ext_test, make_span_from_const_std_array_constructor) TEST(span_ext_test, make_span_from_const_std_array_constructor)
{ {
const std::array<int, 4> arr = {1, 2, 3, 4}; const std::array<int, 4> arr = {1, 2, 3, 4};
{ {
@ -163,10 +162,10 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.size() == arr.size());
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
} }
TEST(span_ext_test, make_span_from_std_array_const_constructor) TEST(span_ext_test, make_span_from_std_array_const_constructor)
{ {
std::array<const int, 4> arr = {1, 2, 3, 4}; std::array<const int, 4> arr = {1, 2, 3, 4};
{ {
@ -174,10 +173,10 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.size() == arr.size());
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
} }
TEST(span_ext_test, make_span_from_container_constructor) TEST(span_ext_test, make_span_from_container_constructor)
{ {
std::vector<int> v = {1, 2, 3}; std::vector<int> v = {1, 2, 3};
const std::vector<int> cv = v; const std::vector<int> cv = v;
@ -190,20 +189,20 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(cs.size() == cv.size()); EXPECT_TRUE(cs.size() == cv.size());
EXPECT_TRUE(cs.data() == cv.data()); EXPECT_TRUE(cs.data() == cv.data());
} }
} }
TEST(span_test, interop_with_gsl_at) TEST(span_test, interop_with_gsl_at)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
span<int> s{arr}; gsl::span<int> s{arr};
EXPECT_TRUE(at(s, 0) == 1); EXPECT_TRUE(at(s, 0) == 1);
EXPECT_TRUE(at(s, 1) == 2); EXPECT_TRUE(at(s, 1) == 2);
} }
TEST(span_ext_test, iterator_free_functions) TEST(span_ext_test, iterator_free_functions)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; gsl::span<int> s{a};
EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value)); 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(s.end()), decltype(end(s))>::value));
@ -228,22 +227,23 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s.rbegin() == crbegin(s)); EXPECT_TRUE(s.rbegin() == crbegin(s));
EXPECT_TRUE(s.rend() == crend(s)); EXPECT_TRUE(s.rend() == crend(s));
} }
TEST(span_ext_test, ssize_free_function) TEST(span_ext_test, ssize_free_function)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; gsl::span<int> s{a};
EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value)); EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s))); EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
} }
TEST(span_ext_test, comparison_operators) #ifndef GSL_KERNEL_MODE
TEST(span_ext_test, comparison_operators)
{
{ {
{ gsl::span<int> s1;
span<int> s1; gsl::span<int> s2;
span<int> s2;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
EXPECT_FALSE(s1 < s2); EXPECT_FALSE(s1 < s2);
@ -260,8 +260,8 @@ TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr[] = {2, 1}; int arr[] = {2, 1};
span<int> s1 = arr; gsl::span<int> s1 = arr;
span<int> s2 = arr; gsl::span<int> s2 = arr;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
@ -280,8 +280,8 @@ TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr[] = {2, 1}; // bigger int arr[] = {2, 1}; // bigger
span<int> s1; gsl::span<int> s1;
span<int> s2 = arr; gsl::span<int> s2 = arr;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
@ -300,8 +300,8 @@ TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr1[] = {1, 2}; int arr1[] = {1, 2};
int arr2[] = {1, 2}; int arr2[] = {1, 2};
span<int> s1 = arr1; gsl::span<int> s1 = arr1;
span<int> s2 = arr2; gsl::span<int> s2 = arr2;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
@ -320,8 +320,8 @@ TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr[] = {1, 2, 3}; int arr[] = {1, 2, 3};
span<int> s1 = {&arr[0], 2}; // shorter gsl::span<int> s1 = {&arr[0], 2}; // shorter
span<int> s2 = arr; // longer gsl::span<int> s2 = arr; // longer
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
@ -341,8 +341,8 @@ TEST(span_ext_test, make_span_from_array_constructor)
int arr1[] = {1, 2}; // smaller int arr1[] = {1, 2}; // smaller
int arr2[] = {2, 1}; // bigger int arr2[] = {2, 1}; // bigger
span<int> s1 = arr1; gsl::span<int> s1 = arr1;
span<int> s2 = arr2; gsl::span<int> s2 = arr2;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
@ -357,4 +357,5 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
EXPECT_FALSE(s1 >= s2); EXPECT_FALSE(s1 >= s2);
} }
} }
#endif // GSL_KERNEL_MODE

View File

@ -17,19 +17,19 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast, at
#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <gsl/span> // for span, span_iterator, operator==, operator!=
#include <gsl/util> // for narrow_cast, at
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t
#include <iostream> // for ptrdiff_t #include <iostream> // for ptrdiff_t
#include <iterator> // for reverse_iterator, operator-, operator== #include <iterator> // for reverse_iterator, operator-, operator==
#include <memory> // for unique_ptr, shared_ptr, make_unique, allo... #include <memory> // for unique_ptr, shared_ptr, make_unique, allo...
#include <regex> // for match_results, sub_match, match_results<>... #include <regex> // for match_results, sub_match, match_results<>...
#include <cstddef> // for ptrdiff_t
#include <string> // for string #include <string> // for string
#include <type_traits> // for integral_constant<>::value, is_default_co... #include <type_traits> // for integral_constant<>::value, is_default_co...
#include <vector> // for vector
#include <utility> #include <utility>
#include <vector> // for vector
// the string_view include and macro are used in the deduction guide verification // the string_view include and macro are used in the deduction guide verification
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
@ -40,13 +40,16 @@
#endif // __has_include(<string_view>) #endif // __has_include(<string_view>)
#endif // __has_include #endif // __has_include
#endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) #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; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
struct BaseClass struct BaseClass
{ {
@ -111,10 +114,12 @@ TEST(span_test, size_optimization)
TEST(span_test, from_nullptr_size_constructor) 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::cerr << "Expected Death. from_nullptr_size_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
span<int> s{nullptr, narrow_cast<span<int>::size_type>(0)}; span<int> s{nullptr, narrow_cast<span<int>::size_type>(0)};
EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.size() == 0);
@ -128,21 +133,21 @@ TEST(span_test, from_nullptr_size_constructor)
auto workaround_macro = []() { auto workaround_macro = []() {
const span<int, 1> s{nullptr, narrow_cast<span<int>::size_type>(0)}; 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}; }; 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}; }; 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}; }; 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}; }; 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)}; 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) 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::cerr << "Expected Death. from_pointer_length_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; 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.size() == narrow_cast<std::size_t>(i));
EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.data() == &arr[0]);
EXPECT_TRUE(s.empty() == (i == 0)); EXPECT_TRUE(s.empty() == (i == 0));
for (int j = 0; j < i; ++j) for (int j = 0; j < i; ++j) EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]);
EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]);
} }
{ {
span<int> s = {&arr[i], 4 - narrow_cast<std::size_t>(i)}; 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; int* p = nullptr;
auto workaround_macro = [=]() { const span<int> s{p, 2}; }; 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 // this will fail the std::distance() precondition, which asserts on MSVC debug builds
//{ //{
// auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; }; // 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 // this will fail the std::distance() precondition, which asserts on MSVC debug builds
//{ //{
// int* p = nullptr; // int* p = nullptr;
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; // auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
// EXPECT_DEATH(workaround_macro(), deathstring); // EXPECT_DEATH(workaround_macro(), expected);
//} //}
{ {
@ -270,12 +276,12 @@ TEST(span_test, from_pointer_pointer_construction)
//{ //{
// int* p = nullptr; // int* p = nullptr;
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; // 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) TEST(span_test, from_array_constructor)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -292,7 +298,7 @@ TEST(span_test, from_array_constructor)
int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int, 6> s{arr}; span<int, 6> s{arr};
} }
@ -320,7 +326,7 @@ TEST(span_test, from_array_constructor)
{ {
span<int, 6> s{arr2d}; span<int, 6> s{arr2d};
} }
#endif #endif
{ {
const span<int[3]> s{std::addressof(arr2d[0]), 1}; const span<int[3]> s{std::addressof(arr2d[0]), 1};
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
@ -329,7 +335,7 @@ TEST(span_test, from_array_constructor)
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 #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int> s{arr3d}; span<int> s{arr3d};
EXPECT_TRUE(s.size() == 12); EXPECT_TRUE(s.size() == 12);
@ -355,7 +361,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s[0] == 1); EXPECT_TRUE(s[0] == 1);
EXPECT_TRUE(s[5] == 6); EXPECT_TRUE(s[5] == 6);
} }
#endif #endif
{ {
const span<int[3][2]> s{std::addressof(arr3d[0]), 1}; const span<int[3][2]> s{std::addressof(arr3d[0]), 1};
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
@ -368,10 +374,10 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.size() == 5); EXPECT_TRUE(s.size() == 5);
EXPECT_TRUE(s.data() == std::addressof(ao_arr[0])); EXPECT_TRUE(s.data() == std::addressof(ao_arr[0]));
} }
} }
TEST(span_test, from_dynamic_array_constructor) TEST(span_test, from_dynamic_array_constructor)
{ {
double(*arr)[3][4] = new double[100][3][4]; double(*arr)[3][4] = new double[100][3][4];
{ {
@ -381,10 +387,10 @@ TEST(span_test, from_array_constructor)
} }
delete[] arr; delete[] arr;
} }
TEST(span_test, from_std_array_constructor) TEST(span_test, from_std_array_constructor)
{ {
std::array<int, 4> arr = {1, 2, 3, 4}; std::array<int, 4> arr = {1, 2, 3, 4};
{ {
@ -422,7 +428,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(ao_arr.data() == fs.data()); EXPECT_TRUE(ao_arr.data() == fs.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int, 2> s{arr}; span<int, 2> s{arr};
EXPECT_TRUE(s.size() == 2); EXPECT_TRUE(s.size() == 2);
@ -453,7 +459,7 @@ TEST(span_test, from_array_constructor)
// try to take a temporary std::array // try to take a temporary std::array
take_a_span(get_an_array()); take_a_span(get_an_array());
} }
#endif #endif
{ {
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
@ -461,10 +467,10 @@ TEST(span_test, from_array_constructor)
// try to take a temporary std::array // try to take a temporary std::array
take_a_span(get_an_array()); take_a_span(get_an_array());
} }
} }
TEST(span_test, from_const_std_array_constructor) TEST(span_test, from_const_std_array_constructor)
{ {
const std::array<int, 4> arr = {1, 2, 3, 4}; const std::array<int, 4> arr = {1, 2, 3, 4};
{ {
@ -487,7 +493,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.data() == ao_arr.data()); EXPECT_TRUE(s.data() == ao_arr.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<const int, 2> s{arr}; span<const int, 2> s{arr};
EXPECT_TRUE(s.size() == 2); EXPECT_TRUE(s.size() == 2);
@ -503,7 +509,7 @@ TEST(span_test, from_array_constructor)
{ {
span<const int, 5> s{arr}; span<const int, 5> s{arr};
} }
#endif #endif
{ {
auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; }; auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; };
@ -511,10 +517,10 @@ TEST(span_test, from_array_constructor)
// try to take a temporary std::array // try to take a temporary std::array
take_a_span(get_an_array()); take_a_span(get_an_array());
} }
} }
TEST(span_test, from_std_array_const_constructor) TEST(span_test, from_std_array_const_constructor)
{ {
std::array<const int, 4> arr = {1, 2, 3, 4}; std::array<const int, 4> arr = {1, 2, 3, 4};
{ {
@ -529,7 +535,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<const int, 2> s{arr}; span<const int, 2> s{arr};
EXPECT_TRUE(s.size() == 2); EXPECT_TRUE(s.size() == 2);
@ -549,11 +555,11 @@ TEST(span_test, from_array_constructor)
{ {
span<int, 4> s{arr}; span<int, 4> s{arr};
} }
#endif #endif
} }
TEST(span_test, from_container_constructor) TEST(span_test, from_container_constructor)
{ {
std::vector<int> v = {1, 2, 3}; std::vector<int> v = {1, 2, 3};
const std::vector<int> cv = v; const std::vector<int> cv = v;
@ -571,31 +577,31 @@ TEST(span_test, from_array_constructor)
const std::string cstr = "hello"; const std::string cstr = "hello";
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
span<char> s{str}; span<char> s{str};
EXPECT_TRUE(s.size() == str.size()); EXPECT_TRUE(s.size() == str.size());
EXPECT_TRUE(s.data() == str.data())); EXPECT_TRUE(s.data() == str.data()));
#endif #endif
span<const char> cs{str}; span<const char> cs{str};
EXPECT_TRUE(cs.size() == str.size()); EXPECT_TRUE(cs.size() == str.size());
EXPECT_TRUE(cs.data() == str.data()); EXPECT_TRUE(cs.data() == str.data());
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
span<char> s{cstr}; span<char> s{cstr};
#endif #endif
span<const char> cs{cstr}; span<const char> cs{cstr};
EXPECT_TRUE(cs.size() == cstr.size()); EXPECT_TRUE(cs.size() == cstr.size());
EXPECT_TRUE(cs.data() == cstr.data()); EXPECT_TRUE(cs.data() == cstr.data());
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_vector = []() -> std::vector<int> { return {}; }; auto get_temp_vector = []() -> std::vector<int> { return {}; };
auto use_span = [](span<int> s) { static_cast<void>(s); }; auto use_span = [](span<int> s) { static_cast<void>(s); };
use_span(get_temp_vector()); use_span(get_temp_vector());
#endif #endif
} }
{ {
@ -605,11 +611,11 @@ TEST(span_test, from_array_constructor)
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_string = []() -> std::string { return {}; }; auto get_temp_string = []() -> std::string { return {}; };
auto use_span = [](span<char> s) { static_cast<void>(s); }; auto use_span = [](span<char> s) { static_cast<void>(s); };
use_span(get_temp_string()); use_span(get_temp_string());
#endif #endif
} }
{ {
@ -619,11 +625,11 @@ TEST(span_test, from_array_constructor)
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_vector = []() -> const std::vector<int> { return {}; }; auto get_temp_vector = []() -> const std::vector<int> { return {}; };
auto use_span = [](span<const char> s) { static_cast<void>(s); }; auto use_span = [](span<const char> s) { static_cast<void>(s); };
use_span(get_temp_vector()); use_span(get_temp_vector());
#endif #endif
} }
{ {
@ -633,49 +639,49 @@ TEST(span_test, from_array_constructor)
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
std::map<int, int> m; std::map<int, int> m;
span<int> s{m}; span<int> s{m};
#endif #endif
}
} }
}
TEST(span_test, from_convertible_span_constructor){{span<DerivedClass> avd; TEST(span_test, from_convertible_span_constructor){{span<DerivedClass> avd;
span<const DerivedClass> avcd = avd; span<const DerivedClass> avcd = avd;
static_cast<void>(avcd); static_cast<void>(avcd);
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
span<DerivedClass> avd; span<DerivedClass> avd;
span<BaseClass> avb = avd; span<BaseClass> avb = avd;
static_cast<void>(avb); static_cast<void>(avb);
#endif #endif
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int> s; span<int> s;
span<unsigned int> s2 = s; span<unsigned int> s2 = s;
static_cast<void>(s2); static_cast<void>(s2);
} }
{ {
span<int> s; span<int> s;
span<const unsigned int> s2 = s; span<const unsigned int> s2 = s;
static_cast<void>(s2); static_cast<void>(s2);
} }
{ {
span<int> s; span<int> s;
span<short> s2 = s; span<short> s2 = s;
static_cast<void>(s2); static_cast<void>(s2);
} }
#endif #endif
} }
TEST(span_test, copy_move_and_assignment) TEST(span_test, copy_move_and_assignment)
{ {
span<int> s1; span<int> s1;
EXPECT_TRUE(s1.empty()); EXPECT_TRUE(s1.empty());
@ -692,19 +698,22 @@ TEST(span_test, from_array_constructor)
auto use_span = [&](span<const int> s) { auto use_span = [&](span<const int> s) {
EXPECT_TRUE(s.size() == 2); EXPECT_TRUE(s.size() == 2);
EXPECT_TRUE(s.data() == &arr[1]); EXPECT_TRUE(s.data() == &arr[1]);
}; use_span(get_temp_span()); };
use_span(get_temp_span());
s1 = get_temp_span(); s1 = get_temp_span();
EXPECT_TRUE(s1.size() == 2); EXPECT_TRUE(s1.size() == 2);
EXPECT_TRUE(s1.data() == &arr[1]); EXPECT_TRUE(s1.data() == &arr[1]);
} }
TEST(span_test, first) TEST(span_test, first)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. first"; std::cerr << "Expected Death. first";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -727,11 +736,11 @@ TEST(span_test, from_array_constructor)
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_TRUE(av.first<6>().size() == 6); EXPECT_TRUE(av.first<6>().size() == 6);
EXPECT_TRUE(av.first<-1>().size() == -1); EXPECT_TRUE(av.first<-1>().size() == -1);
#endif #endif
EXPECT_DEATH(av.first(6).size(), deathstring); EXPECT_DEATH(av.first(6).size(), expected);
} }
{ {
@ -739,14 +748,16 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.first<0>().size() == 0); EXPECT_TRUE(av.first<0>().size() == 0);
EXPECT_TRUE(av.first(0).size() == 0); EXPECT_TRUE(av.first(0).size() == 0);
} }
} }
TEST(span_test, last) TEST(span_test, last)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. last"; std::cerr << "Expected Death. last";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -769,10 +780,10 @@ TEST(span_test, from_array_constructor)
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_TRUE(av.last<6>().size() == 6); EXPECT_TRUE(av.last<6>().size() == 6);
#endif #endif
EXPECT_DEATH(av.last(6).size(), deathstring); EXPECT_DEATH(av.last(6).size(), expected);
} }
{ {
@ -780,14 +791,16 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.last<0>().size() == 0); EXPECT_TRUE(av.last<0>().size() == 0);
EXPECT_TRUE(av.last(0).size() == 0); EXPECT_TRUE(av.last(0).size() == 0);
} }
} }
TEST(span_test, subspan) TEST(span_test, subspan)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. subspan"; std::cerr << "Expected Death. subspan";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -811,8 +824,8 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5);
EXPECT_TRUE(av.subspan(0, 5).size() == 5); EXPECT_TRUE(av.subspan(0, 5).size() == 5);
EXPECT_DEATH(av.subspan(0, 6).size(), deathstring); EXPECT_DEATH(av.subspan(0, 6).size(), expected);
EXPECT_DEATH(av.subspan(1, 5).size(), deathstring); EXPECT_DEATH(av.subspan(1, 5).size(), expected);
} }
{ {
@ -821,7 +834,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0);
EXPECT_TRUE(av.subspan(4, 0).size() == 0); EXPECT_TRUE(av.subspan(4, 0).size() == 0);
EXPECT_TRUE(av.subspan(5, 0).size() == 0); EXPECT_TRUE(av.subspan(5, 0).size() == 0);
EXPECT_DEATH(av.subspan(6, 0).size(), deathstring); EXPECT_DEATH(av.subspan(6, 0).size(), expected);
} }
{ {
@ -835,13 +848,13 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); EXPECT_TRUE((av.subspan<0, 0>().size()) == 0);
EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0);
EXPECT_TRUE(av.subspan(0, 0).size() == 0); EXPECT_TRUE(av.subspan(0, 0).size() == 0);
EXPECT_DEATH((av.subspan<1, 0>().size()), deathstring); EXPECT_DEATH((av.subspan<1, 0>().size()), expected);
} }
{ {
span<int> av; span<int> av;
EXPECT_TRUE(av.subspan(0).size() == 0); EXPECT_TRUE(av.subspan(0).size() == 0);
EXPECT_DEATH(av.subspan(1).size(), deathstring); EXPECT_DEATH(av.subspan(1).size(), expected);
} }
{ {
@ -850,7 +863,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.subspan(1).size() == 4); EXPECT_TRUE(av.subspan(1).size() == 4);
EXPECT_TRUE(av.subspan(4).size() == 1); EXPECT_TRUE(av.subspan(4).size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), deathstring); EXPECT_DEATH(av.subspan(6).size(), expected);
const auto av2 = av.subspan(1); const auto av2 = av.subspan(1);
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
} }
@ -861,21 +874,21 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.subspan(1).size() == 4); EXPECT_TRUE(av.subspan(1).size() == 4);
EXPECT_TRUE(av.subspan(4).size() == 1); EXPECT_TRUE(av.subspan(4).size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), deathstring); EXPECT_DEATH(av.subspan(6).size(), expected);
const auto av2 = av.subspan(1); const auto av2 = av.subspan(1);
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
} }
} }
TEST(span_test, iterator_default_init) TEST(span_test, iterator_default_init)
{ {
span<int>::iterator it1; span<int>::iterator it1;
span<int>::iterator it2; span<int>::iterator it2;
EXPECT_TRUE(it1 == it2); EXPECT_TRUE(it1 == it2);
} }
TEST(span_test, iterator_comparisons) TEST(span_test, iterator_comparisons)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
{ {
span<int> s = a; span<int> s = a;
@ -902,14 +915,15 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.end() > it2); EXPECT_TRUE(s.end() > it2);
EXPECT_TRUE(s.end() >= it2); EXPECT_TRUE(s.end() >= it2);
} }
} }
TEST(span_test, incomparable_iterators) TEST(span_test, incomparable_iterators)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. incomparable_iterators"; std::cerr << "Expected Death. incomparable_iterators";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
int b[] = {1, 2, 3, 4}; int b[] = {1, 2, 3, 4};
@ -917,21 +931,23 @@ TEST(span_test, from_array_constructor)
span<int> s = a; span<int> s = a;
span<int> s2 = b; span<int> s2 = b;
#if (__cplusplus > 201402L) #if (__cplusplus > 201402L)
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()), deathstring); EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), expected);
#else #else
EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), expected);
EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), expected);
#endif #endif
} }
} }
TEST(span_test, begin_end) TEST(span_test, begin_end)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. begin_end"; std::cerr << "Expected Death. begin_end";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s = a; span<int> s = a;
@ -956,7 +972,7 @@ TEST(span_test, from_array_constructor)
auto beyond = s.end(); auto beyond = s.end();
EXPECT_TRUE(it != beyond); EXPECT_TRUE(it != beyond);
EXPECT_DEATH(*beyond, deathstring); EXPECT_DEATH(*beyond, expected);
EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(beyond - first == 4);
EXPECT_TRUE(first - first == 0); EXPECT_TRUE(first - first == 0);
@ -982,14 +998,16 @@ TEST(span_test, from_array_constructor)
for (const auto& n : s) { EXPECT_TRUE(n == 5); } for (const auto& n : s) { EXPECT_TRUE(n == 5); }
} }
} }
TEST(span_test, rbegin_rend) TEST(span_test, rbegin_rend)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. rbegin_rend"; std::cerr << "Expected Death. rbegin_rend";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s = a; span<int> s = a;
@ -1002,9 +1020,9 @@ TEST(span_test, from_array_constructor)
auto beyond = s.rend(); auto beyond = s.rend();
EXPECT_TRUE(it != beyond); EXPECT_TRUE(it != beyond);
#if (__cplusplus > 201402L) #if (__cplusplus > 201402L)
EXPECT_DEATH([[maybe_unused]] auto _ = *beyond , deathstring); EXPECT_DEATH([[maybe_unused]] auto _ = *beyond, expected);
#else #else
EXPECT_DEATH(auto _ = *beyond , deathstring); EXPECT_DEATH(auto _ = *beyond, expected);
#endif #endif
EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(beyond - first == 4);
@ -1031,14 +1049,15 @@ TEST(span_test, from_array_constructor)
for (const auto& n : s) { EXPECT_TRUE(n == 5); } for (const auto& n : s) { EXPECT_TRUE(n == 5); }
} }
} }
TEST(span_test, as_bytes) TEST(span_test, as_bytes)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. as_bytes"; std::cerr << "Expected Death. as_bytes";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
{ {
@ -1068,24 +1087,24 @@ TEST(span_test, from_array_constructor)
int b[5] = {1, 2, 3, 4, 5}; int b[5] = {1, 2, 3, 4, 5};
{ {
span<int> sp(begin(b), static_cast<size_t>(-2)); span<int> sp(std::begin(b), static_cast<size_t>(-2));
EXPECT_DEATH((void) sp.size_bytes(), deathstring); EXPECT_DEATH((void) sp.size_bytes(), expected);
}
} }
}
TEST(span_test, as_writable_bytes) TEST(span_test, as_writable_bytes)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects // you should not be able to get writeable bytes for const objects
span<const int> s = a; span<const int> s = a;
EXPECT_TRUE(s.size() == 4); EXPECT_TRUE(s.size() == 4);
span<const byte> bs = as_writable_bytes(s); span<const byte> bs = as_writable_bytes(s);
EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
EXPECT_TRUE(bs.size() == s.size_bytes()); EXPECT_TRUE(bs.size() == s.size_bytes());
#endif #endif
} }
{ {
@ -1104,14 +1123,16 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data())); EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
EXPECT_TRUE(bs.size() == s.size_bytes()); EXPECT_TRUE(bs.size() == s.size_bytes());
} }
} }
TEST(span_test, fixed_size_conversions) TEST(span_test, fixed_size_conversions)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. fixed_size_conversions"; std::cerr << "Expected Death. fixed_size_conversions";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[] = {1, 2, 3, 4}; int arr[] = {1, 2, 3, 4};
// converting to an span from an equal size array is ok // converting to an span from an equal size array is ok
@ -1125,8 +1146,8 @@ TEST(span_test, from_array_constructor)
static_cast<void>(s); static_cast<void>(s);
} }
// initialization or assignment to static span that REDUCES size is NOT ok // initialization or assignment to static span that REDUCES size is NOT ok
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int, 2> s = arr; span<int, 2> s = arr;
} }
@ -1134,7 +1155,7 @@ TEST(span_test, from_array_constructor)
span<int, 2> s2 = s4; span<int, 2> s2 = s4;
static_cast<void>(s2); static_cast<void>(s2);
} }
#endif #endif
// even when done dynamically // even when done dynamically
{ {
@ -1146,7 +1167,7 @@ TEST(span_test, from_array_constructor)
const span<int, 2> s2 = s; const span<int, 2> s2 = s;
static_cast<void>(s2); static_cast<void>(s2);
}; };
EXPECT_DEATH(f(), deathstring); EXPECT_DEATH(f(), expected);
*/ */
} }
@ -1179,7 +1200,7 @@ TEST(span_test, from_array_constructor)
// initialization or assignment to static span that requires size INCREASE is not ok. // initialization or assignment to static span that requires size INCREASE is not ok.
int arr2[2] = {1, 2}; int arr2[2] = {1, 2};
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int, 4> s3 = arr2; span<int, 4> s3 = arr2;
} }
@ -1187,28 +1208,29 @@ TEST(span_test, from_array_constructor)
span<int, 2> s2 = arr2; span<int, 2> s2 = arr2;
span<int, 4> s4a = s2; span<int, 4> s4a = s2;
} }
#endif #endif
{ {
auto f = [&]() { auto f = [&]() {
const span<int, 4> _s4{arr2, 2}; const span<int, 4> _s4{arr2, 2};
static_cast<void>(_s4); static_cast<void>(_s4);
}; };
EXPECT_DEATH(f(), deathstring); 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 // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one
span<int> av = arr2; auto f = [&]() { span<int> av = arr2; auto f = [&]() {
const span<int, 4> _s4 = av; const span<int, 4> _s4 = av;
static_cast<void>(_s4); static_cast<void>(_s4);
}; };
EXPECT_DEATH(f(), deathstring); EXPECT_DEATH(f(), expected);
*/ */
} }
TEST(span_test, interop_with_std_regex) TEST(span_test, interop_with_std_regex)
{ {
char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'};
span<char> s = lat; span<char> s = lat;
const auto f_it = s.begin() + 7; const auto f_it = s.begin() + 7;
@ -1228,21 +1250,21 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(match[0].matched); EXPECT_TRUE(match[0].matched);
EXPECT_TRUE(match[0].first == f_it); EXPECT_TRUE(match[0].first == f_it);
EXPECT_TRUE(match[0].second == (f_it + 1)); EXPECT_TRUE(match[0].second == (f_it + 1));
} }
TEST(span_test, default_constructible) TEST(span_test, default_constructible)
{ {
EXPECT_TRUE((std::is_default_constructible<span<int>>::value)); EXPECT_TRUE((std::is_default_constructible<span<int>>::value));
EXPECT_TRUE((std::is_default_constructible<span<int, 0>>::value)); EXPECT_TRUE((std::is_default_constructible<span<int, 0>>::value));
EXPECT_FALSE((std::is_default_constructible<span<int, 42>>::value)); EXPECT_FALSE((std::is_default_constructible<span<int, 42>>::value));
} }
TEST(span_test, std_container_ctad) TEST(span_test, std_container_ctad)
{ {
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
// this test is just to verify that these compile // 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}; gsl::span sp{v};
static_assert(std::is_same<decltype(sp), gsl::span<int>>::value); static_assert(std::is_same<decltype(sp), gsl::span<int>>::value);
} }
@ -1259,20 +1281,39 @@ TEST(span_test, from_array_constructor)
} }
#endif #endif
#endif #endif
} }
TEST(span_test, front_back) TEST(span_test, front_back)
{ {
int arr[5] = {1,2,3,4,5}; int arr[5] = {1, 2, 3, 4, 5};
span<int> s{arr}; span<int> s{arr};
EXPECT_TRUE(s.front() == 1); EXPECT_TRUE(s.front() == 1);
EXPECT_TRUE(s.back() == 5); EXPECT_TRUE(s.back() == 5);
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. front_back"; std::cerr << "Expected Death. front_back";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
span<int> s2; span<int> s2;
EXPECT_DEATH(s2.front(), deathstring); EXPECT_DEATH(s2.front(), expected);
EXPECT_DEATH(s2.back(), deathstring); 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

View File

@ -14,30 +14,40 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gtest/gtest.h>
namespace gsl #include "deathTestCommon.h"
{
struct fail_fast;
} // namespace gsl
using namespace gsl; using namespace gsl;
namespace
{
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper(strict_not_null<int*> p) { return *p == 12; } bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; } bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
#ifdef CONFIRM_COMPILATION_ERRORS
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
const int* return_pointer_const() { return nullptr; } const int* return_pointer_const() { return nullptr; }
#endif
} // namespace
TEST(strict_notnull_tests, TestStrictNotNull) TEST(strict_notnull_tests, TestStrictNotNull)
{ {
@ -123,17 +133,14 @@ TEST(strict_notnull_tests, TestStrictNotNull)
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int i = 42; int i = 42;
@ -161,7 +168,7 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
int* p1 = nullptr; int* p1 = nullptr;
const strict_not_null x{p1}; 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 int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(strict_not_null{p}), deathstring); EXPECT_DEATH(helper(strict_not_null{p}), expected);
EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring); EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS

View File

@ -28,13 +28,10 @@
#include <type_traits> // for remove_reference<>::type #include <type_traits> // for remove_reference<>::type
#include <vector> // for vector, allocator #include <vector> // for vector, allocator
using namespace std; #include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
// Generic string functions // Generic string functions
namespace generic namespace generic
@ -76,8 +73,7 @@ T create()
template <class T> template <class T>
void use(basic_string_span<T, gsl::dynamic_extent>) void use(basic_string_span<T, gsl::dynamic_extent>)
{ {}
}
#endif #endif
czstring_span<> CreateTempName(string_span<> span) czstring_span<> CreateTempName(string_span<> span)
@ -85,7 +81,8 @@ czstring_span<> CreateTempName(string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = 't'; span[0] = 't';
span[1] = 'm'; span[1] = 'm';
span[2] = 'p'; span[2] = 'p';
@ -102,7 +99,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = L't'; span[0] = L't';
span[1] = L'm'; span[1] = L'm';
span[2] = L'p'; span[2] = L'p';
@ -119,7 +117,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = u't'; span[0] = u't';
span[1] = u'm'; span[1] = u'm';
span[2] = u'p'; span[2] = u'p';
@ -136,7 +135,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = U't'; span[0] = U't';
span[1] = U'm'; span[1] = U'm';
span[2] = U'p'; span[2] = U'p';
@ -950,10 +950,11 @@ TEST(string_span_tests, Conversion)
TEST(string_span_tests, zstring) TEST(string_span_tests, zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. zstring"; std::cerr << "Expected Death. zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -973,7 +974,7 @@ TEST(string_span_tests, zstring)
buf[0] = 'a'; buf[0] = 'a';
auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; 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 // 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]; char buf[10];
auto name = CreateTempName({buf, 10}); auto name = CreateTempName({buf, 10});
if (!name.empty()) { if (!name.empty())
czstring<> str = name.assume_z(); {
czstring str = name.assume_z();
EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(generic::strlen(str) == 3);
EXPECT_TRUE(*(str + 3) == '\0'); EXPECT_TRUE(*(str + 3) == '\0');
} }
@ -991,10 +993,11 @@ TEST(string_span_tests, zstring)
TEST(string_span_tests, wzstring) TEST(string_span_tests, wzstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. wzstring"; std::cerr << "Expected Death. wzstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1014,7 +1017,7 @@ TEST(string_span_tests, wzstring)
buf[0] = L'a'; buf[0] = L'a';
const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; 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 // 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]; wchar_t buf[10];
const auto name = CreateTempNameW({buf, 10}); const auto name = CreateTempNameW({buf, 10});
if (!name.empty()) { if (!name.empty())
cwzstring<> str = name.assume_z(); {
cwzstring str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
} }
@ -1032,10 +1036,11 @@ TEST(string_span_tests, wzstring)
TEST(string_span_tests, u16zstring) TEST(string_span_tests, u16zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u16zstring"; std::cerr << "Expected Death. u16zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1055,7 +1060,7 @@ TEST(string_span_tests, u16zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; 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 // 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]; char16_t buf[10];
const auto name = CreateTempNameU16({buf, 10}); const auto name = CreateTempNameU16({buf, 10});
if (!name.empty()) { if (!name.empty())
cu16zstring<> str = name.assume_z(); {
cu16zstring str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
} }
@ -1073,10 +1079,11 @@ TEST(string_span_tests, u16zstring)
TEST(string_span_tests, u32zstring) TEST(string_span_tests, u32zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u31zstring"; std::cerr << "Expected Death. u31zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1096,7 +1103,7 @@ TEST(string_span_tests, u32zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; 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 // 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]; char32_t buf[10];
const auto name = CreateTempNameU32({buf, 10}); const auto name = CreateTempNameU32({buf, 10});
if (!name.empty()) { if (!name.empty())
cu32zstring<> str = name.assume_z(); {
cu32zstring str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
} }

View File

@ -16,14 +16,15 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/util> // finally, narrow_cast
#include <gsl/narrow> // for narrow, narrowing_error
#include <algorithm> // for move #include <algorithm> // for move
#include <complex>
#include <cstddef> // for std::ptrdiff_t
#include <functional> // for reference_wrapper, _Bind_helper<>::type #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 <limits> // for numeric_limits
#include <stdint.h> // for uint32_t, int32_t #include <stdint.h> // for uint32_t, int32_t
#include <type_traits> // for is_same #include <type_traits> // for is_same
#include <cstddef> // for std::ptrdiff_t
using namespace gsl; using namespace gsl;
@ -32,8 +33,7 @@ namespace
void f(int& i) { i += 1; } void f(int& i) { i += 1; }
static int j = 0; static int j = 0;
void g() { j += 1; } void g() { j += 1; }
} } // namespace
TEST(utils_tests, sanity_check_for_gsl_index_typedef) TEST(utils_tests, sanity_check_for_gsl_index_typedef)
{ {
@ -123,6 +123,7 @@ TEST(utils_tests, narrow_cast)
EXPECT_TRUE(uc == 44); EXPECT_TRUE(uc == 44);
} }
#ifndef GSL_KERNEL_MODE
TEST(utils_tests, narrow) TEST(utils_tests, narrow)
{ {
int n = 120; int n = 120;
@ -144,4 +145,11 @@ TEST(utils_tests, narrow)
n = -42; n = -42;
EXPECT_THROW(narrow<unsigned>(n), narrowing_error); 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