mirror of
https://github.com/microsoft/GSL.git
synced 2025-04-02 09:18:33 -04:00
Compare commits
237 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3325bbd33d | ||
|
2828399820 | ||
|
c5fbb81ad4 | ||
|
7fabaa499d | ||
|
4742bc192a | ||
|
ec729d63a7 | ||
|
7f4fc9388b | ||
|
355982daf6 | ||
|
50aaf2efbb | ||
|
7b6b8013b1 | ||
|
1cdb8d295e | ||
|
c832885f15 | ||
|
16a60199df | ||
|
fcd55ee924 | ||
|
b8ac820fe1 | ||
|
272463043e | ||
|
8a0e3d8a9b | ||
|
aed09c41b6 | ||
|
4b190d2e2a | ||
|
ddae9d72b6 | ||
|
74d2bb79d4 | ||
|
f8ec309118 | ||
|
87f9d76886 | ||
|
82ba6c77ce | ||
|
32511b8de4 | ||
|
84b2ca1352 | ||
|
ce2a959e02 | ||
|
11fe02d1ac | ||
|
3275f9ccb9 | ||
|
b206bd163b | ||
|
b39e7e4b09 | ||
|
2e0d1ba48c | ||
|
1b4d42ca2e | ||
|
caae4dd0f8 | ||
|
f1a494cfd2 | ||
|
77b2f4f3b8 | ||
|
e64c97fc2c | ||
|
52212c2d76 | ||
|
2940006b5c | ||
|
9695da9b38 | ||
|
4300304ef2 | ||
|
b34f7350fe | ||
|
167c77d28e | ||
|
87e21400dc | ||
|
3549e31ba4 | ||
|
65a5995035 | ||
|
303d964a24 | ||
|
afaaa71bce | ||
|
4b5b5a1ed5 | ||
|
5dc7fae119 | ||
|
9face82309 | ||
|
1d036585cc | ||
|
43d60c5e38 | ||
|
50d6eef541 | ||
|
b080081c9c | ||
|
9f85e4e088 | ||
|
78eb6ca145 | ||
|
7f7108a076 | ||
|
7a297d4283 | ||
|
9851b94d7e | ||
|
743939744c | ||
|
3ba80d5dd4 | ||
|
49c88f27bd | ||
|
f7da2e41f0 | ||
|
cbf5e664fc | ||
|
a381a3759f | ||
|
0822838a7c | ||
|
f94c1f6f2b | ||
|
ac26d7bc71 | ||
|
c016bdc77f | ||
|
46c72713f2 | ||
|
6c6111acb7 | ||
|
f3620bb009 | ||
|
517ed29228 | ||
|
d69e578519 | ||
|
9c4212aca4 | ||
|
1e0d0446dd | ||
|
c52bad36aa | ||
|
991fa6682e | ||
|
7d49d4b45d | ||
|
849f7ceaf7 | ||
|
1683d87a3f | ||
|
10df83d292 | ||
|
2e94541fcf | ||
|
330583f478 | ||
|
d9fc52e20e | ||
|
da01eb28db | ||
|
d8c493c89f | ||
|
7fefaaf2c8 | ||
|
f21f29d210 | ||
|
2bfd495080 | ||
|
383723676c | ||
|
f22f524aa2 | ||
|
4377f6e603 | ||
|
a353456718 | ||
|
99a29ce797 | ||
|
ebf0498363 | ||
|
c412deb31e | ||
|
bcf008ae55 | ||
|
e0880931ae | ||
|
c31a9ad5e8 | ||
|
da80ce15d8 | ||
|
f09b24970d | ||
|
8a4b9ed0bf | ||
|
b26f6d5ec7 | ||
|
c1cbb41b42 | ||
|
ef0ffefe52 | ||
|
176c92e802 | ||
|
84aeb59f26 | ||
|
d9fa328f89 | ||
|
d0052f6320 | ||
|
3b3478eaf8 | ||
|
e427b02c89 | ||
|
25bb4bd948 | ||
|
1c509ad8e1 | ||
|
eca0eca6f1 | ||
|
a47352cb2a | ||
|
d15cb5fdbe | ||
|
a6cef6bc6c | ||
|
ec6cd75d57 | ||
|
0140ab1d73 | ||
|
475b785d2c | ||
|
959ce58bbc | ||
|
804a14fe8b | ||
|
00d4a5aab6 | ||
|
9150ce9a95 | ||
|
a150aaa4ed | ||
|
e8978c01ab | ||
|
2c3ab0211c | ||
|
179fba51f5 | ||
|
d74ae54b60 | ||
|
b6c57e2403 | ||
|
736b62a838 | ||
|
6f4529395c | ||
|
9fa2c5d5b9 | ||
|
8009a703c2 | ||
|
cfb4db0c1e | ||
|
6432f920ea | ||
|
2af9b11fe9 | ||
|
dc6fdff4c0 | ||
|
2ccf36b4b9 | ||
|
bd23bdc0ad | ||
|
1665f07cf6 | ||
|
3f68a0034a | ||
|
7721de88f3 | ||
|
a64c489c78 | ||
|
5e773556fe | ||
|
5de956aaf0 | ||
|
bd803cc7cf | ||
|
e7e3bf4f5f | ||
|
21b69e5cce | ||
|
d58e50c6f4 | ||
|
5fb0c8611e | ||
|
6c518638ac | ||
|
4a4bb3c13a | ||
|
b6451c5db0 | ||
|
81957f6f91 | ||
|
6aa755e9ce | ||
|
e426750695 | ||
|
c25a7544b8 | ||
|
06c46195ee | ||
|
83ce710d6c | ||
|
ec471abe44 | ||
|
dad3d80c25 | ||
|
a9ffcf7f65 | ||
|
e09326eefd | ||
|
d09f1544fd | ||
|
74968d3ef8 | ||
|
0c80f51f7c | ||
|
ef714fa49e | ||
|
9355982fc5 | ||
|
4da6a264c4 | ||
|
2469db7a5a | ||
|
afe824490e | ||
|
72ddfb7a40 | ||
|
bf0697be71 | ||
|
97cb97c685 | ||
|
13f57a1e70 | ||
|
c482c82d3a | ||
|
01eaf5bef1 | ||
|
63379b7935 | ||
|
2231d733c6 | ||
|
f8d9f2e2e3 | ||
|
552eedb390 | ||
|
ca3bf7710f | ||
|
559f8cfaae | ||
|
f79ed1bb5c | ||
|
bf6e103dfd | ||
|
4c66cea06c | ||
|
478d876951 | ||
|
853b061141 | ||
|
301030310e | ||
|
be3bc0e754 | ||
|
98002ab601 | ||
|
cfe9baf02e | ||
|
0f6dbc9e29 | ||
|
78744ed530 | ||
|
794d7bb69b | ||
|
72803a7ecb | ||
|
4d2090ebc4 | ||
|
c4a2ce6cc8 | ||
|
9720cc552a | ||
|
c143a07f61 | ||
|
6c405a1b7f | ||
|
689abc2982 | ||
|
0dbdf322fa | ||
|
283e31478f | ||
|
8cd19412b4 | ||
|
25e7af9c7d | ||
|
7e4ed8da98 | ||
|
34750814fb | ||
|
313a1121bf | ||
|
1e44481646 | ||
|
ed3fea6d93 | ||
|
31604f44f6 | ||
|
d3468230b1 | ||
|
552cd20472 | ||
|
2085c7acde | ||
|
33544a706e | ||
|
f0160fcb1b | ||
|
2a483c1728 | ||
|
031231466d | ||
|
a6d382109e | ||
|
09caa20d99 | ||
|
0843ea444f | ||
|
1e4e23738c | ||
|
839de21707 | ||
|
91858ca3f3 | ||
|
0ab350f5de | ||
|
84847041ee | ||
|
1e5f44d3ea | ||
|
de053645bb | ||
|
29297e7dac | ||
|
879335cebf | ||
|
f5cf01083b | ||
|
830b081de7 | ||
|
423841e965 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
include/gsl/* linguist-language=C++
|
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'Status: Open, Type: Bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
```c++
|
||||
#include <gsl>
|
||||
|
||||
// your repro here: ...
|
||||
```
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Spec (please complete the following information):**
|
||||
- OS: [e.g. Windows]
|
||||
- Compiler: [e.g. MSVC]
|
||||
- C++ Version: [e.g. C++20]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
59
.github/workflows/android.yml
vendored
Normal file
59
.github/workflows/android.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
name: CI_Android
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
Android:
|
||||
runs-on: macos-latest-large
|
||||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
working-directory: .
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 8
|
||||
distribution: zulu
|
||||
|
||||
- name: Start Emulator
|
||||
run: |
|
||||
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-24;default;x86_64'
|
||||
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-24;default;x86_64' --force
|
||||
$ANDROID_HOME/emulator/emulator -list-avds
|
||||
echo "Starting emulator..."
|
||||
nohup $ANDROID_HOME/emulator/emulator -no-audio -no-snapshot -avd xamarin_android_emulator &> /dev/null &
|
||||
echo "Emulator starting in background"
|
||||
|
||||
- name: Configure
|
||||
run: cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --parallel
|
||||
|
||||
- name: Wait for emulator ready
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 10; done; input keyevent 82'
|
||||
$ANDROID_HOME/platform-tools/adb devices
|
||||
$ANDROID_HOME/platform-tools/adb shell getprop ro.product.cpu.abi
|
||||
|
||||
- name: Deploy tests
|
||||
run: |
|
||||
adb push tests /data/local/tmp
|
||||
adb shell find /data/local/tmp/tests -maxdepth 1 -exec chmod +x {} \\\;
|
||||
|
||||
- name: Test
|
||||
run: adb shell find /data/local/tmp/tests -name "*_tests" -maxdepth 1 -exec {} \\\;
|
56
.github/workflows/cmake/action.yml
vendored
Normal file
56
.github/workflows/cmake/action.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name: Composite CMake
|
||||
inputs:
|
||||
cmake_generator:
|
||||
required: false
|
||||
type: string
|
||||
default: 'Unix Makefiles'
|
||||
cmake_build_type:
|
||||
required: true
|
||||
type: string
|
||||
default: ''
|
||||
cmake_cxx_compiler:
|
||||
required: false
|
||||
type: string
|
||||
gsl_cxx_standard:
|
||||
required: true
|
||||
type: number
|
||||
extra_cmake_args:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
build_cmd:
|
||||
required: true
|
||||
type: string
|
||||
default: 'make'
|
||||
test_cmd:
|
||||
required: false
|
||||
type: string
|
||||
default: 'make test'
|
||||
shell:
|
||||
required: false
|
||||
type: string
|
||||
default: 'bash'
|
||||
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create build directory
|
||||
run: mkdir build
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: build
|
||||
run: cmake -G "${{ inputs.cmake_generator }}" -DCMAKE_BUILD_TYPE=${{ inputs.cmake_build_type }} -DCMAKE_CXX_COMPILER=${{ inputs.cmake_cxx_compiler }} -DGSL_CXX_STANDARD=${{ inputs.gsl_cxx_standard }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ inputs.extra_cmake_args }} ..
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: ${{ inputs.build_cmd }}
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Test
|
||||
working-directory: build
|
||||
run: ${{ inputs.test_cmd }}
|
||||
shell: ${{ inputs.shell }}
|
||||
|
25
.github/workflows/cmake_find_package.yml
vendored
Normal file
25
.github/workflows/cmake_find_package.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: cmake_find_package
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
cmake-find-package:
|
||||
name: Build ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-latest ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.14.0
|
||||
- name: Configure GSL
|
||||
run: cmake -S . -B build -G "Ninja" -D GSL_TEST=OFF -D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/build/install
|
||||
- name: Install GSL
|
||||
run: cmake --build build --target install
|
||||
- name: Test GSL find_package support
|
||||
run: cmake -S tests/ -B build/tests_find_package -G "Ninja" -D CMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/build/install -D CMAKE_BUILD_TYPE=Release
|
115
.github/workflows/compilers.yml
vendored
Normal file
115
.github/workflows/compilers.yml
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
name: Compiler Integration Tests
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
# These jobs are correlated with the officially supported compilers
|
||||
# and toolsets. If you change any versions, please update README.md.
|
||||
|
||||
jobs:
|
||||
gcc:
|
||||
strategy:
|
||||
matrix:
|
||||
gcc_version: [ 12, 13, 14 ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
# https://github.com/google/googletest/issues/4232
|
||||
# Looks like GoogleTest is not interested in making version 1.14
|
||||
# work with gcc-12.
|
||||
- gcc_version: 12
|
||||
cxx_version: 20
|
||||
- gcc_version: 12
|
||||
cxx_version: 23
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: g++-${{ matrix.gcc_version }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
clang:
|
||||
strategy:
|
||||
matrix:
|
||||
clang_version: [ 16, 17, 18 ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
# https://github.com/llvm/llvm-project/issues/93734
|
||||
# Looks like clang fixed this issue in clang-18, but won't backport
|
||||
# the fix.
|
||||
- clang_version: 17
|
||||
cxx_version: 23
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: clang++-${{ matrix.clang_version }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
xcode:
|
||||
strategy:
|
||||
matrix:
|
||||
xcode_version: [ '15.4' ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: select xcode version
|
||||
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode_version }}.app
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: clang++
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
VisualStudio:
|
||||
strategy:
|
||||
matrix:
|
||||
generator: [ 'Visual Studio 16 2019', 'Visual Studio 17 2022' ]
|
||||
image: [ windows-2019, windows-2022 ]
|
||||
build_type: [ Debug, Release ]
|
||||
extra_args: [ '', '-T ClangCL' ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
- generator: 'Visual Studio 17 2022'
|
||||
image: windows-2019
|
||||
- generator: 'Visual Studio 16 2019'
|
||||
image: windows-2022
|
||||
- generator: 'Visual Studio 16 2019'
|
||||
cxx_version: 23
|
||||
runs-on: ${{ matrix.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_generator: ${{ matrix.generator }}
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
extra_cmake_args: ${{ matrix.extra_args }}
|
||||
build_cmd: msbuild GSL.sln
|
||||
test_cmd: ctest . --output-on-failure --no-compress-output
|
||||
shell: pwsh
|
||||
|
52
.github/workflows/ios.yml
vendored
Normal file
52
.github/workflows/ios.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
name: CI_iOS
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
iOS:
|
||||
runs-on: macos-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
working-directory: .
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-Werror=dev \
|
||||
-GXcode \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=9 \
|
||||
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
|
||||
"-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \
|
||||
-DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \
|
||||
-DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \
|
||||
..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --parallel `sysctl -n hw.ncpu` --config Release -- -sdk iphonesimulator
|
||||
|
||||
- name: Start simulator
|
||||
run: |
|
||||
RUNTIME=`xcrun simctl list runtimes iOS -j|jq '.runtimes|last.identifier'`
|
||||
UDID=`xcrun simctl list devices iPhone available -j|jq -r ".devices[$RUNTIME]|last.udid"`
|
||||
xcrun simctl bootstatus $UDID -b
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
for TEST in `find tests/Release-iphonesimulator -depth 1 -name "*.app"`
|
||||
do
|
||||
xcrun simctl install booted $TEST
|
||||
TEST_ID=`plutil -convert json -o - $TEST/Info.plist|jq -r ".CFBundleIdentifier"`
|
||||
xcrun simctl launch --console booted $TEST_ID
|
||||
xcrun simctl uninstall booted $TEST_ID
|
||||
done
|
551
.travis.yml
551
.travis.yml
@ -1,551 +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 # build jobs to run first and always
|
||||
- name: Validation # run other jobs
|
||||
- name: Legacy # build with all other supported compilers
|
||||
|
||||
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 8.3
|
||||
- name: AppleClang Xcode-8.3 C++14 Debug
|
||||
stage: Legacy
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
- name: AppleClang Xcode-8.3 C++14 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
|
||||
# Xcode 9.0 earliest C++17 support
|
||||
- name: AppleClang Xcode-9.0 C++17 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode9 # AppleClang 9.1.0 same compiler in Xcode 9.0, 9.1 and 9.2
|
||||
- name: AppleClang Xcode-9.0 C++17 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode9
|
||||
- name: AppleClang Xcode-9.0 C++14 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode9
|
||||
- name: AppleClang Xcode-9.0 C++14 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode9
|
||||
|
||||
# Xcode 9.4
|
||||
- name: AppleClang Xcode-9.4 C++14 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode9.4 # AppleClang 9.1.0 same compiler as Xcode 9.3
|
||||
- name: AppleClang Xcode-9.4 C++14 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode9.4
|
||||
- name: AppleClang Xcode-9.4 C++17 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode9.4
|
||||
- name: AppleClang Xcode-9.4 C++17 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode9.4
|
||||
|
||||
# Xcode 10.1
|
||||
- name: AppleClang Xcode-10.1 C++14 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode10.1 # AppleClang 10.0.0 same compiler as Xcode 10.0
|
||||
- name: AppleClang Xcode-10.1 C++14 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
- name: AppleClang Xcode-10.1 C++17 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
- name: AppleClang Xcode-10.1 C++17 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
|
||||
# Xcode 10.3
|
||||
- name: AppleClang Xcode-10.3 C++14 Debug
|
||||
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.3
|
||||
- name: AppleClang Xcode-11.3 C++17 Debug
|
||||
stage: Latest
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode11.3 # AppleClang 11.0.0 linker update / same as Xcode 11.2
|
||||
- name: AppleClang Xcode-11.3 C++17 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
os: osx
|
||||
osx_image: xcode11.3
|
||||
- name: AppleClang Xcode-11.3 C++14 Debug
|
||||
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode11.3
|
||||
- name: AppleClang Xcode-11.3 C++14 Release
|
||||
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
os: osx
|
||||
osx_image: xcode11.3
|
||||
|
||||
##########################################################################
|
||||
# Clang on Linux
|
||||
##########################################################################
|
||||
|
||||
# Clang 3.6
|
||||
- name: Clang-3.6 C++14 Debug
|
||||
stage: Legacy
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.6 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang36
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
- name: Clang-3.6 C++14 Release
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.6 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang36
|
||||
|
||||
# Clang 3.7
|
||||
- name: Clang-3.7 C++14 Debug
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.7 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang37
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.7
|
||||
- name: Clang-3.7 C++14 Release
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.7 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang37
|
||||
|
||||
# Clang 3.8
|
||||
- name: Clang-3.8 C++14 Debug
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang38
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- name: Clang-3.8 C++14 Release
|
||||
dist: xenial
|
||||
env: CXX=clang++-3.8 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang38
|
||||
|
||||
# Clang 3.9
|
||||
- name: Clang-3.9 C++14 Debug
|
||||
env: CXX=clang++-3.9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang39
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.9
|
||||
- name: Clang-3.9 C++14 Release
|
||||
env: CXX=clang++-3.9 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang39
|
||||
|
||||
# Clang 4.0
|
||||
- name: Clang-4.0 C++14 Debug
|
||||
env: CXX=clang++-4.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang40
|
||||
apt:
|
||||
packages:
|
||||
- clang-4.0
|
||||
- name: Clang-4.0 C++14 Release
|
||||
env: CXX=clang++-4.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang40
|
||||
|
||||
# Clang 5.0
|
||||
- name: Clang-5.0 C++14 Debug
|
||||
env: CXX=clang++-5.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang50
|
||||
apt:
|
||||
packages:
|
||||
- clang-5.0
|
||||
- name: Clang-5.0 C++14 Release
|
||||
env: CXX=clang++-5.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang50
|
||||
- name: Clang-5.0 C++17 Debug
|
||||
env: CXX=clang++-5.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
addons: *clang50
|
||||
- name: Clang 5.0 C++17 Release
|
||||
env: CXX=clang++-5.0 BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
addons: *clang50
|
||||
|
||||
# Clang 6.0
|
||||
- name: Clang-6.0 C++14 Debug
|
||||
env: CXX=clang++-6.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang60
|
||||
apt:
|
||||
packages:
|
||||
- clang-6.0
|
||||
- name: Clang 6.0 C++14 Release
|
||||
env: CXX=clang++-6.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang60
|
||||
- name: Clang-6.0 C++17 Debug
|
||||
env: CXX=clang++-6.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
addons: *clang60
|
||||
- name: Clang 6.0 C++17 Release
|
||||
env: CXX=clang++-6.0 BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
addons: *clang60
|
||||
|
||||
# Clang 7 (default on Xenial and Bionic images)
|
||||
- name: Clang-7 C++14 Debug
|
||||
env: CXX=clang++ BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
- name: Clang-7 C++14 Release
|
||||
env: CXX=clang++ BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
- name: Clang-7 C++17 Debug
|
||||
env: CXX=clang++ BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
- name: Clang-7 C++17 Release
|
||||
env: CXX=clang++ BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
|
||||
# Clang 8
|
||||
- name: Clang-8 C++14 Debug
|
||||
env: CXX=clang++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &clang8
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main'
|
||||
key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
packages:
|
||||
- clang-8
|
||||
- name: Clang-8 C++14 Release
|
||||
env: CXX=clang++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *clang8
|
||||
- name: Clang-8 C++17 Debug
|
||||
env: CXX=clang++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
addons: *clang8
|
||||
- name: Clang-8 C++17 Release
|
||||
env: CXX=clang++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
addons: *clang8
|
||||
|
||||
# Clang 9
|
||||
- name: Clang-9 C++14 Debug
|
||||
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 5 (default on the Xenial image)
|
||||
- name: GCC-5 C++14 Debug
|
||||
stage: Legacy
|
||||
dist: xenial
|
||||
env: CXX=g++-5 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
- name: GCC-5 C++14 Release
|
||||
dist: xenial
|
||||
env: CXX=g++-5 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
|
||||
# GCC 6
|
||||
- name: GCC-6 C++14 Debug
|
||||
env: CXX=g++-6 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
addons: &gcc6
|
||||
apt:
|
||||
packages: g++-6
|
||||
- name: GCC-6 C++14 Release
|
||||
env: CXX=g++-6 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
addons: *gcc6
|
||||
|
||||
# GCC 7 (default on the Bionic image)
|
||||
- name: GCC-7 C++14 Debug
|
||||
env: CXX=g++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
|
||||
- name: GCC-7 C++14 Release
|
||||
env: CXX=g++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=14
|
||||
- name: GCC-7 C++17 Debug
|
||||
env: CXX=g++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
|
||||
- name: GCC-7 C++17 Release
|
||||
env: CXX=g++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=17
|
||||
|
||||
# GCC 8
|
||||
- name: GCC-8 C++14 Debug
|
||||
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}
|
139
CMakeLists.txt
139
CMakeLists.txt
@ -1,103 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.1.3...3.16)
|
||||
cmake_minimum_required(VERSION 3.14...3.16)
|
||||
|
||||
project(GSL CXX)
|
||||
project(GSL VERSION 4.2.0 LANGUAGES CXX)
|
||||
|
||||
include(ExternalProject)
|
||||
find_package(Git)
|
||||
|
||||
# Use GNUInstallDirs to provide the right locations on all platforms
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# creates a library GSL which is an interface (header files only)
|
||||
add_library(GSL INTERFACE)
|
||||
|
||||
# determine whether this is a standalone project or included by other projects
|
||||
set(GSL_STANDALONE_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(GSL_STANDALONE_PROJECT ON)
|
||||
endif ()
|
||||
|
||||
set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard")
|
||||
set(GSL_CXX_STD "cxx_std_${GSL_CXX_STANDARD}")
|
||||
|
||||
if (MSVC)
|
||||
set(GSL_CXX_STD_OPT "-std:c++${GSL_CXX_STANDARD}")
|
||||
else()
|
||||
set(GSL_CXX_STD_OPT "-std=c++${GSL_CXX_STANDARD}")
|
||||
endif()
|
||||
|
||||
# when minimum version required is 3.8.0 remove if below
|
||||
# both branches do exactly the same thing
|
||||
if (CMAKE_VERSION VERSION_LESS 3.7.9)
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("${GSL_CXX_STD_OPT}" COMPILER_SUPPORTS_CXX_STANDARD)
|
||||
|
||||
if(COMPILER_SUPPORTS_CXX_STANDARD)
|
||||
target_compile_options(GSL INTERFACE "${GSL_CXX_STD_OPT}")
|
||||
else()
|
||||
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no c++${GSL_CXX_STANDARD} support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
else ()
|
||||
target_compile_features(GSL INTERFACE "${GSL_CXX_STD}")
|
||||
# on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
# add definitions to the library and targets that consume it
|
||||
target_compile_definitions(GSL INTERFACE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:
|
||||
# remove unnecessary warnings about unchecked iterators
|
||||
_SCL_SECURE_NO_WARNINGS
|
||||
# remove deprecation warnings about std::uncaught_exception() (from catch)
|
||||
_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING
|
||||
>
|
||||
)
|
||||
|
||||
# add include folders to the library and targets that consume it
|
||||
# the SYSTEM keyword suppresses warnings for users of the library
|
||||
if(GSL_STANDALONE_PROJECT)
|
||||
target_include_directories(GSL INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
else()
|
||||
target_include_directories(GSL SYSTEM INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.7.8)
|
||||
if (MSVC_IDE)
|
||||
option(VS_ADD_NATIVE_VISUALIZERS "Configure project to use Visual Studio native visualizers" TRUE)
|
||||
else()
|
||||
set(VS_ADD_NATIVE_VISUALIZERS FALSE CACHE INTERNAL "Native visualizers are Visual Studio extension" FORCE)
|
||||
endif()
|
||||
|
||||
# add natvis file to the library so it will automatically be loaded into Visual Studio
|
||||
if(VS_ADD_NATIVE_VISUALIZERS)
|
||||
target_sources(GSL INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/GSL.natvis>
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(TARGETS GSL EXPORT Microsoft.GSLConfig)
|
||||
install(
|
||||
DIRECTORY include/gsl
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
# Make library importable by other projects
|
||||
install(EXPORT Microsoft.GSLConfig NAMESPACE Microsoft.GSL:: DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
|
||||
export(TARGETS GSL NAMESPACE Microsoft.GSL:: FILE Microsoft.GSLConfig.cmake)
|
||||
|
||||
# Add Microsoft.GSL::GSL alias for GSL so that dependents can be agnostic about
|
||||
# whether GSL was added via `add_subdirectory` or `find_package`
|
||||
add_library(Microsoft.GSL::GSL ALIAS GSL)
|
||||
|
||||
option(GSL_TEST "Generate tests." ${GSL_STANDALONE_PROJECT})
|
||||
# https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html
|
||||
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL)
|
||||
|
||||
option(GSL_INSTALL "Generate and install GSL target" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(GSL_TEST "Build and perform GSL tests" ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
# The implementation generally assumes a platform that implements C++14 support
|
||||
target_compile_features(GSL INTERFACE "cxx_std_14")
|
||||
|
||||
# Setup include directory
|
||||
add_subdirectory(include)
|
||||
|
||||
target_sources(GSL INTERFACE $<BUILD_INTERFACE:${GSL_SOURCE_DIR}/GSL.natvis>)
|
||||
|
||||
if (GSL_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif ()
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (GSL_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/gsl" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(export_name "Microsoft.GSLConfig")
|
||||
set(namespace "Microsoft.GSL::")
|
||||
set(cmake_files_install_dir ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
|
||||
|
||||
install(TARGETS GSL EXPORT ${export_name} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(EXPORT ${export_name} NAMESPACE ${namespace} DESTINATION ${cmake_files_install_dir})
|
||||
export(TARGETS GSL NAMESPACE ${namespace} FILE ${export_name}.cmake)
|
||||
|
||||
set(gls_config_version "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake")
|
||||
|
||||
write_basic_package_version_file(${gls_config_version} COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT)
|
||||
|
||||
install(FILES ${gls_config_version} DESTINATION ${cmake_files_install_dir})
|
||||
|
||||
install(FILES GSL.natvis DESTINATION ${cmake_files_install_dir})
|
||||
endif()
|
||||
|
@ -17,7 +17,7 @@ Please submit a Contributor License Agreement (CLA) before submitting a pull req
|
||||
Your pull request should:
|
||||
|
||||
* Include a description of what your change intends to do
|
||||
* Be a child commit of a reasonably recent commit in the **master** branch
|
||||
* Be a child commit of a reasonably recent commit in the **main** branch
|
||||
* Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR)
|
||||
* It is desirable, but not necessary, for the tests to pass at each commit. Please see [README.md](./README.md) for instructions to build the test suite.
|
||||
* Have clear commit messages
|
||||
|
74
GSL.natvis
74
GSL.natvis
@ -4,13 +4,7 @@
|
||||
vim: syntax=xml
|
||||
-->
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<!-- These types are from the gsl_assert header. -->
|
||||
<Type Name="gsl::fail_fast">
|
||||
<!-- na hides the address, otherwise it would appear as 0x.... "Message" -->
|
||||
<DisplayString>{_Data._What,nasb}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<!-- These types are from the gsl_util header. -->
|
||||
<!-- These types are from the util header. -->
|
||||
<Type Name="gsl::final_action<*>">
|
||||
<DisplayString>{{ invoke = {invoke_}, action = {f_} }}</DisplayString>
|
||||
<Expand>
|
||||
@ -19,9 +13,8 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- These types are from the span header. -->
|
||||
<!-- This is for dynamic_extent spans. -->
|
||||
<Type Name="gsl::span<*, -1>">
|
||||
<!-- These types are from the span header. -->
|
||||
<Type Name="gsl::span<*, *>">
|
||||
<DisplayString>{{ extent = {storage_.size_} }}</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
@ -31,66 +24,7 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- This works for constexpr size spans. -->
|
||||
<Type Name="gsl::span<*, *>">
|
||||
<DisplayString>{{ extent = {extent} }}</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>extent</Size>
|
||||
<ValuePointer>storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- This is for dynamic_extent string_spans. -->
|
||||
<Type Name="gsl::basic_string_span<*, -1>">
|
||||
<DisplayString>{span_.storage_.data_,[span_.storage_.size_]na}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">span_.storage_.size_</Item>
|
||||
<ArrayItems>
|
||||
<Size>span_.storage_.size_</Size>
|
||||
<ValuePointer>span_.storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- This works for constexpr size string_spans. -->
|
||||
<Type Name="gsl::basic_string_span<*, *>">
|
||||
<DisplayString>{span_.storage_.data_,[span_.extent]na}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">span_.extent</Item>
|
||||
<ArrayItems>
|
||||
<Size>span_.extent</Size>
|
||||
<ValuePointer>span_.storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- This is for dynamic_extent zstring_spans. -->
|
||||
<Type Name="gsl::basic_zstring_span<*, -1>">
|
||||
<DisplayString>{span_.storage_.data_,[span_.storage_.size_]na}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">span_.storage_.size_</Item>
|
||||
<ArrayItems>
|
||||
<Size>span_.storage_.size_</Size>
|
||||
<ValuePointer>span_.storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- This works for constexpr size string_spans. -->
|
||||
<Type Name="gsl::basic_zstring_span<*, *>">
|
||||
<DisplayString>{span_.storage_.data_,[span_.extent]na}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">span_.extent</Item>
|
||||
<ArrayItems>
|
||||
<Size>span_.extent</Size>
|
||||
<ValuePointer>span_.storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- These types are from the gsl header. -->
|
||||
<!-- These types are from the pointers header. -->
|
||||
<Type Name="gsl::not_null<*>">
|
||||
<!-- We can always dereference this since it's an invariant. -->
|
||||
<DisplayString>value = {*ptr_}</DisplayString>
|
||||
|
168
README.md
168
README.md
@ -1,12 +1,12 @@
|
||||
# GSL: Guidelines Support Library [](https://travis-ci.org/Microsoft/GSL) [](https://ci.appveyor.com/project/neilmacintosh/GSL)
|
||||
# GSL: Guidelines Support Library
|
||||
[](https://github.com/microsoft/GSL/actions/workflows/compilers.yml?query=branch%3Amain)
|
||||
[](https://vcpkg.io/en/package/ms-gsl)
|
||||
|
||||
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org).
|
||||
This repo contains Microsoft's implementation of GSL.
|
||||
|
||||
The library includes types like `span<T>`, `string_span`, `owner<>` and others.
|
||||
|
||||
The entire implementation is provided inline in the headers under the [gsl](./include/gsl) directory. The implementation generally assumes a platform that implements C++14 support. There are specific workarounds to support MSVC 2015.
|
||||
The entire implementation is provided inline in the headers under the [gsl](./include/gsl) directory. The implementation generally assumes a platform that implements C++14 support.
|
||||
|
||||
While some types have been broken out into their own headers (e.g. [gsl/span](./include/gsl/span)),
|
||||
it is simplest to just include [gsl/gsl](./include/gsl/gsl) and gain access to the entire library.
|
||||
@ -20,44 +20,110 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
|
||||
# Usage of Third Party Libraries
|
||||
This project makes use of the [Google Test](https://github.com/google/googletest) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Google Test.
|
||||
|
||||
# Supported features
|
||||
## Microsoft GSL implements the following from the C++ Core Guidelines:
|
||||
|
||||
Feature | Supported? | Description
|
||||
-------------------------------------------------------------------------|:----------:|-------------
|
||||
[**1. Views**][cg-views] | |
|
||||
[owner](docs/headers.md#user-content-H-pointers-owner) | ☑ | An alias for a raw pointer
|
||||
[not_null](docs/headers.md#user-content-H-pointers-not_null) | ☑ | Restricts a pointer/smart pointer to hold non-null values
|
||||
[span](docs/headers.md#user-content-H-span-span) | ☑ | A view over a contiguous sequence of memory. Based on the standardized version of `std::span`, however `gsl::span` enforces bounds checking.
|
||||
span_p | ☐ | Spans a range starting from a pointer to the first place for which the predicate is true
|
||||
[basic_zstring](docs/headers.md#user-content-H-zstring) | ☑ | A pointer to a C-string (zero-terminated array) with a templated char type
|
||||
[zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char`
|
||||
[czstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char`
|
||||
[wzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `wchar_t`
|
||||
[cwzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const wchar_t`
|
||||
[u16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char16_t`
|
||||
[cu16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char16_t`
|
||||
[u32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t`
|
||||
[cu32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t`
|
||||
[**2. Owners**][cg-owners] | |
|
||||
stack_array | ☐ | A stack-allocated array
|
||||
dyn_array | ☐ | A heap-allocated array
|
||||
[**3. Assertions**][cg-assertions] | |
|
||||
[Expects](docs/headers.md#user-content-H-assert-expects) | ☑ | A precondition assertion; on failure it terminates
|
||||
[Ensures](docs/headers.md#user-content-H-assert-ensures) | ☑ | A postcondition assertion; on failure it terminates
|
||||
[**4. Utilities**][cg-utilities] | |
|
||||
move_owner | ☐ | A helper function that moves one `owner` to the other
|
||||
[final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a functor on its destruction
|
||||
[finally](docs/headers.md#user-content-H-util-finally) | ☑ | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action)
|
||||
[GSL_SUPPRESS](docs/headers.md#user-content-H-assert-gsl_suppress) | ☑ | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
|
||||
[[implicit]] | ☐ | A "marker" to put on single-argument constructors to explicitly make them non-explicit
|
||||
[index](docs/headers.md#user-content-H-util-index) | ☑ | A type to use for all container and array indexing (currently an alias for `std::ptrdiff_t`)
|
||||
[narrow](docs/headers.md#user-content-H-narrow-narrow) | ☑ | A checked version of `narrow_cast`; it can throw [narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error)
|
||||
[narrow_cast](docs/headers.md#user-content-H-util-narrow_cast) | ☑ | A narrowing cast for values and a synonym for `static_cast`
|
||||
[narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error) | ☑ | A custom exception type thrown by [narrow](docs/headers.md#user-content-H-narrow-narrow)
|
||||
[**5. Concepts**][cg-concepts] | ☐ |
|
||||
|
||||
## The following features do not exist in or have been removed from the C++ Core Guidelines:
|
||||
Feature | Supported? | Description
|
||||
-----------------------------------|:----------:|-------------
|
||||
[strict_not_null](docs/headers.md#user-content-H-pointers-strict_not_null) | ☑ | A stricter version of [not_null](docs/headers.md#user-content-H-pointers-not_null) with explicit constructors
|
||||
multi_span | ☐ | Deprecated. Multi-dimensional span.
|
||||
strided_span | ☐ | Deprecated. Support for this type has been discontinued.
|
||||
basic_string_span | ☐ | Deprecated. Like `span` but for strings with a templated char type
|
||||
string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char`
|
||||
cstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char`
|
||||
wstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `wchar_t`
|
||||
cwstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const wchar_t`
|
||||
u16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char16_t`
|
||||
cu16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char16_t`
|
||||
u32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char32_t`
|
||||
cu32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char32_t`
|
||||
|
||||
## The following features have been adopted by WG21. They are deprecated in GSL.
|
||||
Feature | Deprecated Since | Notes
|
||||
------------------------------------------------------------------|------------------|------
|
||||
[unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | C++11 | Use std::unique_ptr instead.
|
||||
[shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | C++11 | Use std::shared_ptr instead.
|
||||
[byte](docs/headers.md#user-content-H-byte-byte) | C++17 | Use std::byte instead.
|
||||
joining_thread | C++20 (Note: Not yet implemented in GSL) | Use std::jthread instead.
|
||||
|
||||
This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library).
|
||||
|
||||
[cg-views]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslview-views
|
||||
[cg-owners]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslowner-ownership-pointers
|
||||
[cg-assertions]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslassert-assertions
|
||||
[cg-utilities]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslutil-utilities
|
||||
[cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts
|
||||
|
||||
# Quick Start
|
||||
## Supported Platforms
|
||||
The test suite that exercises GSL has been built and passes successfully on the following platforms:<sup>1)</sup>
|
||||
## Supported Compilers / Toolsets
|
||||
The GSL officially supports recent major versions of Visual Studio with both MSVC and LLVM, GCC, Clang, and XCode with Apple-Clang.
|
||||
For each of these major versions, the GSL officially supports C++14, C++17, C++20, and C++23 (when supported by the compiler).
|
||||
Below is a table showing the versions currently being tested (also see [.github/workflows/compilers.yml](the workflow).)
|
||||
|
||||
* Windows using Visual Studio 2015
|
||||
* Windows using Visual Studio 2017
|
||||
* Windows using Clang/LLVM 3.6
|
||||
* Windows using Clang/LLVM 7.0.0
|
||||
* Windows using GCC 5.1
|
||||
* Windows using Intel C++ Compiler 18.0
|
||||
* GNU/Linux using Clang/LLVM 3.6-3.9
|
||||
* GNU/Linux using Clang/LLVM 4.0
|
||||
* GNU/Linux using Clang/LLVM 5.0
|
||||
* GNU/Linux using Clang/LLVM 6.0
|
||||
* GNU/Linux using Clang/LLVM 7.0
|
||||
* GNU/Linux using GCC 5.1
|
||||
* OS X Mojave 10.14.4 using Apple LLVM version 10.0.0 (10.0.1.10010046)
|
||||
* OS X Mojave 10.14.3 using Apple LLVM version 10.0.0 (clang-1000.11.45.5)
|
||||
* OS X Yosemite using Xcode with Apple Clang 7.0.0.7000072
|
||||
* OS X Yosemite using GCC-5.2.0
|
||||
* OS X Sierra 10.12.4 using Apple LLVM version 8.1.0 (Clang-802.0.42)
|
||||
* OS X El Capitan (10.11) using Xcode with AppleClang 8.0.0.8000042
|
||||
* OS X High Sierra 10.13.2 (17C88) using Apple LLVM version 9.0.0 (clang-900.0.39.2)
|
||||
* FreeBSD 10.x with Clang/LLVM 3.6
|
||||
Compiler |Toolset Versions Currently Tested
|
||||
:------- |--:
|
||||
GCC | 12, 13, 14
|
||||
XCode | 14.3.1, 15.4
|
||||
Clang | 16, 17, 18
|
||||
Visual Studio with MSVC | VS2019, VS2022
|
||||
Visual Studio with LLVM | VS2019, VS2022
|
||||
|
||||
> If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider
|
||||
contributing any changes that were necessary back to this project to benefit the wider community.
|
||||
---
|
||||
If you successfully port GSL to another platform, we would love to hear from you!
|
||||
- Submit an issue specifying the platform and target.
|
||||
- Consider contributing your changes by filing a pull request with any necessary changes.
|
||||
- If at all possible, add a CI/CD step and add the button to the table below!
|
||||
|
||||
<sup>1)</sup> For `gsl::byte` to work correctly with Clang and GCC you might have to use the ` -fno-strict-aliasing` compiler option.
|
||||
Target | CI/CD Status
|
||||
:------- | -----------:
|
||||
iOS | [](https://github.com/microsoft/GSL/actions/workflows/ios.yml?query=branch%3Amain)
|
||||
Android | [](https://github.com/microsoft/GSL/actions/workflows/android.yml?query=branch%3Amain)
|
||||
|
||||
Note: These CI/CD steps are run with each pull request, however failures in them are non-blocking.
|
||||
|
||||
## Building the tests
|
||||
To build the tests, you will require the following:
|
||||
|
||||
* [CMake](http://cmake.org), version 3.1.3 (3.2.3 for AppleClang) or later to be installed and in your PATH.
|
||||
* [CMake](http://cmake.org), version 3.14 or later to be installed and in your PATH.
|
||||
|
||||
These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`.
|
||||
|
||||
1. Create a directory to contain the build outputs for a particular architecture (we name it c:\GSL\build-x86 in this example).
|
||||
1. Create a directory to contain the build outputs for a particular architecture (we name it `c:\GSL\build-x86` in this example).
|
||||
|
||||
cd GSL
|
||||
md build-x86
|
||||
@ -65,7 +131,7 @@ These steps assume the source code of this repository has been cloned into a dir
|
||||
|
||||
2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`).
|
||||
|
||||
cmake -G "Visual Studio 14 2015" c:\GSL
|
||||
cmake -G "Visual Studio 15 2017" c:\GSL
|
||||
|
||||
3. Build the test suite (in this case, in the Debug configuration, Release is another good choice).
|
||||
|
||||
@ -111,12 +177,44 @@ Include the library using:
|
||||
|
||||
## Usage in CMake
|
||||
|
||||
The library provides a Config file for CMake, once installed it can be found via
|
||||
|
||||
find_package(Microsoft.GSL CONFIG)
|
||||
The library provides a Config file for CMake, once installed it can be found via `find_package`.
|
||||
|
||||
Which, when successful, will add library target called `Microsoft.GSL::GSL` which you can use via the usual
|
||||
`target_link_libraries` mechanism.
|
||||
|
||||
```cmake
|
||||
find_package(Microsoft.GSL CONFIG REQUIRED)
|
||||
|
||||
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
|
||||
```
|
||||
|
||||
### FetchContent
|
||||
|
||||
If you are using CMake version 3.11+ you can use the official [FetchContent module](https://cmake.org/cmake/help/latest/module/FetchContent.html).
|
||||
This allows you to easily incorporate GSL into your project.
|
||||
|
||||
```cmake
|
||||
# NOTE: This example uses CMake version 3.14 (FetchContent_MakeAvailable).
|
||||
# Since it streamlines the FetchContent process
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(GSL
|
||||
GIT_REPOSITORY "https://github.com/microsoft/GSL"
|
||||
GIT_TAG "v4.2.0"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(GSL)
|
||||
|
||||
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
|
||||
```
|
||||
|
||||
## Debugging visualization support
|
||||
|
||||
For Visual Studio users, the file [GSL.natvis](./GSL.natvis) in the root directory of the repository can be added to your project if you would like more helpful visualization of GSL types in the Visual Studio debugger than would be offered by default.
|
||||
|
||||
## See Also
|
||||
|
||||
For information on [Microsoft Gray Systems Lab (GSL)](https://aka.ms/gsl) of applied data management and system research see <https://aka.ms/gsl>.
|
||||
|
41
SECURITY.md
Normal file
41
SECURITY.md
Normal 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 -->
|
128
appveyor.yml
128
appveyor.yml
@ -1,128 +0,0 @@
|
||||
shallow_clone: true
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
image:
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
|
||||
environment:
|
||||
NINJA_TAG: v1.8.2
|
||||
NINJA_SHA512: 9B9CE248240665FCD6404B989F3B3C27ED9682838225E6DC9B67B551774F251E4FF8A207504F941E7C811E7A8BE1945E7BCB94472A335EF15E23A0200A32E6D5
|
||||
NINJA_PATH: C:\Tools\ninja\ninja-%NINJA_TAG%
|
||||
VCVAR2015: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat'
|
||||
VCVAR2017: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat'
|
||||
VCVAR2019: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat'
|
||||
matrix:
|
||||
- GSL_CXX_STANDARD: 14
|
||||
USE_TOOLSET: MSVC
|
||||
USE_GENERATOR: MSBuild
|
||||
- GSL_CXX_STANDARD: 17
|
||||
USE_TOOLSET: MSVC
|
||||
USE_GENERATOR: MSBuild
|
||||
- GSL_CXX_STANDARD: 14
|
||||
USE_TOOLSET: LLVM
|
||||
USE_GENERATOR: Ninja
|
||||
- GSL_CXX_STANDARD: 17
|
||||
USE_TOOLSET: LLVM
|
||||
USE_GENERATOR: Ninja
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- image: Visual Studio 2015
|
||||
GSL_CXX_STANDARD: 17
|
||||
- image: Visual Studio 2015
|
||||
USE_TOOLSET: LLVM
|
||||
USE_GENERATOR: MSBuild
|
||||
|
||||
cache:
|
||||
- C:\cmake-3.14.4-win32-x86
|
||||
- C:\Tools\ninja
|
||||
|
||||
install:
|
||||
- ps: |
|
||||
if (![IO.File]::Exists("$env:NINJA_PATH\ninja.exe")) {
|
||||
Start-FileDownload `
|
||||
"https://github.com/ninja-build/ninja/releases/download/$env:NINJA_TAG/ninja-win.zip"
|
||||
$hash = (Get-FileHash ninja-win.zip -Algorithm SHA512).Hash
|
||||
if ($env:NINJA_SHA512 -eq $hash) {
|
||||
7z e -y -bso0 ninja-win.zip -o"$env:NINJA_PATH"
|
||||
} else { Write-Warning "Ninja download hash changed!"; Write-Output "$hash" }
|
||||
}
|
||||
if ([IO.File]::Exists("$env:NINJA_PATH\ninja.exe")) {
|
||||
$env:PATH = "$env:NINJA_PATH;$env:PATH"
|
||||
} else { Write-Warning "Failed to find ninja.exe in expected location." }
|
||||
if ($env:USE_TOOLSET -ne "LLVM") {
|
||||
if (![IO.File]::Exists("C:\cmake-3.14.0-win32-x86\bin\cmake.exe")) {
|
||||
Start-FileDownload 'https://cmake.org/files/v3.14/cmake-3.14.4-win32-x86.zip'
|
||||
7z x -y -bso0 cmake-3.14.4-win32-x86.zip -oC:\
|
||||
}
|
||||
$env:PATH="C:\cmake-3.14.4-win32-x86\bin;$env:PATH"
|
||||
}
|
||||
|
||||
before_build:
|
||||
- ps: |
|
||||
if ("$env:USE_GENERATOR" -eq "Ninja") {
|
||||
$GeneratorFlags = '-k 10'
|
||||
$Architecture = $env:PLATFORM
|
||||
if ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2015") {
|
||||
$env:VCVARSALL = "`"$env:VCVAR2015`" $Architecture"
|
||||
} elseif ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2017") {
|
||||
$env:VCVARSALL = "`"$env:VCVAR2017`" $Architecture"
|
||||
} else {
|
||||
$env:VCVARSALL = "`"$env:VCVAR2019`" $Architecture"
|
||||
}
|
||||
$env:CMakeGenFlags = "-G Ninja -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD"
|
||||
} else {
|
||||
$GeneratorFlags = '/m /v:minimal'
|
||||
if ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2015") {
|
||||
$Generator = 'Visual Studio 14 2015'
|
||||
} elseif ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2017") {
|
||||
$Generator = 'Visual Studio 15 2017'
|
||||
} else {
|
||||
$Generator = 'Visual Studio 16 2019'
|
||||
}
|
||||
if ("$env:PLATFORM" -eq "x86") {
|
||||
$Architecture = "Win32"
|
||||
} else {
|
||||
$Architecture = "x64"
|
||||
}
|
||||
if ("$env:USE_TOOLSET" -eq "LLVM") {
|
||||
$env:CMakeGenFlags = "-G `"$Generator`" -A $Architecture -T llvm -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD"
|
||||
} else {
|
||||
$env:CMakeGenFlags = "-G `"$Generator`" -A $Architecture -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD"
|
||||
}
|
||||
}
|
||||
if ("$env:USE_TOOLSET" -eq "LLVM") {
|
||||
$env:CC = "clang-cl"
|
||||
$env:CXX = "clang-cl"
|
||||
if ("$env:PLATFORM" -eq "x86") {
|
||||
$env:CFLAGS = "-m32";
|
||||
$env:CXXFLAGS = "-m32";
|
||||
} else {
|
||||
$env:CFLAGS = "-m64";
|
||||
$env:CXXFLAGS = "-m64";
|
||||
}
|
||||
}
|
||||
$env:CMakeBuildFlags = "--config $env:CONFIGURATION -- $GeneratorFlags"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if %USE_GENERATOR%==Ninja (call %VCVARSALL%)
|
||||
- echo %CMakeGenFlags%
|
||||
- cmake .. %CMakeGenFlags%
|
||||
|
||||
build_script:
|
||||
- echo %CMakeBuildFlags%
|
||||
- cmake --build . %CMakeBuildFlags%
|
||||
|
||||
test_script:
|
||||
- ctest -j2
|
||||
|
||||
deploy: off
|
884
docs/headers.md
Normal file
884
docs/headers.md
Normal file
@ -0,0 +1,884 @@
|
||||
The Guidelines Support Library (GSL) interface is very lightweight and exposed via a header-only library. This document attempts to document all of the headers and their exposed classes and functions.
|
||||
|
||||
Types and functions are exported in the namespace `gsl`.
|
||||
|
||||
See [GSL: Guidelines support library](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl)
|
||||
|
||||
# <a name="H" />Headers
|
||||
|
||||
- [`<algorithms>`](#user-content-H-algorithms)
|
||||
- [`<assert>`](#user-content-H-assert)
|
||||
- [`<byte>`](#user-content-H-byte)
|
||||
- [`<gsl>`](#user-content-H-gsl)
|
||||
- [`<narrow>`](#user-content-H-narrow)
|
||||
- [`<pointers>`](#user-content-H-pointers)
|
||||
- [`<span>`](#user-content-H-span)
|
||||
- [`<span_ext>`](#user-content-H-span_ext)
|
||||
- [`<zstring>`](#user-content-H-zstring)
|
||||
- [`<util>`](#user-content-H-util)
|
||||
|
||||
## <a name="H-algorithms" />`<algorithms>`
|
||||
|
||||
This header contains some common algorithms that have been wrapped in GSL safety features.
|
||||
|
||||
- [`gsl::copy`](#user-content-H-algorithms-copy)
|
||||
|
||||
### <a name="H-algorithms-copy" />`gsl::copy`
|
||||
|
||||
```cpp
|
||||
template <class SrcElementType, std::size_t SrcExtent, class DestElementType,
|
||||
std::size_t DestExtent>
|
||||
void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent> dest);
|
||||
```
|
||||
|
||||
This function copies the content from the `src` [`span`](#user-content-H-span-span) to the `dest` [`span`](#user-content-H-span-span). It [`Expects`](#user-content-H-assert-expects)
|
||||
that the destination `span` is at least as large as the source `span`.
|
||||
|
||||
## <a name="H-assert" />`<assert>`
|
||||
|
||||
This header contains some macros used for contract checking and suppressing code analysis warnings.
|
||||
|
||||
See [GSL.assert: Assertions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions)
|
||||
|
||||
- [`GSL_SUPPRESS`](#user-content-H-assert-gsl_suppress)
|
||||
- [`Expects`](#user-content-H-assert-expects)
|
||||
- [`Ensures`](#user-content-H-assert-ensures)
|
||||
|
||||
### <a name="H-assert-gsl_suppress" />`GSL_SUPPRESS`
|
||||
|
||||
This macro can be used to suppress a code analysis warning.
|
||||
|
||||
The core guidelines request tools that check for the rules to respect suppressing a rule by writing
|
||||
`[[gsl::suppress(tag)]]` or `[[gsl::suppress(tag, justification: "message")]]`.
|
||||
|
||||
Clang does not use exactly that syntax, but requires `tag` to be put in double quotes `[[gsl::suppress("tag")]]`.
|
||||
|
||||
For portable code you can use `GSL_SUPPRESS(tag)`.
|
||||
|
||||
See [In.force: Enforcement](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#inforce-enforcement).
|
||||
|
||||
### <a name="H-assert-expects" />`Expects`
|
||||
|
||||
This macro can be used for expressing a precondition. If the precondition is not held, then `std::terminate` will be called.
|
||||
|
||||
See [I.6: Prefer `Expects()` for expressing preconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i6-prefer-expects-for-expressing-preconditions)
|
||||
|
||||
### <a name="H-assert-ensures" />`Ensures`
|
||||
|
||||
This macro can be used for expressing a postcondition. If the postcondition is not held, then `std::terminate` will be called.
|
||||
|
||||
See [I.8: Prefer `Ensures()` for expressing postconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i8-prefer-ensures-for-expressing-postconditions)
|
||||
|
||||
## <a name="H-byte" />`<byte>`
|
||||
|
||||
This header contains the definition of a byte type, implementing `std::byte` before it was standardized into C++17.
|
||||
|
||||
- [`gsl::byte`](#user-content-H-byte-byte)
|
||||
|
||||
### <a name="H-byte-byte" />`gsl::byte`
|
||||
|
||||
If `GSL_USE_STD_BYTE` is defined to be `1`, then `gsl::byte` will be an alias to `std::byte`.
|
||||
If `GSL_USE_STD_BYTE` is defined to be `0`, then `gsl::byte` will be a distinct type that implements the concept of byte.
|
||||
If `GSL_USE_STD_BYTE` is not defined, then the header file will check if `std::byte` is available (C\+\+17 or higher). If yes,
|
||||
`gsl::byte` will be an alias to `std::byte`, otherwise `gsl::byte` will be a distinct type that implements the concept of byte.
|
||||
|
||||
⚠ Take care when linking projects that were compiled with different language standards (before C\+\+17 and C\+\+17 or higher).
|
||||
If you do so, you might want to `#define GSL_USE_STD_BYTE 0` to a fixed value to be sure that both projects use exactly
|
||||
the same type. Otherwise you might get linker errors.
|
||||
|
||||
See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily represent characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-byte)
|
||||
|
||||
### Non-member functions
|
||||
|
||||
```cpp
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
|
||||
```
|
||||
|
||||
Left or right shift a `byte` by a given number of bits.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator|=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator|(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise "or" of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator&=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator&(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise "and" of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator^=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator^(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise xor of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte operator~(byte b) noexcept;
|
||||
```
|
||||
|
||||
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.
|
||||
|
||||
```cpp
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr IntegerType to_integer(byte b) noexcept;
|
||||
```
|
||||
|
||||
Convert the given `byte` value to an integral type.
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
constexpr byte to_byte(T t) noexcept;
|
||||
```
|
||||
|
||||
Convert the given value to a `byte`. The template requires `T` to be an `unsigned char` so that no data loss can occur.
|
||||
If you want to convert an integer constant to a `byte` you probably want to call `to_byte<integer constant>()`.
|
||||
|
||||
```cpp
|
||||
template <int I>
|
||||
constexpr byte to_byte() noexcept;
|
||||
```
|
||||
|
||||
Convert the given value `I` to a `byte`. The template requires `I` to be in the valid range 0..255 for a `gsl::byte`.
|
||||
|
||||
## <a name="H-gsl" />`<gsl>`
|
||||
|
||||
This header is a convenience header that includes all other [GSL headers](#user-content-H).
|
||||
Since `<narrow>` requires exceptions, it will only be included if exceptions are enabled.
|
||||
|
||||
## <a name="H-narrow" />`<narrow>`
|
||||
|
||||
This header contains utility functions and classes, for narrowing casts, which require exceptions. The narrowing-related utilities that don't require exceptions are found inside [util](#user-content-H-util).
|
||||
|
||||
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
|
||||
|
||||
- [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error)
|
||||
- [`gsl::narrow`](#user-content-H-narrow-narrow)
|
||||
|
||||
### <a name="H-narrow-narrowing_error" />`gsl::narrowing_error`
|
||||
|
||||
`gsl::narrowing_error` is the exception thrown by [`gsl::narrow`](#user-content-H-narrow-narrow) when a narrowing conversion fails. It is derived from `std::exception`.
|
||||
|
||||
### <a name="H-narrow-narrow" />`gsl::narrow`
|
||||
|
||||
`gsl::narrow<T>(x)` is a named cast that does a `static_cast<T>(x)` for narrowing conversions with no signedness promotions.
|
||||
If the argument `x` cannot be represented in the target type `T`, then the function throws a [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error) (e.g., `narrow<unsigned>(-42)` and `narrow<char>(300)` throw).
|
||||
|
||||
Note: compare [`gsl::narrow_cast`](#user-content-H-util-narrow_cast) in header [util](#user-content-H-util).
|
||||
|
||||
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
|
||||
|
||||
## <a name="H-pointers" />`<pointers>`
|
||||
|
||||
This header contains some pointer types.
|
||||
|
||||
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views)
|
||||
|
||||
- [`gsl::unique_ptr`](#user-content-H-pointers-unique_ptr)
|
||||
- [`gsl::shared_ptr`](#user-content-H-pointers-shared_ptr)
|
||||
- [`gsl::owner`](#user-content-H-pointers-owner)
|
||||
- [`gsl::not_null`](#user-content-H-pointers-not_null)
|
||||
- [`gsl::strict_not_null`](#user-content-H-pointers-strict_not_null)
|
||||
|
||||
### <a name="H-pointers-unique_ptr" />`gsl::unique_ptr`
|
||||
|
||||
`gsl::unique_ptr` is an alias to `std::unique_ptr`.
|
||||
|
||||
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
|
||||
|
||||
### <a name="H-pointers-shared_ptr" />`gsl::shared_ptr`
|
||||
|
||||
`gsl::shared_ptr` is an alias to `std::shared_ptr`.
|
||||
|
||||
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
|
||||
|
||||
### <a name="H-pointers-owner" />`gsl::owner`
|
||||
|
||||
`gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory. Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used as a stepping point in converting legacy code to use more modern RAII constructs such as smart pointers.
|
||||
`T` must be a pointer type (`std::is_pointer<T>`).
|
||||
|
||||
A `gsl::owner<T>` is a typedef to `T`. It adds no runtime overhead whatsoever, as it is purely syntactic and does not add any runtime checks. Instead, it serves as an annotation for static analysis tools which check for memory safety, and as a code comprehension guide for human readers.
|
||||
|
||||
See Enforcement section of [C.31: All resources acquired by a class must be released by the class’s destructor](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-dtor-release).
|
||||
|
||||
### <a name="H-pointers-not_null" />`gsl::not_null`
|
||||
|
||||
`gsl::not_null<T>` restricts a pointer or smart pointer to only hold non-null values. It has no size overhead over `T`.
|
||||
|
||||
The checks for ensuring that the pointer is not null are done in the constructor. There is no overhead when retrieving or dereferencing the checked pointer.
|
||||
When a nullptr check fails, `std::terminate` is called.
|
||||
|
||||
See [F.23: Use a `not_null<T>` to indicate that “null” is not a valid value](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr)
|
||||
|
||||
#### Member Types
|
||||
|
||||
```cpp
|
||||
using element_type = T;
|
||||
```
|
||||
|
||||
The type of the pointer or smart pointer that is managed by this object.
|
||||
|
||||
#### Member functions
|
||||
|
||||
##### Construct/Copy
|
||||
|
||||
```cpp
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(U&& u);
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr not_null(T u);
|
||||
```
|
||||
|
||||
Constructs a `gsl_owner<T>` from a pointer that is convertible to `T` or that is a `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
|
||||
|
||||
```cpp
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(const not_null<U>& other);
|
||||
```
|
||||
|
||||
Constructs a `gsl_owner<T>` from another `gsl_owner` where the other pointer is convertible to `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
|
||||
|
||||
```cpp
|
||||
not_null(const not_null& other) = default;
|
||||
not_null& operator=(const not_null& other) = default;
|
||||
```
|
||||
|
||||
Copy construction and assignment.
|
||||
|
||||
```cpp
|
||||
not_null(std::nullptr_t) = delete;
|
||||
not_null& operator=(std::nullptr_t) = delete;
|
||||
```
|
||||
|
||||
Construction from `std::nullptr_t` and assignment of `std::nullptr_t` are explicitly deleted.
|
||||
|
||||
##### Modifiers
|
||||
|
||||
```cpp
|
||||
not_null& operator++() = delete;
|
||||
not_null& operator--() = delete;
|
||||
not_null operator++(int) = delete;
|
||||
not_null operator--(int) = delete;
|
||||
not_null& operator+=(std::ptrdiff_t) = delete;
|
||||
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
```
|
||||
|
||||
Explicitly deleted operators. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
|
||||
|
||||
##### Observers
|
||||
|
||||
```cpp
|
||||
constexpr details::value_or_reference_return_t<T> get() const;
|
||||
constexpr operator T() const { return get(); }
|
||||
```
|
||||
|
||||
Get the underlying pointer.
|
||||
|
||||
```cpp
|
||||
constexpr decltype(auto) operator->() const { return get(); }
|
||||
constexpr decltype(auto) operator*() const { return *get(); }
|
||||
```
|
||||
|
||||
Dereference the underlying pointer.
|
||||
|
||||
```cpp
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
```
|
||||
|
||||
Array index operator is explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow treating them as an array.
|
||||
|
||||
```cpp
|
||||
void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
|
||||
```
|
||||
|
||||
Swaps contents with another `gsl::not_null` object.
|
||||
|
||||
#### Non-member functions
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
auto make_not_null(T&& t) noexcept;
|
||||
```
|
||||
|
||||
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
|
||||
|
||||
```cpp
|
||||
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
|
||||
void swap(not_null<T>& a, not_null<T>& b);
|
||||
```
|
||||
|
||||
Swaps the contents of two `gsl::not_null` objects.
|
||||
|
||||
```cpp
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
|
||||
-> decltype(lhs.get() == rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator!=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
|
||||
-> decltype(lhs.get() != rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator<(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
|
||||
-> decltype(lhs.get() < rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator<=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
|
||||
-> decltype(lhs.get() <= rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator>(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
|
||||
-> decltype(lhs.get() > rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator>=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
|
||||
-> decltype(lhs.get() >= rhs.get());
|
||||
```
|
||||
|
||||
Comparison of pointers that are convertible to each other.
|
||||
|
||||
##### Input/Output
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& os, const not_null<T>& val);
|
||||
```
|
||||
|
||||
Performs stream output on a `not_null` pointer, invoking `os << val.get()`. This function is only available when `GSL_NO_IOSTREAMS` is not defined.
|
||||
|
||||
##### Modifiers
|
||||
|
||||
```cpp
|
||||
template <class T, class U>
|
||||
std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
|
||||
```
|
||||
|
||||
Addition and subtraction are explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
|
||||
|
||||
##### STL integration
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
struct std::hash<gsl::not_null<T>> { ... };
|
||||
```
|
||||
|
||||
Specialization of `std::hash` for `gsl::not_null`.
|
||||
|
||||
### <a name="H-pointers-strict_not_null" />`gsl::strict_not_null`
|
||||
|
||||
`strict_not_null` is the same as [`not_null`](#user-content-H-pointers-not_null) except that the constructors are `explicit`.
|
||||
|
||||
The free function that deduces the target type from the type of the argument and creates a `gsl::strict_not_null` object is `gsl::make_strict_not_null`.
|
||||
|
||||
## <a name="H-span" />`<span>`
|
||||
|
||||
This header file exports the class `gsl::span`, a bounds-checked implementation of `std::span`.
|
||||
|
||||
- [`gsl::span`](#user-content-H-span-span)
|
||||
|
||||
### <a name="H-span-span" />`gsl::span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
class span;
|
||||
```
|
||||
|
||||
`gsl::span` is a view over memory. It does not own the memory and is only a way to access contiguous sequences of objects.
|
||||
The extent can be either a fixed size or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
|
||||
|
||||
The `gsl::span` is based on the standardized version of `std::span` which was added to C++20. Originally, the plan was to
|
||||
deprecate `gsl::span` when `std::span` finished standardization, however that plan changed when the runtime bounds checking
|
||||
was removed from `std::span`'s design.
|
||||
|
||||
The only difference between `gsl::span` and `std::span` is that `gsl::span` strictly enforces runtime bounds checking.
|
||||
Any violations of the bounds check results in termination of the program.
|
||||
Like `gsl::span`, `gsl::span`'s iterators also differ from `std::span`'s iterator in that all access operations are bounds checked.
|
||||
|
||||
#### Which version of span should I use?
|
||||
|
||||
##### Use `gsl::span` if
|
||||
|
||||
- you want to guarantee bounds safety in your project.
|
||||
- All data accessing operations use bounds checking to ensure you are only accessing valid memory.
|
||||
- your project uses C++14 or C++17.
|
||||
- `std::span` is not available as it was not introduced into the STL until C++20.
|
||||
|
||||
##### Use `std::span` if
|
||||
|
||||
- your project is C++20 and you need the performance offered by `std::span`.
|
||||
|
||||
#### Types
|
||||
|
||||
```cpp
|
||||
using element_type = ElementType;
|
||||
using value_type = std::remove_cv_t<ElementType>;
|
||||
using size_type = std::size_t;
|
||||
using pointer = element_type*;
|
||||
using const_pointer = const element_type*;
|
||||
using reference = element_type&;
|
||||
using const_reference = const element_type&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = details::span_iterator<ElementType>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
```
|
||||
|
||||
#### Member functions
|
||||
|
||||
```cpp
|
||||
constexpr span() noexcept;
|
||||
```
|
||||
|
||||
Constructs an empty `span`. This constructor is only available if `Extent` is 0 or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
|
||||
`span::data()` will return `nullptr`.
|
||||
|
||||
```cpp
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer ptr, size_type count) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a pointer and a size. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `count == Extent`.
|
||||
|
||||
```cpp
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer firstElem, pointer lastElem) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a pointer to the begin and the end of the data. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `lastElem - firstElem == Extent`.
|
||||
|
||||
```cpp
|
||||
template <std::size_t N>
|
||||
constexpr span(element_type (&arr)[N]) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a C style array. This overload is available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`.
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr span(std::array<T, N>& arr) noexcept;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr span(const std::array<T, N>& arr) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a `std::array`. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`, and if the array can be interpreted as a `ElementType` array.
|
||||
|
||||
```cpp
|
||||
template <class Container>
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(Container& cont) noexcept;
|
||||
|
||||
template <class Container>
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(const Container& cont) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a container. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`, and if the container can be interpreted as a contiguous `ElementType` array.
|
||||
|
||||
```cpp
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
```
|
||||
|
||||
Copy constructor.
|
||||
|
||||
```cpp
|
||||
template <class OtherElementType, std::size_t OtherExtent>
|
||||
explicit(Extent != gsl::dynamic_extent && OtherExtent == dynamic_extent)
|
||||
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from another `span`. This constructor is available if `OtherExtent == Extent || Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)` || OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
and if `ElementType` and `OtherElementType` are compatible.
|
||||
|
||||
If `Extent !=`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) and `OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `other.size() == Extent`.
|
||||
|
||||
```cpp
|
||||
constexpr span& operator=(const span& other) noexcept = default;
|
||||
```
|
||||
|
||||
Copy assignment
|
||||
|
||||
```cpp
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept;
|
||||
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> last() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept;
|
||||
```
|
||||
|
||||
Return a subspan of the first/last `Count` elements. [`Expects`](#user-content-H-assert-expects) that `Count` does not exceed the `span`'s size.
|
||||
|
||||
```cpp
|
||||
template <std::size_t offset, std::size_t count = dynamic_extent>
|
||||
constexpr auto subspan() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const noexcept;
|
||||
```
|
||||
|
||||
Return a subspan starting at `offset` and having size `count`. [`Expects`](#user-content-H-assert-expects) that `offset` does not exceed the `span`'s size,
|
||||
and that `offset == `[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) or `offset + count` does not exceed the `span`'s size.
|
||||
If `count` is `gsl::dynamic_extent`, the number of elements in the subspan is `size() - offset`.
|
||||
|
||||
```cpp
|
||||
constexpr size_type size() const noexcept;
|
||||
|
||||
constexpr size_type size_bytes() const noexcept;
|
||||
```
|
||||
|
||||
Returns the size respective the size in bytes of the `span`.
|
||||
|
||||
```cpp
|
||||
constexpr bool empty() const noexcept;
|
||||
```
|
||||
|
||||
Is the `span` empty?
|
||||
|
||||
```cpp
|
||||
constexpr reference operator[](size_type idx) const noexcept;
|
||||
```
|
||||
|
||||
Returns a reference to the element at the given index. [`Expects`](#user-content-H-assert-expects) that `idx` is less than the `span`'s size.
|
||||
|
||||
```cpp
|
||||
constexpr reference front() const noexcept;
|
||||
constexpr reference back() const noexcept;
|
||||
```
|
||||
|
||||
Returns a reference to the first/last element in the `span`. [`Expects`](#user-content-H-assert-expects) that the `span` is not empty.
|
||||
|
||||
```cpp
|
||||
constexpr pointer data() const noexcept;
|
||||
```
|
||||
|
||||
Returns a pointer to the beginning of the contained data.
|
||||
|
||||
```cpp
|
||||
constexpr iterator begin() const noexcept;
|
||||
constexpr iterator end() const noexcept;
|
||||
constexpr reverse_iterator rbegin() const noexcept;
|
||||
constexpr reverse_iterator rend() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to the first/last normal/reverse iterator.
|
||||
|
||||
```cpp
|
||||
template <class Type, std::size_t Extent>
|
||||
span(Type (&)[Extent]) -> span<Type, Extent>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(std::array<Type, Size>&) -> span<Type, Size>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(const std::array<Type, Size>&) -> span<const Type, Size>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
|
||||
span(Container&) -> span<Element>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
|
||||
span(const Container&) -> span<Element>;
|
||||
```
|
||||
|
||||
Deduction guides.
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept;
|
||||
```
|
||||
|
||||
Converts a `span` into a `span` of `byte`s.
|
||||
|
||||
`as_writable_bytes` will only be available for non-const `ElementType`s.
|
||||
|
||||
## <a name="H-span_ext" />`<span_ext>`
|
||||
|
||||
This file is a companion for and included by [`<gsl/span>`](#user-content-H-span), and should not be used on its own. It contains useful features that aren't part of the `std::span` API as found inside the STL `<span>` header (with the exception of [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent), which is included here due to implementation constraints).
|
||||
|
||||
- [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
- [`gsl::span`](#user-content-H-span_ext-span)
|
||||
- [`gsl::span` comparison operators](#user-content-H-span_ext-span_comparison_operators)
|
||||
- [`gsl::make_span`](#user-content-H-span_ext-make_span)
|
||||
- [`gsl::at`](#user-content-H-span_ext-at)
|
||||
- [`gsl::ssize`](#user-content-H-span_ext-ssize)
|
||||
- [`gsl::span` iterator functions](#user-content-H-span_ext-span_iterator_functions)
|
||||
|
||||
### <a name="H-span_ext-dynamic_extent" />`gsl::dynamic_extent`
|
||||
|
||||
Defines the extent value to be used by all `gsl::span` with dynamic extent.
|
||||
|
||||
Note: `std::dynamic_extent` is exposed by the STL `<span>` header and so ideally `gsl::dynamic_extent` would be under [`<gsl/span>`](#user-content-H-span), but to avoid cyclic dependency issues it is under `<span_ext>` instead.
|
||||
|
||||
### <a name="H-span_ext-span" />`gsl::span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
```
|
||||
|
||||
Forward declaration of `gsl::span`.
|
||||
|
||||
### <a name="H-span_ext-span_comparison_operators" />`gsl::span` comparison operators
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator!=(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
```
|
||||
|
||||
The comparison operators for two `span`s lexicographically compare the elements in the `span`s.
|
||||
|
||||
### <a name="H-span_ext-make_span" />`gsl::make_span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::size_type count);
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem);
|
||||
template <class ElementType, std::size_t N>
|
||||
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept;
|
||||
template <class Container>
|
||||
constexpr span<typename Container::value_type> make_span(Container& cont);
|
||||
template <class Container>
|
||||
constexpr span<const typename Container::value_type> make_span(const Container& cont);
|
||||
```
|
||||
|
||||
Utility function for creating a `span` with [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) from
|
||||
- pointer and length,
|
||||
- pointer to start and pointer to end,
|
||||
- a C style array, or
|
||||
- a container.
|
||||
|
||||
### <a name="H-span_ext-at" />`gsl::at`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr ElementType& at(span<ElementType, Extent> s, index i);
|
||||
```
|
||||
|
||||
The function `gsl::at` offers a safe way to access data with index bounds checking.
|
||||
|
||||
This is the specialization of [`gsl::at`](#user-content-H-util-at) for [`span`](#user-content-H-span-span). It returns a reference to the `i`th element and
|
||||
[`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the `span`.
|
||||
|
||||
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
|
||||
|
||||
### <a name="H-span_ext-ssize" />`gsl::ssize`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept;
|
||||
```
|
||||
|
||||
Return the size of a [`span`](#user-content-H-span-span) as a `ptrdiff_t`.
|
||||
|
||||
### <a name="H-span_ext-span_iterator_functions" />`gsl::span` iterator functions
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
begin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
end(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rend(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cend(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crend(const span<ElementType, Extent>& s) noexcept;
|
||||
```
|
||||
|
||||
Free functions for getting a non-const/const begin/end normal/reverse iterator for a [`span`](#user-content-H-span-span).
|
||||
|
||||
## <a name="H-zstring" />`<zstring>`
|
||||
|
||||
This header exports a family of `*zstring` types.
|
||||
|
||||
A `gsl::XXzstring<T>` is a typedef to `T`. It adds no checks whatsoever, it is just for having a syntax to describe
|
||||
that a pointer points to a zero terminated C style string. This helps static code analysis, and it helps human readers.
|
||||
|
||||
`basic_zstring` is a pointer to a C-string (zero-terminated array) with a templated char type. Used to implement the rest of the `*zstring` family.
|
||||
`zstring` is a zero terminated `char` string.
|
||||
`czstring` is a const zero terminated `char` string.
|
||||
`wzstring` is a zero terminated `wchar_t` string.
|
||||
`cwzstring` is a const zero terminated `wchar_t` string.
|
||||
`u16zstring` is a zero terminated `char16_t` string.
|
||||
`cu16zstring` is a const zero terminated `char16_t` string.
|
||||
`u32zstring` is a zero terminated `char32_t` string.
|
||||
`cu32zstring` is a const zero terminated `char32_t` string.
|
||||
|
||||
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views) and [SL.str.3: Use zstring or czstring to refer to a C-style, zero-terminated, sequence of characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-zstring).
|
||||
|
||||
## <a name="H-util" />`<util>`
|
||||
|
||||
This header contains utility functions and classes. This header works without exceptions being available. The parts that require
|
||||
exceptions being available are in their own header file [narrow](#user-content-H-narrow).
|
||||
|
||||
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
|
||||
|
||||
- [`gsl::narrow_cast`](#user-content-H-util-narrow_cast)
|
||||
- [`gsl::final_action`](#user-content-H-util-final_action)
|
||||
- [`gsl::at`](#user-content-H-util-at)
|
||||
|
||||
### <a name="H-util-index" />`gsl::index`
|
||||
|
||||
An alias to `std::ptrdiff_t`. It serves as the index type for all container indexes/subscripts/sizes.
|
||||
|
||||
### <a name="H-util-narrow_cast" />`gsl::narrow_cast`
|
||||
|
||||
`gsl::narrow_cast<T>(x)` is a named cast that is identical to a `static_cast<T>(x)`. It exists to make clear to static code analysis tools and to human readers that a lossy conversion is acceptable.
|
||||
|
||||
Note: compare the throwing version [`gsl::narrow`](#user-content-H-narrow-narrow) in header [narrow](#user-content-H-narrow).
|
||||
|
||||
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
|
||||
|
||||
### <a name="H-util-final_action" />`gsl::final_action`
|
||||
|
||||
```cpp
|
||||
template <class F>
|
||||
class final_action { ... };
|
||||
```
|
||||
|
||||
`final_action` allows you to ensure something gets run at the end of a scope.
|
||||
|
||||
See [E.19: Use a final_action object to express cleanup if no suitable resource handle is available](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-finally)
|
||||
|
||||
#### Member functions
|
||||
|
||||
```cpp
|
||||
explicit final_action(const F& ff) noexcept;
|
||||
explicit final_action(F&& ff) noexcept;
|
||||
```
|
||||
|
||||
Construct an object with the action to invoke in the destructor.
|
||||
|
||||
```cpp
|
||||
~final_action() noexcept;
|
||||
```
|
||||
|
||||
The destructor will call the action that was passed in the constructor.
|
||||
|
||||
```cpp
|
||||
final_action(final_action&& other) noexcept;
|
||||
final_action(const final_action&) = delete;
|
||||
void operator=(const final_action&) = delete;
|
||||
void operator=(final_action&&) = delete;
|
||||
```
|
||||
|
||||
Move construction is allowed. Copy construction is deleted. Copy and move assignment are also explicitly deleted.
|
||||
|
||||
#### <a name="H-util-finally" />Non-member functions
|
||||
```cpp
|
||||
template <class F>
|
||||
auto finally(F&& f) noexcept;
|
||||
```
|
||||
|
||||
Creates a `gsl::final_action` object, deducing the template argument type from the type of the argument.
|
||||
|
||||
### <a name="H-util-at" />`gsl::at`
|
||||
|
||||
The function `gsl::at` offers a safe way to access data with index bounds checking.
|
||||
|
||||
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
|
||||
|
||||
See [ES.42: Keep use of pointers simple and straightforward](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-ptr)
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr T& at(T (&arr)[N], const index i);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of a C style array `arr`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class Cont>
|
||||
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the container `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
constexpr T at(const std::initializer_list<T> cont, const index i);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the initializer list `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t extent = std::dynamic_extent>
|
||||
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()]);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the `std::span` `sp`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
For [`gsl::at`](#user-content-H-span_ext-at) for [`gsl::span`](#user-content-H-span-span) see header [`span_ext`](#user-content-H-span_ext).
|
||||
|
||||
```cpp
|
||||
template <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
|
||||
void swap(T& a, T& b);
|
||||
```
|
||||
|
||||
Swaps the contents of two objects. Exists only to specialize `gsl::swap<T>(gsl::not_null<T>&, gsl::not_null<T>&)`.
|
13
include/CMakeLists.txt
Normal file
13
include/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Add include folders to the library and targets that consume it
|
||||
# the SYSTEM keyword suppresses warnings for users of the library
|
||||
#
|
||||
# By adding this directory as an include directory the user gets a
|
||||
# namespace effect.
|
||||
#
|
||||
# IE:
|
||||
# #include <gsl/gsl>
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
target_include_directories(GSL INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
else()
|
||||
target_include_directories(GSL SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
endif()
|
@ -17,8 +17,8 @@
|
||||
#ifndef GSL_ALGORITHM_H
|
||||
#define GSL_ALGORITHM_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include <gsl/span> // for dynamic_extent, span
|
||||
#include "./assert" // for Expects
|
||||
#include "./span" // for dynamic_extent, span
|
||||
|
||||
#include <algorithm> // for copy_n
|
||||
#include <cstddef> // for ptrdiff_t
|
||||
@ -48,7 +48,9 @@ void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent>
|
||||
"Source range is longer than target range");
|
||||
|
||||
Expects(dest.size() >= src.size());
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
std::copy_n(src.data(), src.size(), dest.data());
|
||||
}
|
||||
|
@ -14,14 +14,15 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_CONTRACTS_H
|
||||
#define GSL_CONTRACTS_H
|
||||
#ifndef GSL_ASSERT_H
|
||||
#define GSL_ASSERT_H
|
||||
|
||||
//
|
||||
// Temporary until MSVC STL supports no-exceptions mode.
|
||||
// Currently terminate is a no-op in this mode, so we add termination behavior back
|
||||
//
|
||||
#if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
|
||||
#define GSL_KERNEL_MODE
|
||||
|
||||
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
|
||||
#include <intrin.h>
|
||||
@ -32,29 +33,28 @@
|
||||
#pragma clang diagnostic ignored "-Winvalid-noreturn"
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
|
||||
#else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
|
||||
// !_HAS_EXCEPTIONS))
|
||||
|
||||
#include <exception>
|
||||
|
||||
#endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
|
||||
#endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
|
||||
// !_HAS_EXCEPTIONS))
|
||||
|
||||
//
|
||||
// make suppress attributes parse for some compilers
|
||||
// Hopefully temporary until suppression standardization occurs
|
||||
//
|
||||
#if defined(__clang__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]]
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
|
||||
#else
|
||||
#define GSL_SUPPRESS(x)
|
||||
#endif // _MSC_VER
|
||||
#endif // __clang__
|
||||
|
||||
#define GSL_STRINGIFY_DETAIL(x) #x
|
||||
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
@ -130,4 +130,4 @@ namespace details
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // GSL_CONTRACTS_H
|
||||
#endif // GSL_ASSERT_H
|
@ -17,53 +17,40 @@
|
||||
#ifndef GSL_BYTE_H
|
||||
#define GSL_BYTE_H
|
||||
|
||||
//
|
||||
// make suppress attributes work for some compilers
|
||||
// Hopefully temporary until suppression standardization occurs
|
||||
//
|
||||
#if defined(__clang__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
|
||||
#else
|
||||
#define GSL_SUPPRESS(x)
|
||||
#endif // _MSC_VER
|
||||
#endif // __clang__
|
||||
#include "./util" // for GSL_DEPRECATED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// VS2017 15.8 added support for the __cpp_lib_byte definition
|
||||
// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(push)
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates does not always work
|
||||
#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates
|
||||
// does not always work
|
||||
|
||||
#ifndef GSL_USE_STD_BYTE
|
||||
// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
|
||||
#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
|
||||
#define GSL_USE_STD_BYTE 1
|
||||
|
||||
#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
|
||||
#else // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
|
||||
#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
|
||||
#endif // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#ifndef GSL_USE_STD_BYTE
|
||||
#include <cstddef> /* __cpp_lib_byte */
|
||||
// this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte
|
||||
// also check if libc++ version is sufficient (> 5.0) or libstc++ actually contains std::byte
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L) && \
|
||||
(defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \
|
||||
defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
// this tests if we are under GCC or Clang with enough -std=c++1z power to get us std::byte
|
||||
// also check if libc++ version is sufficient (> 5.0) or libstdc++ actually contains std::byte
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L) && \
|
||||
(defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \
|
||||
defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
|
||||
#define GSL_USE_STD_BYTE 1
|
||||
|
||||
@ -73,7 +60,7 @@
|
||||
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
|
||||
#endif //defined(__cplusplus) && (__cplusplus >= 201703L) &&
|
||||
#endif // defined(__cplusplus) && (__cplusplus >= 201703L) &&
|
||||
// (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) ||
|
||||
// defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
@ -95,7 +82,14 @@ namespace gsl
|
||||
{
|
||||
#if GSL_USE_STD_BYTE
|
||||
|
||||
using std::byte;
|
||||
namespace impl {
|
||||
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
|
||||
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
|
||||
using byte = std::byte;
|
||||
}
|
||||
|
||||
using byte GSL_DEPRECATED("Use std::byte instead.") = std::byte;
|
||||
|
||||
using std::to_integer;
|
||||
|
||||
#else // GSL_USE_STD_BYTE
|
||||
@ -106,25 +100,31 @@ enum class byte_may_alias byte : unsigned char
|
||||
{
|
||||
};
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
namespace impl {
|
||||
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
|
||||
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
|
||||
using byte = gsl::byte;
|
||||
}
|
||||
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) >> shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) >> shift);
|
||||
@ -162,7 +162,7 @@ constexpr byte operator^(byte l, byte r) noexcept
|
||||
|
||||
constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr IntegerType to_integer(byte b) noexcept
|
||||
{
|
||||
return static_cast<IntegerType>(b);
|
||||
@ -170,34 +170,24 @@ constexpr IntegerType to_integer(byte b) noexcept
|
||||
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
template <bool E, typename T>
|
||||
constexpr byte to_byte_impl(T t) noexcept
|
||||
{
|
||||
static_assert(
|
||||
E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
|
||||
"If you are calling to_byte with an integer contant use: gsl::to_byte<t>() version.");
|
||||
return static_cast<byte>(t);
|
||||
}
|
||||
template <>
|
||||
// NOTE: need suppression since c++14 does not allow "return {t}"
|
||||
// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
|
||||
constexpr byte to_byte_impl<true, unsigned char>(unsigned char t) noexcept
|
||||
{
|
||||
return byte(t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr byte to_byte(T t) noexcept
|
||||
// NOTE: need suppression since c++14 does not allow "return {t}"
|
||||
// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
|
||||
constexpr gsl::impl::byte to_byte(T t) noexcept
|
||||
{
|
||||
return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
|
||||
static_assert(std::is_same<T, unsigned char>::value,
|
||||
"gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
|
||||
"If you are calling to_byte with an integer constant use: gsl::to_byte<t>() version.");
|
||||
return gsl::impl::byte(t);
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr byte to_byte() noexcept
|
||||
constexpr gsl::impl::byte to_byte() noexcept
|
||||
{
|
||||
static_assert(I >= 0 && I <= 255,
|
||||
"gsl::byte only has 8 bits of storage, values must be in range 0-255");
|
||||
return static_cast<byte>(I);
|
||||
return static_cast<gsl::impl::byte>(I);
|
||||
}
|
||||
|
||||
} // namespace gsl
|
@ -17,13 +17,18 @@
|
||||
#ifndef GSL_GSL_H
|
||||
#define GSL_GSL_H
|
||||
|
||||
#include <gsl/gsl_algorithm> // copy
|
||||
#include <gsl/gsl_assert> // Ensures/Expects
|
||||
#include <gsl/gsl_byte> // byte
|
||||
#include <gsl/gsl_util> // finally()/narrow()/narrow_cast()...
|
||||
#include <gsl/multi_span> // multi_span, strided_span...
|
||||
#include <gsl/pointers> // owner, not_null
|
||||
#include <gsl/span> // span
|
||||
#include <gsl/string_span> // zstring, string_span, zstring_builder...
|
||||
// IWYU pragma: begin_exports
|
||||
#include "./algorithm" // copy
|
||||
#include "./assert" // Ensures/Expects
|
||||
#include "./byte" // byte
|
||||
#include "./pointers" // owner, not_null
|
||||
#include "./span" // span
|
||||
#include "./zstring" // zstring
|
||||
#include "./util" // finally()/narrow_cast()...
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
#include "./narrow" // narrow()
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif // GSL_GSL_H
|
||||
|
@ -1,171 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_UTIL_H
|
||||
#define GSL_UTIL_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <type_traits> // for is_signed, integral_constant
|
||||
#include <utility> // for exchange, forward
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
|
||||
#if _MSC_VER < 1910
|
||||
#pragma push_macro("constexpr")
|
||||
#define constexpr /*constexpr*/
|
||||
#endif // _MSC_VER < 1910
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1910) || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ < 6)
|
||||
#define GSL_CONSTEXPR_NARROW 0
|
||||
#else
|
||||
#define GSL_CONSTEXPR_NARROW 1
|
||||
#endif
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// GSL.util: utilities
|
||||
//
|
||||
|
||||
// index type for all container indexes/subscripts/sizes
|
||||
using index = std::ptrdiff_t;
|
||||
|
||||
// final_action allows you to ensure something gets run at the end of a scope
|
||||
template <class F>
|
||||
class final_action
|
||||
{
|
||||
public:
|
||||
explicit final_action(F f) noexcept : f_(std::move(f)) {}
|
||||
|
||||
final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) {}
|
||||
|
||||
final_action(const final_action&) = delete;
|
||||
final_action& operator=(const final_action&) = delete;
|
||||
final_action& operator=(final_action&&) = delete;
|
||||
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
|
||||
~final_action() noexcept
|
||||
{
|
||||
if (invoke_) f_();
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
bool invoke_{true};
|
||||
};
|
||||
|
||||
// finally() - convenience function to generate a final_action
|
||||
template <class F>
|
||||
final_action<F> finally(const F& f) noexcept
|
||||
{
|
||||
return final_action<F>(f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
final_action<F> finally(F&& f) noexcept
|
||||
{
|
||||
return final_action<F>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
// narrow_cast(): a searchable way to do narrowing casts of values
|
||||
template <class T, class U>
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
constexpr T narrow_cast(U&& u) noexcept
|
||||
{
|
||||
return static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
struct narrowing_error : public std::exception
|
||||
{
|
||||
};
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <class T, class U>
|
||||
struct is_same_signedness
|
||||
: public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
|
||||
{
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
|
||||
template <class T, class U>
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
|
||||
#if GSL_CONSTEXPR_NARROW
|
||||
constexpr
|
||||
#endif
|
||||
T narrow(U u) noexcept(false)
|
||||
{
|
||||
T t = narrow_cast<T>(u);
|
||||
if (static_cast<U>(t) != u) throw narrowing_error{};
|
||||
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
|
||||
throw narrowing_error{};
|
||||
return t;
|
||||
}
|
||||
|
||||
//
|
||||
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
|
||||
//
|
||||
template <class T, std::size_t N>
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
constexpr T& at(T (&arr)[N], const index i)
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(N));
|
||||
return arr[narrow_cast<std::size_t>(i)];
|
||||
}
|
||||
|
||||
template <class Cont>
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
using size_type = decltype(cont.size());
|
||||
return cont[narrow_cast<size_type>(i)];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
constexpr T at(const std::initializer_list<T> cont, const index i)
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
return *(cont.begin() + i);
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#if _MSC_VER < 1910
|
||||
#undef constexpr
|
||||
#pragma pop_macro("constexpr")
|
||||
|
||||
#endif // _MSC_VER < 1910
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GSL_UTIL_H
|
File diff suppressed because it is too large
Load Diff
82
include/gsl/narrow
Normal file
82
include/gsl/narrow
Normal file
@ -0,0 +1,82 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_NARROW_H
|
||||
#define GSL_NARROW_H
|
||||
#include "./assert" // for GSL_SUPPRESS
|
||||
#include "./util" // for narrow_cast
|
||||
#include <exception> // for std::exception
|
||||
namespace gsl
|
||||
{
|
||||
struct narrowing_error : public std::exception
|
||||
{
|
||||
const char* what() const noexcept override { return "narrowing_error"; }
|
||||
};
|
||||
|
||||
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
|
||||
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(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)
|
||||
{
|
||||
constexpr const bool is_different_signedness =
|
||||
(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
|
||||
// Note: NaN will always throw, since NaN != NaN
|
||||
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
|
||||
// clang-format on
|
||||
constexpr T narrow(U u)
|
||||
{
|
||||
const T t = narrow_cast<T>(u);
|
||||
|
||||
if (static_cast<U>(t) != u)
|
||||
{
|
||||
throw narrowing_error{};
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
} // namespace gsl
|
||||
#endif // GSL_NARROW_H
|
@ -17,38 +17,69 @@
|
||||
#ifndef GSL_POINTERS_H
|
||||
#define GSL_POINTERS_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Ensures, Expects
|
||||
#include "./assert" // for Ensures, Expects
|
||||
#include "./util" // for GSL_DEPRECATED
|
||||
|
||||
#include <algorithm> // for forward
|
||||
#include <iosfwd> // for ptrdiff_t, nullptr_t, ostream, size_t
|
||||
#include <memory> // for shared_ptr, unique_ptr
|
||||
#include <system_error> // for hash
|
||||
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t
|
||||
#include <functional> // for less, greater
|
||||
#include <memory> // for shared_ptr, unique_ptr, hash
|
||||
#include <type_traits> // for enable_if_t, is_convertible, is_assignable
|
||||
#include <utility> // for declval, forward
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__)
|
||||
#pragma push_macro("constexpr")
|
||||
#define constexpr /*constexpr*/
|
||||
|
||||
#endif // defined(_MSC_VER) && _MSC_VER < 1910
|
||||
#if !defined(GSL_NO_IOSTREAMS)
|
||||
#include <iosfwd> // for ostream
|
||||
#endif // !defined(GSL_NO_IOSTREAMS)
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <typename T, typename = void>
|
||||
struct is_comparable_to_nullptr : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_comparable_to_nullptr<
|
||||
T,
|
||||
std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
// Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value
|
||||
// of type T.
|
||||
//
|
||||
// Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-in)
|
||||
template<typename T>
|
||||
using value_or_reference_return_t = std::conditional_t<
|
||||
sizeof(T) < 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
|
||||
const T,
|
||||
const T&>;
|
||||
|
||||
} // namespace details
|
||||
|
||||
//
|
||||
// GSL.owner: ownership pointers
|
||||
//
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
template <typename... Ts>
|
||||
using shared_ptr GSL_DEPRECATED("Use std::shared_ptr instead") = std::shared_ptr<Ts...>;
|
||||
|
||||
template <typename... Ts>
|
||||
using unique_ptr GSL_DEPRECATED("Use std::unique_ptr instead") = std::unique_ptr<Ts...>;
|
||||
|
||||
//
|
||||
// owner
|
||||
//
|
||||
// owner<T> is designed as a bridge for code that must deal directly with owning pointers for some reason
|
||||
// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory.
|
||||
// Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used
|
||||
// as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers.
|
||||
//
|
||||
// T must be a pointer type
|
||||
// - disallow construction from any type other than pointer type
|
||||
//
|
||||
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
|
||||
template <class T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
using owner = T;
|
||||
|
||||
//
|
||||
@ -69,36 +100,36 @@ template <class T>
|
||||
class not_null
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
|
||||
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
|
||||
|
||||
using element_type = T;
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(U&& u) : ptr_(std::forward<U>(u))
|
||||
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
|
||||
{
|
||||
Expects(ptr_ != nullptr);
|
||||
}
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr not_null(T u) : ptr_(u)
|
||||
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
|
||||
{
|
||||
Expects(ptr_ != nullptr);
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(const not_null<U>& other) : not_null(other.get())
|
||||
{
|
||||
}
|
||||
constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
|
||||
{}
|
||||
|
||||
not_null(const not_null& other) = default;
|
||||
not_null& operator=(const not_null& other) = default;
|
||||
|
||||
constexpr T get() const
|
||||
constexpr details::value_or_reference_return_t<T> get() const
|
||||
noexcept(noexcept(details::value_or_reference_return_t<T>(std::declval<T&>())))
|
||||
{
|
||||
Ensures(ptr_ != nullptr);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
constexpr operator T() const { return get(); }
|
||||
constexpr T operator->() const { return get(); }
|
||||
constexpr decltype(auto) operator->() const { return get(); }
|
||||
constexpr decltype(auto) operator*() const { return *get(); }
|
||||
|
||||
// prevents compilation when someone attempts to assign a null pointer constant
|
||||
@ -114,56 +145,79 @@ public:
|
||||
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
|
||||
void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
|
||||
|
||||
private:
|
||||
T ptr_;
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
|
||||
void swap(not_null<T>& a, not_null<T>& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_not_null(T&& t) {
|
||||
auto make_not_null(T&& t) noexcept
|
||||
{
|
||||
return not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
#if !defined(GSL_NO_IOSTREAMS)
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
|
||||
{
|
||||
os << val.get();
|
||||
return os;
|
||||
}
|
||||
#endif // !defined(GSL_NO_IOSTREAMS)
|
||||
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() == rhs.get())
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
|
||||
-> decltype(lhs.get() == rhs.get())
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator!=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() != rhs.get())
|
||||
auto operator!=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
|
||||
-> decltype(lhs.get() != rhs.get())
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() < rhs.get())
|
||||
auto operator<(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::less<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return lhs.get() < rhs.get();
|
||||
return std::less<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() <= rhs.get())
|
||||
auto operator<=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return lhs.get() <= rhs.get();
|
||||
return std::less_equal<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() > rhs.get())
|
||||
auto operator>(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::greater<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return lhs.get() > rhs.get();
|
||||
return std::greater<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() >= rhs.get())
|
||||
auto operator>=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return lhs.get() >= rhs.get();
|
||||
return std::greater_equal<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
// more unwanted operators
|
||||
@ -176,14 +230,28 @@ not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
|
||||
|
||||
|
||||
template <class T, class U = decltype(std::declval<const T&>().get()), bool = std::is_default_constructible<std::hash<U>>::value>
|
||||
struct not_null_hash
|
||||
{
|
||||
std::size_t operator()(const T& value) const { return std::hash<U>{}(value.get()); }
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct not_null_hash<T, U, false>
|
||||
{
|
||||
not_null_hash() = delete;
|
||||
not_null_hash(const not_null_hash&) = delete;
|
||||
not_null_hash& operator=(const not_null_hash&) = delete;
|
||||
};
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class T>
|
||||
struct hash<gsl::not_null<T>>
|
||||
struct hash<gsl::not_null<T>> : gsl::not_null_hash<gsl::not_null<T>>
|
||||
{
|
||||
std::size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
@ -209,31 +277,28 @@ namespace gsl
|
||||
// - remove unnecessary asserts
|
||||
//
|
||||
template <class T>
|
||||
class strict_not_null: public not_null<T>
|
||||
class strict_not_null : public not_null<T>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr explicit strict_not_null(U&& u) :
|
||||
not_null<T>(std::forward<U>(u))
|
||||
constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::forward<U>(u))
|
||||
{}
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr explicit strict_not_null(T u) :
|
||||
not_null<T>(u)
|
||||
constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::move(u))
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const not_null<U>& other) :
|
||||
not_null<T>(other)
|
||||
constexpr strict_not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const strict_not_null<U>& other) :
|
||||
not_null<T>(other)
|
||||
constexpr strict_not_null(const strict_not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
strict_not_null(strict_not_null&& other) = default;
|
||||
// To avoid invalidating the "not null" invariant, the contained pointer is actually copied
|
||||
// instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions.
|
||||
strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
|
||||
strict_not_null(const strict_not_null& other) = default;
|
||||
strict_not_null& operator=(const strict_not_null& other) = default;
|
||||
strict_not_null& operator=(const not_null<T>& other)
|
||||
@ -267,15 +332,18 @@ template <class T>
|
||||
strict_not_null<T> operator+(std::ptrdiff_t, const strict_not_null<T>&) = delete;
|
||||
|
||||
template <class T>
|
||||
auto make_strict_not_null(T&& t) {
|
||||
auto make_strict_not_null(T&& t) noexcept
|
||||
{
|
||||
return strict_not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
#if ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
|
||||
|
||||
// deduction guides to prevent the ctad-maybe-unsupported warning
|
||||
template <class T> not_null(T) -> not_null<T>;
|
||||
template <class T> strict_not_null(T) -> strict_not_null<T>;
|
||||
template <class T>
|
||||
not_null(T) -> not_null<T>;
|
||||
template <class T>
|
||||
strict_not_null(T) -> strict_not_null<T>;
|
||||
|
||||
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||
|
||||
@ -284,18 +352,10 @@ template <class T> strict_not_null(T) -> strict_not_null<T>;
|
||||
namespace std
|
||||
{
|
||||
template <class T>
|
||||
struct hash<gsl::strict_not_null<T>>
|
||||
struct hash<gsl::strict_not_null<T>> : gsl::not_null_hash<gsl::strict_not_null<T>>
|
||||
{
|
||||
std::size_t operator()(const gsl::strict_not_null<T>& value) const { return hash<T>{}(value); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__)
|
||||
|
||||
#undef constexpr
|
||||
#pragma pop_macro("constexpr")
|
||||
|
||||
#endif // defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__)
|
||||
|
||||
#endif // GSL_POINTERS_H
|
||||
|
298
include/gsl/span
298
include/gsl/span
@ -17,14 +17,21 @@
|
||||
#ifndef GSL_SPAN_H
|
||||
#define GSL_SPAN_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include <gsl/gsl_byte> // for byte
|
||||
#include "./assert" // for Expects
|
||||
#include "./byte" // for gsl::impl::byte
|
||||
#include "./span_ext" // for span specialization of gsl::at and other span-related extensions
|
||||
#include "./util" // for narrow_cast
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
|
||||
#include <iterator> // for reverse_iterator, distance, random_access_...
|
||||
#include <memory> // for pointer_traits
|
||||
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
|
||||
|
||||
#if defined(__has_include) && __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#pragma warning(push)
|
||||
|
||||
@ -35,15 +42,9 @@
|
||||
#pragma warning(disable : 4702) // unreachable code
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
|
||||
#pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
|
||||
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
|
||||
|
||||
#if _MSC_VER < 1910
|
||||
#pragma push_macro("constexpr")
|
||||
#define constexpr /*constexpr*/
|
||||
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||
|
||||
#endif // _MSC_VER < 1910
|
||||
#endif // _MSC_VER
|
||||
|
||||
// See if we have enough C++17 power to use a static constexpr data member
|
||||
@ -52,7 +53,7 @@
|
||||
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||
|
||||
// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
|
||||
// GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
|
||||
// While there is a conversion from signed to unsigned, it happens at
|
||||
// compiletime, so the compiler wouldn't have to warn indiscriminately, but
|
||||
// could check if the source value actually doesn't fit into the target type
|
||||
@ -62,15 +63,17 @@
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
// Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wunsafe-buffer-usage")
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#endif // __has_warning("-Wunsafe-buffer-usage")
|
||||
#endif // defined(__clang__)
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
// [views.constants], constants
|
||||
constexpr const std::size_t dynamic_extent = static_cast<std::size_t>(-1);
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
|
||||
// implementation details
|
||||
namespace details
|
||||
{
|
||||
@ -106,7 +109,7 @@ namespace details
|
||||
|
||||
template <std::size_t From, std::size_t To>
|
||||
struct is_allowed_extent_conversion
|
||||
: std::integral_constant<bool, From == To || To == gsl::dynamic_extent>
|
||||
: std::integral_constant<bool, From == To || To == dynamic_extent>
|
||||
{
|
||||
};
|
||||
|
||||
@ -120,6 +123,9 @@ namespace details
|
||||
class span_iterator
|
||||
{
|
||||
public:
|
||||
#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
|
||||
using iterator_concept = std::contiguous_iterator_tag;
|
||||
#endif // __cpp_lib_ranges
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = std::remove_cv_t<Type>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
@ -128,12 +134,15 @@ namespace details
|
||||
|
||||
#ifdef _MSC_VER
|
||||
using _Unchecked_type = pointer;
|
||||
using _Prevent_inheriting_unwrap = span_iterator;
|
||||
#endif // _MSC_VER
|
||||
constexpr span_iterator() = default;
|
||||
|
||||
constexpr span_iterator(pointer begin, pointer end, pointer current)
|
||||
: begin_(begin), end_(end), current_(current)
|
||||
{}
|
||||
{
|
||||
Expects(begin_ <= current_ && current <= end_);
|
||||
}
|
||||
|
||||
constexpr operator span_iterator<const Type>() const noexcept
|
||||
{
|
||||
@ -142,21 +151,21 @@ namespace details
|
||||
|
||||
constexpr reference operator*() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
return *current_;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
return current_;
|
||||
}
|
||||
constexpr span_iterator& operator++() noexcept
|
||||
{
|
||||
Expects(begin_ && current_ && end_);
|
||||
Expects(current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
++current_;
|
||||
return *this;
|
||||
}
|
||||
@ -170,8 +179,7 @@ namespace details
|
||||
|
||||
constexpr span_iterator& operator--() noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ < current_);
|
||||
Expects(begin_ != current_);
|
||||
--current_;
|
||||
return *this;
|
||||
}
|
||||
@ -188,6 +196,9 @@ namespace details
|
||||
if (n != 0) Expects(begin_ && current_ && end_);
|
||||
if (n > 0) Expects(end_ - current_ >= n);
|
||||
if (n < 0) Expects(current_ - begin_ >= -n);
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
current_ += n;
|
||||
return *this;
|
||||
}
|
||||
@ -210,6 +221,7 @@ namespace details
|
||||
if (n != 0) Expects(begin_ && current_ && end_);
|
||||
if (n > 0) Expects(current_ - begin_ >= n);
|
||||
if (n < 0) Expects(end_ - current_ >= -n);
|
||||
GSL_SUPPRESS(bounds .1)
|
||||
current_ -= n;
|
||||
return *this;
|
||||
}
|
||||
@ -333,8 +345,26 @@ namespace details
|
||||
pointer begin_ = nullptr;
|
||||
pointer end_ = nullptr;
|
||||
pointer current_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename Ptr>
|
||||
friend struct std::pointer_traits;
|
||||
};
|
||||
}} // namespace gsl::details
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class Type>
|
||||
struct pointer_traits<::gsl::details::span_iterator<Type>>
|
||||
{
|
||||
using pointer = ::gsl::details::span_iterator<Type>;
|
||||
using element_type = Type;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; }
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace gsl { namespace details {
|
||||
template <std::size_t Ext>
|
||||
class extent_type
|
||||
{
|
||||
@ -343,17 +373,18 @@ namespace details
|
||||
|
||||
constexpr extent_type() noexcept = default;
|
||||
|
||||
template <size_type Other>
|
||||
constexpr extent_type(extent_type<Other> ext)
|
||||
{
|
||||
static_assert(Other == Ext,
|
||||
"Mismatch between fixed-size extent and size of initializing data.");
|
||||
Expects(ext.size() == Ext);
|
||||
}
|
||||
constexpr explicit extent_type(extent_type<dynamic_extent>);
|
||||
|
||||
constexpr extent_type(size_type size) { Expects(size == Ext); }
|
||||
constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
|
||||
|
||||
constexpr size_type size() const noexcept { return Ext; }
|
||||
|
||||
private:
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
static constexpr const size_type size_ = Ext; // static size equal to Ext
|
||||
#else
|
||||
static constexpr size_type size_ = Ext; // static size equal to Ext
|
||||
#endif
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -363,10 +394,10 @@ namespace details
|
||||
using size_type = std::size_t;
|
||||
|
||||
template <size_type Other>
|
||||
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
|
||||
constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
|
||||
{}
|
||||
|
||||
explicit constexpr extent_type(size_type size) : size_(size)
|
||||
constexpr explicit extent_type(size_type size) : size_(size)
|
||||
{
|
||||
Expects(size != dynamic_extent);
|
||||
}
|
||||
@ -377,6 +408,12 @@ namespace details
|
||||
size_type size_;
|
||||
};
|
||||
|
||||
template <std::size_t Ext>
|
||||
constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
|
||||
{
|
||||
Expects(ext.size() == Ext);
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
|
||||
struct calculate_subspan_type
|
||||
{
|
||||
@ -420,22 +457,32 @@ public:
|
||||
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
||||
{}
|
||||
|
||||
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||
{
|
||||
if (Extent != dynamic_extent) Expects(count == Extent);
|
||||
Expects(count == Extent);
|
||||
}
|
||||
|
||||
constexpr span(pointer firstElem, pointer lastElem) noexcept
|
||||
: storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem))
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
|
||||
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||
{}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
|
||||
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
|
||||
{
|
||||
if (Extent != dynamic_extent)
|
||||
{ Expects(lastElem - firstElem == static_cast<difference_type>(Extent)); }
|
||||
Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
|
||||
}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
|
||||
constexpr span(pointer firstElem, pointer lastElem) noexcept
|
||||
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
|
||||
{}
|
||||
|
||||
template <std::size_t N,
|
||||
std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
|
||||
constexpr span(element_type (&arr)[N]) noexcept
|
||||
: storage_(KnownNotNull{arr + 0}, details::extent_type<N>())
|
||||
: storage_(KnownNotNull{arr}, details::extent_type<N>())
|
||||
{}
|
||||
|
||||
template <
|
||||
@ -456,40 +503,78 @@ public:
|
||||
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
||||
{}
|
||||
|
||||
// NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement
|
||||
// on Container to be a contiguous sequence container.
|
||||
template <class Container,
|
||||
class = std::enable_if_t<
|
||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value>>
|
||||
// NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
|
||||
// requirement on Container to be a contiguous sequence container.
|
||||
template <std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent != dynamic_extent && !details::is_span<Container>::value &&
|
||||
!details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent == dynamic_extent && !details::is_span<Container>::value &&
|
||||
!details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <class Container,
|
||||
class = std::enable_if_t<
|
||||
std::is_const<element_type>::value && !details::is_span<Container>::value &&
|
||||
!details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
|
||||
std::is_convertible<std::remove_pointer_t<
|
||||
decltype(std::declval<const Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value>>
|
||||
template <
|
||||
std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent != dynamic_extent && std::is_const<element_type>::value &&
|
||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <
|
||||
std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent == dynamic_extent && std::is_const<element_type>::value &&
|
||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
|
||||
template <
|
||||
class OtherElementType, std::size_t OtherExtent,
|
||||
class = std::enable_if_t<
|
||||
details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
|
||||
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
|
||||
template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
|
||||
std::enable_if_t<(MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
|
||||
details::is_allowed_element_type_conversion<OtherElementType,
|
||||
element_type>::value,
|
||||
int> = 0>
|
||||
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||
{}
|
||||
|
||||
template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
|
||||
std::enable_if_t<MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
|
||||
details::is_allowed_element_type_conversion<OtherElementType,
|
||||
element_type>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||
{}
|
||||
|
||||
~span() noexcept = default;
|
||||
constexpr span& operator=(const span& other) noexcept = default;
|
||||
|
||||
@ -497,8 +582,10 @@ public:
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const noexcept
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"first() cannot extract more elements from a span than it contains.");
|
||||
Expects(Count <= size());
|
||||
return {data(), Count};
|
||||
return span<element_type, Count>{data(), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
@ -507,8 +594,10 @@ public:
|
||||
// clang-format on
|
||||
constexpr span<element_type, Count> last() const noexcept
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"last() cannot extract more elements from a span than it contains.");
|
||||
Expects(Count <= size());
|
||||
return {data() + (size() - Count), Count};
|
||||
return span<element_type, Count>{data() + (size() - Count), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
@ -518,9 +607,13 @@ public:
|
||||
constexpr auto subspan() const noexcept ->
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
|
||||
Count <= Extent - Offset)),
|
||||
"subspan() cannot extract more elements from a span than it contains.");
|
||||
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
|
||||
|
||||
return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
|
||||
using type =
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
|
||||
return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
|
||||
@ -535,9 +628,8 @@ public:
|
||||
return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> subspan(size_type offset,
|
||||
size_type count = dynamic_extent) const
|
||||
noexcept
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const noexcept
|
||||
{
|
||||
return make_subspan(offset, count, subspan_selector<Extent>{});
|
||||
}
|
||||
@ -545,11 +637,7 @@ public:
|
||||
// [span.obs], span observers
|
||||
constexpr size_type size() const noexcept { return storage_.size(); }
|
||||
|
||||
constexpr size_type size_bytes() const noexcept
|
||||
{
|
||||
Expects(size() < dynamic_extent / sizeof(element_type));
|
||||
return size() * sizeof(element_type);
|
||||
}
|
||||
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
|
||||
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
@ -631,14 +719,11 @@ private:
|
||||
template <class OtherExtentType>
|
||||
constexpr storage_type(KnownNotNull data, OtherExtentType ext)
|
||||
: ExtentType(ext), data_(data.p)
|
||||
{
|
||||
Expects(ExtentType::size() != dynamic_extent);
|
||||
}
|
||||
{}
|
||||
|
||||
template <class OtherExtentType>
|
||||
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
|
||||
{
|
||||
Expects(ExtentType::size() != dynamic_extent);
|
||||
Expects(data || ExtentType::size() == 0);
|
||||
}
|
||||
|
||||
@ -660,9 +745,8 @@ private:
|
||||
};
|
||||
|
||||
template <std::size_t CallerExtent>
|
||||
constexpr span<element_type, dynamic_extent> make_subspan(size_type offset, size_type count,
|
||||
subspan_selector<CallerExtent>) const
|
||||
noexcept
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
make_subspan(size_type offset, size_type count, subspan_selector<CallerExtent>) const noexcept
|
||||
{
|
||||
const span<element_type, dynamic_extent> tmp(*this);
|
||||
return tmp.subspan(offset, count);
|
||||
@ -687,19 +771,34 @@ private:
|
||||
|
||||
// Deduction Guides
|
||||
template <class Type, std::size_t Extent>
|
||||
span(Type (&)[Extent])->span<Type, Extent>;
|
||||
span(Type (&)[Extent]) -> span<Type, Extent>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(std::array<Type, Size>&)->span<Type, Size>;
|
||||
span(std::array<Type, Size>&) -> span<Type, Size>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(const std::array<Type, Size>&)->span<const Type, Size>;
|
||||
span(const std::array<Type, Size>&) -> span<const Type, Size>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
|
||||
span(Container&) -> span<Element>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
|
||||
span(const Container&) -> span<Element>;
|
||||
|
||||
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this static constexpr workaround in C++14 mode.
|
||||
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
|
||||
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#pragma clang diagnostic pop
|
||||
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#endif
|
||||
|
||||
namespace details
|
||||
@ -725,34 +824,33 @@ namespace details
|
||||
|
||||
// [span.objectrep], views of object representation
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||
return type{reinterpret_cast<const gsl::impl::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent,
|
||||
std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
|
||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||
return type{reinterpret_cast<gsl::impl::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#if _MSC_VER < 1910
|
||||
#undef constexpr
|
||||
#pragma pop_macro("constexpr")
|
||||
|
||||
#endif // _MSC_VER < 1910
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
@ -761,4 +859,10 @@ as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
#pragma GCC diagnostic pop
|
||||
#endif // __GNUC__ > 6
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wunsafe-buffer-usage")
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __has_warning("-Wunsafe-buffer-usage")
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#endif // GSL_SPAN_H
|
||||
|
@ -27,17 +27,29 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "./assert" // GSL_KERNEL_MODE
|
||||
#include "./util" // for narrow_cast, narrow
|
||||
|
||||
#include <gsl/gsl_util> // for narrow_cast, narrow
|
||||
#include <gsl/span> // for span
|
||||
|
||||
#include <algorithm> // for lexicographical_compare
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <utility>
|
||||
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
#include <algorithm> // for lexicographical_compare
|
||||
#endif // GSL_KERNEL_MODE
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
// [span.views.constants], constants
|
||||
GSL_INLINE constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
|
||||
// std::equal and std::lexicographical_compare are not /kernel compatible
|
||||
// so all comparison operators must be removed for kernel mode.
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
|
||||
// [span.comparison], span comparison operators
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
|
||||
@ -75,6 +87,8 @@ constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent>
|
||||
return !(l < r);
|
||||
}
|
||||
|
||||
#endif // GSL_KERNEL_MODE
|
||||
|
||||
//
|
||||
// make_span() - Utility functions for creating spans
|
||||
//
|
||||
@ -109,12 +123,14 @@ constexpr span<const typename Container::value_type> make_span(const Container&
|
||||
}
|
||||
|
||||
template <class Ptr>
|
||||
GSL_DEPRECATED("This function is deprecated. See GSL issue #1092.")
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count)
|
||||
{
|
||||
return span<typename Ptr::element_type>(cont, count);
|
||||
}
|
||||
|
||||
template <class Ptr>
|
||||
GSL_DEPRECATED("This function is deprecated. See GSL issue #1092.")
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
|
||||
{
|
||||
return span<typename Ptr::element_type>(cont);
|
||||
|
@ -1,716 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_STRING_SPAN_H
|
||||
#define GSL_STRING_SPAN_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Ensures, Expects
|
||||
#include <gsl/gsl_util> // for narrow_cast
|
||||
#include <gsl/span_ext> // for operator!=, operator==, dynamic_extent
|
||||
|
||||
#include <algorithm> // for equal, lexicographical_compare
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t, nullptr_t
|
||||
#include <cstdint> // for PTRDIFF_MAX
|
||||
#include <cstring>
|
||||
#include <string> // for basic_string, allocator, char_traits
|
||||
#include <type_traits> // for declval, is_convertible, enable_if_t, add_...
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#pragma warning(push)
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates
|
||||
#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes
|
||||
|
||||
#if _MSC_VER < 1910
|
||||
#pragma push_macro("constexpr")
|
||||
#define constexpr /*constexpr*/
|
||||
|
||||
#endif // _MSC_VER < 1910
|
||||
#endif // _MSC_VER
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// czstring and wzstring
|
||||
//
|
||||
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
|
||||
// that allow static analysis to help find bugs.
|
||||
//
|
||||
// There are no additional features/semantics that we can find a way to add inside the
|
||||
// type system for these types that will not either incur significant runtime costs or
|
||||
// (sometimes needlessly) break existing programs when introduced.
|
||||
//
|
||||
|
||||
template <typename CharT, std::size_t Extent = dynamic_extent>
|
||||
using basic_zstring = CharT*;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using czstring = basic_zstring<const char, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cwzstring = basic_zstring<const wchar_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cu16zstring = basic_zstring<const char16_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cu32zstring = basic_zstring<const char32_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using zstring = basic_zstring<char, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using wzstring = basic_zstring<wchar_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using u16zstring = basic_zstring<char16_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using u32zstring = basic_zstring<char32_t, Extent>;
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <class CharT>
|
||||
std::size_t string_length(const CharT* str, std::size_t n)
|
||||
{
|
||||
if (str == nullptr || n == dynamic_extent) return 0;
|
||||
|
||||
const span<const CharT> str_span{str, n};
|
||||
|
||||
std::size_t len = 0;
|
||||
while (len < n && str_span[len]) len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
//
|
||||
// ensure_sentinel()
|
||||
//
|
||||
// Provides a way to obtain an span from a contiguous sequence
|
||||
// that ends with a (non-inclusive) sentinel value.
|
||||
//
|
||||
// Will fail-fast if sentinel cannot be found before max elements are examined.
|
||||
//
|
||||
template <typename T, const T Sentinel>
|
||||
span<T, dynamic_extent> ensure_sentinel(T* seq,
|
||||
std::size_t max = static_cast<std::size_t>(-1))
|
||||
{
|
||||
Ensures(seq != nullptr);
|
||||
|
||||
GSL_SUPPRESS(
|
||||
f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work
|
||||
auto cur = seq;
|
||||
Ensures(cur != nullptr); // workaround for removing the warning
|
||||
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work
|
||||
while (static_cast<std::size_t>(cur - seq) < max && *cur != Sentinel) ++cur;
|
||||
Ensures(*cur == Sentinel);
|
||||
return {seq, static_cast<std::size_t>(cur - seq)};
|
||||
}
|
||||
|
||||
//
|
||||
// ensure_z - creates a span for a zero terminated strings.
|
||||
// Will fail fast if a null-terminator cannot be found before
|
||||
// the limit of size_type.
|
||||
//
|
||||
template <typename CharT>
|
||||
span<CharT, dynamic_extent> ensure_z(CharT* const& sz,
|
||||
std::size_t max = static_cast<std::size_t>(-1))
|
||||
{
|
||||
return ensure_sentinel<CharT, CharT(0)>(sz, max);
|
||||
}
|
||||
|
||||
template <typename CharT, std::size_t N>
|
||||
span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
|
||||
{
|
||||
return ensure_z(&sz[0], N);
|
||||
}
|
||||
|
||||
template <class Cont>
|
||||
span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent>
|
||||
ensure_z(Cont& cont)
|
||||
{
|
||||
return ensure_z(cont.data(), cont.size());
|
||||
}
|
||||
|
||||
template <typename CharT, std::size_t>
|
||||
class basic_string_span;
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <typename T>
|
||||
struct is_basic_string_span_oracle : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename CharT, std::size_t Extent>
|
||||
struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>>
|
||||
{
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
//
|
||||
// string_span and relatives
|
||||
//
|
||||
template <typename CharT, std::size_t Extent = dynamic_extent>
|
||||
class basic_string_span
|
||||
{
|
||||
public:
|
||||
using element_type = CharT;
|
||||
using value_type = std::remove_cv_t<element_type>;
|
||||
using pointer = std::add_pointer_t<element_type>;
|
||||
using reference = std::add_lvalue_reference_t<element_type>;
|
||||
using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>;
|
||||
using impl_type = span<element_type, Extent>;
|
||||
|
||||
using size_type = typename impl_type::size_type;
|
||||
using iterator = typename impl_type::iterator;
|
||||
using reverse_iterator = typename impl_type::reverse_iterator;
|
||||
|
||||
// default (empty)
|
||||
constexpr basic_string_span() noexcept = default;
|
||||
|
||||
// copy
|
||||
constexpr basic_string_span(const basic_string_span& other) noexcept = default;
|
||||
|
||||
// assign
|
||||
constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default;
|
||||
|
||||
constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {}
|
||||
constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {}
|
||||
|
||||
// From static arrays - if 0-terminated, remove 0 from the view
|
||||
// All other containers allow 0s within the length, so we do not remove them
|
||||
template <std::size_t N>
|
||||
constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr))
|
||||
{}
|
||||
|
||||
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||
constexpr basic_string_span(std::array<ArrayElementType, N>& arr) noexcept : span_(arr)
|
||||
{}
|
||||
|
||||
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||
constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) noexcept : span_(arr)
|
||||
{}
|
||||
|
||||
// Container signature should work for basic_string after C++17 version exists
|
||||
template <class Traits, class Allocator>
|
||||
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
|
||||
constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator>& str)
|
||||
: span_(&str[0], str.length())
|
||||
{}
|
||||
|
||||
template <class Traits, class Allocator>
|
||||
constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str)
|
||||
: span_(&str[0], str.length())
|
||||
{}
|
||||
|
||||
// from containers. Containers must have a pointer type and data() function signatures
|
||||
template <class Container,
|
||||
class = std::enable_if_t<
|
||||
!details::is_basic_string_span<Container>::value &&
|
||||
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||
std::is_convertible<typename Container::pointer,
|
||||
decltype(std::declval<Container>().data())>::value>>
|
||||
constexpr basic_string_span(Container& cont) : span_(cont)
|
||||
{}
|
||||
|
||||
template <class Container,
|
||||
class = std::enable_if_t<
|
||||
!details::is_basic_string_span<Container>::value &&
|
||||
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||
std::is_convertible<typename Container::pointer,
|
||||
decltype(std::declval<Container>().data())>::value>>
|
||||
constexpr basic_string_span(const Container& cont) : span_(cont)
|
||||
{}
|
||||
|
||||
// from string_span
|
||||
template <
|
||||
class OtherValueType, std::size_t OtherExtent,
|
||||
class = std::enable_if_t<std::is_convertible<
|
||||
typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>>
|
||||
constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other)
|
||||
: span_(other.data(), other.length())
|
||||
{}
|
||||
|
||||
template <size_type Count>
|
||||
constexpr basic_string_span<element_type, Count> first() const
|
||||
{
|
||||
return {span_.template first<Count>()};
|
||||
}
|
||||
|
||||
constexpr basic_string_span<element_type, dynamic_extent> first(size_type count) const
|
||||
{
|
||||
return {span_.first(count)};
|
||||
}
|
||||
|
||||
template <size_type Count>
|
||||
constexpr basic_string_span<element_type, Count> last() const
|
||||
{
|
||||
return {span_.template last<Count>()};
|
||||
}
|
||||
|
||||
constexpr basic_string_span<element_type, dynamic_extent> last(size_type count) const
|
||||
{
|
||||
return {span_.last(count)};
|
||||
}
|
||||
|
||||
template <size_type Offset, size_type Count>
|
||||
constexpr basic_string_span<element_type, Count> subspan() const
|
||||
{
|
||||
return {span_.template subspan<Offset, Count>()};
|
||||
}
|
||||
|
||||
constexpr basic_string_span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const
|
||||
{
|
||||
return {span_.subspan(offset, count)};
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type idx) const { return span_[idx]; }
|
||||
constexpr reference operator()(size_type idx) const { return span_[idx]; }
|
||||
|
||||
constexpr pointer data() const { return span_.data(); }
|
||||
|
||||
constexpr size_type length() const noexcept { return span_.size(); }
|
||||
constexpr size_type size() const noexcept { return span_.size(); }
|
||||
constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); }
|
||||
constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); }
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
constexpr iterator begin() const noexcept { return span_.begin(); }
|
||||
constexpr iterator end() const noexcept { return span_.end(); }
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); }
|
||||
constexpr reverse_iterator rend() const noexcept { return span_.rend(); }
|
||||
|
||||
private:
|
||||
static impl_type remove_z(pointer const& sz, std::size_t max)
|
||||
{
|
||||
return {sz, details::string_length(sz, max)};
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
static impl_type remove_z(element_type (&sz)[N])
|
||||
{
|
||||
return remove_z(&sz[0], N);
|
||||
}
|
||||
|
||||
impl_type span_;
|
||||
};
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using string_span = basic_string_span<char, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cstring_span = basic_string_span<const char, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using wstring_span = basic_string_span<wchar_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cwstring_span = basic_string_span<const wchar_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using u16string_span = basic_string_span<char16_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cu16string_span = basic_string_span<const char16_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using u32string_span = basic_string_span<char32_t, Extent>;
|
||||
|
||||
template <std::size_t Extent = dynamic_extent>
|
||||
using cu32string_span = basic_string_span<const char32_t, Extent>;
|
||||
|
||||
//
|
||||
// to_string() allow (explicit) conversions from string_span to string
|
||||
//
|
||||
|
||||
template <typename CharT, std::size_t Extent>
|
||||
std::basic_string<typename std::remove_const<CharT>::type>
|
||||
to_string(basic_string_span<CharT, Extent> view)
|
||||
{
|
||||
return {view.data(), narrow_cast<std::size_t>(view.length())};
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits = typename std::char_traits<CharT>,
|
||||
typename Allocator = std::allocator<CharT>, typename gCharT, std::size_t Extent>
|
||||
std::basic_string<CharT, Traits, Allocator> to_basic_string(basic_string_span<gCharT, Extent> view)
|
||||
{
|
||||
return {view.data(), narrow_cast<std::size_t>(view.length())};
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(basic_string_span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent,
|
||||
class = std::enable_if_t<!std::is_const<ElementType>::value>>
|
||||
basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(basic_string_span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
// zero-terminated string span, used to convert
|
||||
// zero-terminated spans to legacy strings
|
||||
template <typename CharT, std::size_t Extent = dynamic_extent>
|
||||
class basic_zstring_span
|
||||
{
|
||||
public:
|
||||
using value_type = CharT;
|
||||
using const_value_type = std::add_const_t<CharT>;
|
||||
|
||||
using pointer = std::add_pointer_t<value_type>;
|
||||
using const_pointer = std::add_pointer_t<const_value_type>;
|
||||
|
||||
using zstring_type = basic_zstring<value_type, Extent>;
|
||||
using const_zstring_type = basic_zstring<const_value_type, Extent>;
|
||||
|
||||
using impl_type = span<value_type, Extent>;
|
||||
using string_span_type = basic_string_span<value_type, Extent>;
|
||||
|
||||
constexpr basic_zstring_span(impl_type s) : span_(s)
|
||||
{
|
||||
// expects a zero-terminated span
|
||||
Expects(s[s.size() - 1] == '\0');
|
||||
}
|
||||
|
||||
// copy
|
||||
constexpr basic_zstring_span(const basic_zstring_span& other) = default;
|
||||
|
||||
// move
|
||||
constexpr basic_zstring_span(basic_zstring_span&& other) = default;
|
||||
|
||||
// assign
|
||||
constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;
|
||||
|
||||
// move assign
|
||||
constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;
|
||||
|
||||
constexpr bool empty() const noexcept { return span_.size() == 0; }
|
||||
|
||||
constexpr string_span_type as_string_span() const noexcept
|
||||
{
|
||||
const auto sz = span_.size();
|
||||
return {span_.data(), sz > 1 ? sz - 1 : 0};
|
||||
}
|
||||
constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); }
|
||||
|
||||
constexpr const_zstring_type assume_z() const noexcept { return span_.data(); }
|
||||
|
||||
private:
|
||||
impl_type span_;
|
||||
};
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using zstring_span = basic_zstring_span<char, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using wzstring_span = basic_zstring_span<wchar_t, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using u16zstring_span = basic_zstring_span<char16_t, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using u32zstring_span = basic_zstring_span<char32_t, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using czstring_span = basic_zstring_span<const char, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using cwzstring_span = basic_zstring_span<const wchar_t, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using cu16zstring_span = basic_zstring_span<const char16_t, Max>;
|
||||
|
||||
template <std::size_t Max = dynamic_extent>
|
||||
using cu32zstring_span = basic_zstring_span<const char32_t, Max>;
|
||||
|
||||
// operator ==
|
||||
template <class CharT, std::size_t Extent, class T,
|
||||
class = std::enable_if_t<
|
||||
details::is_basic_string_span<T>::value ||
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
|
||||
bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other)
|
||||
{
|
||||
const gsl::basic_string_span<std::add_const_t<CharT>> tmp(other);
|
||||
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
template <class CharT, std::size_t Extent, class T,
|
||||
class = std::enable_if_t<
|
||||
!details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
|
||||
bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other)
|
||||
{
|
||||
const gsl::basic_string_span<std::add_const_t<CharT>> tmp(one);
|
||||
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||
}
|
||||
|
||||
// operator !=
|
||||
template <typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return !(one == other);
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||
!gsl::details::is_basic_string_span<T>::value>>
|
||||
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return !(one == other);
|
||||
}
|
||||
|
||||
// operator<
|
||||
template <typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
const gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||
!gsl::details::is_basic_string_span<T>::value>>
|
||||
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// VS treats temp and const containers as convertible to basic_string_span,
|
||||
// so the cases below are already covered by the previous operators
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||
}
|
||||
#endif
|
||||
|
||||
// operator <=
|
||||
template <typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return !(other < one);
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||
!gsl::details::is_basic_string_span<T>::value>>
|
||||
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return !(other < one);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// VS treats temp and const containers as convertible to basic_string_span,
|
||||
// so the cases below are already covered by the previous operators
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return !(other < one);
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return !(other < one);
|
||||
}
|
||||
#endif
|
||||
|
||||
// operator>
|
||||
template <typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return other < one;
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||
!gsl::details::is_basic_string_span<T>::value>>
|
||||
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return other < one;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// VS treats temp and const containers as convertible to basic_string_span,
|
||||
// so the cases below are already covered by the previous operators
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return other < one;
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return other < one;
|
||||
}
|
||||
#endif
|
||||
|
||||
// operator >=
|
||||
template <typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return !(one < other);
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||
!gsl::details::is_basic_string_span<T>::value>>
|
||||
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return !(one < other);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// VS treats temp and const containers as convertible to basic_string_span,
|
||||
// so the cases below are already covered by the previous operators
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
|
||||
{
|
||||
return !(one < other);
|
||||
}
|
||||
|
||||
template <
|
||||
typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T,
|
||||
typename DataType = typename T::value_type,
|
||||
typename = std::enable_if_t<
|
||||
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||
std::is_convertible<DataType*, CharT*>::value &&
|
||||
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||
DataType>::value>>
|
||||
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
|
||||
{
|
||||
return !(one < other);
|
||||
}
|
||||
#endif
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#pragma warning(pop)
|
||||
|
||||
#if _MSC_VER < 1910
|
||||
#undef constexpr
|
||||
#pragma pop_macro("constexpr")
|
||||
|
||||
#endif // _MSC_VER < 1910
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GSL_STRING_SPAN_H
|
200
include/gsl/util
Normal file
200
include/gsl/util
Normal file
@ -0,0 +1,200 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_UTIL_H
|
||||
#define GSL_UTIL_H
|
||||
|
||||
#include "./assert" // for Expects
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <limits> // for numeric_limits
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <type_traits> // for is_signed, integral_constant
|
||||
#include <utility> // for exchange, forward
|
||||
|
||||
#if defined(__has_include) && __has_include(<version>)
|
||||
#include <version>
|
||||
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
#include <span>
|
||||
#endif // __cpp_lib_span >= 202002L
|
||||
#endif //__has_include(<version>)
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wunsafe-buffer-usage")
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#endif // __has_warning("-Wunsafe-buffer-usage")
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
#define GSL_NODISCARD [[nodiscard]]
|
||||
#else
|
||||
#define GSL_NODISCARD
|
||||
#endif // defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
#if defined(__cpp_inline_variables)
|
||||
#define GSL_INLINE inline
|
||||
#else
|
||||
#define GSL_INLINE
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
#if __has_cpp_attribute(deprecated)
|
||||
#define GSL_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#endif // __has_cpp_attribute(deprecated)
|
||||
#endif // defined(__has_cpp_attribute)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#if defined(__cplusplus)
|
||||
#if __cplusplus >= 201309L
|
||||
#define GSL_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#endif // __cplusplus >= 201309L
|
||||
#endif // defined(__cplusplus)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#if defined(_MSC_VER)
|
||||
#define GSL_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#elif defined(__GNUC__)
|
||||
#define GSL_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#endif // defined(_MSC_VER)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#define GSL_DEPRECATED(msg)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// GSL.util: utilities
|
||||
//
|
||||
|
||||
// index type for all container indexes/subscripts/sizes
|
||||
using index = std::ptrdiff_t;
|
||||
|
||||
// final_action allows you to ensure something gets run at the end of a scope
|
||||
template <class F>
|
||||
class final_action
|
||||
{
|
||||
public:
|
||||
explicit final_action(const F& ff) noexcept : f{ff} { }
|
||||
explicit final_action(F&& ff) noexcept : f{std::move(ff)} { }
|
||||
|
||||
~final_action() noexcept { if (invoke) f(); }
|
||||
|
||||
final_action(final_action&& other) noexcept
|
||||
: f(std::move(other.f)), invoke(std::exchange(other.invoke, false))
|
||||
{ }
|
||||
|
||||
final_action(const final_action&) = delete;
|
||||
void operator=(const final_action&) = delete;
|
||||
void operator=(final_action&&) = delete;
|
||||
|
||||
private:
|
||||
F f;
|
||||
bool invoke = true;
|
||||
};
|
||||
|
||||
// finally() - convenience function to generate a final_action
|
||||
template <class F>
|
||||
GSL_NODISCARD auto finally(F&& f) noexcept
|
||||
{
|
||||
return final_action<std::decay_t<F>>{std::forward<F>(f)};
|
||||
}
|
||||
|
||||
// narrow_cast(): a searchable way to do narrowing casts of values
|
||||
template <class T, class U>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T narrow_cast(U&& u) noexcept
|
||||
{
|
||||
return static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
//
|
||||
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
|
||||
//
|
||||
template <class T, std::size_t N>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T& at(T (&arr)[N], const index i)
|
||||
{
|
||||
static_assert(N <= static_cast<std::size_t>((std::numeric_limits<std::ptrdiff_t>::max)()), "We only support arrays up to PTRDIFF_MAX bytes.");
|
||||
Expects(i >= 0 && i < narrow_cast<index>(N));
|
||||
return arr[narrow_cast<std::size_t>(i)];
|
||||
}
|
||||
|
||||
template <class Cont>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
using size_type = decltype(cont.size());
|
||||
return cont[narrow_cast<size_type>(i)];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T at(const std::initializer_list<T> cont, const index i)
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
return *(cont.begin() + i);
|
||||
}
|
||||
|
||||
template <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
|
||||
void swap(T& a, T& b) { std::swap(a, b); }
|
||||
|
||||
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
template <class T, std::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<std::size_t>(i)];
|
||||
}
|
||||
#endif // __cpp_lib_span >= 202002L
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wunsafe-buffer-usage")
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __has_warning("-Wunsafe-buffer-usage")
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#endif // GSL_UTIL_H
|
58
include/gsl/zstring
Normal file
58
include/gsl/zstring
Normal file
@ -0,0 +1,58 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_ZSTRING_H
|
||||
#define GSL_ZSTRING_H
|
||||
|
||||
#include "./span_ext" // for dynamic_extent
|
||||
|
||||
#include <cstddef> // for size_t, nullptr_t
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// czstring and wzstring
|
||||
//
|
||||
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
|
||||
// that allow static analysis to help find bugs.
|
||||
//
|
||||
// There are no additional features/semantics that we can find a way to add inside the
|
||||
// type system for these types that will not either incur significant runtime costs or
|
||||
// (sometimes needlessly) break existing programs when introduced.
|
||||
//
|
||||
|
||||
template <typename CharT, std::size_t Extent = dynamic_extent>
|
||||
using basic_zstring = CharT*;
|
||||
|
||||
using czstring = basic_zstring<const char, dynamic_extent>;
|
||||
|
||||
using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
|
||||
|
||||
using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
|
||||
|
||||
using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
|
||||
|
||||
using zstring = basic_zstring<char, dynamic_extent>;
|
||||
|
||||
using wzstring = basic_zstring<wchar_t, dynamic_extent>;
|
||||
|
||||
using u16zstring = basic_zstring<char16_t, dynamic_extent>;
|
||||
|
||||
using u32zstring = basic_zstring<char32_t, dynamic_extent>;
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#endif // GSL_ZSTRING_H
|
@ -1,41 +1,77 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
cmake_minimum_required(VERSION 3.14...3.16)
|
||||
|
||||
project(GSLTests CXX)
|
||||
project(GSLTests LANGUAGES CXX)
|
||||
|
||||
set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard")
|
||||
|
||||
set(CMAKE_CXX_STANDARD ${GSL_CXX_STANDARD})
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(FindPkgConfig)
|
||||
include(ExternalProject)
|
||||
|
||||
# will make visual studio generated project group files
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20)
|
||||
add_compile_definitions(FORCE_STD_SPAN_TESTS=1)
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
if(IOS)
|
||||
add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1)
|
||||
endif()
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
pkg_search_module(GTestMain gtest_main)
|
||||
if (NOT GTestMain_FOUND)
|
||||
# No pre-installed GTest is available, try to download it using Git.
|
||||
find_package(Git REQUIRED QUIET)
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
if (MSVC AND (GSL_CXX_STANDARD EQUAL 17))
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(GTestMain_LIBRARIES gtest_main)
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
find_package(Microsoft.GSL CONFIG REQUIRED)
|
||||
enable_testing()
|
||||
|
||||
if (NOT DEFINED Microsoft.GSL_VERSION)
|
||||
message(FATAL_ERROR "Microsoft.GSL_VERSION not defined!")
|
||||
endif()
|
||||
|
||||
message(STATUS "Microsoft.GSL_VERSION = ${Microsoft.GSL_VERSION}")
|
||||
endif()
|
||||
|
||||
if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17))
|
||||
set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-)
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
# this interface adds compile options to how the tests are run
|
||||
# please try to keep entries ordered =)
|
||||
add_library(gsl_tests_config INTERFACE)
|
||||
@ -62,6 +98,7 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:Clang>:
|
||||
-Weverything
|
||||
-Wfloat-equal
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-covered-switch-default # GTest
|
||||
@ -73,12 +110,20 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
-Wno-shift-sign-overflow # GTest gtest-port.h
|
||||
-Wno-undef # GTest
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
-Wno-switch-default # GTest EXPECT_DEATH
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
|
||||
-Wno-unused-member-function
|
||||
-Wno-unused-variable
|
||||
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
|
||||
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config INTERFACE
|
||||
-fno-strict-aliasing
|
||||
@ -91,6 +136,7 @@ else()
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wsign-conversion
|
||||
-Wfloat-equal
|
||||
-Wno-deprecated-declarations # Allow tests for [[deprecated]] elements
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
|
||||
-Weverything
|
||||
@ -101,6 +147,7 @@ else()
|
||||
-Wno-global-constructors # GTest
|
||||
-Wno-missing-prototypes
|
||||
-Wno-padded
|
||||
-Wno-switch-default
|
||||
-Wno-unknown-attributes
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
-Wno-weak-vtables
|
||||
@ -113,6 +160,11 @@ else()
|
||||
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template>
|
||||
>
|
||||
$<$<AND:$<EQUAL:${GSL_CXX_STANDARD},20>,$<OR:$<CXX_COMPILER_VERSION:11.0.0>,$<CXX_COMPILER_VERSION:10.0.0>>>:
|
||||
-Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 10.0.0
|
||||
# and clang 11.0.0. (operator< is being re-written by the compiler
|
||||
# as operator<=> and raising the warning)
|
||||
>
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:
|
||||
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>:
|
||||
@ -136,45 +188,39 @@ else()
|
||||
>
|
||||
)
|
||||
endif(MSVC)
|
||||
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
|
||||
if (WARN_UNSAFE_BUFFER)
|
||||
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
|
||||
target_compile_options(gsl_tests_config INTERFACE "-Wno-unsafe-buffer-usage")
|
||||
endif()
|
||||
|
||||
# for tests to find the gtest header
|
||||
target_include_directories(gsl_tests_config SYSTEM INTERFACE
|
||||
googletest/googletest/include
|
||||
)
|
||||
|
||||
set_property(TARGET PROPERTY FOLDER "GSL_tests")
|
||||
|
||||
function(add_gsl_test name)
|
||||
add_executable(${name} ${name}.cpp)
|
||||
target_link_libraries(${name}
|
||||
GSL
|
||||
gsl_tests_config
|
||||
gtest_main
|
||||
)
|
||||
add_test(
|
||||
${name}
|
||||
${name}
|
||||
)
|
||||
# group all tests under GSL_tests
|
||||
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests")
|
||||
endfunction()
|
||||
|
||||
add_gsl_test(span_tests)
|
||||
add_gsl_test(span_ext_tests)
|
||||
add_gsl_test(span_compatibility_tests)
|
||||
add_gsl_test(multi_span_tests)
|
||||
add_gsl_test(strided_span_tests)
|
||||
add_gsl_test(string_span_tests)
|
||||
add_gsl_test(at_tests)
|
||||
add_gsl_test(bounds_tests)
|
||||
add_gsl_test(notnull_tests)
|
||||
add_gsl_test(assertion_tests)
|
||||
add_gsl_test(utils_tests)
|
||||
add_gsl_test(owner_tests)
|
||||
add_gsl_test(byte_tests)
|
||||
add_gsl_test(algorithm_tests)
|
||||
add_gsl_test(strict_notnull_tests)
|
||||
add_executable(gsl_tests
|
||||
algorithm_tests.cpp
|
||||
assertion_tests.cpp
|
||||
at_tests.cpp
|
||||
byte_tests.cpp
|
||||
notnull_tests.cpp
|
||||
owner_tests.cpp
|
||||
pointers_tests.cpp
|
||||
span_compatibility_tests.cpp
|
||||
span_ext_tests.cpp
|
||||
span_tests.cpp
|
||||
strict_notnull_tests.cpp
|
||||
|
||||
utils_tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(gsl_tests
|
||||
Microsoft.GSL::GSL
|
||||
gsl_tests_config
|
||||
${GTestMain_LIBRARIES}
|
||||
)
|
||||
add_test(gsl_tests gsl_tests)
|
||||
|
||||
# No exception tests
|
||||
|
||||
@ -203,12 +249,22 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:Clang>:
|
||||
-Weverything
|
||||
-Wfloat-equal
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-missing-prototypes
|
||||
-Wno-unknown-attributes
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>:
|
||||
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
|
||||
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE
|
||||
-fno-exceptions
|
||||
@ -222,6 +278,7 @@ else()
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wsign-conversion
|
||||
-Wfloat-equal
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
|
||||
-Weverything
|
||||
-Wno-c++98-compat
|
||||
@ -248,20 +305,15 @@ else()
|
||||
>
|
||||
)
|
||||
endif(MSVC)
|
||||
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
|
||||
if (WARN_UNSAFE_BUFFER)
|
||||
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-unsafe-buffer-usage")
|
||||
endif()
|
||||
|
||||
function(add_gsl_test_noexcept name)
|
||||
add_executable(${name} ${name}.cpp)
|
||||
target_link_libraries(${name}
|
||||
GSL
|
||||
gsl_tests_config_noexcept
|
||||
gtest_main
|
||||
)
|
||||
add_test(
|
||||
${name}
|
||||
${name}
|
||||
)
|
||||
# group all tests under GSL_tests_noexcept
|
||||
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept")
|
||||
endfunction()
|
||||
|
||||
add_gsl_test_noexcept(no_exception_ensure_tests)
|
||||
add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp)
|
||||
target_link_libraries(gsl_noexcept_tests
|
||||
Microsoft.GSL::GSL
|
||||
gsl_tests_config_noexcept
|
||||
)
|
||||
add_test(gsl_noexcept_tests gsl_noexcept_tests)
|
||||
|
@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e
|
||||
GIT_TAG v1.14.0
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
|
@ -14,23 +14,19 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t
|
||||
#include <gsl/algorithm> // for copy
|
||||
#include <gsl/span> // for span
|
||||
#include <gtest/gtest.h>
|
||||
#include <gsl/gsl_algorithm> // for copy
|
||||
#include <gsl/span> // for span
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
}
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
struct fail_fast;
|
||||
} // namespace gsl
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
TEST(algorithm_tests, same_type)
|
||||
@ -76,8 +72,8 @@ TEST(algorithm_tests, same_type)
|
||||
std::array<int, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<int> src_span(src);
|
||||
const span<int, 10> dst_span(dst);
|
||||
const gsl::span<int> src_span(src);
|
||||
const gsl::span<int, 10> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
@ -192,7 +188,7 @@ TEST(algorithm_tests, incompatible_type)
|
||||
span<int> src_span_dyn(src);
|
||||
span<int, 4> src_span_static(src);
|
||||
span<int*> dst_span_dyn(dst);
|
||||
span<int*, 4> dst_span_static(dst);
|
||||
span<int*, 4> dst_span_static(gsl::make_span(dst));
|
||||
|
||||
// every line should produce a compilation error
|
||||
copy(src_span_dyn, dst_span_dyn);
|
||||
@ -204,10 +200,11 @@ TEST(algorithm_tests, incompatible_type)
|
||||
|
||||
TEST(algorithm_tests, small_destination_span)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. small_destination_span";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
std::array<int, 12> src{1, 2, 3, 4};
|
||||
std::array<int, 4> dst{};
|
||||
@ -217,9 +214,9 @@ TEST(algorithm_tests, small_destination_span)
|
||||
const span<int> dst_span_dyn(dst);
|
||||
const span<int, 4> dst_span_static(dst);
|
||||
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring);
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring);
|
||||
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring);
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected);
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
|
||||
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
|
@ -14,14 +14,14 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
#include <gsl/assert> // for Ensures, Expects
|
||||
#include <gtest/gtest.h>
|
||||
#include <gsl/gsl_assert> // for fail_fast (ptr only), Ensures, Expects
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
|
||||
int f(int i)
|
||||
{
|
||||
@ -39,23 +39,22 @@ int g(int i)
|
||||
|
||||
TEST(assertion_tests, expects)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. expects";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
EXPECT_TRUE(f(2) == 2);
|
||||
EXPECT_DEATH(f(10), deathstring);
|
||||
EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
|
||||
}
|
||||
|
||||
|
||||
TEST(assertion_tests, ensures)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. ensures";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
EXPECT_TRUE(g(2) == 3);
|
||||
EXPECT_DEATH(g(9), deathstring);
|
||||
EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
|
||||
}
|
||||
|
@ -16,37 +16,40 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/gsl_util> // for at
|
||||
#include <gsl/util> // for at
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t
|
||||
#include <exception> // for terminate
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <vector> // for vector
|
||||
#if defined(__cplusplus) && __cplusplus >= 202002L
|
||||
#include <span>
|
||||
#endif // __cplusplus >= 202002L
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
}
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
TEST(at_tests, static_array)
|
||||
{
|
||||
int a[4] = {1, 2, 3, 4};
|
||||
const int(&c_a)[4] = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[i]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. static_array";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, std_array)
|
||||
@ -54,20 +57,22 @@ TEST(at_tests, std_array)
|
||||
std::array<int, 4> a = {1, 2, 3, 4};
|
||||
const std::array<int, 4>& c_a = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_array";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, std_vector)
|
||||
@ -75,42 +80,74 @@ TEST(at_tests, std_vector)
|
||||
std::vector<int> a = {1, 2, 3, 4};
|
||||
const std::vector<int>& c_a = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_vector";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, InitializerList)
|
||||
{
|
||||
const std::initializer_list<int> a = {1, 2, 3, 4};
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(gsl::at(a, i) == i + 1);
|
||||
EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. InitializerList";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring);
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
|
||||
}
|
||||
|
||||
#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
TEST(at_tests, std_span)
|
||||
{
|
||||
std::vector<int> vec{1, 2, 3, 4, 5};
|
||||
std::span sp{vec};
|
||||
|
||||
std::vector<int> cvec{1, 2, 3, 4, 5};
|
||||
std::span csp{cvec};
|
||||
|
||||
for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_span";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(sp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
}
|
||||
#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
|
||||
static constexpr bool test_constexpr()
|
||||
{
|
||||
@ -119,7 +156,8 @@ static constexpr bool test_constexpr()
|
||||
std::array<int, 4> a2 = {1, 2, 3, 4};
|
||||
const std::array<int, 4>& c_a2 = a2;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (&gsl::at(a1, i) != &a1[i]) return false;
|
||||
if (&gsl::at(c_a1, i) != &a1[i]) return false;
|
||||
// requires C++17:
|
||||
|
@ -1,102 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/multi_span> // for static_bounds, static_bounds_dynamic_range_t
|
||||
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
void use(std::ptrdiff_t&) {}
|
||||
}
|
||||
|
||||
TEST(bounds_tests, basic_bounds)
|
||||
{
|
||||
for (auto point : static_bounds<dynamic_range, 3, 4>{2}) {
|
||||
for (decltype(point)::size_type j = 0;
|
||||
j < static_cast<decltype(point)::size_type>(decltype(point)::rank); j++)
|
||||
{
|
||||
use(j);
|
||||
use(point[static_cast<std::size_t>(j)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bounds_tests, bounds_basic)
|
||||
{
|
||||
static_bounds<3, 4, 5> b;
|
||||
const auto a = b.slice();
|
||||
(void) a;
|
||||
static_bounds<4, dynamic_range, 2> x{4};
|
||||
x.slice().slice();
|
||||
}
|
||||
|
||||
TEST(bounds_tests, arrayview_iterator)
|
||||
{
|
||||
static_bounds<4, dynamic_range, 2> bounds{3};
|
||||
|
||||
const auto itr = bounds.begin();
|
||||
(void) itr;
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
multi_span<int, 4, dynamic_range, 2> av(nullptr, bounds);
|
||||
|
||||
auto itr2 = av.cbegin();
|
||||
|
||||
for (auto& v : av) {
|
||||
v = 4;
|
||||
}
|
||||
fill(av.begin(), av.end(), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(bounds_tests, bounds_convertible)
|
||||
{
|
||||
static_bounds<7, 4, 2> b1;
|
||||
static_bounds<7, dynamic_range, 2> b2 = b1;
|
||||
(void) b2;
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
static_bounds<7, dynamic_range, 1> b4 = b2;
|
||||
#endif
|
||||
|
||||
static_bounds<dynamic_range, dynamic_range, dynamic_range> b3 = b1;
|
||||
static_bounds<7, 4, 2> b4 = b3;
|
||||
(void) b4;
|
||||
|
||||
static_bounds<dynamic_range> b5;
|
||||
static_bounds<34> b6;
|
||||
|
||||
std::set_terminate([] {
|
||||
std::cerr << "Expected Death. bounds_convertible";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
b5 = static_bounds<20>();
|
||||
EXPECT_DEATH(b6 = b5, ".*");
|
||||
b5 = static_bounds<34>();
|
||||
b6 = b5;
|
||||
|
||||
EXPECT_TRUE(b5 == b6);
|
||||
EXPECT_TRUE(b5.size() == b6.size());
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
#endif
|
@ -16,7 +16,11 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/gsl_byte> // for to_byte, to_integer, byte, operator&, ope...
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
#include <gsl/byte> // for to_byte, to_integer, byte, operator&, ope...
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
@ -33,39 +37,46 @@ int modify_both(gsl::byte& b, int& i)
|
||||
TEST(byte_tests, construction)
|
||||
{
|
||||
{
|
||||
const byte b = static_cast<byte>(4);
|
||||
const gsl::byte b = static_cast<gsl::byte>(4);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
|
||||
}
|
||||
|
||||
GSL_SUPPRESS(es.49)
|
||||
{
|
||||
const byte b = byte(12);
|
||||
const gsl::byte b = gsl::byte(12);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
{
|
||||
const byte b = to_byte<12>();
|
||||
const gsl::byte b = to_byte<12>();
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
{
|
||||
const unsigned char uc = 12;
|
||||
const byte b = to_byte(uc);
|
||||
const gsl::byte b = to_byte(uc);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
{
|
||||
const byte b { 14 };
|
||||
const gsl::byte b{14};
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
to_byte(char{});
|
||||
to_byte(3);
|
||||
to_byte(3u);
|
||||
to_byte<-1>();
|
||||
to_byte<256u>();
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(byte_tests, bitwise_operations)
|
||||
{
|
||||
const byte b = to_byte<0xFF>();
|
||||
const gsl::byte b = to_byte<0xFF>();
|
||||
|
||||
byte a = to_byte<0x00>();
|
||||
gsl::byte a = to_byte<0x00>();
|
||||
EXPECT_TRUE((b | a) == to_byte<0xFF>());
|
||||
EXPECT_TRUE(a == to_byte<0x00>());
|
||||
|
||||
@ -99,7 +110,7 @@ TEST(byte_tests, bitwise_operations)
|
||||
|
||||
TEST(byte_tests, to_integer)
|
||||
{
|
||||
const byte b = to_byte<0x12>();
|
||||
const gsl::byte b = to_byte<0x12>();
|
||||
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<char>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<short>(b));
|
||||
@ -118,12 +129,50 @@ TEST(byte_tests, to_integer)
|
||||
TEST(byte_tests, aliasing)
|
||||
{
|
||||
int i{0};
|
||||
const int res = modify_both(reinterpret_cast<byte&>(i), i);
|
||||
const int res = modify_both(reinterpret_cast<gsl::byte&>(i), i);
|
||||
EXPECT_TRUE(res == i);
|
||||
}
|
||||
|
||||
}
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
#endif
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool LShiftCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool LShiftCompilesFor<
|
||||
U, void_t<decltype(gsl::operator<< <float>(declval<gsl::byte>(), declval<U>()))>> = true;
|
||||
static_assert(!LShiftCompilesFor<float>, "!LShiftCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool RShiftCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool RShiftCompilesFor<
|
||||
U, void_t<decltype(gsl::operator>> <U>(declval<gsl::byte>(), declval<U>()))>> = true;
|
||||
static_assert(!RShiftCompilesFor<float>, "!RShiftCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool LShiftAssignCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool LShiftAssignCompilesFor<
|
||||
U, void_t<decltype(gsl::operator<<= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
|
||||
static_assert(!LShiftAssignCompilesFor<float>, "!LShiftAssignCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool RShiftAssignCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool RShiftAssignCompilesFor<
|
||||
U, void_t<decltype(gsl::operator>>= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
|
||||
static_assert(!RShiftAssignCompilesFor<float>, "!RShiftAssignCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool ToIntegerCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
ToIntegerCompilesFor<U, void_t<decltype(gsl::to_integer<U>(gsl::byte{}))>> = true;
|
||||
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");
|
||||
|
||||
} // namespace
|
||||
|
11
tests/deathTestCommon.h
Normal file
11
tests/deathTestCommon.h
Normal 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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,11 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <gsl/span> // for span
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
int operator_subscript_no_throw() noexcept
|
||||
{
|
||||
@ -42,6 +45,10 @@ void setup_termination_handler() noexcept
|
||||
|
||||
int main() noexcept
|
||||
{
|
||||
std::cout << "Running main() from " __FILE__ "\n";
|
||||
#if defined(IOS_PROCESS_DELAY_WORKAROUND)
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
#endif
|
||||
setup_termination_handler();
|
||||
operator_subscript_no_throw();
|
||||
return -1;
|
||||
|
@ -18,19 +18,24 @@
|
||||
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
|
||||
#include <algorithm> // for addressof
|
||||
#include <memory> // for shared_ptr, make_shared, operator<, opera...
|
||||
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
|
||||
#include <stdint.h> // for uint16_t
|
||||
#include <string> // for basic_string, operator==, string, operator<<
|
||||
#include <typeinfo> // for type_info
|
||||
#include <algorithm> // for addressof
|
||||
#include <cstdint> // for uint16_t
|
||||
#include <memory> // for shared_ptr, make_shared, operator<, opera...
|
||||
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
|
||||
#include <string> // for basic_string, operator==, string, operator<<
|
||||
#include <type_traits> // for declval
|
||||
#include <typeinfo> // for type_info
|
||||
#include <variant> // for variant, monostate, get
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
} //namespace
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
struct MyBase
|
||||
{
|
||||
@ -56,7 +61,7 @@ template <typename T>
|
||||
struct CustomPtr
|
||||
{
|
||||
CustomPtr(T* p) : p_(p) {}
|
||||
operator T*() { return p_; }
|
||||
operator T*() const { return p_; }
|
||||
bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
|
||||
T* p_ = nullptr;
|
||||
};
|
||||
@ -64,7 +69,9 @@ struct CustomPtr
|
||||
template <typename T, typename U>
|
||||
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -72,7 +79,9 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
template <typename T, typename U>
|
||||
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -80,7 +89,9 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
template <typename T, typename U>
|
||||
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -88,7 +99,9 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
template <typename T, typename U>
|
||||
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -96,7 +109,9 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
template <typename T, typename U>
|
||||
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -104,7 +119,9 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
template <typename T, typename U>
|
||||
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
@ -118,23 +135,53 @@ struct NonCopyableNonMovable
|
||||
NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
|
||||
};
|
||||
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper(not_null<int*> p) { return *p == 12; }
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper_const(not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
int* return_pointer() { return nullptr; }
|
||||
} // namespace
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_A = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_A<U, void_t<decltype(gsl::not_null<void*>{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, int N, typename = void>
|
||||
static constexpr bool CtorCompilesFor_B = false;
|
||||
template <typename U, int N>
|
||||
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::not_null<U>{N})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool DefaultCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::not_null<U>{})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_C = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_C<U, void_t<decltype(gsl::not_null<U*>{std::declval<std::unique_ptr<U>>()})>> =
|
||||
true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructors)
|
||||
{
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
not_null<int*> p = nullptr; // yay...does not compile!
|
||||
not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
|
||||
not_null<int*> p2; // yay...does not compile!
|
||||
std::unique_ptr<int> up = std::make_unique<int>(120);
|
||||
not_null<int*> p3 = up;
|
||||
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
|
||||
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
|
||||
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
|
||||
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
|
||||
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
// Forbid non-nullptr assignable types
|
||||
not_null<std::vector<int>> f(std::vector<int>{1});
|
||||
not_null<int> z(10);
|
||||
@ -142,10 +189,12 @@ TEST(notnull_tests, TestNotNullConstructors)
|
||||
#endif
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructors";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
// from shared pointer
|
||||
int i = 12;
|
||||
@ -157,7 +206,15 @@ TEST(notnull_tests, TestNotNullConstructors)
|
||||
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
|
||||
|
||||
int* pi = nullptr;
|
||||
EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring);
|
||||
EXPECT_DEATH((not_null<decltype(pi)>(pi)), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from unique pointer
|
||||
not_null<std::unique_ptr<int>> x(
|
||||
std::make_unique<int>(10)); // unique_ptr<int> is nullptr assignable
|
||||
|
||||
EXPECT_DEATH((not_null<std::unique_ptr<int>>(std::unique_ptr<int>{})), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@ -214,8 +271,8 @@ TEST(notnull_tests, TestNotNullConstructors)
|
||||
{
|
||||
// from returned pointer
|
||||
|
||||
EXPECT_DEATH(helper(return_pointer()), deathstring);
|
||||
EXPECT_DEATH(helper_const(return_pointer()), deathstring);
|
||||
EXPECT_DEATH(helper(return_pointer()), expected);
|
||||
EXPECT_DEATH(helper_const(return_pointer()), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,6 +307,27 @@ TEST(notnull_tests, TestNotNullostream)
|
||||
ostream_helper<std::string>("string");
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool AssignmentCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool
|
||||
AssignmentCompilesFor<U, V,
|
||||
void_t<decltype(std::declval<gsl::not_null<U*>&>().operator=(
|
||||
std::declval<gsl::not_null<V*>&>()))>> = true;
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool SCastCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool
|
||||
SCastCompilesFor<U, V, void_t<decltype(static_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> =
|
||||
true;
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool RCastCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool RCastCompilesFor<
|
||||
U, V, void_t<decltype(reinterpret_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> = true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullCasting)
|
||||
{
|
||||
MyBase base;
|
||||
@ -262,30 +340,46 @@ TEST(notnull_tests, TestNotNullCasting)
|
||||
q = p; // allowed with heterogeneous copy ctor
|
||||
EXPECT_TRUE(q == p);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
q = u; // no viable conversion possible between MyBase* and Unrelated*
|
||||
p = q; // not possible to implicitly convert MyBase* to MyDerived*
|
||||
static_assert(AssignmentCompilesFor<MyBase, MyDerived>,
|
||||
"AssignmentCompilesFor<MyBase, MyDerived>");
|
||||
static_assert(!AssignmentCompilesFor<MyBase, Unrelated>,
|
||||
"!AssignmentCompilesFor<MyBase, Unrelated>");
|
||||
static_assert(!AssignmentCompilesFor<Unrelated, MyDerived>,
|
||||
"!AssignmentCompilesFor<Unrelated, MyDerived>");
|
||||
static_assert(!AssignmentCompilesFor<MyDerived, MyBase>,
|
||||
"!AssignmentCompilesFor<MyDerived, MyBase>");
|
||||
|
||||
static_assert(SCastCompilesFor<MyDerived, MyDerived>, "SCastCompilesFor<MyDerived, MyDerived>");
|
||||
static_assert(SCastCompilesFor<MyBase, MyDerived>, "SCastCompilesFor<MyBase, MyDerived>");
|
||||
static_assert(!SCastCompilesFor<MyDerived, MyBase>, "!SCastCompilesFor<MyDerived, MyBase>");
|
||||
static_assert(!SCastCompilesFor<Unrelated, MyDerived>,
|
||||
"!SCastCompilesFor<Unrelated, MyDerived>");
|
||||
static_assert(!RCastCompilesFor<MyDerived, MyDerived>,
|
||||
"!SCastCompilesFor<MyDerived, MyDerived>");
|
||||
static_assert(!RCastCompilesFor<Unrelated, MyDerived>,
|
||||
"!SCastCompilesFor<Unrelated, MyDerived>");
|
||||
|
||||
not_null<Unrelated*> r = p;
|
||||
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
|
||||
#endif
|
||||
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
|
||||
EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
|
||||
|
||||
(void) static_cast<MyDerived*>(p);
|
||||
(void) static_cast<MyBase*>(p);
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullAssignment)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullAssignmentd";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
int i = 12;
|
||||
not_null<int*> p(&i);
|
||||
EXPECT_TRUE(helper(p));
|
||||
|
||||
int* q = nullptr;
|
||||
EXPECT_DEATH(p = not_null<int*>(q), deathstring);
|
||||
EXPECT_DEATH(p = not_null<int*>(q), expected);
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullRawPointerComparison)
|
||||
@ -411,6 +505,18 @@ TEST(notnull_tests, TestNotNullCustomPtrComparison)
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool TypeDeductionCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
TypeDeductionCtorCompilesFor<U, void_t<decltype(not_null{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool TypeDeductionHelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
TypeDeductionHelperCompilesFor<U, void_t<decltype(helper(not_null{std::declval<U>()}))>> = true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
{
|
||||
{
|
||||
@ -423,6 +529,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
not_null x{&i};
|
||||
static_assert(TypeDeductionHelperCompilesFor<int*>, "TypeDeductionHelperCompilesFor<int*>");
|
||||
static_assert(!TypeDeductionHelperCompilesFor<const int*>,
|
||||
"!TypeDeductionHelperCompilesFor<const int*>");
|
||||
helper_const(not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
@ -434,17 +552,28 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
not_null x{p};
|
||||
helper_const(not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
int* p1 = nullptr;
|
||||
const not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@ -452,26 +581,45 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
const int* p1 = nullptr;
|
||||
const not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(not_null{p}), deathstring);
|
||||
EXPECT_DEATH(helper_const(not_null{p}), deathstring);
|
||||
EXPECT_DEATH(helper(not_null{p}), expected);
|
||||
EXPECT_DEATH(helper_const(not_null{p}), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
not_null x{nullptr};
|
||||
helper(not_null{nullptr});
|
||||
helper_const(not_null{nullptr});
|
||||
}
|
||||
static_assert(TypeDeductionCtorCompilesFor<void*>, "TypeDeductionCtorCompilesFor<void*>");
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// Fails on gcc, clang, xcode, VS clang with
|
||||
// "error : no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to
|
||||
// disable this declaration"
|
||||
static_assert(!TypeDeductionCtorCompilesFor<std::nullptr_t>,
|
||||
"!TypeDeductionCtorCompilesFor<std::nullptr_t>");
|
||||
static_assert(!TypeDeductionHelperCompilesFor<std::nullptr_t>,
|
||||
"!TypeDeductionHelperCompilesFor<std::nullptr_t>");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestVariantEmplace)
|
||||
{
|
||||
int i = 0;
|
||||
std::variant<std::monostate, not_null<int*>> v;
|
||||
v.emplace<not_null<int*>>(&i);
|
||||
|
||||
EXPECT_FALSE(v.valueless_by_exception());
|
||||
EXPECT_TRUE(v.index() == 1);
|
||||
EXPECT_TRUE(std::get<not_null<int*>>(v) == &i);
|
||||
}
|
||||
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool HelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
|
||||
|
||||
TEST(notnull_tests, TestMakeNotNull)
|
||||
{
|
||||
{
|
||||
@ -484,6 +632,17 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
const auto x = make_not_null(&i);
|
||||
static_assert(HelperCompilesFor<gsl::not_null<int*>>,
|
||||
"HelperCompilesFor<gsl::not_null<int*>>");
|
||||
helper_const(make_not_null(&i));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
@ -495,10 +654,23 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
std::set_terminate([] {
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
const auto x = make_not_null(p);
|
||||
static_assert(!HelperCompilesFor<gsl::not_null<const int*>>,
|
||||
"!HelperCompilesFor<gsl::not_null<const int*>>");
|
||||
helper_const(make_not_null(p));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestMakeNotNull";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
const auto workaround_macro = []() {
|
||||
@ -506,7 +678,7 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
const auto x = make_not_null(p1);
|
||||
EXPECT_TRUE(*x == 42);
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@ -515,21 +687,52 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
const auto x = make_not_null(p1);
|
||||
EXPECT_TRUE(*x == 42);
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(make_not_null(p)), deathstring);
|
||||
EXPECT_DEATH(helper_const(make_not_null(p)), deathstring);
|
||||
EXPECT_DEATH(helper(make_not_null(p)), expected);
|
||||
EXPECT_DEATH(helper_const(make_not_null(p)), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
EXPECT_DEATH(make_not_null(nullptr), deathstring);
|
||||
EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring);
|
||||
EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring);
|
||||
EXPECT_DEATH(make_not_null(nullptr), expected);
|
||||
EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
|
||||
EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestStdHash)
|
||||
{
|
||||
{
|
||||
int x = 42;
|
||||
int y = 99;
|
||||
not_null<int*> nn{&x};
|
||||
const not_null<int*> cnn{&x};
|
||||
|
||||
std::hash<not_null<int*>> hash_nn;
|
||||
std::hash<int*> hash_intptr;
|
||||
|
||||
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
|
||||
}
|
||||
|
||||
{
|
||||
const int x = 42;
|
||||
const int y = 99;
|
||||
not_null<const int*> nn{&x};
|
||||
const not_null<const int*> cnn{&x};
|
||||
|
||||
std::hash<not_null<const int*>> hash_nn;
|
||||
std::hash<const int*> hash_intptr;
|
||||
|
||||
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,11 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers> // for owner
|
||||
#include <type_traits> // for declval
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f .23) // NO-FORMAT: attribute
|
||||
void f(int* i) { *i += 1; }
|
||||
|
||||
TEST(owner_tests, basic_test)
|
||||
@ -32,12 +33,18 @@ TEST(owner_tests, basic_test)
|
||||
delete p;
|
||||
}
|
||||
|
||||
TEST(owner_tests, check_pointer_constraint)
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
owner<int> integerTest = 10;
|
||||
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool OwnerCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> =
|
||||
true;
|
||||
static_assert(OwnerCompilesFor<int*>, "OwnerCompilesFor<int*>");
|
||||
static_assert(!OwnerCompilesFor<int>, "!OwnerCompilesFor<int>");
|
||||
static_assert(!OwnerCompilesFor<std::shared_ptr<int>>, "!OwnerCompilesFor<std::shared_ptr<int>>");
|
||||
|
97
tests/pointers_tests.cpp
Normal file
97
tests/pointers_tests.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers>
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
namespace
|
||||
{
|
||||
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
|
||||
struct NotMoveAssignableCustomPtr
|
||||
{
|
||||
NotMoveAssignableCustomPtr() = default;
|
||||
NotMoveAssignableCustomPtr(const NotMoveAssignableCustomPtr&) = default;
|
||||
NotMoveAssignableCustomPtr& operator=(const NotMoveAssignableCustomPtr&) = default;
|
||||
NotMoveAssignableCustomPtr(NotMoveAssignableCustomPtr&&) = default;
|
||||
NotMoveAssignableCustomPtr& operator=(NotMoveAssignableCustomPtr&&) = delete;
|
||||
|
||||
bool operator!=(std::nullptr_t) const { return true; }
|
||||
|
||||
int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
|
||||
};
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool SwapCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
|
||||
std::declval<gsl::not_null<U>&>()))>> = true;
|
||||
|
||||
TEST(pointers_test, swap)
|
||||
{
|
||||
// taken from gh-1129:
|
||||
{
|
||||
gsl::not_null<std::unique_ptr<int>> a(std::make_unique<int>(0));
|
||||
gsl::not_null<std::unique_ptr<int>> b(std::make_unique<int>(1));
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
|
||||
// Make sure our custom ptr can be used with not_null. The shared_pr is to prevent "unused"
|
||||
// compiler warnings.
|
||||
const auto shared_custom_ptr{std::make_shared<NotMoveAssignableCustomPtr>()};
|
||||
gsl::not_null<NotMoveAssignableCustomPtr> c{*shared_custom_ptr};
|
||||
EXPECT_TRUE(c.get() != nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
gsl::strict_not_null<std::unique_ptr<int>> a{std::make_unique<int>(0)};
|
||||
gsl::strict_not_null<std::unique_ptr<int>> b{std::make_unique<int>(1)};
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
}
|
||||
|
||||
{
|
||||
gsl::not_null<std::unique_ptr<int>> a{std::make_unique<int>(0)};
|
||||
gsl::strict_not_null<std::unique_ptr<int>> b{std::make_unique<int>(1)};
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
}
|
||||
|
||||
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
|
||||
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
|
||||
}
|
||||
|
||||
TEST(pointers_test, member_types)
|
||||
{
|
||||
static_assert(std::is_same<gsl::not_null<int*>::element_type, int*>::value,
|
||||
"check member type: element_type");
|
||||
}
|
||||
|
||||
} // namespace
|
@ -16,8 +16,8 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/gsl_byte> // for byte
|
||||
#include <gsl/span> // for span, span_iterator, operator==, operator!=
|
||||
#include <gsl/byte> // for byte
|
||||
#include <gsl/span> // for span, span_iterator, operator==, operator!=
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for ptrdiff_t
|
||||
@ -55,14 +55,14 @@ void ArrayConvertibilityCheck()
|
||||
EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
|
||||
EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
|
||||
|
||||
span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
|
||||
gsl::span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
|
||||
EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
|
||||
EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
|
||||
|
||||
static_assert(std::is_same<decltype(span{stl_nullptr}), span<T*, 3>>::value,
|
||||
static_assert(std::is_same<decltype(gsl::span{stl_nullptr}), gsl::span<T*, 3>>::value,
|
||||
"std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
|
||||
static_assert(
|
||||
std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<T* const, 3>>::value,
|
||||
std::is_same<decltype(gsl::span{std::as_const(stl_nullptr)}), gsl::span<T* const, 3>>::value,
|
||||
"std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
|
||||
"3>>::value");
|
||||
}
|
||||
@ -519,7 +519,7 @@ TEST(span_compatibility_tests, assertion_tests)
|
||||
|
||||
// assertions for span's definition
|
||||
static_assert(std::is_same<decltype(gsl::dynamic_extent), const std::size_t>::value,
|
||||
"gsl::dynamic_extent must be respresented as std::size_t");
|
||||
"gsl::dynamic_extent must be represented as std::size_t");
|
||||
static_assert(gsl::dynamic_extent == static_cast<std::size_t>(-1),
|
||||
"gsl::dynamic_extent must be defined as the max value of std::size_t");
|
||||
|
||||
@ -846,8 +846,6 @@ static_assert(!std::is_constructible<gsl::span<int, 3>, std::array<int, 500>&>::
|
||||
"!std::is_constructible<gsl::span<int, 3>, std::array<int, 500>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>::value,
|
||||
"!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>::value,
|
||||
"!std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>::value,
|
||||
"!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<const int>&>::value,
|
||||
@ -866,12 +864,8 @@ static_assert(!std::is_constructible<gsl::span<const int>, std::array<double, 3>
|
||||
static_assert(!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>::value,
|
||||
"!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>");
|
||||
|
||||
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>::value,
|
||||
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>::value,
|
||||
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>");
|
||||
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>::value,
|
||||
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>");
|
||||
static_assert(
|
||||
!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>::value,
|
||||
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>");
|
||||
@ -925,6 +919,14 @@ static_assert(!std::is_constructible<gsl::span<const Derived>, std::array<Base,
|
||||
static_assert(!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>::value,
|
||||
"!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>");
|
||||
|
||||
// Explicit construction enabled in P1976R2
|
||||
static_assert(std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>::value,
|
||||
"std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>");
|
||||
static_assert(std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>::value,
|
||||
"std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>");
|
||||
static_assert(std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>::value,
|
||||
"std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>");
|
||||
|
||||
// no throw copy constructor
|
||||
static_assert(std::is_nothrow_copy_constructible<gsl::span<int>>::value,
|
||||
"std::is_nothrow_copy_constructible<gsl::span<int>>");
|
||||
@ -1003,12 +1005,18 @@ static_assert(std::is_convertible<const std::array<int, 3>&, gsl::span<const int
|
||||
"std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>");
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool AsWritableBytesCompilesFor = false;
|
||||
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
|
||||
AsWritableBytesCompilesFor<U, ::void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
|
||||
|
||||
static_assert(AsWritableBytesCompilesFor<gsl::span<int>>,
|
||||
"AsWritableBytesCompilesFor<gsl::span<int>>");
|
||||
@ -1018,4 +1026,3 @@ static_assert(!AsWritableBytesCompilesFor<gsl::span<const int>>,
|
||||
"!AsWritableBytesCompilesFor<gsl::span<const int>>");
|
||||
static_assert(!AsWritableBytesCompilesFor<gsl::span<const int, 9>>,
|
||||
"!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
|
||||
#endif // __cplusplus >= 201703l
|
||||
|
@ -16,27 +16,27 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/gsl_util> // for narrow_cast, at
|
||||
#include <gsl/span_ext> // for operator==, operator!=, make_span
|
||||
#include <gsl/span> // for span and span_ext
|
||||
#include <gsl/util> // for narrow_cast, at
|
||||
|
||||
#include <array> // for array
|
||||
#include <iostream> // for cerr
|
||||
#include <vector> // for vector
|
||||
#include <array> // for array
|
||||
#include <exception> // for terminate
|
||||
#include <iostream> // for cerr
|
||||
#include <vector> // for vector
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
} // namespace
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
TEST(span_ext_test, make_span_from_pointer_length_constructor)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. from_pointer_length_constructor";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
int arr[4] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
@ -49,7 +49,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
auto s = make_span(p, narrow_cast<span<int>::size_type>(0));
|
||||
auto s = make_span(p, narrow_cast<gsl::span<int>::size_type>(0));
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == nullptr);
|
||||
}
|
||||
@ -57,7 +57,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
|
||||
{
|
||||
int* p = nullptr;
|
||||
auto workaround_macro = [=]() { make_span(p, 2); };
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,273 +88,293 @@ TEST(span_ext_test, make_span_from_pointer_pointer_construction)
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_array_constructor)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
|
||||
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
|
||||
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
|
||||
{
|
||||
const auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == 5);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr[0]));
|
||||
}
|
||||
{
|
||||
const auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == 5);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr[0]));
|
||||
}
|
||||
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr2d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
|
||||
}
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr2d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
|
||||
}
|
||||
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr3d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr3d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_dynamic_array_constructor)
|
||||
{
|
||||
double(*arr)[3][4] = new double[100][3][4];
|
||||
TEST(span_ext_test, make_span_from_dynamic_array_constructor)
|
||||
{
|
||||
double(*arr)[3][4] = new double[100][3][4];
|
||||
|
||||
{
|
||||
auto s = make_span(&arr[0][0][0], 10);
|
||||
EXPECT_TRUE(s.size() == 10);
|
||||
EXPECT_TRUE(s.data() == &arr[0][0][0]);
|
||||
}
|
||||
{
|
||||
auto s = make_span(&arr[0][0][0], 10);
|
||||
EXPECT_TRUE(s.size() == 10);
|
||||
EXPECT_TRUE(s.data() == &arr[0][0][0]);
|
||||
}
|
||||
|
||||
delete[] arr;
|
||||
}
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_std_array_constructor)
|
||||
{
|
||||
std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
TEST(span_ext_test, make_span_from_std_array_constructor)
|
||||
{
|
||||
std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
// This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
|
||||
{
|
||||
span<int> s1 = make_span(arr);
|
||||
// This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
|
||||
{
|
||||
gsl::span<int> s1 = make_span(arr);
|
||||
|
||||
static span<int> s2;
|
||||
s2 = s1;
|
||||
static gsl::span<int> s2;
|
||||
s2 = s1;
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
|
||||
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
|
||||
// Known to be broken in gcc 6.4 and 6.5 with optimizations
|
||||
// Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
|
||||
EXPECT_TRUE(s1.size() == 4);
|
||||
EXPECT_TRUE(s2.size() == 0);
|
||||
#else
|
||||
EXPECT_TRUE(s1.size() == s2.size());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
|
||||
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
|
||||
// Known to be broken in gcc 6.4 and 6.5 with optimizations
|
||||
// Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
|
||||
EXPECT_TRUE(s1.size() == 4);
|
||||
EXPECT_TRUE(s2.size() == 0);
|
||||
#else
|
||||
EXPECT_TRUE(s1.size() == s2.size());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_const_std_array_constructor)
|
||||
{
|
||||
const std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
TEST(span_ext_test, make_span_from_const_std_array_constructor)
|
||||
{
|
||||
const std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_std_array_const_constructor)
|
||||
{
|
||||
std::array<const int, 4> arr = {1, 2, 3, 4};
|
||||
TEST(span_ext_test, make_span_from_std_array_const_constructor)
|
||||
{
|
||||
std::array<const int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_container_constructor)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
const std::vector<int> cv = v;
|
||||
TEST(span_ext_test, make_span_from_container_constructor)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
const std::vector<int> cv = v;
|
||||
|
||||
{
|
||||
auto s = make_span(v);
|
||||
EXPECT_TRUE(s.size() == v.size());
|
||||
EXPECT_TRUE(s.data() == v.data());
|
||||
{
|
||||
auto s = make_span(v);
|
||||
EXPECT_TRUE(s.size() == v.size());
|
||||
EXPECT_TRUE(s.data() == v.data());
|
||||
|
||||
auto cs = make_span(cv);
|
||||
EXPECT_TRUE(cs.size() == cv.size());
|
||||
EXPECT_TRUE(cs.data() == cv.data());
|
||||
}
|
||||
}
|
||||
auto cs = make_span(cv);
|
||||
EXPECT_TRUE(cs.size() == cv.size());
|
||||
EXPECT_TRUE(cs.data() == cv.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_test, interop_with_gsl_at)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
span<int> s{arr};
|
||||
EXPECT_TRUE(at(s, 0) == 1);
|
||||
EXPECT_TRUE(at(s, 1) == 2);
|
||||
}
|
||||
TEST(span_test, interop_with_gsl_at)
|
||||
{
|
||||
std::vector<int> vec{1, 2, 3, 4, 5};
|
||||
gsl::span<int> sp{vec};
|
||||
|
||||
TEST(span_ext_test, iterator_free_functions)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
span<int> s{a};
|
||||
std::vector<int> cvec{1, 2, 3, 4, 5};
|
||||
gsl::span<int> csp{cvec};
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
|
||||
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)]);
|
||||
}
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. interop_with_gsl_at";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
|
||||
EXPECT_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);
|
||||
}
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
|
||||
TEST(span_ext_test, iterator_free_functions)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
gsl::span<int> s{a};
|
||||
|
||||
EXPECT_TRUE(s.begin() == begin(s));
|
||||
EXPECT_TRUE(s.end() == end(s));
|
||||
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(s.rbegin() == rbegin(s));
|
||||
EXPECT_TRUE(s.rend() == rend(s));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
|
||||
|
||||
EXPECT_TRUE(s.begin() == cbegin(s));
|
||||
EXPECT_TRUE(s.end() == cend(s));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
|
||||
|
||||
EXPECT_TRUE(s.rbegin() == crbegin(s));
|
||||
EXPECT_TRUE(s.rend() == crend(s));
|
||||
}
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
|
||||
|
||||
TEST(span_ext_test, ssize_free_function)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
span<int> s{a};
|
||||
EXPECT_TRUE(s.begin() == begin(s));
|
||||
EXPECT_TRUE(s.end() == end(s));
|
||||
|
||||
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.rbegin() == rbegin(s));
|
||||
EXPECT_TRUE(s.rend() == rend(s));
|
||||
|
||||
TEST(span_ext_test, comparison_operators)
|
||||
{
|
||||
{
|
||||
span<int> s1;
|
||||
span<int> s2;
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
EXPECT_TRUE(s.begin() == cbegin(s));
|
||||
EXPECT_TRUE(s.end() == cend(s));
|
||||
|
||||
{
|
||||
int arr[] = {2, 1};
|
||||
span<int> s1 = arr;
|
||||
span<int> s2 = arr;
|
||||
EXPECT_TRUE(s.rbegin() == crbegin(s));
|
||||
EXPECT_TRUE(s.rend() == crend(s));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
TEST(span_ext_test, ssize_free_function)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
gsl::span<int> s{a};
|
||||
|
||||
{
|
||||
int arr[] = {2, 1}; // bigger
|
||||
EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
|
||||
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
|
||||
}
|
||||
|
||||
span<int> s1;
|
||||
span<int> s2 = arr;
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
TEST(span_ext_test, comparison_operators)
|
||||
{
|
||||
{
|
||||
gsl::span<int> s1;
|
||||
gsl::span<int> s2;
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
{
|
||||
int arr[] = {2, 1};
|
||||
gsl::span<int> s1 = arr;
|
||||
gsl::span<int> s2 = arr;
|
||||
|
||||
{
|
||||
int arr1[] = {1, 2};
|
||||
int arr2[] = {1, 2};
|
||||
span<int> s1 = arr1;
|
||||
span<int> s2 = arr2;
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
{
|
||||
int arr[] = {2, 1}; // bigger
|
||||
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
gsl::span<int> s1;
|
||||
gsl::span<int> s2 = arr;
|
||||
|
||||
span<int> s1 = {&arr[0], 2}; // shorter
|
||||
span<int> s2 = arr; // longer
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
{
|
||||
int arr1[] = {1, 2};
|
||||
int arr2[] = {1, 2};
|
||||
gsl::span<int> s1 = arr1;
|
||||
gsl::span<int> s2 = arr2;
|
||||
|
||||
{
|
||||
int arr1[] = {1, 2}; // smaller
|
||||
int arr2[] = {2, 1}; // bigger
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
span<int> s1 = arr1;
|
||||
span<int> s2 = arr2;
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
}
|
||||
gsl::span<int> s1 = {&arr[0], 2}; // shorter
|
||||
gsl::span<int> s2 = arr; // longer
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
|
||||
{
|
||||
int arr1[] = {1, 2}; // smaller
|
||||
int arr2[] = {2, 1}; // bigger
|
||||
|
||||
gsl::span<int> s1 = arr1;
|
||||
gsl::span<int> s2 = arr2;
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
}
|
||||
#endif // GSL_KERNEL_MODE
|
||||
|
2020
tests/span_tests.cpp
2020
tests/span_tests.cpp
File diff suppressed because it is too large
Load Diff
@ -14,30 +14,200 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
struct fail_fast;
|
||||
} // namespace gsl
|
||||
#include <type_traits> // for declval
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
// stand-in for a user-defined ref-counted class
|
||||
template <typename T>
|
||||
struct RefCounted
|
||||
{
|
||||
RefCounted(T* p) : p_(p) {}
|
||||
operator T*() { return p_; }
|
||||
T* p_;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper(not_null<int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper_const(not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
int* return_pointer() { return nullptr; }
|
||||
const int* return_pointer_const() { return nullptr; }
|
||||
} // namespace
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_A = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_A<U, void_t<decltype(gsl::strict_not_null<void*>{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, int N, typename = void>
|
||||
static constexpr bool CtorCompilesFor_B = false;
|
||||
template <typename U, int N>
|
||||
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::strict_not_null<U>{N})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool DefaultCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::strict_not_null<U>{})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_C = false;
|
||||
template <typename U>
|
||||
static constexpr bool CtorCompilesFor_C<
|
||||
U, void_t<decltype(gsl::strict_not_null<U*>{std::declval<std::unique_ptr<U>>()})>> = true;
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNullConstructors)
|
||||
{
|
||||
{
|
||||
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
|
||||
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
|
||||
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
|
||||
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
|
||||
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
// Forbid non-nullptr assignable types
|
||||
strict_not_null<std::vector<int>> f(std::vector<int>{1});
|
||||
strict_not_null<int> z(10);
|
||||
strict_not_null<std::vector<int>> y({1, 2});
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructors";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
// from shared pointer
|
||||
int i = 12;
|
||||
auto rp = RefCounted<int>(&i);
|
||||
strict_not_null<int*> p(rp);
|
||||
EXPECT_TRUE(p.get() == &i);
|
||||
|
||||
strict_not_null<std::shared_ptr<int>> x(
|
||||
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
|
||||
|
||||
int* pi = nullptr;
|
||||
EXPECT_DEATH((strict_not_null<decltype(pi)>(pi)), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from unique pointer
|
||||
strict_not_null<std::unique_ptr<int>> x(
|
||||
std::make_unique<int>(10)); // unique_ptr<int> is nullptr assignable
|
||||
|
||||
EXPECT_DEATH((strict_not_null<std::unique_ptr<int>>(std::unique_ptr<int>{})), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from pointer to local
|
||||
int t = 42;
|
||||
|
||||
strict_not_null<int*> x{&t};
|
||||
helper(&t);
|
||||
helper_const(&t);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw pointer
|
||||
// from strict_not_null pointer
|
||||
|
||||
int t = 42;
|
||||
int* p = &t;
|
||||
|
||||
strict_not_null<int*> x{p};
|
||||
helper(p);
|
||||
helper_const(p);
|
||||
helper(x);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw const pointer
|
||||
// from strict_not_null const pointer
|
||||
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
strict_not_null<const int*> x{cp};
|
||||
helper_const(cp);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from strict_not_null const pointer, using auto
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
auto x = strict_not_null<const int*>{cp};
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from returned pointer
|
||||
|
||||
EXPECT_DEATH(helper(return_pointer()), expected);
|
||||
EXPECT_DEATH(helper_const(return_pointer()), expected);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool StrictHelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
StrictHelperCompilesFor<U, void_t<decltype(strict_helper(std::declval<U>()))>> = true;
|
||||
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool StrictHelperConstCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
StrictHelperConstCompilesFor<U, void_t<decltype(strict_helper_const(std::declval<U>()))>> =
|
||||
true;
|
||||
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool HelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
{
|
||||
@ -47,20 +217,43 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_not_null<int*> snn = &x;
|
||||
strict_helper(&x);
|
||||
strict_helper_const(&x);
|
||||
strict_helper(return_pointer());
|
||||
strict_helper_const(return_pointer_const());
|
||||
#endif
|
||||
static_assert(!StrictHelperCompilesFor<int*>, "!StrictHelperCompilesFor<int*>");
|
||||
static_assert(!StrictHelperConstCompilesFor<int*>,
|
||||
"!StrictHelperCompilesFor<int*>");
|
||||
|
||||
const strict_not_null<int*> snn1{&x};
|
||||
|
||||
static_assert(StrictHelperCompilesFor<const strict_not_null<int*>>,
|
||||
"StrictHelperCompilesFor<const strict_not_null<int*>>");
|
||||
helper(snn1);
|
||||
helper_const(snn1);
|
||||
|
||||
EXPECT_TRUE(*snn1 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// raw ptr <-> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_not_null<int*> snn = &x;
|
||||
#endif
|
||||
static_assert(!StrictHelperCompilesFor<const int*>, "!StrictHelperFor<const int*>");
|
||||
static_assert(!StrictHelperConstCompilesFor<const int*>,
|
||||
"!StrictHelperCompilesFor<const int*>");
|
||||
|
||||
const strict_not_null<const int*> snn1{&x};
|
||||
|
||||
static_assert(!HelperCompilesFor<const strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<const strict_not_null<const int*>>");
|
||||
static_assert(StrictHelperConstCompilesFor<const strict_not_null<const int*>>,
|
||||
"StrictHelperCompilesFor<const strict_not_null<const int*>>");
|
||||
helper_const(snn1);
|
||||
|
||||
EXPECT_TRUE(*snn1 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> strict_not_null
|
||||
int x = 42;
|
||||
@ -75,6 +268,21 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
EXPECT_TRUE(snn1 == snn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
strict_not_null<const int*> snn1{&x};
|
||||
const strict_not_null<const int*> snn2{&x};
|
||||
|
||||
static_assert(!StrictHelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!StrictHelperCompilesFor<strict_not_null<const int*>>");
|
||||
strict_helper_const(snn1);
|
||||
strict_helper_const(snn2);
|
||||
|
||||
EXPECT_TRUE(snn1 == snn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> not_null
|
||||
int x = 42;
|
||||
@ -91,6 +299,23 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
EXPECT_TRUE(snn == nn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> not_null
|
||||
const int x = 42;
|
||||
|
||||
strict_not_null<const int*> snn{&x};
|
||||
|
||||
const not_null<const int*> nn1 = snn;
|
||||
const not_null<const int*> nn2{snn};
|
||||
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(snn);
|
||||
|
||||
EXPECT_TRUE(snn == nn1);
|
||||
EXPECT_TRUE(snn == nn2);
|
||||
}
|
||||
|
||||
{
|
||||
// not_null -> strict_not_null
|
||||
int x = 42;
|
||||
@ -115,25 +340,48 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
strict_not_null<int*> p{nullptr};
|
||||
// not_null -> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
not_null<const int*> nn{&x};
|
||||
|
||||
const strict_not_null<const int*> snn1{nn};
|
||||
const strict_not_null<const int*> snn2{nn};
|
||||
|
||||
static_assert(!StrictHelperCompilesFor<not_null<const int*>>,
|
||||
"!StrictHelperCompilesFor<not_null<const int*>>");
|
||||
strict_helper_const(nn);
|
||||
|
||||
EXPECT_TRUE(snn1 == nn);
|
||||
EXPECT_TRUE(snn2 == nn);
|
||||
|
||||
std::hash<strict_not_null<const int*>> hash_snn;
|
||||
std::hash<not_null<const int*>> hash_nn;
|
||||
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(pointers_test, member_types)
|
||||
{
|
||||
// make sure `element_type` is inherited from `gsl::not_null`
|
||||
static_assert(std::is_same<gsl::strict_not_null<int*>::element_type, int*>::value,
|
||||
"check member type: element_type");
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
}
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
@ -145,6 +393,17 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
strict_not_null x{&i};
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(strict_not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
@ -156,12 +415,24 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
strict_not_null x{p};
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(strict_not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
int* p1 = nullptr;
|
||||
const strict_not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@ -169,14 +440,14 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
const int* p1 = nullptr;
|
||||
const strict_not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), deathstring);
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(strict_not_null{p}), deathstring);
|
||||
EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring);
|
||||
EXPECT_DEATH(helper(strict_not_null{p}), expected);
|
||||
EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
|
@ -1,790 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gsl/gsl_byte> // for byte
|
||||
#include <gsl/gsl_util> // for narrow_cast
|
||||
#include <gsl/multi_span> // for strided_span, index, multi_span, strided_...
|
||||
|
||||
#include <iostream> // for size_t
|
||||
#include <iterator> // for begin, end
|
||||
#include <numeric> // for iota
|
||||
#include <type_traits> // for integral_constant<>::value, is_convertible
|
||||
#include <vector> // for vector
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr char deathstring[] = "Expected Death";
|
||||
|
||||
struct BaseClass
|
||||
{
|
||||
};
|
||||
struct DerivedClass : BaseClass
|
||||
{
|
||||
};
|
||||
|
||||
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
void iterate_every_other_element(multi_span<int, dynamic_range> av)
|
||||
{
|
||||
// pick every other element
|
||||
|
||||
auto length = av.size() / 2;
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
auto bounds = strided_bounds<1>({length}, {2});
|
||||
#else
|
||||
auto bounds = strided_bounds<1>(multi_span_index<1>{length}, multi_span_index<1>{2});
|
||||
#endif
|
||||
strided_span<int, 1> strided(&av.data()[1], av.size() - 1, bounds);
|
||||
|
||||
EXPECT_TRUE(strided.size() == length);
|
||||
EXPECT_TRUE(strided.bounds().index_bounds()[0] == length);
|
||||
for (auto i = 0; i < strided.size(); ++i) {
|
||||
EXPECT_TRUE(strided[i] == av[2 * i + 1]);
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for (auto num : strided) {
|
||||
EXPECT_TRUE(num == av[2 * idx + 1]);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute // TODO: does not work
|
||||
void iterate_second_slice(multi_span<int, dynamic_range, dynamic_range, dynamic_range> av)
|
||||
{
|
||||
const int expected[6] = {2, 3, 10, 11, 18, 19};
|
||||
auto section = av.section({0, 1, 0}, {3, 1, 2});
|
||||
|
||||
for (auto i = 0; i < section.extent<0>(); ++i) {
|
||||
for (auto j = 0; j < section.extent<1>(); ++j)
|
||||
for (auto k = 0; k < section.extent<2>(); ++k) {
|
||||
auto idx = multi_span_index<3>{i, j, k}; // avoid braces in the EXPECT_TRUE macro
|
||||
EXPECT_TRUE(section[idx] == expected[2 * i + 2 * j + k]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = 0; i < section.extent<0>(); ++i) {
|
||||
for (auto j = 0; j < section.extent<1>(); ++j)
|
||||
for (auto k = 0; k < section.extent<2>(); ++k)
|
||||
EXPECT_TRUE(section[i][j][k] == expected[2 * i + 2 * j + k]);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (const auto num : section) {
|
||||
EXPECT_TRUE(num == expected[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, span_section_test)
|
||||
{
|
||||
int a[30][4][5];
|
||||
|
||||
const auto av = as_multi_span(a);
|
||||
const auto sub = av.section({15, 0, 0}, gsl::multi_span_index<3>{2, 2, 2});
|
||||
const auto subsub = sub.section({1, 0, 0}, gsl::multi_span_index<3>{1, 1, 1});
|
||||
(void) subsub;
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, span_section)
|
||||
{
|
||||
std::vector<int> data(5 * 10);
|
||||
std::iota(begin(data), end(data), 0);
|
||||
const multi_span<int, 5, 10> av = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>());
|
||||
|
||||
const strided_span<int, 2> av_section_1 = av.section({1, 2}, {3, 4});
|
||||
EXPECT_TRUE(!av_section_1.empty());
|
||||
EXPECT_TRUE((av_section_1[{0, 0}] == 12));
|
||||
EXPECT_TRUE((av_section_1[{0, 1}] == 13));
|
||||
EXPECT_TRUE((av_section_1[{1, 0}] == 22));
|
||||
EXPECT_TRUE((av_section_1[{2, 3}] == 35));
|
||||
|
||||
const strided_span<int, 2> av_section_2 = av_section_1.section({1, 2}, {2, 2});
|
||||
EXPECT_TRUE(!av_section_2.empty());
|
||||
EXPECT_TRUE((av_section_2[{0, 0}] == 24));
|
||||
EXPECT_TRUE((av_section_2[{0, 1}] == 25));
|
||||
EXPECT_TRUE((av_section_2[{1, 0}] == 34));
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_constructors)
|
||||
{
|
||||
// EXPECT_TRUE stride constructor
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
strided_span<int, 1> sav1{arr, {{9}, {1}}}; // T -> T
|
||||
EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{9});
|
||||
EXPECT_TRUE(sav1.bounds().stride() == 1);
|
||||
EXPECT_TRUE(sav1[0] == 1);
|
||||
EXPECT_TRUE(sav1[8] == 9);
|
||||
|
||||
strided_span<const int, 1> sav2{carr, {{4}, {2}}}; // const T -> const T
|
||||
EXPECT_TRUE(sav2.bounds().index_bounds() == multi_span_index<1>{4});
|
||||
EXPECT_TRUE(sav2.bounds().strides() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav2[0] == 1);
|
||||
EXPECT_TRUE(sav2[3] == 7);
|
||||
|
||||
strided_span<int, 2> sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T
|
||||
EXPECT_TRUE((sav3.bounds().index_bounds() == multi_span_index<2>{2, 2}));
|
||||
EXPECT_TRUE((sav3.bounds().strides() == multi_span_index<2>{6, 2}));
|
||||
EXPECT_TRUE((sav3[{0, 0}]) == 1);
|
||||
EXPECT_TRUE((sav3[{0, 1}]) == 3);
|
||||
EXPECT_TRUE((sav3[{1, 0}]) == 7);
|
||||
}
|
||||
|
||||
// EXPECT_TRUE multi_span constructor
|
||||
{
|
||||
int arr[] = {1, 2};
|
||||
|
||||
// From non-cv-qualified source
|
||||
{
|
||||
const multi_span<int> src = arr;
|
||||
|
||||
strided_span<int, 1> sav{src, {2, 1}};
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav[1] == 2);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
// strided_span<const int, 1> sav_c{ {src}, {2, 1} };
|
||||
strided_span<const int, 1> sav_c{multi_span<const int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#else
|
||||
strided_span<const int, 1> sav_c{multi_span<const int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#endif
|
||||
EXPECT_TRUE(sav_c.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_c.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_c[1] == 2);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
strided_span<volatile int, 1> sav_v{src, {2, 1}};
|
||||
#else
|
||||
strided_span<volatile int, 1> sav_v{multi_span<volatile int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#endif
|
||||
EXPECT_TRUE(sav_v.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_v.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_v[1] == 2);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
|
||||
#else
|
||||
strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#endif
|
||||
EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_cv[1] == 2);
|
||||
}
|
||||
|
||||
// From const-qualified source
|
||||
{
|
||||
const multi_span<const int> src{arr};
|
||||
|
||||
strided_span<const int, 1> sav_c{src, {2, 1}};
|
||||
EXPECT_TRUE(sav_c.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_c.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_c[1] == 2);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
|
||||
#else
|
||||
strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_cv[1] == 2);
|
||||
}
|
||||
|
||||
// From volatile-qualified source
|
||||
{
|
||||
const multi_span<volatile int> src{arr};
|
||||
|
||||
strided_span<volatile int, 1> sav_v{src, {2, 1}};
|
||||
EXPECT_TRUE(sav_v.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_v.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_v[1] == 2);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||||
strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
|
||||
#else
|
||||
strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src},
|
||||
strided_bounds<1>{2, 1}};
|
||||
#endif
|
||||
EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_cv[1] == 2);
|
||||
}
|
||||
|
||||
// From cv-qualified source
|
||||
{
|
||||
const multi_span<const volatile int> src{arr};
|
||||
|
||||
strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
|
||||
EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav_cv[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
// EXPECT_TRUE const-casting constructor
|
||||
{
|
||||
int arr[2] = {4, 5};
|
||||
|
||||
const multi_span<int, 2> av(arr, 2);
|
||||
multi_span<const int, 2> av2{av};
|
||||
EXPECT_TRUE(av2[1] == 5);
|
||||
|
||||
static_assert(
|
||||
std::is_convertible<const multi_span<int, 2>, multi_span<const int, 2>>::value,
|
||||
"ctor is not implicit!");
|
||||
|
||||
const strided_span<int, 1> src{arr, {2, 1}};
|
||||
strided_span<const int, 1> sav{src};
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav.bounds().stride() == 1);
|
||||
EXPECT_TRUE(sav[1] == 5);
|
||||
|
||||
static_assert(
|
||||
std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value,
|
||||
"ctor is not implicit!");
|
||||
}
|
||||
|
||||
// EXPECT_TRUE copy constructor
|
||||
{
|
||||
int arr1[2] = {3, 4};
|
||||
const strided_span<int, 1> src1{arr1, {2, 1}};
|
||||
strided_span<int, 1> sav1{src1};
|
||||
|
||||
EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav1.bounds().stride() == 1);
|
||||
EXPECT_TRUE(sav1[0] == 3);
|
||||
|
||||
int arr2[6] = {1, 2, 3, 4, 5, 6};
|
||||
const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}};
|
||||
strided_span<const int, 2> sav2{src2};
|
||||
EXPECT_TRUE((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2}));
|
||||
EXPECT_TRUE((sav2.bounds().strides() == multi_span_index<2>{2, 1}));
|
||||
EXPECT_TRUE((sav2[{0, 0}]) == 1);
|
||||
EXPECT_TRUE((sav2[{2, 0}]) == 5);
|
||||
}
|
||||
|
||||
// EXPECT_TRUE const-casting assignment operator
|
||||
{
|
||||
int arr1[2] = {1, 2};
|
||||
int arr2[6] = {3, 4, 5, 6, 7, 8};
|
||||
|
||||
const strided_span<int, 1> src{arr1, {{2}, {1}}};
|
||||
strided_span<const int, 1> sav{arr2, {{3}, {2}}};
|
||||
strided_span<const int, 1>& sav_ref = (sav = src);
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav[0] == 1);
|
||||
EXPECT_TRUE(&sav_ref == &sav);
|
||||
}
|
||||
|
||||
// EXPECT_TRUE copy assignment operator
|
||||
{
|
||||
int arr1[2] = {3, 4};
|
||||
int arr1b[1] = {0};
|
||||
const strided_span<int, 1> src1{arr1, {2, 1}};
|
||||
strided_span<int, 1> sav1{arr1b, {1, 1}};
|
||||
strided_span<int, 1>& sav1_ref = (sav1 = src1);
|
||||
EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav1.bounds().strides() == multi_span_index<1>{1});
|
||||
EXPECT_TRUE(sav1[0] == 3);
|
||||
EXPECT_TRUE(&sav1_ref == &sav1);
|
||||
|
||||
const int arr2[6] = {1, 2, 3, 4, 5, 6};
|
||||
const int arr2b[1] = {0};
|
||||
const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}};
|
||||
strided_span<const int, 2> sav2{arr2b, {{1, 1}, {1, 1}}};
|
||||
strided_span<const int, 2>& sav2_ref = (sav2 = src2);
|
||||
EXPECT_TRUE((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2}));
|
||||
EXPECT_TRUE((sav2.bounds().strides() == multi_span_index<2>{2, 1}));
|
||||
EXPECT_TRUE((sav2[{0, 0}] == 1));
|
||||
EXPECT_TRUE((sav2[{2, 0}] == 5));
|
||||
EXPECT_TRUE(&sav2_ref == &sav2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_slice)
|
||||
{
|
||||
std::vector<int> data(5 * 10);
|
||||
std::iota(begin(data), end(data), 0);
|
||||
const multi_span<int, 5, 10> src =
|
||||
as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>());
|
||||
|
||||
const strided_span<int, 2> sav{src, {{5, 10}, {10, 1}}};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
const strided_span<const int, 2> csav{{src}, {{5, 10}, {10, 1}}};
|
||||
#endif
|
||||
const strided_span<const int, 2> csav{multi_span<const int, 5, 10>{src},
|
||||
{{5, 10}, {10, 1}}};
|
||||
|
||||
strided_span<int, 1> sav_sl = sav[2];
|
||||
EXPECT_TRUE(sav_sl[0] == 20);
|
||||
EXPECT_TRUE(sav_sl[9] == 29);
|
||||
|
||||
strided_span<const int, 1> csav_sl = sav[3];
|
||||
EXPECT_TRUE(csav_sl[0] == 30);
|
||||
EXPECT_TRUE(csav_sl[9] == 39);
|
||||
|
||||
EXPECT_TRUE(sav[4][0] == 40);
|
||||
EXPECT_TRUE(sav[4][9] == 49);
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_column_major)
|
||||
{
|
||||
// strided_span may be used to accommodate more peculiar
|
||||
// use cases, such as column-major multidimensional array
|
||||
// (aka. "FORTRAN" layout).
|
||||
|
||||
int cm_array[3 * 5] = {1, 4, 7, 10, 13, 2, 5, 8, 11, 14, 3, 6, 9, 12, 15};
|
||||
strided_span<int, 2> cm_sav{cm_array, {{5, 3}, {1, 5}}};
|
||||
|
||||
// Accessing elements
|
||||
EXPECT_TRUE((cm_sav[{0, 0}] == 1));
|
||||
EXPECT_TRUE((cm_sav[{0, 1}] == 2));
|
||||
EXPECT_TRUE((cm_sav[{1, 0}] == 4));
|
||||
EXPECT_TRUE((cm_sav[{4, 2}] == 15));
|
||||
|
||||
// Slice
|
||||
strided_span<int, 1> cm_sl = cm_sav[3];
|
||||
|
||||
EXPECT_TRUE(cm_sl[0] == 10);
|
||||
EXPECT_TRUE(cm_sl[1] == 11);
|
||||
EXPECT_TRUE(cm_sl[2] == 12);
|
||||
|
||||
// Section
|
||||
strided_span<int, 2> cm_sec = cm_sav.section({2, 1}, {3, 2});
|
||||
|
||||
EXPECT_TRUE((cm_sec.bounds().index_bounds() == multi_span_index<2>{3, 2}));
|
||||
EXPECT_TRUE((cm_sec[{0, 0}] == 8));
|
||||
EXPECT_TRUE((cm_sec[{0, 1}] == 9));
|
||||
EXPECT_TRUE((cm_sec[{1, 0}] == 11));
|
||||
EXPECT_TRUE((cm_sec[{2, 1}] == 15));
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_bounds)
|
||||
{
|
||||
int arr[] = {0, 1, 2, 3};
|
||||
multi_span<int> av(arr);
|
||||
|
||||
std::set_terminate([] {
|
||||
std::cerr << "Expected Death. strided_span_bounds";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
{
|
||||
// incorrect sections
|
||||
|
||||
EXPECT_DEATH(av.section(0, 0)[0], deathstring);
|
||||
EXPECT_DEATH(av.section(1, 0)[0], deathstring);
|
||||
EXPECT_DEATH(av.section(1, 1)[1], deathstring);
|
||||
|
||||
EXPECT_DEATH(av.section(2, 5), deathstring);
|
||||
EXPECT_DEATH(av.section(5, 2), deathstring);
|
||||
EXPECT_DEATH(av.section(5, 0), deathstring);
|
||||
EXPECT_DEATH(av.section(0, 5), deathstring);
|
||||
EXPECT_DEATH(av.section(5, 5), deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// zero stride
|
||||
strided_span<int, 1> sav{av, {{4}, {}}};
|
||||
EXPECT_TRUE(sav[0] == 0);
|
||||
EXPECT_TRUE(sav[3] == 0);
|
||||
EXPECT_DEATH(sav[4], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// zero extent
|
||||
strided_span<int, 1> sav{av, {{}, {1}}};
|
||||
EXPECT_DEATH(sav[0], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// zero extent and stride
|
||||
strided_span<int, 1> sav{av, {{}, {}}};
|
||||
EXPECT_DEATH(sav[0], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// strided array ctor with matching strided bounds
|
||||
strided_span<int, 1> sav{arr, {4, 1}};
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{4});
|
||||
EXPECT_TRUE(sav[3] == 3);
|
||||
EXPECT_DEATH(sav[4], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// strided array ctor with smaller strided bounds
|
||||
strided_span<int, 1> sav{arr, {2, 1}};
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav[1] == 1);
|
||||
EXPECT_DEATH(sav[2], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// strided array ctor with fitting irregular bounds
|
||||
strided_span<int, 1> sav{arr, {2, 3}};
|
||||
EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
|
||||
EXPECT_TRUE(sav[0] == 0);
|
||||
EXPECT_TRUE(sav[1] == 3);
|
||||
EXPECT_DEATH(sav[2], deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// bounds cross data boundaries - from static arrays
|
||||
EXPECT_DEATH((strided_span<int, 1>{arr, {3, 2}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{arr, {3, 3}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{arr, {4, 5}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{arr, {5, 1}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{arr, {5, 5}}), deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// bounds cross data boundaries - from array view
|
||||
EXPECT_DEATH((strided_span<int, 1>{av, {3, 2}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av, {3, 3}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av, {4, 5}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av, {5, 1}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av, {5, 5}}), deathstring);
|
||||
}
|
||||
|
||||
{
|
||||
// bounds cross data boundaries - from dynamic arrays
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {3, 2}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {3, 3}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {4, 5}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {5, 1}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {5, 5}}), deathstring);
|
||||
EXPECT_DEATH((strided_span<int, 1>{av.data(), 2, {2, 2}}), deathstring);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
strided_span<int, 1> sav0{av.data(), {3, 2}};
|
||||
strided_span<int, 1> sav1{arr, {1}};
|
||||
strided_span<int, 1> sav2{arr, {1, 1, 1}};
|
||||
strided_span<int, 1> sav3{av, {1}};
|
||||
strided_span<int, 1> sav4{av, {1, 1, 1}};
|
||||
strided_span<int, 2> sav5{av.as_multi_span(dim<2>(), dim<2>()), {1}};
|
||||
strided_span<int, 2> sav6{av.as_multi_span(dim<2>(), dim<2>()), {1, 1, 1}};
|
||||
strided_span<int, 2> sav7{av.as_multi_span(dim<2>(), dim<2>()),
|
||||
{{1, 1}, {1, 1}, {1, 1}}};
|
||||
|
||||
multi_span_index<1> index{0, 1};
|
||||
strided_span<int, 1> sav8{arr, {1, {1, 1}}};
|
||||
strided_span<int, 1> sav9{arr, {{1, 1}, {1, 1}}};
|
||||
strided_span<int, 1> sav10{av, {1, {1, 1}}};
|
||||
strided_span<int, 1> sav11{av, {{1, 1}, {1, 1}}};
|
||||
strided_span<int, 2> sav12{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1}}};
|
||||
strided_span<int, 2> sav13{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1, 1, 1}}};
|
||||
strided_span<int, 2> sav14{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1, 1}, {1}}};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_type_conversion)
|
||||
{
|
||||
int arr[] = {0, 1, 2, 3};
|
||||
multi_span<int> av(arr);
|
||||
|
||||
std::set_terminate([] {
|
||||
std::cerr << "Expected Death. strided_span_type_conversion";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
{
|
||||
strided_span<int, 1> sav{av.data(), av.size(), {av.size() / 2, 2}};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
|
||||
#endif
|
||||
}
|
||||
{
|
||||
strided_span<int, 1> sav{av, {av.size() / 2, 2}};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
|
||||
#endif
|
||||
}
|
||||
|
||||
multi_span<const byte, dynamic_range> bytes = as_bytes(av);
|
||||
|
||||
// retype strided array with regular strides - from raw data
|
||||
{
|
||||
strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}};
|
||||
strided_span<const byte, 2> sav2{bytes.data(), bytes.size(), bounds};
|
||||
strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>();
|
||||
EXPECT_TRUE(sav3[0][0] == 0);
|
||||
EXPECT_TRUE(sav3[1][0] == 2);
|
||||
EXPECT_DEATH(sav3[1][1], deathstring);
|
||||
EXPECT_DEATH(sav3[0][1], deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with regular strides - from multi_span
|
||||
{
|
||||
strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}};
|
||||
multi_span<const byte, 2, dynamic_range> bytes2 =
|
||||
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
|
||||
strided_span<const byte, 2> sav2{bytes2, bounds};
|
||||
strided_span<int, 2> sav3 = sav2.as_strided_span<int>();
|
||||
EXPECT_TRUE(sav3[0][0] == 0);
|
||||
EXPECT_TRUE(sav3[1][0] == 2);
|
||||
EXPECT_DEATH(sav3[1][1], deathstring);
|
||||
EXPECT_DEATH(sav3[0][1], deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with not enough elements - last dimension of the array is too small
|
||||
{
|
||||
strided_bounds<2> bounds{{4, 2}, {4, 1}};
|
||||
multi_span<const byte, 2, dynamic_range> bytes2 =
|
||||
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
|
||||
strided_span<const byte, 2> sav2{bytes2, bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with not enough elements - strides are too small
|
||||
{
|
||||
strided_bounds<2> bounds{{4, 2}, {2, 1}};
|
||||
multi_span<const byte, 2, dynamic_range> bytes2 =
|
||||
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
|
||||
strided_span<const byte, 2> sav2{bytes2, bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with not enough elements - last dimension does not divide by the new
|
||||
// typesize
|
||||
{
|
||||
strided_bounds<2> bounds{{2, 6}, {4, 1}};
|
||||
multi_span<const byte, 2, dynamic_range> bytes2 =
|
||||
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
|
||||
strided_span<const byte, 2> sav2{bytes2, bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with not enough elements - strides does not divide by the new
|
||||
// typesize
|
||||
{
|
||||
strided_bounds<2> bounds{{2, 1}, {6, 1}};
|
||||
multi_span<const byte, 2, dynamic_range> bytes2 =
|
||||
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
|
||||
strided_span<const byte, 2> sav2{bytes2, bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with irregular strides - from raw data
|
||||
{
|
||||
strided_bounds<1> bounds{bytes.size() / 2, 2};
|
||||
strided_span<const byte, 1> sav2{bytes.data(), bytes.size(), bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
|
||||
// retype strided array with irregular strides - from multi_span
|
||||
{
|
||||
strided_bounds<1> bounds{bytes.size() / 2, 2};
|
||||
strided_span<const byte, 1> sav2{bytes, bounds};
|
||||
EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, empty_strided_spans)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
std::cerr << "Expected Death. empty_strided_spans";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
{
|
||||
multi_span<int, 0> empty_av(nullptr);
|
||||
strided_span<int, 1> empty_sav{empty_av, {0, 1}};
|
||||
|
||||
EXPECT_TRUE(empty_sav.bounds().index_bounds() == multi_span_index<1>{0});
|
||||
EXPECT_TRUE(empty_sav.empty());
|
||||
EXPECT_DEATH(empty_sav[0], deathstring);
|
||||
EXPECT_DEATH(empty_sav.begin()[0], deathstring);
|
||||
EXPECT_DEATH(empty_sav.cbegin()[0], deathstring);
|
||||
|
||||
for (const auto& v : empty_sav) {
|
||||
(void) v;
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
strided_span<int, 1> empty_sav{nullptr, 0, {0, 1}};
|
||||
|
||||
EXPECT_TRUE(empty_sav.bounds().index_bounds() == multi_span_index<1>{0});
|
||||
EXPECT_DEATH(empty_sav[0], deathstring);
|
||||
EXPECT_DEATH(empty_sav.begin()[0], deathstring);
|
||||
EXPECT_DEATH(empty_sav.cbegin()[0], deathstring);
|
||||
|
||||
for (const auto& v : empty_sav) {
|
||||
(void) v;
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_section_iteration)
|
||||
{
|
||||
int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3};
|
||||
|
||||
// static bounds
|
||||
{
|
||||
multi_span<int, 8> av(arr, 8);
|
||||
iterate_every_other_element(av);
|
||||
}
|
||||
|
||||
// dynamic bounds
|
||||
{
|
||||
multi_span<int, dynamic_range> av(arr, 8);
|
||||
iterate_every_other_element(av);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, dynamic_strided_span_section_iteration)
|
||||
{
|
||||
auto arr = new int[8];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
arr[2 * i] = 4 + i;
|
||||
arr[2 * i + 1] = i;
|
||||
}
|
||||
|
||||
auto av = as_multi_span(arr, 8);
|
||||
iterate_every_other_element(av);
|
||||
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_section_iteration_3d)
|
||||
{
|
||||
int arr[3][4][2]{};
|
||||
for (auto i = 0; i < 3; ++i) {
|
||||
for (auto j = 0; j < 4; ++j)
|
||||
for (auto k = 0; k < 2; ++k) arr[i][j][k] = 8 * i + 2 * j + k;
|
||||
}
|
||||
|
||||
{
|
||||
multi_span<int, 3, 4, 2> av = arr;
|
||||
iterate_second_slice(av);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, dynamic_strided_span_section_iteration_3d)
|
||||
{
|
||||
const auto height = 12, width = 2;
|
||||
const auto size = height * width;
|
||||
|
||||
auto arr = new int[static_cast<std::size_t>(size)];
|
||||
for (auto i = 0; i < size; ++i) {
|
||||
arr[i] = i;
|
||||
}
|
||||
|
||||
{
|
||||
auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>());
|
||||
iterate_second_slice(av);
|
||||
}
|
||||
|
||||
{
|
||||
auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>());
|
||||
iterate_second_slice(av);
|
||||
}
|
||||
|
||||
{
|
||||
auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>());
|
||||
iterate_second_slice(av);
|
||||
}
|
||||
|
||||
{
|
||||
auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2));
|
||||
iterate_second_slice(av);
|
||||
}
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
TEST(strided_span_tests, strided_span_conversion)
|
||||
{
|
||||
std::set_terminate([] {
|
||||
std::cerr << "Expected Death. strided_span_conversion";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
// get an multi_span of 'c' values from the list of X's
|
||||
|
||||
struct X
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
X arr[4] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}};
|
||||
|
||||
int s = sizeof(int) / sizeof(byte);
|
||||
auto d2 = 3 * s;
|
||||
auto d1 = narrow_cast<int>(sizeof(int)) * 12 / d2;
|
||||
|
||||
// convert to 4x12 array of bytes
|
||||
auto av = as_multi_span(as_bytes(as_multi_span(&arr[0], 4)), dim(d1), dim(d2));
|
||||
|
||||
EXPECT_TRUE(av.bounds().index_bounds()[0] == 4);
|
||||
EXPECT_TRUE(av.bounds().index_bounds()[1] == 12);
|
||||
|
||||
// get the last 4 columns
|
||||
auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2],
|
||||
// arr[0].c[3] } , { arr[1].c[0], ... } , ...
|
||||
// }
|
||||
|
||||
// convert to array 4x1 array of integers
|
||||
auto cs = section.as_strided_span<int>(); // { { arr[0].c }, {arr[1].c } , ... }
|
||||
|
||||
EXPECT_TRUE(cs.bounds().index_bounds()[0] == 4);
|
||||
EXPECT_TRUE(cs.bounds().index_bounds()[1] == 1);
|
||||
|
||||
// transpose to 1x4 array
|
||||
strided_bounds<2> reverse_bounds{
|
||||
{cs.bounds().index_bounds()[1], cs.bounds().index_bounds()[0]},
|
||||
{cs.bounds().strides()[1], cs.bounds().strides()[0]}};
|
||||
|
||||
strided_span<int, 2> transposed{cs.data(), cs.bounds().total_size(), reverse_bounds};
|
||||
|
||||
// slice to get a one-dimensional array of c's
|
||||
strided_span<int, 1> result = transposed[0];
|
||||
|
||||
EXPECT_TRUE(result.bounds().index_bounds()[0] == 4);
|
||||
EXPECT_DEATH(result.bounds().index_bounds()[1], deathstring);
|
||||
|
||||
int i = 0;
|
||||
for (auto& num : result) {
|
||||
EXPECT_TRUE(num == arr[i].c);
|
||||
i++;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -16,14 +16,15 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/gsl_util> // for narrow, finally, narrow_cast, narrowing_e...
|
||||
|
||||
#include <algorithm> // for move
|
||||
#include <functional> // for reference_wrapper, _Bind_helper<>::type
|
||||
#include <limits> // for numeric_limits
|
||||
#include <stdint.h> // for uint32_t, int32_t
|
||||
#include <type_traits> // for is_same
|
||||
#include <complex>
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <cstdint> // for uint32_t, int32_t
|
||||
#include <functional> // for reference_wrapper, _Bind_helper<>::type
|
||||
#include <gsl/narrow> // for narrow, narrowing_error
|
||||
#include <gsl/util> // finally, narrow_cast
|
||||
#include <limits> // for numeric_limits
|
||||
#include <type_traits> // for is_same
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
@ -32,8 +33,7 @@ namespace
|
||||
void f(int& i) { i += 1; }
|
||||
static int j = 0;
|
||||
void g() { j += 1; }
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(utils_tests, sanity_check_for_gsl_index_typedef)
|
||||
{
|
||||
@ -70,11 +70,33 @@ TEST(utils_tests, finally_lambda_move)
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_const_lvalue_lambda)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
const auto const_lvalue_lambda = [&]() { f(i); };
|
||||
auto _ = finally(const_lvalue_lambda);
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_mutable_lvalue_lambda)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto mutable_lvalue_lambda = [&]() { f(i); };
|
||||
auto _ = finally(mutable_lvalue_lambda);
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_function_with_bind)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto _ = finally(std::bind(&f, std::ref(i)));
|
||||
auto _ = finally([&i] { return f(i); });
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
@ -90,6 +112,16 @@ TEST(utils_tests, finally_function_ptr)
|
||||
EXPECT_TRUE(j == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_function)
|
||||
{
|
||||
j = 0;
|
||||
{
|
||||
auto _ = finally(g);
|
||||
EXPECT_TRUE(j == 0);
|
||||
}
|
||||
EXPECT_TRUE(j == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, narrow_cast)
|
||||
{
|
||||
int n = 120;
|
||||
@ -101,6 +133,7 @@ TEST(utils_tests, narrow_cast)
|
||||
EXPECT_TRUE(uc == 44);
|
||||
}
|
||||
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
TEST(utils_tests, narrow)
|
||||
{
|
||||
int n = 120;
|
||||
@ -123,7 +156,10 @@ TEST(utils_tests, narrow)
|
||||
n = -42;
|
||||
EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
|
||||
|
||||
#if GSL_CONSTEXPR_NARROW
|
||||
static_assert(narrow<char>(120) == 120, "Fix GSL_CONSTEXPR_NARROW");
|
||||
#endif
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user