Compare commits

..

28 Commits

Author SHA1 Message Date
Herb Sutter 882720bd73 Changed default to per-TU violation handlers
And removed the feature test macro to instead tgest for a specific C++ version.
2021-01-27 16:36:59 -08:00
Herb Sutter 81c10b8017 normalize is a more accurate name than sanitize 2020-12-22 17:04:07 -08:00
Herb Sutter 0b80ac7d02 gsl/assert cleanup
Removed unnecessary headers
Added missing const
2020-12-19 12:58:31 -08:00
Herb Sutter e269976910 Added inline variable support 2020-12-18 13:16:40 -08:00
Herb Sutter 60beb7a363 Fixed the default
Accidentally flipped on the previous commit
2020-12-18 12:53:36 -08:00
Herb Sutter d5fc4efbf6 Turn off GCC bounds checking for the tests where we intentionally test out of bounds 2020-12-18 12:48:15 -08:00
Herb Sutter 25c0dee6e3 Reinstance the GSL_*_ON_CONTRACT_VIOLATION macros
At least the nonthrowing ones
2020-12-18 12:45:05 -08:00
Herb Sutter e02baff283 Remove minor code duplication 2020-12-18 12:34:07 -08:00
Herb Sutter 71fd73fa04 Make constructor more constinit-friendly 2020-12-18 12:27:33 -08:00
Herb Sutter c78ad8661c Added "vestigial" comments for downlevel feature test workarounds 2020-12-18 12:18:23 -08:00
Herb Sutter 070db845f8 Add -Wno-global-constructors for Clang 2020-12-18 12:10:36 -08:00
Herb Sutter 0c5a66b666 Added workaround for non-constexpr std::exchange 2020-12-18 12:02:42 -08:00
Herb Sutter 248a7cbdce Add feature test for literal constructor in downlevel compilers 2020-12-18 11:56:36 -08:00
Herb Sutter b77eaa87ee Make contract_group a literal type 2020-12-18 11:40:50 -08:00
Herb Sutter 9033021831 Removed stray .exchange 2020-12-18 11:34:25 -08:00
Herb Sutter a45265a75e Handler shouldn't be internally synchronized 2020-12-18 11:30:17 -08:00
Herb Sutter 8bd828744f Remove constexpr again to see what the failures were 2020-12-18 11:25:04 -08:00
Herb Sutter 1c37688ccd Replaced some of the previous workarounds with feature tests
As always with feature tests, they can only be used to aggressively adopt new features even before all compilers we need have the features -- the test lets us write a vestigial workaround for downllevel compilers, to be removed as soon as all compilers support the feature.
2020-12-18 11:20:03 -08:00
Herb Sutter 8dfd03feeb Remove constexpr from contract_group constructor 2020-12-17 13:19:29 -08:00
Herb Sutter d83e9ea05f Add workarounds for Android compiler and constexpr test 2020-12-17 12:11:42 -08:00
Herb Sutter 59f38376b9 Change auto to void to satisfy some compilers about definition ordering 2020-12-17 12:03:59 -08:00
Herb Sutter dd45e5cfbd Went back to old-style declaration for older compilers that don't do C++17 guaranteed copy elision
A concession to older compilers.
2020-12-17 11:58:53 -08:00
Herb Sutter 0cbb9e221d Removed double .load
Require `chandler` to be never null by installing `[]()noexcept{}` as the handler if given a null pointer.
This lets us remove the double test in `assertion`.
2020-12-17 11:36:23 -08:00
Herb Sutter b7548fd1cd Update multi_span
Revert changes in multi_span to avoid a merge conflict, since this file was deleted in a parallel PR
2020-12-17 10:35:34 -08:00
Herb Sutter cbfd8cd734 Parameterize Expects1 and Ensures` by contract group
Allows independently controlling handling of different categories of bugs, such as bounds checks vs. null checks.
User-extensible: Companies can instantiate their own `contract_group` objects for their own categories of contract checks, including for distinguishing contract "levels" like `Normal` vs. `Audit` by just creating those two groups that can then be controlled independently or in combination.
2020-11-27 17:06:01 -08:00
Herb Sutter c16e4ce59f Replace GSL_CONTRACT_CHECK with contract_group 2020-11-27 16:33:12 -08:00
Herb Sutter b34dc221a1 Remove GSL_ASSUME (unused code)
This is not specified in the C++ Core Guidelines as part of GSL, so it should not be documented or supported with a GSL name. And since we don't use it in the GSL repo either, we should just remove it directly. For more about why assumptions are a dangerous blunt instrument, including that they actively eliminate contracts checks including GSL's `Expects` and `Ensures`, see [P2064](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2064r0.pdf).
2020-11-27 11:10:53 -08:00
Herb Sutter c20a54c8e7 Remove __builtin_expect prediction assistance
In microbenchmarks I tried, using `__builtin_expect` to indicate which branch was likely/unlikely was never faster, and often slower, than just omitting. In GSL, this is used only for `Expects` and `Ensures` which are nearly always true, and all processors have long been great at predicting such branches well.
2020-11-27 11:07:55 -08:00
71 changed files with 9732 additions and 6267 deletions
+1 -1
View File
@@ -31,4 +31,4 @@ AlignConsecutiveAssignments: false
AlignTrailingComments: true
SpaceAfterCStyleCast: true
WhitespaceSensitiveMacros: [GSL_SUPPRESS]
CommentPragmas: '^ NO-FORMAT:'
-1
View File
@@ -1 +0,0 @@
include/gsl/* linguist-language=C++
-29
View File
@@ -1,29 +0,0 @@
---
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.
-84
View File
@@ -1,84 +0,0 @@
# GitHub Copilot Instructions for GSL (Guidelines Support Library)
## Project Overview
This repository contains the Guidelines Support Library (GSL), a Microsoft implementation of types and functions
suggested for use by the C++ Core Guidelines. It's a header-only C++ library with emphasis on safety,
correctness, and zero overhead.
## Coding Standards
### General
- Follow C++ Core Guidelines wherever possible
- Use meaningful type, function, and template parameter names
- Keep functions small and focused with clear preconditions/postconditions
- Include comments for complex code, but prefer self-documenting code
- Use the Expects() and Ensures() macros for contract verification
### Style Guidelines
- Use 4 spaces for indentation (not tabs)
- Maximum line length of 100 characters
- Follow GSL naming conventions (lowercase with underscores)
- Keep templates clean and readable with appropriate spacing
- Use C++14 features since this is the minimum standard supported
### Error Handling
- Use Expects() for preconditions and Ensures() for postconditions
- Design for fail-fast semantics (std::terminate) on contract violations
- Template constraints should use static_assert or SFINAE
- Don't throw exceptions from basic operations
### Testing
- Write thorough unit tests for every component using GTest
- Test for all edge cases and error conditions
- Ensure cross-platform compatibility in tests
- Maintain 100% code coverage for changed code
## Project-Specific Conventions
### Architecture
- All public types must be in the gsl namespace
- Design for zero overhead abstractions when possible
- Respect the distinction between Owners and Views
- Maintain backward compatibility with existing GSL code
### Version Control
- Link all PRs to related issues
- Use clear commit messages explaining what and why
- Follow the contribution guidelines documented in CONTRIBUTING.md
- PRs should include appropriate tests with 100% coverage for changed code
### Documentation
- Document all public APIs with clarity on preconditions and postconditions
- Keep header comments up-to-date
- Include examples for complex functionality in docs/headers.md
## Technology Stack
- C++14 (minimum) for core implementation
- CMake build system (3.14+)
- Google Test for unit testing
- Support for multiple compilers (MSVC, GCC, Clang)
## Security Considerations
- Bounds checking is a core principle - enforce it consistently
- Design for safety while minimizing overhead
- Ensure undefined behavior is explicitly detected where possible
## Performance Guidelines
- Optimize for both safety and performance
- Constexpr-enable functions wherever possible
- Avoid hidden allocations
- Use noexcept appropriately for move operations and other performance-critical functions
## Cross-Platform Support
- Code must work across:
- Windows (MSVC)
- Linux (GCC, Clang)
- macOS (AppleClang)
- Android and iOS where applicable
## Copilot Tasks
- You can find the CMake artifacts for C++20 in build-cxx20 and C++14 in build-cxx14.
- Before publishing a PR, verify the following:
- There are no compiler warnings or errors when building the test suite.
- The test suite passes on all supported platforms and compilers.
- The test suite passes for both C++14 and C++20.
+12 -21
View File
@@ -1,54 +1,45 @@
name: CI_Android
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches: [ main ]
branches: [ master ]
pull_request:
branches: [ main ]
branches: [ master ]
jobs:
Android:
runs-on: macos-latest-large
runs-on: macos-latest
defaults:
run:
working-directory: build
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v2
- name: Create build directory
run: mkdir -p build
working-directory: .
- uses: actions/setup-java@v5
with:
java-version: 8
distribution: zulu
- name: Start Emulator
- 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"
echo "Starting emulator"
# Start emulator in background
nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot > /dev/null 2>&1 &
echo "Emulator starting"
- 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 ..
run: cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk-bundle/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
echo "Emulator started"
- name: Deploy tests
run: |
@@ -56,4 +47,4 @@ jobs:
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 {} \\\;
run: adb shell find /data/local/tmp/tests -name "*_tests" -maxdepth 1 -exec {} \\\;
-39
View File
@@ -1,39 +0,0 @@
name: Code Formatting
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
env:
CLANG_VERSION: "20"
jobs:
clang-format:
name: Run clang-format
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Install the exact clang-format binary
- name: Install clang-format
run: |
sudo apt install clang-format-${{ env.CLANG_VERSION }}
# Prints the version of clang-format being used
- name: Log clang-format version
run: clang-format-${{ env.CLANG_VERSION }} --version
# Runs clang-format over the repository codebase
- name: Check format
run: |
{
find include/gsl -type f
find tests -type f \( -name '*.cpp' -o -name '*.h' \)
} | xargs clang-format-${{ env.CLANG_VERSION }} --dry-run --Werror
-33
View File
@@ -1,33 +0,0 @@
name: Composite CMake
inputs:
cmake_preset:
required: true
type: string
extra_cmake_build_args:
required: false
type: string
default: ''
extra_cmake_configure_args:
required: false
type: string
default: ''
extra_ctest_args:
required: false
type: string
default: ''
runs:
using: composite
steps:
- name: Configure CMake
run: cmake --preset ${{ inputs.cmake_preset }} ${{ inputs.extra_cmake_configure_args }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev
shell: ${{ env.RUNNER_OS == 'Windows' && 'pwsh' || 'bash' }}
- name: Build (with preset)
run: cmake --build --preset ${{ inputs.cmake_preset }} ${{ inputs.extra_cmake_build_args }}
shell: ${{ env.RUNNER_OS == 'Windows' && 'pwsh' || 'bash' }}
- name: Test (with preset)
run: ctest --preset ${{ inputs.cmake_preset }} ${{ inputs.extra_ctest_args }} --output-on-failure --no-compress-output
shell: ${{ env.RUNNER_OS == 'Windows' && 'pwsh' || 'bash' }}
-25
View File
@@ -1,25 +0,0 @@
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@v6
- 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
-106
View File
@@ -1,106 +0,0 @@
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@v6
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_preset: gcc-${{ matrix.cxx_version }}-${{ matrix.build_type == 'Debug' && 'debug' || 'release' }}
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@v6
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_preset: clang-${{ matrix.cxx_version }}-${{ matrix.build_type == 'Debug' && 'debug' || 'release' }}
xcode:
strategy:
matrix:
xcode_version: [ '16.4' ]
build_type: [ Debug, Release ]
cxx_version: [ 14, 17, 20, 23 ]
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- 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_preset: clang-${{ matrix.cxx_version }}-${{ matrix.build_type == 'Debug' && 'debug' || 'release' }}
extra_cmake_configure_args: '-DCMAKE_CXX_FLAGS="-isysroot \"$(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk\""'
msvc:
strategy:
matrix:
image: [ windows-2022, windows-2025 ]
build_type: [ Debug, Release ]
toolset: [ 'msvc', 'ClangCL' ]
cxx_version: [ 14, 17, 20, 23 ]
include:
# Regular MSVC builds use Ninja (from preset)
- toolset: 'msvc'
generator_override: ''
# ClangCL builds require Visual Studio generator
- toolset: 'ClangCL'
generator_override: '-G "Visual Studio 17 2022" -T ClangCL'
runs-on: ${{ matrix.image }}
steps:
- uses: actions/checkout@v6
- uses: microsoft/setup-msbuild@v3
- uses: ilammy/msvc-dev-cmd@v1
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_preset: msvc-${{ matrix.cxx_version }}-${{ matrix.build_type == 'Debug' && 'debug' || 'release' }}
extra_cmake_configure_args: ${{ matrix.generator_override }}
extra_cmake_build_args: ${{ matrix.toolset == 'ClangCL' && format('--config {0}', matrix.build_type) || '' }}
extra_ctest_args: ${{ matrix.toolset == 'ClangCL' && format('-C {0}', matrix.build_type) || '' }}
-21
View File
@@ -1,21 +0,0 @@
name: "Copilot Setup Steps"
on: workflow_dispatch
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Build Dependencies
run: sudo apt-get update && sudo apt-get install -y clang cmake make
- name: Configure CMake (C++14)
run: cmake --preset clang-14-debug
- name: Configure CMake (C++20)
run: cmake --preset clang-20-debug
+6 -8
View File
@@ -1,9 +1,9 @@
name: CI_iOS
on:
push:
branches: [ main ]
branches: [ master ]
pull_request:
branches: [ main ]
branches: [ master ]
jobs:
iOS:
@@ -12,7 +12,7 @@ jobs:
run:
working-directory: build
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v2
- name: Create build directory
run: mkdir -p build
@@ -21,16 +21,14 @@ jobs:
- name: Configure
run: |
cmake \
-Werror=dev \
-GXcode \
-DCMAKE_SYSTEM_NAME=iOS \
"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=8 \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
"-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \
-DMACOSX_BUNDLE_BUNDLE_VERSION=4.2.0 \
-DMACOSX_BUNDLE_SHORT_VERSION_STRING=4.2.0 \
-DCMAKE_CXX_FLAGS="-Wno-missing-include-dirs" \
-DMACOSX_BUNDLE_BUNDLE_VERSION=3.0.1 \
-DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.0.1 \
..
- name: Build
-32
View File
@@ -1,32 +0,0 @@
name: Shell script linter
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
clang-format:
name: Run shfmt and shellcheck
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Install the needed binaries
- name: Install shfmt and shellcheck
run: |
sudo apt install shfmt shellcheck
- name: Check format
run: |
find scripts -type f -name '*.sh' -exec shfmt -l {} \;
- name: Run shellcheck
run: |
find scripts -type f -name '*.sh' -exec shellcheck {} \;
+1 -1
View File
@@ -1,5 +1,5 @@
CMakeFiles
build*/
build
tests/CMakeFiles
tests/Debug
*.opensdf
+337
View File
@@ -0,0 +1,337 @@
language: cpp
notifications:
email: false
# Use Linux unless specified otherwise
os: linux
dist: bionic
cache:
directories:
- ${TRAVIS_BUILD_DIR}/deps
stages:
- name: Latest # Compiler with the latest major version
- name: Previous # Compilers with the major version Latest - 1
- name: Validation # run other jobs
jobs:
include:
##########################################################################
# Validate CMake configuration
##########################################################################
- name: CMake 3.1.3 - latest
stage: Validation
env: &CMAKE_VERSION_LIST
- CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3 3.1.3"'
- GSL_CXX_STANDARD: 14
addons: # Get latest release (candidate)
apt:
sources:
- sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic main'
key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc'
- sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic-rc main'
packages:
- cmake
script:
- |
cd ./build
( set -eu
for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done
export CXX=clang++
for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done
)
- name: CMake 3.2.3 - 3.17.0
stage: Validation
os: osx
osx_image: xcode11.3
env:
- CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3"'
script:
- |
cd ./build
( set -eu
for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done
)
##########################################################################
# AppleClang on OSX
##########################################################################
# Xcode 10.3
- name: AppleClang Xcode-10.3 C++14 Debug
stage: Previous
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
os: osx
osx_image: xcode10.3 # AppleClang 10.0.1 same compiler as Xcode 10.2
- name: AppleClang Xcode-10.3 C++14 Release
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
os: osx
osx_image: xcode10.3
- name: AppleClang Xcode-10.3 C++17 Debug
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
os: osx
osx_image: xcode10.3
- name: AppleClang Xcode-10.3 C++17 Release
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
os: osx
osx_image: xcode10.3
# Xcode 11.4
- name: AppleClang Xcode-11.4 C++17 Debug
stage: Latest
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17
os: osx
osx_image: xcode11.4
- name: AppleClang Xcode-11.4 C++17 Release
env: BUILD_TYPE=Release GSL_CXX_STANDARD=17
os: osx
osx_image: xcode11.4
- name: AppleClang Xcode-11.4 C++14 Debug
env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14
os: osx
osx_image: xcode11.4
- name: AppleClang Xcode-11.4 C++14 Release
env: BUILD_TYPE=Release GSL_CXX_STANDARD=14
os: osx
osx_image: xcode11.4
##########################################################################
# Clang on Linux
##########################################################################
# Clang 9
- name: Clang-9 C++14 Debug
stage: Previous
env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
addons: &clang9
apt:
sources:
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'
key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
packages:
- clang-9
- name: Clang-9 C++14 Release
env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14
addons: *clang9
- name: Clang-9 C++17 Debug
env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
addons: *clang9
- name: Clang-9 C++17 Release
env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17
addons: *clang9
# Clang 10
- name: Clang-10 C++14 Debug
stage: Latest
env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
addons: &clang10
apt:
sources:
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
packages:
- clang-10
- name: Clang-10 C++14 Release
env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=14
addons: *clang10
- name: Clang-10 C++17 Debug
env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
addons: *clang10
- name: Clang-10 C++17 Release
env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=17
addons: *clang10
##########################################################################
# GCC on Linux
##########################################################################
# GCC 8
- name: GCC-8 C++14 Debug
stage: Previous
env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
addons: &gcc8
apt:
packages: g++-8
- name: GCC-8 C++14 Release
env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=14
addons: *gcc8
- name: GCC-8 C++17 Debug
env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
addons: *gcc8
- name: GCC-8 C++17 Release
env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=17
addons: *gcc8
# GCC 9
- name: GCC-9 C++14 Debug
stage: Latest
env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14
addons: &gcc9
apt:
sources:
- sourceline: ppa:ubuntu-toolchain-r/test
packages:
- g++-9
- name: GCC-9 C++14 Release
env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14
addons: *gcc9
- name: GCC-9 C++17 Debug
env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17
addons: *gcc9
- name: GCC-9 C++17 Release
env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17
addons: *gcc9
before_install:
- |
# Configuration
JOBS=2 # Travis machines have 2 cores
# Dependencies required by the CI (cached directory)
DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- |
# Setup
mkdir -p "${DEPS_DIR:?}" && cd "${DEPS_DIR:?}"
mkdir -p ~/tools && cd ~/tools
if [[ ${TRAVIS_OS_NAME:?} == "osx" ]]; then
export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
fi
- |
# Helper functions
# usage: if [[ $(check_url '<url>') ]]; then ...
function check_url {( set +e
if [[ "$1" =~ 'github.com' ]]; then # check for first byte
if curl --fail --silent --output /dev/null --connect-timeout 12 --range 0-0 "$1"
then echo true; fi
else # request head
if curl --fail --silent --output /dev/null --connect-timeout 12 --head "$1"
then echo true; fi
fi
return
)}
install:
############################################################################
# Install a different CMake version (or several)
############################################################################
- |
# Install CMake versions
( set -euo pipefail
if [[ ${CMAKE_VERSION:-} ]]; then
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
OS="Linux"; EXT="sh"
if [[ ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]]; then
# Single entry -> default CMake version
CMAKE_DEFAULT_DIR="/usr/local"
fi
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then OS="Darwin"; EXT="tar.gz"
else echo "CMake install not supported for this OS."; exit 1
fi
CMAKE_INSTALLER="install-cmake.${EXT}"
fi
for VERSION in ${CMAKE_VERSION:-}; do
CMAKE_URL="https://github.com/Kitware/CMake/releases/download/v${VERSION}/cmake-${VERSION}-${OS}-x86_64.${EXT}"
if [[ $(check_url "$CMAKE_URL") ]]; then
curl -sSL ${CMAKE_URL} -o ${CMAKE_INSTALLER}
CMAKE_DIR="${CMAKE_DEFAULT_DIR:-"${HOME}/tools/cmake-${VERSION}"}"
mkdir -p ${CMAKE_DIR}
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
chmod +x ${CMAKE_INSTALLER}
sudo ./${CMAKE_INSTALLER} --prefix=${CMAKE_DIR} --skip-license
else # OSX
mkdir -p ./CMake_tmp
tar --extract --gzip --file=${CMAKE_INSTALLER} --directory=./CMake_tmp
mv ./CMake_tmp/*/CMake.app/Contents/* ${CMAKE_DIR}
fi
rm --recursive --force ./CMake_tmp ${CMAKE_INSTALLER}
else echo 'Invalid url!'; echo "Version: ${VERSION}"
fi
done
)
if [[ ${CMAKE_VERSION:-} && "${TRAVIS_OS_NAME:?}" == "osx" && ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]]
then # Single entry -> default CMake version
export PATH=${HOME}/tools/cmake-${CMAKE_VERSION:?}/bin:$PATH
fi
CMAKE_path=("cmake") # start with installed CMake version
for VERSION in ${CMAKE_VERSION:-}; do
tmp_path="$HOME/tools/cmake-${VERSION:?}/bin/cmake"
if [[ -x "$(command -v ${tmp_path:?})" ]]; then CMAKE_path+=("${tmp_path:?}"); fi
done
function test_CMake_generate {
# $1: cmake or full path to cmake
shopt -s extglob
if [[ "$1" == "cmake" || -x "$(command -v $1)" && "$1" =~ .*cmake$ ]]; then
echo "----------------"
$1 --version
echo "Configuration = ${BUILD_TYPE:-Debug}"
$1 -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} ${CMAKE_GEN_FLAGS[@]:?} ..
rm -rf !(tests/googletest-*)
if [[ ! ${BUILD_TYPE:-} ]]; then echo "" && echo "Configuration = Release"
$1 -DCMAKE_BUILD_TYPE=Release ${CMAKE_GEN_FLAGS[@]:?} ..
rm -rf !(tests/googletest-*)
fi
else echo "Non existing command: $1"
fi
}
- |
# CMake wrapper (Trusty, Xenial & Bionic); restore default behaviour.
if [[ "${TRAVIS_OS_NAME:?}" == "linux" &&
"$(lsb_release --codename)" =~ (trusty|xenial|bionic)$ ]]
then
if [[ -x $(command -v /usr/local/bin/cmake) ]]; then
function cmake { command /usr/local/bin/cmake $@; }
elif [[ -x $(command -v /usr/bin/cmake) ]]; then
function cmake { command /usr/bin/cmake $@; }
fi
fi
############################################################################
# [linux]: Install the right version of libc++
# Based on https://github.com/ldionne/hana/blob/master/.travis.yml
############################################################################
- |
LLVM_INSTALL=${DEPS_DIR:?}/llvm/install
# if in linux and compiler clang and llvm not installed
if [[ "${TRAVIS_OS_NAME:?}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL:?})" ]]; then
if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2";
elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1";
elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1";
elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1";
fi
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz"
LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz"
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi
travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm
travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx
travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi
(cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL})
(cd llvm/build/projects/libcxx && make install -j2)
(cd llvm/build/projects/libcxxabi && make install -j2)
export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1"
export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib"
fi
before_script:
- |
cd "${TRAVIS_BUILD_DIR:?}"
mkdir build && cd build
if [[ ${GSL_CXX_STANDARD:-} ]]; then
CMAKE_GEN_FLAGS=("-DGSL_CXX_STANDARD=$GSL_CXX_STANDARD")
fi
CMAKE_GEN_FLAGS+=("-Wdev -Werror=dev --warn-uninitialized")
script:
# generate build files
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE:?} ${CMAKE_GEN_FLAGS[@]:?}
# build and run tests
- cmake --build . -- -j${JOBS}
- ctest --output-on-failure -j${JOBS}
+104 -35
View File
@@ -1,48 +1,117 @@
cmake_minimum_required(VERSION 3.14...3.16)
cmake_minimum_required(VERSION 3.1.3...3.16)
project(GSL VERSION 4.2.0 LANGUAGES CXX)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(guidelineSupportLibrary)
project(GSL VERSION 3.1.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)
# NOTE: If you want to use GSL prefer to link against GSL using this alias target
# EX:
# target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
#
# 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)
# 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)
# 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()
option(GSL_INSTALL "Generate and install GSL target" ${PROJECT_IS_TOP_LEVEL})
option(GSL_TEST "Build and perform GSL tests" ${PROJECT_IS_TOP_LEVEL})
# This GSL implementation generally assumes a platform that implements C++14 support.
set(gsl_min_cxx_standard "14")
# The implementation generally assumes a platform that implements C++14 support
target_compile_features(GSL INTERFACE "cxx_std_14")
if (GSL_STANDALONE_PROJECT)
gsl_set_default_cxx_standard(${gsl_min_cxx_standard})
else()
gsl_client_set_cxx_standard(${gsl_min_cxx_standard})
endif()
# Setup include directory
add_subdirectory(include)
# 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
>
)
target_sources(GSL INTERFACE $<BUILD_INTERFACE:${GSL_SOURCE_DIR}/GSL.natvis>)
# 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(GSL_VS_ADD_NATIVE_VISUALIZERS "Configure project to use Visual Studio native visualizers" TRUE)
else()
set(GSL_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(GSL_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 find_package() versioning support. The version for
# generated Microsoft.GSLConfigVersion.cmake will be used from
# last project() command. The version's compatibility is set between all
# minor versions (as it was in prev. GSL releases).
include(CMakePackageConfigHelpers)
if(${CMAKE_VERSION} VERSION_LESS "3.14.0")
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake
COMPATIBILITY SameMajorVersion
)
else()
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake
COMPATIBILITY SameMajorVersion
ARCH_INDEPENDENT
)
endif()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
option(GSL_TEST "Generate tests." ${GSL_STANDALONE_PROJECT})
if (GSL_TEST)
enable_testing()
if(IOS)
add_compile_definitions(
GTEST_HAS_DEATH_TEST=1
)
endif()
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()
endif ()
-459
View File
@@ -1,459 +0,0 @@
{
"version": 3,
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"installDir": "${sourceDir}/install/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"GSL_CXX_STANDARD": "14",
"GSL_TEST": "ON"
}
},
{
"name": "msvc-base",
"inherits": "base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"cacheVariables": {
"CMAKE_CXX_COMPILER": "cl"
}
},
{
"name": "gcc-base",
"inherits": "base",
"hidden": true,
"cacheVariables": {
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER": "gcc"
}
},
{
"name": "clang-base",
"inherits": "base",
"hidden": true,
"cacheVariables": {
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_C_COMPILER": "clang"
}
},
{
"name": "msvc-14-debug",
"displayName": "MSVC C++14 Debug",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "msvc-14-release",
"displayName": "MSVC C++14 Release",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "msvc-17-debug",
"displayName": "MSVC C++17 Debug",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "msvc-17-release",
"displayName": "MSVC C++17 Release",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "msvc-20-debug",
"displayName": "MSVC C++20 Debug",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "msvc-20-release",
"displayName": "MSVC C++20 Release",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "msvc-23-debug",
"displayName": "MSVC C++23 Debug",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "23"
}
},
{
"name": "msvc-23-release",
"displayName": "MSVC C++23 Release",
"inherits": "msvc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "23"
}
},
{
"name": "gcc-14-debug",
"displayName": "GCC C++14 Debug",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "gcc-14-release",
"displayName": "GCC C++14 Release",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "gcc-17-debug",
"displayName": "GCC C++17 Debug",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "gcc-17-release",
"displayName": "GCC C++17 Release",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "gcc-20-debug",
"displayName": "GCC C++20 Debug",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "gcc-20-release",
"displayName": "GCC C++20 Release",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "gcc-23-debug",
"displayName": "GCC C++23 Debug",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "23"
}
},
{
"name": "gcc-23-release",
"displayName": "GCC C++23 Release",
"inherits": "gcc-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "23"
}
},
{
"name": "clang-14-debug",
"displayName": "Clang C++14 Debug",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "clang-14-release",
"displayName": "Clang C++14 Release",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "14"
}
},
{
"name": "clang-17-debug",
"displayName": "Clang C++17 Debug",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "clang-17-release",
"displayName": "Clang C++17 Release",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "17"
}
},
{
"name": "clang-20-debug",
"displayName": "Clang C++20 Debug",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "clang-20-release",
"displayName": "Clang C++20 Release",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "20"
}
},
{
"name": "clang-23-debug",
"displayName": "Clang C++23 Debug",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"GSL_CXX_STANDARD": "23"
}
},
{
"name": "clang-23-release",
"displayName": "Clang C++23 Release",
"inherits": "clang-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"GSL_CXX_STANDARD": "23"
}
}
],
"buildPresets": [
{
"name": "msvc-14-debug",
"configurePreset": "msvc-14-debug"
},
{
"name": "msvc-14-release",
"configurePreset": "msvc-14-release"
},
{
"name": "msvc-17-debug",
"configurePreset": "msvc-17-debug"
},
{
"name": "msvc-17-release",
"configurePreset": "msvc-17-release"
},
{
"name": "msvc-20-debug",
"configurePreset": "msvc-20-debug"
},
{
"name": "msvc-20-release",
"configurePreset": "msvc-20-release"
},
{
"name": "msvc-23-debug",
"configurePreset": "msvc-23-debug"
},
{
"name": "msvc-23-release",
"configurePreset": "msvc-23-release"
},
{
"name": "gcc-14-debug",
"configurePreset": "gcc-14-debug"
},
{
"name": "gcc-14-release",
"configurePreset": "gcc-14-release"
},
{
"name": "gcc-17-debug",
"configurePreset": "gcc-17-debug"
},
{
"name": "gcc-17-release",
"configurePreset": "gcc-17-release"
},
{
"name": "gcc-20-debug",
"configurePreset": "gcc-20-debug"
},
{
"name": "gcc-20-release",
"configurePreset": "gcc-20-release"
},
{
"name": "gcc-23-debug",
"configurePreset": "gcc-23-debug"
},
{
"name": "gcc-23-release",
"configurePreset": "gcc-23-release"
},
{
"name": "clang-14-debug",
"configurePreset": "clang-14-debug"
},
{
"name": "clang-14-release",
"configurePreset": "clang-14-release"
},
{
"name": "clang-17-debug",
"configurePreset": "clang-17-debug"
},
{
"name": "clang-17-release",
"configurePreset": "clang-17-release"
},
{
"name": "clang-20-debug",
"configurePreset": "clang-20-debug"
},
{
"name": "clang-20-release",
"configurePreset": "clang-20-release"
},
{
"name": "clang-23-debug",
"configurePreset": "clang-23-debug"
},
{
"name": "clang-23-release",
"configurePreset": "clang-23-release"
}
],
"testPresets": [
{
"name": "msvc-14-debug",
"configurePreset": "msvc-14-debug"
},
{
"name": "msvc-14-release",
"configurePreset": "msvc-14-release"
},
{
"name": "msvc-17-debug",
"configurePreset": "msvc-17-debug"
},
{
"name": "msvc-17-release",
"configurePreset": "msvc-17-release"
},
{
"name": "msvc-20-debug",
"configurePreset": "msvc-20-debug"
},
{
"name": "msvc-20-release",
"configurePreset": "msvc-20-release"
},
{
"name": "msvc-23-debug",
"configurePreset": "msvc-23-debug"
},
{
"name": "msvc-23-release",
"configurePreset": "msvc-23-release"
},
{
"name": "gcc-14-debug",
"configurePreset": "gcc-14-debug"
},
{
"name": "gcc-14-release",
"configurePreset": "gcc-14-release"
},
{
"name": "gcc-17-debug",
"configurePreset": "gcc-17-debug"
},
{
"name": "gcc-17-release",
"configurePreset": "gcc-17-release"
},
{
"name": "gcc-20-debug",
"configurePreset": "gcc-20-debug"
},
{
"name": "gcc-20-release",
"configurePreset": "gcc-20-release"
},
{
"name": "gcc-23-debug",
"configurePreset": "gcc-23-debug"
},
{
"name": "gcc-23-release",
"configurePreset": "gcc-23-release"
},
{
"name": "clang-14-debug",
"configurePreset": "clang-14-debug"
},
{
"name": "clang-14-release",
"configurePreset": "clang-14-release"
},
{
"name": "clang-17-debug",
"configurePreset": "clang-17-debug"
},
{
"name": "clang-17-release",
"configurePreset": "clang-17-release"
},
{
"name": "clang-20-debug",
"configurePreset": "clang-20-debug"
},
{
"name": "clang-20-release",
"configurePreset": "clang-20-release"
},
{
"name": "clang-23-debug",
"configurePreset": "clang-23-debug"
},
{
"name": "clang-23-release",
"configurePreset": "clang-23-release"
}
]
}
+18
View File
@@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "-DGSL_CXX_STANDARD=17",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"codeAnalysisRuleset": "CppCoreCheckRules.ruleset"
}
]
}
+1 -1
View File
@@ -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 **main** branch
* Be a child commit of a reasonably recent commit in the **master** 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
+31 -4
View File
@@ -4,7 +4,13 @@
vim: syntax=xml
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- These types are from the util header. -->
<!-- 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. -->
<Type Name="gsl::final_action&lt;*&gt;">
<DisplayString>{{ invoke = {invoke_}, action = {f_} }}</DisplayString>
<Expand>
@@ -13,8 +19,7 @@
</Expand>
</Type>
<!-- These types are from the span header. -->
<Type Name="gsl::span&lt;*, *&gt;">
<Type Name="gsl::span&lt;*, *&gt;">
<DisplayString>{{ extent = {storage_.size_} }}</DisplayString>
<Expand>
<ArrayItems>
@@ -24,7 +29,29 @@
</Expand>
</Type>
<!-- These types are from the pointers header. -->
<Type Name="gsl::basic_string_span&lt;*, *&gt;">
<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>
<Type Name="gsl::basic_zstring_span&lt;*, *&gt;">
<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>
<!-- These types are from the gsl header. -->
<Type Name="gsl::not_null&lt;*&gt;">
<!-- We can always dereference this since it's an invariant. -->
<DisplayString>value = {*ptr_}</DisplayString>
+62 -100
View File
@@ -1,6 +1,5 @@
# GSL: Guidelines Support Library
[![CI](https://github.com/Microsoft/GSL/actions/workflows/compilers.yml/badge.svg)](https://github.com/microsoft/GSL/actions/workflows/compilers.yml?query=branch%3Amain)
[![vcpkg](https://img.shields.io/vcpkg/v/ms-gsl)](https://vcpkg.io/en/package/ms-gsl)
[![Build Status](https://dev.azure.com/cppstat/GSL/_apis/build/status/microsoft.GSL?branchName=master)](https://dev.azure.com/cppstat/GSL/_build/latest?definitionId=1&branchName=master)
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).
@@ -23,63 +22,59 @@ This project makes use of the [Google Test](https://github.com/google/googletest
# 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) | &#x2611; | An alias for a raw pointer
[not_null](docs/headers.md#user-content-H-pointers-not_null) | &#x2611; | Restricts a pointer/smart pointer to hold non-null values
[span](docs/headers.md#user-content-H-span-span) | &#x2611; | A view over a contiguous sequence of memory. Based on the standardized version of `std::span`, however `gsl::span` enforces bounds checking.
span_p | &#x2610; | 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) | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type
[zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char`
[czstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char`
[wzstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `wchar_t`
[cwzstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const wchar_t`
[u16zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char16_t`
[cu16zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char16_t`
[u32zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t`
[cu32zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t`
[**2. Owners**][cg-owners] | |
stack_array | &#x2610; | A stack-allocated array
dyn_array | &#x2611; | A heap-allocated array
[**3. Assertions**][cg-assertions] | |
[Expects](docs/headers.md#user-content-H-assert-expects) | &#x2611; | A precondition assertion; on failure it terminates
[Ensures](docs/headers.md#user-content-H-assert-ensures) | &#x2611; | A postcondition assertion; on failure it terminates
[**4. Utilities**][cg-utilities] | |
move_owner | &#x2610; | A helper function that moves one `owner` to the other
[final_action](docs/headers.md#user-content-H-util-final_action) | &#x2611; | A RAII style class that invokes a functor on its destruction
[finally](docs/headers.md#user-content-H-util-finally) | &#x2611; | 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) | &#x2611; | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]` depending on the compiler.
[[implicit]] | &#x2610; | A "marker" to put on single-argument constructors to explicitly make them non-explicit
[index](docs/headers.md#user-content-H-util-index) | &#x2611; | 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) | &#x2611; | 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) | &#x2611; | A narrowing cast for values and a synonym for `static_cast`
[narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error) | &#x2611; | A custom exception type thrown by [narrow](docs/headers.md#user-content-H-narrow-narrow)
[**5. Concepts**][cg-concepts] | &#x2610; |
Feature | Supported? | Description
-----------------------------------|:----------:|-------------
[**1. Views**][cg-views] | |
owner | &#x2611; | an alias for a raw pointer
not_null | &#x2611; | restricts a pointer / smart pointer to hold non-null values
span | &#x2611; | a view over a contiguous sequence of memory. Based on the standardized verison of `std::span`, however `gsl::span` enforces bounds checking. See the [wiki](https://github.com/microsoft/GSL/wiki/gsl::span-and-std::span) for additional information.
span_p | &#x2610; | spans a range starting from a pointer to the first place for which the predicate is true
basic_zstring | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type
zstring | &#x2611; | An alias to `basic_zstring` with a char type of char
czstring | &#x2611; | An alias to `basic_zstring` with a char type of const char
wzstring | &#x2611; | An alias to `basic_zstring` with a char type of wchar_t
cwzstring | &#x2611; | An alias to `basic_zstring` with a char type of const wchar_t
u16zstring | &#x2611; | An alias to `basic_zstring` with a char type of char16_t
cu16zstring | &#x2611; | An alias to `basic_zstring` with a char type of const char16_t
u32zstring | &#x2611; | An alias to `basic_zstring` with a char type of char32_t
cu32zstring | &#x2611; | An alias to `basic_zstring` with a char type of const char32_t
[**2. Owners**][cg-owners] | |
unique_ptr | &#x2611; | an alias to `std::unique_ptr`
shared_ptr | &#x2611; | an alias to `std::shared_ptr`
stack_array | &#x2610; | a stack-allocated array
dyn_array | &#x2610; | a heap-allocated array
[**3. Assertions**][cg-assertions] | |
Expects | &#x2611; | a precondition assertion; on failure it terminates by default if no user-installed handler
Ensures | &#x2611; | a postcondition assertion; on failure it terminates by default if no user-installed handler
[**4. Utilities**][cg-utilities] | |
move_owner | &#x2610; | a helper function that moves one `owner` to the other
byte | &#x2611; | either an alias to std::byte or a byte type
final_action | &#x2611; | a RAII style class that invokes a functor on its destruction
finally | &#x2611; | a helper function instantiating `final_action`
GSL_SUPPRESS | &#x2611; | a macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
[[implicit]] | &#x2610; | a "marker" to put on single-argument constructors to explicitly make them non-explicit
index | &#x2611; | a type to use for all container and array indexing (currently an alias for std::ptrdiff_t)
joining_thread | &#x2610; | a RAII style version of `std::thread` that joins
narrow | &#x2611; | a checked version of narrow_cast; it can throw `narrowing_error`
narrow_cast | &#x2611; | a narrowing cast for values and a synonym for static_cast
narrowing_error | &#x2611; | a custom exception type thrown by `narrow()`
[**5. Concepts**][cg-concepts] | &#x2610; |
## 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) | &#x2611; | A stricter version of [not_null](docs/headers.md#user-content-H-pointers-not_null) with explicit constructors
strict_not_null | &#x2611; | A stricter version of `not_null` with explicit constructors
multi_span | &#x2610; | Deprecated. Multi-dimensional span.
strided_span | &#x2610; | Deprecated. Support for this type has been discontinued.
basic_string_span | &#x2610; | Deprecated. Like `span` but for strings with a templated char type
string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char`
cstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const char`
wstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `wchar_t`
cwstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const wchar_t`
u16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char16_t`
cu16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const char16_t`
u32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char32_t`
cu32string_span | &#x2610; | 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.
string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char
cstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char
wstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of wchar_t
cwstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const wchar_t
u16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char16_t
cu16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char16_t
u32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char32_t
cu32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char32_t
This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library).
@@ -90,18 +85,17 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp
[cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts
# Quick Start
## Supported Compilers / 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).)
## Supported Compilers
The GSL officially supports the current and previous major release of MSVC, GCC, Clang, and XCode's Apple-Clang.
See our latest test results for the most up-to-date list of supported configurations.
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
XCode |11.4 & 10.3
GCC |9 & 8
Clang |11 & 10
Visual Studio with MSVC | VS2017 (15.9) & VS2019 (16.4)
Visual Studio with LLVM | VS2017 (Clang 9) & VS2019 (Clang 10)
---
If you successfully port GSL to another platform, we would love to hear from you!
@@ -111,19 +105,19 @@ If you successfully port GSL to another platform, we would love to hear from you
Target | CI/CD Status
:------- | -----------:
iOS | [![CI_iOS](https://github.com/microsoft/GSL/workflows/CI_iOS/badge.svg?branch=main)](https://github.com/microsoft/GSL/actions/workflows/ios.yml?query=branch%3Amain)
Android | [![CI_Android](https://github.com/microsoft/GSL/workflows/CI_Android/badge.svg?branch=main)](https://github.com/microsoft/GSL/actions/workflows/android.yml?query=branch%3Amain)
iOS | ![CI_iOS](https://github.com/microsoft/GSL/workflows/CI_iOS/badge.svg)
Android | ![CI_Android](https://github.com/microsoft/GSL/workflows/CI_Android/badge.svg)
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.14 or later to be installed and in your PATH.
* [CMake](http://cmake.org), version 3.1.3 (3.2.3 for AppleClang) 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
@@ -177,44 +171,12 @@ Include the library using:
## Usage in CMake
The library provides a Config file for CMake, once installed it can be found via `find_package`.
The library provides a Config file for CMake, once installed it can be found via
find_package(Microsoft.GSL CONFIG)
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
View File
@@ -1,41 +0,0 @@
<!-- 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 -->
+114
View File
@@ -0,0 +1,114 @@
shallow_clone: true
platform:
- x86
- x64
configuration:
- Debug
- Release
image:
- Visual Studio 2017
- Visual Studio 2019
environment:
NINJA_TAG: v1.8.2
NINJA_SHA512: 9B9CE248240665FCD6404B989F3B3C27ED9682838225E6DC9B67B551774F251E4FF8A207504F941E7C811E7A8BE1945E7BCB94472A335EF15E23A0200A32E6D5
NINJA_PATH: C:\Tools\ninja\ninja-%NINJA_TAG%
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
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 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 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
+68
View File
@@ -0,0 +1,68 @@
trigger:
- master
pr:
autoCancel: true
# GCC
stages:
- stage: GCC
dependsOn: []
variables:
- name: CC
value: gcc
- name: CXX
value: g++
jobs:
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate GCC latest'
imageName: ubuntu-20.04
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate GCC Previous'
imageName: ubuntu-18.04
# Clang
- stage: Clang
dependsOn: []
variables:
- name: CC
value: clang
- name: CXX
value: clang++
jobs:
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate Clang latest'
imageName: ubuntu-20.04
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate Clang Previous'
imageName: ubuntu-18.04
# MSVC
- stage: MSVC
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate MSVC latest'
imageName: windows-latest
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate MSVC Previous'
imageName: vs2017-win2016
# Apple-Clang
- stage: Apple_Clang
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate Apple-Clang latest'
imageName: macos-10.15
- template: ./pipelines/jobs.yml
parameters:
jobName: 'Validate Apple-Clang Previous'
imageName: macos-10.14
+61
View File
@@ -0,0 +1,61 @@
# This cmake module is meant to hold helper functions/macros
# that make maintaining the cmake build system much easier.
# This is especially helpful since gsl needs to provide coverage
# for multiple versions of cmake.
#
# Any functions/macros should have a gsl_* prefix to avoid problems
if (DEFINED guideline_support_library_include_guard)
return()
endif()
set(guideline_support_library_include_guard ON)
function(gsl_set_default_cxx_standard min_cxx_standard)
set(GSL_CXX_STANDARD "${min_cxx_standard}" 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()
endfunction()
# The best way for a project to specify the GSL's C++ standard is by the client specifying
# the CMAKE_CXX_STANDARD. However, this isn't always ideal. Since the CMAKE_CXX_STANDARD is
# tied to the cmake version. And many projects have low cmake minimums.
#
# So provide an alternative approach in case that doesn't work.
function(gsl_client_set_cxx_standard min_cxx_standard)
if (DEFINED CMAKE_CXX_STANDARD)
if (${CMAKE_CXX_STANDARD} VERSION_LESS ${min_cxx_standard})
message(FATAL_ERROR "GSL: Requires at least CXX standard ${min_cxx_standard}, user provided ${CMAKE_CXX_STANDARD}")
endif()
# Set the GSL standard to what the client desires
set(GSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
# Exit out early to avoid extra unneccessary work
return()
endif()
# Otherwise pick a reasonable default
gsl_set_default_cxx_standard(${min_cxx_standard})
endfunction()
-1071
View File
File diff suppressed because it is too large Load Diff
-19
View File
@@ -1,19 +0,0 @@
> When bumping the version, you need to update the following files:
1. [ ] [CMakeLists.txt](../CMakeLists.txt) Bump `GSL_VERSION`
1. [ ] [README.md](../README.md) Bump `GIT_TAG`
1. [ ] [ios.yml](../.github/workflows/ios.yml) Bump `MACOSX_BUNDLE_BUNDLE_VERSION` and
`MACOSX_BUNDLE_SHORT_VERSION_STRING`
> After updating, you need to create a new GitHub release:
1. [ ] [Microsoft/GSL - Create Release](https://github.com/microsoft/GSL/releases/new)
Be sure to update the release notes accordingly and properly mention open-source
contributors.
> After a new release exists, update the `ms-gsl` vcpkg port:
1. [ ] [Microsoft/vcpkg - ms-gsl port](https://github.com/microsoft/vcpkg/tree/master/ports/ms-gsl)
Be sure to monitor the PR that updates the port for any feedback from vcpkg maintainers.
-13
View File
@@ -1,13 +0,0 @@
# 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()
+7 -5
View File
@@ -17,8 +17,8 @@
#ifndef GSL_ALGORITHM_H
#define GSL_ALGORITHM_H
#include "./assert" // for Expects
#include "./span" // for dynamic_extent, span
#include <gsl/assert> // for contracts
#include <gsl/span> // for dynamic_extent, span
#include <algorithm> // for copy_n
#include <cstddef> // for ptrdiff_t
@@ -27,7 +27,7 @@
#ifdef _MSC_VER
#pragma warning(push)
// turn off some warnings that are noisy about our Expects statements
// turn off some warnings that are noisy about our contract checks
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4996) // unsafe use of std::copy_n
@@ -47,8 +47,10 @@ void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent>
(SrcExtent <= DestExtent),
"Source range is longer than target range");
Expects(dest.size() >= src.size());
GSL_SUPPRESS(stl.1)
Expects(dest.size() >= src.size(), Bounds);
// clang-format off
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
// clang-format on
std::copy_n(src.data(), src.size(), dest.data());
}
+56 -39
View File
@@ -14,15 +14,15 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef GSL_ASSERT_H
#define GSL_ASSERT_H
#ifndef GSL_CONTRACTS_H
#define GSL_CONTRACTS_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>
@@ -46,39 +46,17 @@
// Hopefully temporary until suppression standardization occurs
//
#if defined(__clang__)
#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]]
#elif defined(_MSC_VER) && _MSC_VER >= 1950
// Visual Studio versions after 2022 (_MSC_VER > 1944) support the justification message.
#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]]
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__)
#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
#else
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
#else
#define GSL_SUPPRESS(x)
#endif // defined(__clang__)
#endif // _MSC_VER
#endif // __clang__
#if defined(__clang__) || defined(__GNUC__)
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define GSL_LIKELY(x) (!!(x))
#define GSL_UNLIKELY(x) (!!(x))
#endif // defined(__clang__) || defined(__GNUC__)
//
// GSL_ASSUME(cond)
//
// Tell the optimizer that the predicate cond must hold. It is unspecified
// whether or not cond is actually evaluated.
//
#ifdef _MSC_VER
#define GSL_ASSUME(cond) __assume(cond)
#elif defined(__GNUC__)
#define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
#else
#define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
#endif
#define GSL_STRINGIFY_DETAIL(x) #x
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
//
// GSL.assert: assertions
@@ -93,7 +71,9 @@ namespace details
typedef void(__cdecl* terminate_handler)();
GSL_SUPPRESS(f.6)
// clang-format off
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute
// clang-format on
[[noreturn]] inline void __cdecl default_terminate_handler()
{
__fastfail(RANGE_CHECKS_FAILURE);
@@ -117,16 +97,53 @@ namespace details
}
} // namespace details
class contract_group {
public:
#if defined __cpp_noexcept_function_type
using handler = void (*)() noexcept;
#else // VESTIGIAL, remove when no longer needed for downlevel compilers
using handler = void (*)();
#endif
constexpr contract_group (handler h = nullptr) : chandler(normalize(h)) { }
constexpr auto set_handler(handler h) -> handler { auto old = chandler; chandler = normalize(h); return old; }
constexpr auto get_handler() const -> handler { return chandler; }
constexpr auto expects (bool b) -> void { assertion(b); }
constexpr auto ensures (bool b) -> void { assertion(b); }
private:
constexpr auto assertion(bool b) -> void { if (!b) chandler(); }
constexpr auto normalize(handler h) -> handler { return h ? h : []()noexcept{}; }
handler chandler;
};
// By default, there is one violation handler per translation unit.
// Defining GSL_GLOBAL_CONTRACT_VIOLATION_HANDLERS and compiling as
// C++17 (or later) opts into using a global violation handler.
#if defined GSL_GLOBAL_CONTRACT_VIOLATION_HANDLERS && __cplusplus >= 201703L
#define GSL_CONTRACT_VIOLATION_GRANULARITY inline
#else
#define GSL_CONTRACT_VIOLATION_GRANULARITY static
#endif
auto GSL_CONTRACT_VIOLATION_GRANULARITY Default = contract_group(
#if defined GSL_UNENFORCED_ON_CONTRACT_VIOLATION
// use default == null handler
#else // if defined GSL_TERMINATE_ON_CONTRACT_VIOLATION
&gsl::details::terminate
#endif
);
auto GSL_CONTRACT_VIOLATION_GRANULARITY Bounds = Default;
auto GSL_CONTRACT_VIOLATION_GRANULARITY Null = Default;
auto GSL_CONTRACT_VIOLATION_GRANULARITY Testing = Default;
} // namespace gsl
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
#define Expects(cond, kind) kind.expects(cond)
#define Ensures(cond, kind) kind.ensures(cond)
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // GSL_ASSERT_H
#endif // GSL_CONTRACTS_H
+47 -35
View File
@@ -17,10 +17,24 @@
#ifndef GSL_BYTE_H
#define GSL_BYTE_H
#include "./util" // for GSL_DEPRECATED
//
// 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) && !defined(__INTEL_COMPILER)
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
#else
#define GSL_SUPPRESS(x)
#endif // _MSC_VER
#endif // __clang__
#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)
@@ -31,15 +45,18 @@
#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(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \
(defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
#define GSL_USE_STD_BYTE 1
#else // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
// 201603)
#define GSL_USE_STD_BYTE 0
#endif // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
// 201603)
#endif // GSL_USE_STD_BYTE
#else // _MSC_VER
@@ -82,16 +99,7 @@ namespace gsl
{
#if GSL_USE_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;
} // namespace impl
using byte GSL_DEPRECATED("Use std::byte instead.") = std::byte;
using std::byte;
using std::to_integer;
#else // GSL_USE_STD_BYTE
@@ -102,33 +110,25 @@ enum class byte_may_alias byte : unsigned char
{
};
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;
} // namespace impl
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
{
return b = byte(static_cast<unsigned char>(b) << shift);
}
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator<<(byte b, IntegerType shift) noexcept
{
return byte(static_cast<unsigned char>(b) << shift);
}
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
{
return b = byte(static_cast<unsigned char>(b) >> shift);
}
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator>>(byte b, IntegerType shift) noexcept
{
return byte(static_cast<unsigned char>(b) >> shift);
@@ -166,7 +166,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, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr IntegerType to_integer(byte b) noexcept
{
return static_cast<IntegerType>(b);
@@ -174,22 +174,34 @@ constexpr IntegerType to_integer(byte b) noexcept
#endif // GSL_USE_STD_BYTE
template <typename T>
constexpr gsl::impl::byte to_byte(T t) noexcept
template <bool E, typename T>
constexpr byte to_byte_impl(T t) noexcept
{
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);
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
{
return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
}
template <int I>
constexpr gsl::impl::byte to_byte() noexcept
constexpr 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<gsl::impl::byte>(I);
return static_cast<byte>(I);
}
} // namespace gsl
-439
View File
@@ -1,439 +0,0 @@
// -*- C++ -*-
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2026 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_DYN_ARRAY_H
#define GSL_DYN_ARRAY_H
#include "./assert"
#include "./narrow"
#include "./util"
#include <algorithm>
#include <iterator>
#include <memory>
#include <type_traits>
#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L)
#include <ranges>
#endif /* __cpp_lib_ranges >= 201911L */
namespace gsl
{
namespace details
{
template <typename T, typename Allocator = std::allocator<T>>
class dyn_array_base : public Allocator
{
using pointer = T*;
using size_type = std::size_t;
template <typename... Args>
GSL_CONSTEXPR_SINCE_CPP20 void construct(pointer ptr, Args&&... args)
{
std::allocator_traits<Allocator>::construct(static_cast<Allocator&>(*this), ptr,
std::forward<Args>(args)...);
}
GSL_CONSTEXPR_SINCE_CPP20 void destroy(pointer ptr)
{
std::allocator_traits<Allocator>::destroy(static_cast<Allocator&>(*this), ptr);
}
GSL_CONSTEXPR_SINCE_CPP20 void destroy_range(pointer first, pointer last)
{
for (; first != last; ++first) { destroy(first); }
}
GSL_CONSTEXPR_SINCE_CPP20 void rollback_construction(pointer first, pointer last)
{
destroy_range(first, last);
std::allocator_traits<Allocator>::deallocate(static_cast<Allocator&>(*this), _data,
_count);
_data = nullptr;
_count = 0;
}
protected:
constexpr auto data() const { return _data; }
constexpr auto count() const { return _count; }
GSL_CONSTEXPR_SINCE_CPP20 void resize(size_type count)
{
// This should only be called when constructing a non-forward iterator.
// It neither frees nor copies `_data`.
Expects(_data == nullptr && _count == 0);
if (count != 0)
{
_data = std::allocator_traits<Allocator>::allocate(static_cast<Allocator&>(*this),
count);
_count = count;
}
}
GSL_CONSTEXPR_SINCE_CPP20 void fill(pointer first, size_type count, const T& value)
{
pointer current = first;
try
{
for (size_type i = 0; i < count; ++i, ++current) { construct(current, value); }
} catch (...)
{
rollback_construction(first, current);
throw;
}
}
template <typename InputIt>
GSL_CONSTEXPR_SINCE_CPP20 void copy(InputIt first, InputIt last, pointer output)
{
pointer current = output;
try
{
for (; first != last; ++first, ++current) { construct(current, *first); }
} catch (...)
{
rollback_construction(output, current);
throw;
}
}
GSL_CONSTEXPR_SINCE_CPP20 void default_construct(pointer first, size_type count)
{
pointer current = first;
try
{
for (size_type i = 0; i < count; ++i, ++current) { construct(current); }
} catch (...)
{
rollback_construction(first, current);
throw;
}
}
private:
pointer _data;
size_type _count;
public:
constexpr dyn_array_base(const Allocator& alloc)
: Allocator{alloc}, _data{nullptr}, _count{0}
{
Ensures((_count == 0 && _data == nullptr) || (_count > 0 && _data != nullptr));
}
constexpr dyn_array_base(size_type count, const Allocator& alloc)
: Allocator{alloc}
, _data{count == 0 ? nullptr
: std::allocator_traits<Allocator>::allocate(
static_cast<Allocator&>(*this), count)}
, _count{count}
{
Ensures((_count == 0 && _data == nullptr) || (_count > 0 && _data != nullptr));
}
GSL_CONSTEXPR_SINCE_CPP20 ~dyn_array_base()
{
if (_data)
{
if (!std::is_trivially_destructible<T>::value)
{
destroy_range(_data, _data + _count);
}
std::allocator_traits<Allocator>::deallocate(static_cast<Allocator&>(*this), _data,
_count);
}
}
};
template <typename T>
class dyn_array_iterator
{
using size_type = std::size_t;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using const_reference = const T&;
using iterator_category = std::random_access_iterator_tag;
#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L)
constexpr dyn_array_iterator() = default;
#endif /* __cpp_lib_ranges >= 201911L */
constexpr dyn_array_iterator(pointer ptr, size_type pos, size_type end_pos)
: _ptr{ptr}, _pos{pos}, _end_pos{end_pos}
{
Ensures((_ptr != nullptr && _end_pos > 0) || (_ptr == nullptr && _end_pos == 0));
Ensures(_pos <= _end_pos);
}
#if defined(_MSC_VER) && defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L)
constexpr operator pointer() const { return _ptr + gsl::narrow<size_type>(_pos); }
#endif /* defined(_MSC_VER) && __cpp_lib_ranges >= 201911L */
constexpr auto operator==(const dyn_array_iterator& other) const
{
Expects(_ptr == other._ptr);
Expects(_end_pos == other._end_pos);
return _pos == other._pos;
}
constexpr auto operator!=(const dyn_array_iterator& other) const
{
return !(*this == other);
}
constexpr auto operator*() const -> reference
{
Expects(_ptr != nullptr);
Expects(_pos < _end_pos);
return _ptr[_pos];
}
constexpr auto operator++() -> dyn_array_iterator&
{
Expects(_pos < _end_pos);
++_pos;
return *this;
}
constexpr auto operator++(int)
{
auto rv = *this;
++(*this);
return rv;
}
constexpr auto operator--() -> dyn_array_iterator&
{
Expects(_pos > 0);
--_pos;
return *this;
}
constexpr auto operator--(int)
{
auto rv = *this;
--(*this);
return rv;
}
constexpr auto operator+=(difference_type diff) -> dyn_array_iterator&
{
auto new_pos = gsl::narrow<difference_type>(_pos) + diff;
Expects(new_pos >= 0);
Expects(new_pos <= gsl::narrow<difference_type>(_end_pos));
_pos = gsl::narrow<size_type>(new_pos);
return *this;
}
constexpr auto operator-=(difference_type diff) -> dyn_array_iterator&
{
auto new_pos = gsl::narrow<difference_type>(_pos) - diff;
Expects(new_pos >= 0);
Expects(new_pos <= gsl::narrow<difference_type>(_end_pos));
_pos = gsl::narrow<size_type>(new_pos);
return *this;
}
constexpr auto operator+(difference_type diff) const
{
auto new_pos = gsl::narrow<difference_type>(_pos) + diff;
return dyn_array_iterator{_ptr, gsl::narrow<size_type>(new_pos), _end_pos};
}
constexpr auto operator-(difference_type diff) const { return *this + (-diff); }
constexpr auto operator-(const dyn_array_iterator& other) const
{
Expects(_ptr == other._ptr);
Expects(_end_pos == other._end_pos);
return gsl::narrow<difference_type>(_pos) - gsl::narrow<difference_type>(other._pos);
}
constexpr auto operator[](size_type pos) -> reference
{
Expects(_pos + pos < _end_pos);
return _ptr[_pos + pos];
}
constexpr auto operator[](size_type pos) const -> const_reference
{
return const_cast<dyn_array_iterator&>(*this).operator[](pos);
}
private:
pointer _ptr{};
size_type _pos{};
size_type _end_pos{};
};
} // namespace details
template <typename T, typename Allocator = std::allocator<T>>
class dyn_array : private details::dyn_array_base<T, Allocator>
{
using base = details::dyn_array_base<T, Allocator>;
using pointer = T*;
public:
using value_type = T;
using reference = T&;
using const_reference = const T&;
using iterator = details::dyn_array_iterator<T>;
using const_iterator = details::dyn_array_iterator<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using allocator_type = Allocator;
explicit constexpr dyn_array(const Allocator& alloc = {}) : base{alloc} {}
constexpr dyn_array(size_type count, const T& value, const Allocator& alloc = {})
: base{count, alloc}
{
base::fill(data(), size(), value);
}
template <typename InputIt,
std::enable_if_t<details::is_fwd_iterator<InputIt>::value, bool> = true>
constexpr dyn_array(InputIt first, InputIt last, const Allocator& alloc = {})
: base{gsl::narrow<size_type>(std::distance(first, last)), alloc}
{
base::copy(first, last, data());
}
template <typename InputIt, std::enable_if_t<!details::is_fwd_iterator<InputIt>::value &&
details::is_iterator<InputIt>::value,
bool> = true>
constexpr dyn_array(InputIt first, InputIt last, const Allocator& alloc = {}) : dyn_array{alloc}
{
std::vector<T> tmp(first, last);
base::resize(tmp.size());
base::copy(std::begin(tmp), std::end(tmp), data());
}
#if defined(__cpp_lib_containers_ranges) && (__cpp_lib_containers_ranges >= 202202L)
template <typename InputRg>
requires(std::ranges::input_range<InputRg>)
constexpr dyn_array(std::from_range_t, InputRg&& rg, const Allocator& alloc = {})
: base{gsl::narrow<size_type>(std::size(rg)), alloc}
{
base::copy(std::ranges::begin(rg), std::ranges::end(rg), data());
}
#endif /* __cpp_lib_containers_ranges >= 202202L */
constexpr explicit dyn_array(size_type count, const Allocator& alloc = {}) : base{count, alloc}
{
base::default_construct(data(), size());
}
constexpr dyn_array(const dyn_array& other, const Allocator& alloc = {})
: dyn_array(other.begin(), other.end(), alloc)
{}
constexpr dyn_array(std::initializer_list<T> init, const Allocator& alloc = {})
: dyn_array(init.begin(), init.end(), alloc)
{}
constexpr dyn_array(dyn_array&&) = delete;
dyn_array& operator=(dyn_array&&) = delete;
constexpr auto operator==(const dyn_array& other) const
{
return size() == other.size() && std::equal(begin(), end(), other.begin(), other.end());
}
constexpr auto operator!=(const dyn_array& other) const { return !(*this == other); }
constexpr auto size() const { return base::count(); }
constexpr auto empty() const { return size() == 0; }
constexpr auto max_size() const { return static_cast<size_type>(-1); }
constexpr auto get_allocator() -> Allocator& { return *this; }
constexpr auto operator[](size_type pos) -> reference
{
Expects(pos < size());
return data()[pos];
}
constexpr auto operator[](size_type pos) const -> const_reference
{
return const_cast<dyn_array&>(*this)[pos];
}
constexpr auto data() { return base::data(); }
constexpr auto data() const -> const T* { return const_cast<dyn_array&>(*this).data(); }
constexpr auto begin() { return iterator{data(), 0, size()}; }
constexpr auto begin() const { return const_iterator{data(), 0, size()}; }
constexpr auto cbegin() const { return begin(); }
constexpr auto rbegin() { return reverse_iterator{end()}; }
constexpr auto rbegin() const { return const_reverse_iterator{end()}; }
constexpr auto crbegin() const { return rbegin(); }
#ifdef _MSC_VER
constexpr auto _Unchecked_begin() { return data(); }
constexpr auto _Unchecked_begin() const -> const T*
{
return const_cast<dyn_array&>(*this)._Unchecked_begin();
}
#endif /* _MSC_VER */
constexpr auto end() { return iterator{data(), size(), size()}; }
constexpr auto end() const { return const_iterator{data(), size(), size()}; }
constexpr auto cend() const { return end(); }
constexpr auto rend() { return reverse_iterator{begin()}; }
constexpr auto rend() const { return const_reverse_iterator{begin()}; }
constexpr auto crend() const { return rend(); }
#ifdef _MSC_VER
constexpr auto _Unchecked_end() { return data() + size(); }
constexpr auto _Unchecked_end() const -> const T*
{
return const_cast<dyn_array&>(*this)._Unchecked_end();
}
#endif /* _MSC_VER */
};
#if defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201703L)
template <class InputIt,
class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
dyn_array(InputIt, InputIt, Alloc = {})
-> dyn_array<typename std::iterator_traits<InputIt>::value_type, Alloc>;
#if defined(__cpp_lib_containers_ranges) && (__cpp_lib_containers_ranges >= 202202L)
template <std::ranges::input_range InputRg,
class Alloc = std::allocator<std::ranges::range_value_t<InputRg>>>
dyn_array(std::from_range_t, InputRg&&, Alloc = {})
-> dyn_array<std::ranges::range_value_t<InputRg>, Alloc>;
#endif /* __cpp_lib_containers_ranges >= 202202L */
#endif /* __cpp_deduction_guides >= 201703L */
} // namespace gsl
#endif /* defined(GSL_DYN_ARRAY_H) */
+9 -10
View File
@@ -17,18 +17,17 @@
#ifndef GSL_GSL_H
#define GSL_GSL_H
// IWYU pragma: begin_exports
#include "./algorithm" // copy
#include "./assert" // Ensures/Expects
#include "./byte" // byte
#include "./pointers" // owner, not_null
#include "./span" // span
#include "./util" // finally()/narrow_cast()...
#include "./zstring" // zstring
#include <gsl/algorithm> // copy
#include <gsl/assert> // contracts
#include <gsl/byte> // byte
#include <gsl/pointers> // owner, not_null
#include <gsl/multi_span> // multi_span, strided_span...
#include <gsl/span> // span
#include <gsl/string_span> // zstring, string_span, zstring_builder...
#include <gsl/util> // finally()/narrow_cast()...
#ifdef __cpp_exceptions
#include "./narrow" // narrow()
#include <gsl/narrow> // narrow()
#endif
// IWYU pragma: end_exports
#endif // GSL_GSL_H
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
#include <gsl/algorithm>
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/assert> instead of <gsl/gsl_assert>")
#include <gsl/assert>
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/byte> instead of <gsl/gsl_byte>")
#include <gsl/byte>
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/narrow> instead of <gsl/gsl_narrow>")
#include <gsl/narrow>
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/util> instead of <gsl/gsl_util>")
#include <gsl/util>
File diff suppressed because it is too large Load Diff
+9 -36
View File
@@ -16,9 +16,8 @@
#ifndef GSL_NARROW_H
#define GSL_NARROW_H
#include "./assert" // for GSL_SUPPRESS
#include "./util" // for narrow_cast
#include <exception> // for std::exception
#include <gsl/assert> // for contracts
#include <gsl/util> // for narrow_cast
namespace gsl
{
struct narrowing_error : public std::exception
@@ -27,48 +26,22 @@ struct narrowing_error : public std::exception
};
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(es.46) // 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
constexpr T narrow(U u)
template <class T, class U>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
// clang-format on
constexpr T narrow(U u) noexcept(false)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
GSL_SUPPRESS(es.103) // don't overflow
GSL_SUPPRESS(es.104) // don't underflow
GSL_SUPPRESS(p.2) // 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).
const T t = narrow_cast<T>(u);
#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>
GSL_SUPPRESS(type.1) constexpr T narrow(U u)
{
const T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u) { throw narrowing_error{}; }
return t;
}
+54 -128
View File
@@ -1,4 +1,3 @@
// -*- C++ -*-
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
@@ -18,14 +17,13 @@
#ifndef GSL_POINTERS_H
#define GSL_POINTERS_H
#include "./assert" // for Ensures, Expects
#include "./util" // for GSL_DEPRECATED
#include <gsl/assert> // for contracts
#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
#include <algorithm> // for forward
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t
#include <memory> // for shared_ptr, unique_ptr
#include <system_error> // for hash
#include <type_traits> // for enable_if_t, is_convertible, is_assignable
#if !defined(GSL_NO_IOSTREAMS)
#include <iosfwd> // for ostream
@@ -34,55 +32,22 @@
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
//
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...>;
using std::shared_ptr;
using std::unique_ptr;
//
// 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.
// owner<T> is designed as a bridge for code that must deal directly with owning pointers for some
// reason
//
// T must be a pointer type
// - disallow construction from any type other than pointer type
//
template <class T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
using owner = T;
//
@@ -103,35 +68,30 @@ template <class T>
class not_null
{
public:
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
using element_type = T;
static_assert(std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value,
"T cannot be compared to nullptr.");
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value)
: ptr_(std::forward<U>(u))
constexpr not_null(U&& u) : ptr_(std::forward<U>(u))
{
Expects(ptr_ != nullptr);
Expects(ptr_ != nullptr, Null);
}
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value)
: ptr_(std::move(u))
constexpr not_null(T u) : ptr_(std::move(u))
{
Expects(ptr_ != nullptr);
Expects(ptr_ != nullptr, Null);
}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null(other.get())
constexpr not_null(const not_null<U>& other) : not_null(other.get())
{}
not_null(const not_null& other) = default;
not_null& operator=(const not_null& other) = default;
constexpr details::value_or_reference_return_t<T> get() const
noexcept(noexcept(details::value_or_reference_return_t<T>(std::declval<T&>())))
constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const
{
Ensures(ptr_ != nullptr, Null);
return ptr_;
}
@@ -152,20 +112,10 @@ public:
not_null& operator-=(std::ptrdiff_t) = delete;
void operator[](std::ptrdiff_t) const = delete;
void swap(not_null<T>& other) noexcept { 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) noexcept
{
a.swap(b);
}
template <class T>
auto make_not_null(T&& t) noexcept
{
@@ -182,53 +132,51 @@ std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
#endif // !defined(GSL_NO_IOSTREAMS)
template <class T, class U>
constexpr auto operator==(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(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>
constexpr auto operator!=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(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>
constexpr 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()))
auto operator<(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
-> decltype(lhs.get() < rhs.get())
{
return std::less<>{}(lhs.get(), rhs.get());
return lhs.get() < rhs.get();
}
template <class T, class U>
constexpr 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()))
auto operator<=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
-> decltype(lhs.get() <= rhs.get())
{
return std::less_equal<>{}(lhs.get(), rhs.get());
return lhs.get() <= rhs.get();
}
template <class T, class U>
constexpr 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()))
auto operator>(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
-> decltype(lhs.get() > rhs.get())
{
return std::greater<>{}(lhs.get(), rhs.get());
return lhs.get() > rhs.get();
}
template <class T, class U>
constexpr 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()))
auto operator>=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
-> decltype(lhs.get() >= rhs.get())
{
return std::greater_equal<>{}(lhs.get(), rhs.get());
return lhs.get() >= rhs.get();
}
// more unwanted operators
@@ -241,30 +189,14 @@ 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;
// T is conceptually a pointer so we don't have to worry about it being a reference and violating
// std::hash requirements
template <class T, class U = typename T::element_type,
bool = std::is_default_constructible<std::hash<U>>::value>
struct not_null_hash
{
std::size_t operator()(const T& value) const noexcept { 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>> : gsl::not_null_hash<gsl::not_null<T>>
struct hash<gsl::not_null<T>>
{
std::size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value.get()); }
};
} // namespace std
@@ -294,32 +226,22 @@ 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) noexcept(std::is_nothrow_move_constructible<T>::value)
: not_null<T>(std::forward<U>(u))
constexpr explicit strict_not_null(U&& u) : 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) noexcept(std::is_nothrow_move_constructible<T>::value)
: not_null<T>(std::move(u))
constexpr explicit strict_not_null(T u) : not_null<T>(u)
{}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr strict_not_null(const not_null<U>& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null<T>(other)
constexpr strict_not_null(const not_null<U>& other) : 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) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null<T>(other)
constexpr strict_not_null(const strict_not_null<U>& other) : not_null<T>(other)
{}
// 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(strict_not_null&& other) = 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)
@@ -358,7 +280,7 @@ 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 >= 201703L)
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
// deduction guides to prevent the ctad-maybe-unsupported warning
template <class T>
@@ -366,15 +288,19 @@ 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 >= 201703L)
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
} // namespace gsl
namespace std
{
template <class T>
struct hash<gsl::strict_not_null<T>> : gsl::not_null_hash<gsl::strict_not_null<T>>
struct hash<gsl::strict_not_null<T>>
{
std::size_t operator()(const gsl::strict_not_null<T>& value) const
{
return hash<T>{}(value.get());
}
};
} // namespace std
+108 -130
View File
@@ -1,4 +1,3 @@
// -*- C++ -*-
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
@@ -18,32 +17,26 @@
#ifndef GSL_SPAN_H
#define GSL_SPAN_H
#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 <gsl/assert> // for contracts
#include <gsl/byte> // for byte
#include <gsl/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)
// turn off some warnings that are noisy about our Expects statements
// turn off some warnings that are noisy about our contract checks
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning( \
disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning(disable : 4702) // unreachable code
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
#pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
#endif // _MSC_VER
@@ -54,7 +47,7 @@
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
// GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
// GCC 7 does not like the signed unsigned missmatch (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
@@ -64,17 +57,15 @@
#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 = narrow_cast<std::size_t>(-1);
template <class ElementType, std::size_t Extent = dynamic_extent>
class span;
// implementation details
namespace details
{
@@ -124,9 +115,6 @@ 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;
@@ -135,15 +123,12 @@ 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
{
@@ -152,19 +137,24 @@ namespace details
constexpr reference operator*() const noexcept
{
Expects(current_ != end_);
Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_, Bounds);
return *current_;
}
constexpr pointer operator->() const noexcept
{
Expects(current_ != end_);
Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_, Bounds);
return current_;
}
constexpr span_iterator& operator++() noexcept
{
Expects(current_ != end_);
GSL_SUPPRESS(bounds.1)
Expects(begin_ && current_ && end_, Bounds);
Expects(current_ < end_, Bounds);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
++current_;
return *this;
}
@@ -178,7 +168,8 @@ namespace details
constexpr span_iterator& operator--() noexcept
{
Expects(begin_ != current_);
Expects(begin_ && end_, Bounds);
Expects(begin_ < current_, Bounds);
--current_;
return *this;
}
@@ -192,10 +183,12 @@ namespace details
constexpr span_iterator& operator+=(const difference_type n) noexcept
{
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(end_ - current_ >= n);
if (n < 0) Expects(current_ - begin_ >= -n);
GSL_SUPPRESS(bounds.1)
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
current_ += n;
return *this;
}
@@ -215,10 +208,9 @@ namespace details
constexpr span_iterator& operator-=(const difference_type n) noexcept
{
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)
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(current_ - begin_ >= n, Bounds);
if (n < 0) Expects(end_ - current_ >= -n, Bounds);
current_ -= n;
return *this;
}
@@ -235,7 +227,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
{
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ - rhs.current_;
}
@@ -249,7 +241,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
{
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ == rhs.current_;
}
@@ -266,7 +258,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
{
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ < rhs.current_;
}
@@ -302,17 +294,19 @@ namespace details
{ // test that [lhs, rhs) forms a valid range inside an STL algorithm
Expects(lhs.begin_ == rhs.begin_ // range spans have to match
&& lhs.end_ == rhs.end_ &&
lhs.current_ <= rhs.current_); // range must not be transposed
lhs.current_ <= rhs.current_, Bounds); // range must not be transposed
}
constexpr void _Verify_offset(const difference_type n) const noexcept
{ // test that *this + n is within the range of this call
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(end_ - current_ >= n);
if (n < 0) Expects(current_ - begin_ >= -n);
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
}
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr pointer _Unwrapped() const noexcept
{ // after seeking *this to a high water mark, or using one of the
// _Verify_xxx functions above, unwrap this span_iterator to a raw
@@ -327,7 +321,9 @@ namespace details
#else
static constexpr bool _Unwrap_when_unverified = false;
#endif
GSL_SUPPRESS(con.3) // TODO: false positive
// clang-format off
GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
// clang-format on
constexpr void _Seek_to(const pointer p) noexcept
{ // adjust the position of *this to previously verified location p
// after _Unwrapped
@@ -338,30 +334,8 @@ namespace details
pointer begin_ = nullptr;
pointer end_ = nullptr;
pointer current_ = nullptr;
template <typename Ptr>
friend struct std::pointer_traits;
};
} // namespace details
} // namespace gsl
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
{
@@ -372,7 +346,7 @@ namespace details
constexpr explicit extent_type(extent_type<dynamic_extent>);
constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
constexpr explicit extent_type(size_type size) { Expects(size == Ext, Bounds); }
constexpr size_type size() const noexcept { return Ext; }
@@ -396,7 +370,7 @@ namespace details
constexpr explicit extent_type(size_type size) : size_(size)
{
Expects(size != dynamic_extent);
Expects(size != dynamic_extent, Bounds);
}
constexpr size_type size() const noexcept { return size_; }
@@ -408,7 +382,7 @@ namespace details
template <std::size_t Ext>
constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
{
Expects(ext.size() == Ext);
Expects(ext.size() == Ext, Bounds);
}
template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
@@ -457,7 +431,7 @@ public:
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)
{
Expects(count == Extent);
Expects(count == Extent, Bounds);
}
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
@@ -468,7 +442,7 @@ public:
constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
{
Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
Expects(lastElem - firstElem == static_cast<difference_type>(Extent), Bounds);
}
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
@@ -579,29 +553,28 @@ 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());
Expects(Count <= size(), Bounds);
return span<element_type, Count>{data(), Count};
}
template <std::size_t Count>
GSL_SUPPRESS(bounds.1) constexpr span<element_type, Count> last() const noexcept
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// 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());
Expects(Count <= size(), Bounds);
return span<element_type, Count>{data() + (size() - Count), Count};
}
template <std::size_t Offset, std::size_t Count = dynamic_extent>
GSL_SUPPRESS(bounds.1) constexpr auto subspan() const noexcept ->
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
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)));
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)), Bounds);
using type =
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
@@ -609,13 +582,13 @@ public:
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
{
Expects(count <= size());
Expects(count <= size(), Bounds);
return {data(), count};
}
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
{
Expects(count <= size());
Expects(count <= size(), Bounds);
return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
}
@@ -628,27 +601,33 @@ public:
// [span.obs], span observers
constexpr size_type size() const noexcept { return storage_.size(); }
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
constexpr size_type size_bytes() const noexcept
{
Expects(size() < dynamic_extent / sizeof(element_type), Bounds);
return size() * sizeof(element_type);
}
constexpr bool empty() const noexcept { return size() == 0; }
// [span.elem], span element access
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr reference operator[](size_type idx) const noexcept
{
Expects(idx < size());
Expects(idx < size(), Bounds);
return data()[idx];
}
constexpr reference front() const noexcept
{
Expects(size() > 0);
Expects(size() > 0, Bounds);
return data()[0];
}
constexpr reference back() const noexcept
{
Expects(size() > 0);
Expects(size() > 0, Bounds);
return data()[size() - 1];
}
@@ -658,14 +637,18 @@ public:
constexpr iterator begin() const noexcept
{
const auto data = storage_.data();
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
return {data, data + size(), data};
}
constexpr iterator end() const noexcept
{
const auto data = storage_.data();
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
const auto endData = data + storage_.size();
return {data, endData, endData};
}
@@ -678,7 +661,9 @@ public:
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
constexpr pointer _Unchecked_end() const noexcept
{
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
return data() + size();
}
#endif // _MSC_VER
@@ -702,12 +687,15 @@ private:
template <class OtherExtentType>
constexpr storage_type(KnownNotNull data, OtherExtentType ext)
: ExtentType(ext), data_(data.p)
{}
{
Expects(ExtentType::size() != dynamic_extent, Bounds);
}
template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
{
Expects(data || ExtentType::size() == 0);
Expects(ExtentType::size() != dynamic_extent, Bounds);
Expects(data || ExtentType::size() == 0, Bounds);
}
constexpr pointer data() const noexcept { return data_; }
@@ -735,20 +723,22 @@ private:
return tmp.subspan(offset, count);
}
GSL_SUPPRESS(bounds.1)
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr span<element_type, dynamic_extent>
make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
{
Expects(size() >= offset);
Expects(size() >= offset, Bounds);
if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
Expects(size() - offset >= count);
Expects(size() - offset >= count, Bounds);
return {KnownNotNull{data() + offset}, count};
}
};
#if defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201703L)
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
// Deduction Guides
template <class Type, std::size_t Extent>
@@ -768,20 +758,11 @@ 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 >= 201703L)
#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
@@ -807,25 +788,28 @@ namespace details
// [span.objectrep], views of object representation
template <class ElementType, std::size_t Extent>
span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
span<const 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>;
using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
GSL_SUPPRESS(type.1)
return type{reinterpret_cast<const gsl::impl::byte*>(s.data()), s.size_bytes()};
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return type{reinterpret_cast<const 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<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
span<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>;
using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
GSL_SUPPRESS(type.1)
return type{reinterpret_cast<gsl::impl::byte*>(s.data()), s.size_bytes()};
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
}
} // namespace gsl
@@ -839,10 +823,4 @@ 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
+6 -23
View File
@@ -27,29 +27,16 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "./assert" // GSL_KERNEL_MODE
#include "./util" // for narrow_cast, narrow
#include <gsl/span> // for span
#include <gsl/util> // for narrow_cast, narrow
#include <cstddef> // for ptrdiff_t, size_t
#include <utility>
#ifndef GSL_KERNEL_MODE
#include <algorithm> // for lexicographical_compare
#endif // GSL_KERNEL_MODE
#include <cstddef> // for ptrdiff_t, size_t
#include <utility>
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)
@@ -87,8 +74,6 @@ constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent>
return !(l < r);
}
#endif // GSL_KERNEL_MODE
//
// make_span() - Utility functions for creating spans
//
@@ -123,14 +108,12 @@ 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);
@@ -141,7 +124,7 @@ template <class ElementType, std::size_t Extent>
constexpr ElementType& at(span<ElementType, Extent> s, index i)
{
// No bounds checking here because it is done in span::operator[] called below
Ensures(i >= 0);
Ensures(i >= 0, Bounds);
return s[narrow_cast<std::size_t>(i)];
}
@@ -149,7 +132,7 @@ constexpr ElementType& at(span<ElementType, Extent> s, index i)
template <class ElementType, std::size_t Extent>
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept
{
return gsl::narrow_cast<std::ptrdiff_t>(s.size());
return static_cast<std::ptrdiff_t>(s.size());
}
// [span.iter] Free functions for begin/end functions
+767
View File
@@ -0,0 +1,767 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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/assert> // for contracts
#include <gsl/span_ext> // for operator!=, operator==, dynamic_extent
#include <gsl/util> // for narrow_cast
#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
#pragma warning(disable : 4996) // use of functions & classes marked [[deprecated]]
#endif // _MSC_VER
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
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>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr 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>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<T, dynamic_extent>
ensure_sentinel(T* seq, std::size_t max = static_cast<std::size_t>(-1))
{
Ensures(seq != nullptr, Null);
// clang-format off
GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work
// clang-format on
auto cur = seq;
Ensures(cur != nullptr, Null); // workaround for removing the warning
// clang-format off
GSL_SUPPRESS(bounds.1) // TODO: suppress does not work
// clang-format on
while (static_cast<std::size_t>(cur - seq) < max && *cur != Sentinel) ++cur;
Ensures(*cur == Sentinel, Bounds);
return {seq, static_cast<std::size_t>(cur - seq)};
}
//
// ensure_z - creates a span for a zero terminated strings. The span will not contain the zero
// termination. Will fail fast if a null-terminator cannot be found before the limit of size_type.
//
template <typename CharT>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr 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>
constexpr span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
{
return ensure_z(&sz[0], N);
}
template <class Cont>
[[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr 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 [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span;
namespace details
{
template <typename T>
struct [[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle : std::false_type{};
template <typename CharT, std::size_t Extent>
struct [[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle<basic_string_span<CharT,
Extent>>
: std::true_type{};
template <typename T>
struct [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] 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 [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] 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) // 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 constexpr impl_type remove_z(pointer const& sz, std::size_t max)
{
return impl_type(sz, details::string_length(sz, max));
}
template <std::size_t N>
static constexpr 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 [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char, Extent>;
template <std::size_t Extent = dynamic_extent>
using cstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char, Extent>;
template <std::size_t Extent = dynamic_extent>
using wstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cwstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using u16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char16_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cu16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char16_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using u32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char32_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cu32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char32_t, Extent>;
//
// to_string() allow (explicit) conversions from string_span to string
//
template <typename CharT, std::size_t Extent>
constexpr 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>
constexpr 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>
constexpr basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(basic_string_span<ElementType, Extent> s) noexcept
{
// clang-format off
GSL_SUPPRESS(type.1)
// clang-format on
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>>
constexpr basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writable_bytes(basic_string_span<ElementType, Extent> s) noexcept
{
// clang-format off
GSL_SUPPRESS(type.1)
// clang-format on
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 [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] 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.size() > 0, Bounds);
Expects(s[s.size() - 1] == value_type{}, Bounds);
}
// 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 false; }
constexpr string_span_type as_string_span() const noexcept
{
return {span_.data(), span_.size() - 1};
}
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 [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char, Max>;
template <std::size_t Max = dynamic_extent>
using wzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<wchar_t, Max>;
template <std::size_t Max = dynamic_extent>
using u16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char16_t, Max>;
template <std::size_t Max = dynamic_extent>
using u32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char32_t, Max>;
template <std::size_t Max = dynamic_extent>
using czstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const char, Max>;
template <std::size_t Max = dynamic_extent>
using cwzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const wchar_t, Max>;
template <std::size_t Max = dynamic_extent>
using cu16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For "
"more information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const char16_t, Max>;
template <std::size_t Max = dynamic_extent>
using cu32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For "
"more information, see isocpp/CppCoreGuidelines PR#1680")]] =
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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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)
#endif // _MSC_VER
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif // GSL_STRING_SPAN_H
+44 -131
View File
@@ -1,4 +1,3 @@
// -*- C++ -*-
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
@@ -18,22 +17,14 @@
#ifndef GSL_UTIL_H
#define GSL_UTIL_H
#include "./assert" // for Expects
#include <gsl/assert> // for contracts
#include <array>
#include <cstddef> // for ptrdiff_t, size_t
#include <initializer_list> // for initializer_list
#include <iterator> // for iterator_traits
#include <limits> // for numeric_limits
#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)
@@ -41,59 +32,12 @@
#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)
#if __cplusplus >= 202002L
#define GSL_CONSTEXPR_SINCE_CPP20 constexpr
#else // ^^^ since C++20 /// before C++20 vvv
#define GSL_BEFORE_CPP20
#define GSL_CONSTEXPR_SINCE_CPP20
#endif // __cplusplus >= 202002L
namespace gsl
{
//
@@ -103,71 +47,53 @@ namespace gsl
// index type for all container indexes/subscripts/sizes
using index = std::ptrdiff_t;
namespace details
{
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct is_iterator : std::false_type
{
};
template <typename T>
struct is_iterator<T, void_t<typename std::iterator_traits<T>::value_type>> : std::true_type
{
};
template <typename T, typename = void>
struct is_fwd_iterator : std::false_type
{
};
template <typename T>
struct is_fwd_iterator<T, void_t<typename std::iterator_traits<T>::iterator_category>>
: std::integral_constant<
bool, std::is_base_of<std::forward_iterator_tag,
typename std::iterator_traits<T>::iterator_category>::value>
{
};
} // namespace details
// 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)} {}
static_assert(!std::is_reference<F>::value && !std::is_const<F>::value &&
!std::is_volatile<F>::value,
"Final_action should store its callable by value");
~final_action() noexcept
{
if (invoke) f();
}
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))
: 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;
final_action& operator=(const final_action&) = delete;
final_action& operator=(final_action&&) = delete;
// clang-format off
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
// clang-format on
~final_action() noexcept
{
if (invoke_) f_();
}
private:
F f;
bool invoke = true;
F f_;
bool invoke_{true};
};
// finally() - convenience function to generate a final_action
template <class F>
GSL_NODISCARD auto finally(F&& f) noexcept
GSL_NODISCARD final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>
finally(F&& f) noexcept
{
return final_action<std::decay_t<F>>{std::forward<F>(f)};
return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(
std::forward<F>(f));
}
// narrow_cast(): a searchable way to do narrowing casts of values
template <class T, class U>
GSL_SUPPRESS(type.1) constexpr T narrow_cast(U&& u) noexcept
// 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));
}
@@ -176,45 +102,38 @@ GSL_SUPPRESS(type.1) constexpr T narrow_cast(U&& u) noexcept
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
//
template <class T, std::size_t N>
GSL_SUPPRESS(bounds.4) GSL_SUPPRESS(bounds.2) constexpr T& at(T (&arr)[N], const index i)
// 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));
Expects(i >= 0 && i < narrow_cast<index>(N), Bounds);
return arr[narrow_cast<std::size_t>(i)];
}
template <class Cont>
GSL_SUPPRESS(bounds.4) GSL_SUPPRESS(bounds.2) constexpr auto at(Cont& cont, const index i)
-> decltype(cont[cont.size()])
// 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()));
Expects(i >= 0 && i < narrow_cast<index>(cont.size()), Bounds);
using size_type = decltype(cont.size());
return cont[narrow_cast<size_type>(i)];
}
template <class T>
GSL_SUPPRESS(bounds.1) constexpr T at(const std::initializer_list<T> cont, const index i)
// 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()));
Expects(i >= 0 && i < narrow_cast<index>(cont.size()), Bounds);
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__)
@@ -223,10 +142,4 @@ constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size
#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
View File
@@ -1,58 +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_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
+26
View File
@@ -0,0 +1,26 @@
parameters:
jobName: ''
imageName: ''
jobs:
- job:
displayName: ${{ parameters.imageName }}
pool:
vmImage: ${{ parameters.imageName }}
strategy:
matrix:
14_debug:
GSL_CXX_STANDARD: '14'
BUILD_TYPE: 'Debug'
14_release:
GSL_CXX_STANDARD: '14'
BUILD_TYPE: 'Release'
17_debug:
GSL_CXX_STANDARD: '17'
BUILD_TYPE: 'Debug'
17_release:
GSL_CXX_STANDARD: '17'
BUILD_TYPE: 'Release'
continueOnError: false
steps:
- template: ./steps.yml
+17
View File
@@ -0,0 +1,17 @@
steps:
- task: CMake@1
name: Configure
inputs:
workingDirectory: build
cmakeArgs: '-DCMAKE_CXX_STANDARD=$(GSL_CXX_STANDARD) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) .. '
- task: CMake@1
name: Build
inputs:
workingDirectory: build
cmakeArgs: '--build . '
- script: ctest . --output-on-failure --no-compress-output
name: CTest
workingDirectory: build
failOnStderr: true
-13
View File
@@ -1,13 +0,0 @@
@echo off
setlocal enabledelayedexpansion
"%VCINSTALLDIR%Tools\Llvm\bin\clang-format" -version
if %errorlevel% neq 0 (
echo [ERROR] clang-format not found, script should be called from a visual studio developer command prompt.
exit /b %errorlevel%
)
for %%f in (include\gsl\* tests\*.h tests\*.cpp) do (
echo formatting %%f
"%VCINSTALLDIR%Tools\Llvm\bin\clang-format" -i --assume-filename x.cpp "%%f"
)
-18
View File
@@ -1,18 +0,0 @@
#!/bin/bash
set -euo pipefail
cf=clang-format-$(grep -i 'CLANG_VERSION:' .github/workflows/clang-format.yml | sed -E 's/.*"([^"]+)".*/\1/')
readonly cf
if ! "${cf}" -version; then
echo "[ERROR] clang-format not found. Please install it using: sudo apt install ${cf}"
exit 1
fi
{
find include/gsl -type f
find tests -type f \( -name '*.cpp' -o -name '*.h' \)
} | xargs "${cf}" -i --assume-filename=x.cpp --verbose
find scripts -type f -name '*.sh' -print -exec shfmt -w {} \;
+59 -96
View File
@@ -1,32 +1,13 @@
cmake_minimum_required(VERSION 3.14...3.16)
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)
cmake_minimum_required(VERSION 3.0.2)
project(GSLTests CXX)
include(FindPkgConfig)
include(ExternalProject)
# will make visual studio generated project group files
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20)
add_compile_definitions(FORCE_STD_SPAN_TESTS=1)
endif()
if(IOS)
add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1)
endif()
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)
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
@@ -56,22 +37,10 @@ if (NOT GTestMain_FOUND)
)
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))
if (MSVC AND (GSL_CXX_STANDARD 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)
@@ -98,7 +67,6 @@ 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
@@ -110,20 +78,13 @@ 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
-Wno-global-constructors
$<$<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
@@ -136,7 +97,6 @@ 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
@@ -147,11 +107,10 @@ 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
-Wno-poison-system-directories
-Wno-global-constructors
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-member-function
-Wno-unused-variable
@@ -161,11 +120,6 @@ 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>>:
@@ -178,7 +132,8 @@ else()
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
-Wduplicated-cond # duplicated if-else conditions
-Wmisleading-indentation
-Wnull-dereference
-Wno-null-dereference
-Wno-array-bounds
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-variable
>
@@ -189,33 +144,45 @@ 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
)
# Individually build and register each test source (except no_exception_ensure_tests.cpp)
# no_exception_ensure_tests.cpp is built separately with exceptions disabled
file(GLOB GSL_TEST_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
list(FILTER GSL_TEST_SOURCES EXCLUDE REGEX "no_exception_ensure_tests\\.cpp$")
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
${GTestMain_LIBRARIES}
)
add_test(
${name}
${name}
)
# group all tests under GSL_tests
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests")
endfunction()
add_gsl_test(span_tests)
add_gsl_test(span_ext_tests)
add_gsl_test(span_compatibility_tests)
add_gsl_test(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)
foreach(src IN LISTS GSL_TEST_SOURCES)
get_filename_component(test_name "${src}" NAME_WE)
add_executable(${test_name} ${src})
target_link_libraries(${test_name}
Microsoft.GSL::GSL
gsl_tests_config
${GTestMain_LIBRARIES}
)
add_test(NAME ${test_name} COMMAND ${test_name})
set_target_properties(${test_name} PROPERTIES FOLDER "tests")
endforeach()
# No exception tests
@@ -244,22 +211,13 @@ 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
>
>
-Wno-global-constructors
>
)
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
@@ -273,7 +231,6 @@ else()
-Wpedantic
-Wshadow
-Wsign-conversion
-Wfloat-equal
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Weverything
-Wno-c++98-compat
@@ -281,7 +238,7 @@ else()
-Wno-missing-prototypes
-Wno-unknown-attributes
-Wno-weak-vtables
-Wno-poison-system-directories
-Wno-global-constructors
>
$<$<CXX_COMPILER_ID:GNU>:
-Wdouble-promotion # float implicit to double
@@ -290,7 +247,8 @@ else()
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
-Wduplicated-cond # duplicated if-else conditions
-Wmisleading-indentation
-Wnull-dereference
-Wno-null-dereference
-Wno-array-bounds
>
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,7>>:
-Wduplicated-branches # identical if-else branches
@@ -301,15 +259,20 @@ 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()
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)
function(add_gsl_test_noexcept name)
add_executable(${name} ${name}.cpp)
target_link_libraries(${name}
GSL
gsl_tests_config_noexcept
${GTestMain_LIBRARIES}
)
add_test(
${name}
${name}
)
# group all tests under GSL_tests_noexcept
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept")
endfunction()
add_gsl_test_noexcept(no_exception_ensure_tests)
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.0.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
+16 -13
View File
@@ -14,19 +14,23 @@
//
///////////////////////////////////////////////////////////////////////////////
#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/algorithm> // for copy
#include <gsl/span> // for span
#include <array> // for array
#include <cstddef> // for size_t
#include "deathTestCommon.h"
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl
{
struct fail_fast;
} // namespace gsl
using namespace std;
using namespace gsl;
TEST(algorithm_tests, same_type)
@@ -72,8 +76,8 @@ TEST(algorithm_tests, same_type)
std::array<int, 5> src{1, 2, 3, 4, 5};
std::array<int, 10> dst{};
const gsl::span<int> src_span(src);
const gsl::span<int, 10> dst_span(dst);
const span<int> src_span(src);
const span<int, 10> dst_span(dst);
copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size()));
@@ -188,7 +192,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(gsl::make_span(dst));
span<int*, 4> dst_span_static(dst);
// every line should produce a compilation error
copy(src_span_dyn, dst_span_dyn);
@@ -200,11 +204,10 @@ TEST(algorithm_tests, incompatible_type)
TEST(algorithm_tests, small_destination_span)
{
const auto terminateHandler = std::set_terminate([] {
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{};
@@ -214,9 +217,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), expected);
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
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);
#ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static);
+9 -8
View File
@@ -14,47 +14,48 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "deathTestCommon.h"
#include <gsl/assert> // for Ensures, Expects
#include <gtest/gtest.h>
#include <gsl/assert> // for fail_fast (ptr only), contracts
using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
int f(int i)
{
Expects(i > 0 && i < 10);
Expects(i > 0 && i < 10, Testing);
return i;
}
int g(int i)
{
i++;
Ensures(i > 0 && i < 10);
Ensures(i > 0 && i < 10, Testing);
return i;
}
} // namespace
TEST(assertion_tests, expects)
{
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. expects";
std::abort();
});
EXPECT_TRUE(f(2) == 2);
EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
EXPECT_DEATH(f(10), deathstring);
}
TEST(assertion_tests, ensures)
{
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. ensures";
std::abort();
});
EXPECT_TRUE(g(2) == 3);
EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
EXPECT_DEATH(g(9), deathstring);
}
+31 -69
View File
@@ -20,36 +20,33 @@
#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
#include "deathTestCommon.h"
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(at_tests, static_array)
{
int a[4] = {1, 2, 3, 4};
const int (&c_a)[4] = a;
const int(&c_a)[4] = a;
for (int i = 0; i < 4; ++i)
{
for (int i = 0; i < 4; ++i) {
EXPECT_TRUE(&gsl::at(a, i) == &a[i]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]);
}
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. static_array";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), expected);
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);
}
TEST(at_tests, std_array)
@@ -57,22 +54,20 @@ 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)]);
}
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. std_array";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), expected);
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);
}
TEST(at_tests, std_vector)
@@ -80,84 +75,51 @@ 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)]);
}
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. std_vector";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), expected);
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);
}
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);
}
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. InitializerList";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
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);
}
#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()
{
int a1[4] = {1, 2, 3, 4};
const int (&c_a1)[4] = a1;
const int(&c_a1)[4] = a1;
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:
+102
View File
@@ -0,0 +1,102 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
+14 -63
View File
@@ -16,12 +16,8 @@
#include <gtest/gtest.h>
#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;
@@ -37,46 +33,39 @@ int modify_both(gsl::byte& b, int& i)
TEST(byte_tests, construction)
{
{
const gsl::byte b = static_cast<gsl::byte>(4);
const byte b = static_cast<byte>(4);
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
}
GSL_SUPPRESS(es.49)
{
const gsl::byte b = gsl::byte(12);
const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
{
const gsl::byte b = to_byte<12>();
const byte b = to_byte<12>();
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
{
const unsigned char uc = 12;
const gsl::byte b = to_byte(uc);
const byte b = to_byte(uc);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
#if defined(__cplusplus) && (__cplusplus >= 201703L)
{
const gsl::byte b{14};
const 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 gsl::byte b = to_byte<0xFF>();
const byte b = to_byte<0xFF>();
gsl::byte a = to_byte<0x00>();
byte a = to_byte<0x00>();
EXPECT_TRUE((b | a) == to_byte<0xFF>());
EXPECT_TRUE(a == to_byte<0x00>());
@@ -110,7 +99,7 @@ TEST(byte_tests, bitwise_operations)
TEST(byte_tests, to_integer)
{
const gsl::byte b = to_byte<0x12>();
const byte b = to_byte<0x12>();
EXPECT_TRUE(0x12 == gsl::to_integer<char>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<short>(b));
@@ -129,50 +118,12 @@ TEST(byte_tests, to_integer)
TEST(byte_tests, aliasing)
{
int i{0};
const int res = modify_both(reinterpret_cast<gsl::byte&>(i), i);
const int res = modify_both(reinterpret_cast<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
}
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
#ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static);
#endif
-75
View File
@@ -1,75 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2025 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 <gsl/pointers> // for not_null
#include <gtest/gtest.h>
#include <type_traits> // for declval
using namespace gsl;
namespace
{
constexpr bool comparison_test(const int* ptr1, const int* ptr2)
{
const not_null<const int*> p1(ptr1);
const not_null<const int*> p1_same(ptr1);
const not_null<const int*> p2(ptr2);
// Testing operator==
const bool eq_result = (p1 == p1_same); // Should be true
const bool neq_result = (p1 != p2); // Should be true
// Testing operator<= and operator>=
const bool le_result = (p1 <= p1_same); // Should be true
const bool ge_result = (p1 >= p1_same); // Should be true
// The exact comparison results will depend on pointer ordering,
// but we can verify that the basic equality checks work as expected
return eq_result && neq_result && le_result && ge_result;
}
constexpr bool workaround_test(const int* ptr1, const int* ptr2)
{
const not_null<const int*> p1(ptr1);
const not_null<const int*> p1_same(ptr1);
const not_null<const int*> p2(ptr2);
// Using .get() to compare
const bool eq_result = (p1.get() == p1_same.get()); // Should be true
const bool neq_result = (p1.get() != p2.get()); // Should be true
return eq_result && neq_result;
}
} // namespace
constexpr int test_value1 = 1;
constexpr int test_value2 = 2;
static_assert(comparison_test(&test_value1, &test_value2),
"not_null comparison operators should be constexpr");
static_assert(workaround_test(&test_value1, &test_value2),
"not_null .get() comparison workaround should work");
TEST(notnull_constexpr_tests, TestNotNullConstexprComparison)
{
// This test simply verifies that the constexpr functions compile and run
// If we got here, it means the constexpr comparison operators are working
static const int value1 = 1;
static const int value2 = 2;
EXPECT_TRUE(comparison_test(&value1, &value2));
EXPECT_TRUE(workaround_test(&value1, &value2));
}
-11
View File
@@ -1,11 +0,0 @@
#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;
}
-684
View File
@@ -1,684 +0,0 @@
#include <gtest/gtest.h>
#include "deathTestCommon.h"
#include "gsl/dyn_array"
#include <cstdlib>
#include <exception>
#include <gsl/dyn_array>
#include <gsl/util>
#include <iostream>
#include <sstream>
#include <type_traits>
// Despite using <algorithm> and <ranges> utilities in this test, they
// are not being included directly by this file as a test to ensure
// transitive inclusion via <gsl/dyn_array>.
static_assert(sizeof(gsl::dyn_array<int>) == 2 * sizeof(void*),
"gsl::dyn_array (with the default allocator) should be 16 bytes");
#if defined(__cpp_lib_concepts) && (__cpp_lib_concepts >= 202002L)
static_assert(std::input_iterator<gsl::dyn_array<int>::iterator>,
"gsl::dyn_array should expose a valid input_iterator");
#endif /* __cpp_lib_concepts >= 202002L */
#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L)
static_assert(std::ranges::input_range<gsl::dyn_array<int>>,
"gsl::dyn_array should be a valid input range");
#endif /* __cpp_lib_ranges >= 201911L */
TEST(dyn_array_tests, default_ctor)
{
gsl::dyn_array<char> diamondbacks;
EXPECT_TRUE(diamondbacks.empty());
EXPECT_EQ(diamondbacks.size(), 0);
EXPECT_EQ(diamondbacks.data(), nullptr);
}
TEST(dyn_array_tests, count_ctor)
{
gsl::dyn_array<char> athletics(10);
EXPECT_FALSE(athletics.empty());
EXPECT_EQ(athletics.size(), 10);
EXPECT_NE(athletics.data(), nullptr);
gsl::dyn_array<char> braves(0);
EXPECT_TRUE(braves.empty());
EXPECT_EQ(braves.size(), 0);
EXPECT_EQ(braves.data(), nullptr);
EXPECT_TRUE(std::all_of(braves.begin(), braves.end(), [](char c) { return c == char{}; }));
}
TEST(dyn_array_tests, count_value_ctor)
{
gsl::dyn_array<char> orioles(10, 'c');
EXPECT_FALSE(orioles.empty());
EXPECT_EQ(orioles.size(), 10);
EXPECT_NE(orioles.data(), nullptr);
EXPECT_TRUE(std::all_of(orioles.begin(), orioles.end(), [](char c) { return c == 'c'; }));
gsl::dyn_array<int> redsox(10, 42);
EXPECT_FALSE(redsox.empty());
EXPECT_EQ(redsox.size(), 10);
EXPECT_NE(redsox.data(), nullptr);
EXPECT_TRUE(std::all_of(redsox.begin(), redsox.end(), [](int i) { return i == 42; }));
}
TEST(dyn_array_tests, inputit_ctor)
{
std::vector<char> cubs(10, 'c');
gsl::dyn_array<char> whitesox(cubs.begin(), cubs.end());
EXPECT_FALSE(whitesox.empty());
EXPECT_EQ(whitesox.size(), cubs.size());
EXPECT_NE(whitesox.data(), nullptr);
EXPECT_TRUE(std::all_of(whitesox.begin(), whitesox.end(), [](char c) { return c == 'c'; }));
}
TEST(dyn_array_tests, copy_ctor)
{
gsl::dyn_array<char> reds(10, 'c');
gsl::dyn_array<char> guardians(reds);
EXPECT_FALSE(guardians.empty());
EXPECT_EQ(guardians.size(), reds.size());
EXPECT_NE(guardians.data(), nullptr);
EXPECT_TRUE(std::all_of(guardians.begin(), guardians.end(), [](char c) { return c == 'c'; }));
}
TEST(dyn_array_tests, access_operator)
{
gsl::dyn_array<char> rockies(10, 'c');
using ST = typename decltype(rockies)::size_type;
for (int i = 0; i < gsl::narrow<int>(rockies.size()); i++)
EXPECT_EQ(rockies[gsl::narrow<ST>(i)], 'c');
for (int i = 0; i < gsl::narrow<int>(rockies.size()); i++) rockies[gsl::narrow<ST>(i)] = 'r';
for (int i = 0; i < gsl::narrow<int>(rockies.size()); i++)
EXPECT_EQ(rockies[gsl::narrow<ST>(i)], 'r');
gsl::dyn_array<int> tigers(10);
for (int i = 0; i < gsl::narrow<int>(tigers.size()); i++) tigers[gsl::narrow<ST>(i)] = i;
for (int i = 0; i < gsl::narrow<int>(tigers.size()); i++)
EXPECT_EQ(tigers[gsl::narrow<ST>(i)], i);
}
TEST(dyn_array_tests, iterators)
{
gsl::dyn_array<char> astros(10, 'c');
for (auto it = astros.begin(); it != astros.end(); it++) EXPECT_EQ(*it, 'c');
for (auto it = astros.begin(); it != astros.end(); it++) *it = 'r';
for (auto it = astros.begin(); it != astros.end(); it++) EXPECT_EQ(*it, 'r');
EXPECT_TRUE(std::all_of(astros.begin(), astros.end(), [](char c) { return c == 'r'; }));
gsl::dyn_array<char> royals(10, 'c');
for (auto it = royals.begin(); it != royals.end(); ++it) EXPECT_EQ(*it, 'c');
for (auto it = royals.begin(); it != royals.end(); ++it) *it = 'r';
for (auto it = royals.begin(); it != royals.end(); ++it) EXPECT_EQ(*it, 'r');
EXPECT_TRUE(std::all_of(royals.begin(), royals.end(), [](char c) { return c == 'r'; }));
}
TEST(dyn_array_tests, range_for)
{
gsl::dyn_array<char> angels(10, 'c');
for (auto x : angels) EXPECT_EQ(x, 'c');
for (auto& x : angels) x = 'r';
for (auto x : angels) EXPECT_EQ(x, 'r');
EXPECT_TRUE(std::all_of(angels.begin(), angels.end(), [](char c) { return c == 'r'; }));
}
TEST(dyn_array_tests, use_std_algorithms)
{
gsl::dyn_array<char> dodgers(26);
std::generate(dodgers.begin(), dodgers.end(), [i = 0]() mutable { return 'a' + i++; });
char ch = 'a';
for (auto x : dodgers) EXPECT_EQ(x, ch++);
EXPECT_EQ(std::find(dodgers.begin(), dodgers.end(), 'a'), dodgers.begin());
{
auto it = std::find(dodgers.begin(), dodgers.end(), 'c');
EXPECT_EQ(std::distance(dodgers.begin(), it), 'c' - 'a');
EXPECT_EQ(std::distance(it, dodgers.begin()), 'a' - 'c');
}
{
auto it = std::lower_bound(dodgers.begin(), dodgers.end(), 'j');
EXPECT_EQ(*it, 'j');
EXPECT_EQ(std::distance(dodgers.begin(), it), 'j' - 'a');
EXPECT_EQ(std::distance(it, dodgers.begin()), 'a' - 'j');
}
EXPECT_EQ(dodgers.begin(), std::begin(dodgers));
EXPECT_EQ(dodgers.end(), std::end(dodgers));
}
#if defined(__cpp_lib_constexpr_dynamic_alloc) && (__cpp_lib_constexpr_dynamic_alloc >= 201907L)
constexpr auto default_constructed_count_dyn_array_is_constexpr()
{
gsl::dyn_array<int> values(3);
return values.size() == 3 && values[0] == 0 && values[1] == 0 && values[2] == 0;
}
TEST(dyn_array_tests, constexprness)
{
constexpr gsl::dyn_array<char> marlins;
static_assert(marlins == marlins);
static_assert(marlins.empty());
static_assert(marlins.size() == 0);
static_assert(marlins.data() == nullptr);
static_assert(marlins.begin() == marlins.end());
static_assert(std::distance(marlins.begin(), marlins.end()) == 0);
static_assert(default_constructed_count_dyn_array_is_constexpr());
}
#endif /* __cpp_lib_constexpr_dynamic_alloc >= 201907L */
#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L)
TEST(dyn_array_tests, ranges)
{
gsl::dyn_array<char> brewers(26);
std::ranges::generate(brewers, [c = 'a']() mutable { return c++; });
char ch = 'a';
for (auto x : brewers) EXPECT_EQ(x, ch++);
EXPECT_EQ(std::ranges::find(brewers, 'a'), std::ranges::begin(brewers));
{
auto it = std::ranges::find(brewers, 'c');
EXPECT_EQ(std::ranges::distance(std::ranges::begin(brewers), it), 'c' - 'a');
EXPECT_EQ(std::ranges::distance(it, std::ranges::begin(brewers)), 'a' - 'c');
}
#if defined(__cpp_lib_containers_ranges) && (__cpp_lib_containers_ranges >= 202202L)
std::vector<char> twins(10, 'c');
gsl::dyn_array<char> mets(std::from_range, twins);
EXPECT_EQ(twins.size(), mets.size());
EXPECT_TRUE(std::ranges::all_of(mets, [](char c) { return c == 'c'; }));
#endif /* __cpp_lib_containers_ranges >= 202202L */
}
#endif /* __cpp_lib_ranges >= 201911L */
#if defined(__cpp_lib_constexpr_dynamic_alloc) && (__cpp_lib_constexpr_dynamic_alloc >= 201907L)
template <typename T, unsigned N>
struct ConstexprAllocator
{
using value_type = T;
T buf[N]{};
std::size_t sz{};
constexpr ConstexprAllocator() = default;
template <typename U>
constexpr ConstexprAllocator(const ConstexprAllocator<U, N>&) noexcept : buf{}, sz{}
{}
template <typename U>
struct rebind
{
using other = ConstexprAllocator<U, N>;
};
constexpr auto allocate(std::size_t n) -> value_type*
{
auto addr = &buf[sz];
sz += n;
return addr;
}
constexpr void deallocate(value_type*, std::size_t) noexcept {}
};
template <typename T1, unsigned N1, typename T2, unsigned N2>
constexpr auto operator==(const ConstexprAllocator<T1, N1>& lhs,
const ConstexprAllocator<T2, N2>& rhs) noexcept
{
return std::addressof(lhs) == std::addressof(rhs);
}
template <typename T1, unsigned N1, typename T2, unsigned N2>
constexpr auto operator!=(const ConstexprAllocator<T1, N1>& lhs,
const ConstexprAllocator<T2, N2>& rhs) noexcept
{
return !(lhs == rhs);
}
#endif /* __cpp_lib_constexpr_dynamic_alloc >= 201907L */
template <typename T>
static int AllocCounter = 0;
template <typename T>
static int DeallocCounter = 0;
struct LifetimeCounter
{
static int alive_count;
int value{};
explicit LifetimeCounter(int v = 0) : value(v) { ++alive_count; }
LifetimeCounter(const LifetimeCounter& other) : value(other.value) { ++alive_count; }
~LifetimeCounter() { --alive_count; }
};
int LifetimeCounter::alive_count = 0;
struct DefaultConstructionCounter
{
static int default_constructor_count;
static int copy_constructor_count;
int value{};
DefaultConstructionCounter() { ++default_constructor_count; }
DefaultConstructionCounter(const DefaultConstructionCounter& other) : value(other.value)
{
++copy_constructor_count;
}
static void reset()
{
default_constructor_count = 0;
copy_constructor_count = 0;
}
};
int DefaultConstructionCounter::default_constructor_count = 0;
int DefaultConstructionCounter::copy_constructor_count = 0;
struct DefaultOnlyElement
{
DefaultOnlyElement() = default;
DefaultOnlyElement(const DefaultOnlyElement&) = delete;
DefaultOnlyElement& operator=(const DefaultOnlyElement&) = delete;
DefaultOnlyElement(DefaultOnlyElement&&) = delete;
DefaultOnlyElement& operator=(DefaultOnlyElement&&) = delete;
};
struct ThrowOnCopy
{
static int alive_count;
static int copy_count;
static int throw_on_copy_index;
int value{};
explicit ThrowOnCopy(int v = 0) : value(v) { ++alive_count; }
ThrowOnCopy(const ThrowOnCopy& other) : value(other.value)
{
if (copy_count == throw_on_copy_index)
{
++copy_count;
throw 42;
}
++copy_count;
++alive_count;
}
~ThrowOnCopy() { --alive_count; }
};
int ThrowOnCopy::alive_count = 0;
int ThrowOnCopy::copy_count = 0;
int ThrowOnCopy::throw_on_copy_index = -1;
template <typename T>
class Newocator
{
public:
using value_type = T;
Newocator() = default;
template <typename U>
Newocator(const Newocator<U>&) noexcept
{}
static void init()
{
AllocCounter<Newocator<T>> = 0;
DeallocCounter<Newocator<T>> = 0;
}
static void check() { EXPECT_EQ(AllocCounter<Newocator<T>>, DeallocCounter<Newocator<T>>); }
auto allocate(std::size_t n) -> value_type*
{
AllocCounter<Newocator<T>> ++;
return static_cast<value_type*>(::operator new(n * sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t) noexcept
{
DeallocCounter<Newocator<T>> ++;
::operator delete(p);
}
template <typename U>
struct rebind
{
using other = Newocator<U>;
};
};
template <typename T, typename U>
constexpr auto operator==(const Newocator<T>&, const Newocator<U>&) noexcept
{
return true;
}
template <typename T, typename U>
constexpr auto operator!=(const Newocator<T>& lhs, const Newocator<U>& rhs) noexcept
{
return !(lhs == rhs);
}
template <typename T>
class OwnershipTrackingAllocator
{
public:
using value_type = T;
OwnershipTrackingAllocator() noexcept : owner_id(next_owner_id()) { ++next_owner_id(); }
explicit OwnershipTrackingAllocator(int owner) noexcept : owner_id(owner) {}
template <typename U>
OwnershipTrackingAllocator(const OwnershipTrackingAllocator<U>& other) noexcept
: owner_id(other.owner())
{}
auto allocate(std::size_t count) -> value_type*
{
static_assert(alignof(value_type) <= alignof(int),
"test allocator only supports types with int-or-smaller alignment");
auto raw =
static_cast<unsigned char*>(::operator new(sizeof(int) + count * sizeof(value_type)));
*reinterpret_cast<int*>(raw) = owner_id;
++allocation_count();
return reinterpret_cast<value_type*>(raw + sizeof(int));
}
void deallocate(value_type* pointer, std::size_t) noexcept
{
auto raw = reinterpret_cast<unsigned char*>(pointer) - sizeof(int);
if (*reinterpret_cast<int*>(raw) != owner_id) { ++mismatched_deallocation_count(); }
++deallocation_count();
::operator delete(raw);
}
auto owner() const noexcept { return owner_id; }
static void reset()
{
next_owner_id() = 1;
allocation_count() = 0;
deallocation_count() = 0;
mismatched_deallocation_count() = 0;
}
static auto mismatched_deallocations() { return mismatched_deallocation_count(); }
private:
int owner_id;
static auto next_owner_id() -> int&
{
static int value = 1;
return value;
}
static auto allocation_count() -> int&
{
static int value = 0;
return value;
}
static auto deallocation_count() -> int&
{
static int value = 0;
return value;
}
static auto mismatched_deallocation_count() -> int&
{
static int value = 0;
return value;
}
};
template <typename T, typename U>
constexpr auto operator==(const OwnershipTrackingAllocator<T>& lhs,
const OwnershipTrackingAllocator<U>& rhs) noexcept
{
return lhs.owner() == rhs.owner();
}
template <typename T, typename U>
constexpr auto operator!=(const OwnershipTrackingAllocator<T>& lhs,
const OwnershipTrackingAllocator<U>& rhs) noexcept
{
return !(lhs == rhs);
}
TEST(dyn_array_tests, custom_allocator_models_allocator)
{
using traits = std::allocator_traits<Newocator<char>>;
using ptr = traits::pointer;
static_assert(std::is_same<traits::value_type, char>::value, "allocator trait type mismatch");
static_assert(std::is_same<ptr, char*>::value, "allocator trait type mismatch");
Newocator<char> alloc;
auto p = traits::allocate(alloc, 1);
traits::deallocate(alloc, p, 1);
#if defined(__cpp_lib_constexpr_dynamic_alloc) && (__cpp_lib_constexpr_dynamic_alloc >= 201907L)
using constexpr_traits = std::allocator_traits<ConstexprAllocator<char, 10>>;
static_assert(std::is_same<constexpr_traits::value_type, char>::value,
"allocator trait type mismatch");
#endif /* __cpp_lib_constexpr_dynamic_alloc >= 201907L */
}
TEST(dyn_array_tests, custom_allocator)
{
#if defined(__cpp_lib_constexpr_dynamic_alloc) && (__cpp_lib_constexpr_dynamic_alloc >= 201907L)
static constexpr gsl::dyn_array<char, ConstexprAllocator<char, 10>> mets(10, 'c');
static_assert(mets.size() == 10);
static_assert(mets[0] == 'c');
static_assert(std::all_of(std::begin(mets), std::end(mets), [](char c) { return c == 'c'; }));
#endif /* __cpp_lib_constexpr_dynamic_alloc >= 201907L */
Newocator<char>::init();
{
gsl::dyn_array<char, Newocator<char>> yankees(10, 'c');
EXPECT_EQ(yankees.size(), 10);
EXPECT_TRUE(
std::all_of(std::begin(yankees), std::end(yankees), [](char c) { return c == 'c'; }));
yankees[0] = 'a';
yankees[1] = 'b';
EXPECT_EQ(yankees[0], 'a');
EXPECT_EQ(yankees[1], 'b');
EXPECT_EQ(yankees[2], 'c');
yankees.get_allocator().deallocate(yankees.get_allocator().allocate(1), 1);
}
Newocator<char>::check();
}
TEST(dyn_array_tests, non_trivial_elements_are_destroyed)
{
LifetimeCounter::alive_count = 0;
{
gsl::dyn_array<LifetimeCounter> values(5, LifetimeCounter{7});
EXPECT_EQ(values.size(), 5);
EXPECT_EQ(LifetimeCounter::alive_count, 5);
}
EXPECT_EQ(LifetimeCounter::alive_count, 0);
}
TEST(dyn_array_tests, count_constructor_default_constructs_each_element)
{
DefaultConstructionCounter::reset();
{
gsl::dyn_array<DefaultConstructionCounter> values(4);
EXPECT_EQ(values.size(), 4);
}
EXPECT_EQ(DefaultConstructionCounter::default_constructor_count, 4);
EXPECT_EQ(DefaultConstructionCounter::copy_constructor_count, 0);
}
#ifdef GSL_DYN_ARRAY_COMPILE_FAILURE_TESTS
TEST(dyn_array_compile_failure_tests, count_constructor_accepts_default_constructible_only_elements)
{
gsl::dyn_array<DefaultOnlyElement> values(4);
EXPECT_EQ(values.size(), 4);
}
#endif /* GSL_DYN_ARRAY_COMPILE_FAILURE_TESTS */
TEST(dyn_array_tests, failed_element_construction_rolls_back)
{
ThrowOnCopy::alive_count = 0;
ThrowOnCopy::copy_count = 0;
ThrowOnCopy::throw_on_copy_index = 2;
EXPECT_THROW((gsl::dyn_array<ThrowOnCopy>(5, ThrowOnCopy{1})), int);
EXPECT_EQ(ThrowOnCopy::alive_count, 0);
ThrowOnCopy::throw_on_copy_index = -1;
}
TEST(dyn_array_tests, init_list)
{
gsl::dyn_array<char> phillies = {'a', 'b', 'c'};
EXPECT_EQ(phillies.size(), 3);
EXPECT_EQ(phillies[0], 'a');
EXPECT_EQ(phillies[1], 'b');
EXPECT_EQ(phillies[2], 'c');
}
TEST(dyn_array_tests, const_operations)
{
const gsl::dyn_array<char> pirates{'a', 'b', 'c', 'd'};
EXPECT_EQ(pirates.size(), 4);
EXPECT_EQ(pirates[0], 'a');
}
TEST(dyn_array_tests, reverse_iterator)
{
const gsl::dyn_array<char> padres{'a', 'b', 'c'};
auto it = std::rbegin(padres);
EXPECT_EQ(*it++, 'c');
EXPECT_EQ(*it++, 'b');
EXPECT_EQ(*it++, 'a');
}
TEST(dyn_array_tests, random_access_iterator_arithmetic)
{
gsl::dyn_array<char> bluejays{'a', 'b', 'c', 'd'};
auto first = bluejays.begin();
auto third = first + 2;
EXPECT_EQ(*third, 'c');
EXPECT_EQ(third - first, 2);
EXPECT_EQ(*(third - 1), 'b');
EXPECT_EQ(*std::prev(third), 'b');
}
TEST(dyn_array_tests, random_access_iterator_arithmetic_accepts_negative_offsets)
{
gsl::dyn_array<char> bluejays{'a', 'b', 'c', 'd'};
auto third = bluejays.begin() + 2;
char previous{};
char next{};
EXPECT_NO_THROW(previous = *(third + -1));
EXPECT_EQ(previous, 'b');
EXPECT_NO_THROW(next = *(third - -1));
EXPECT_EQ(next, 'd');
}
TEST(dyn_array_tests, input_iterator_constructor)
{
std::istringstream stream{"n a t s"};
std::istream_iterator<char> first{stream};
const std::istream_iterator<char> last{};
gsl::dyn_array<char> nationals(first, last);
ASSERT_EQ(nationals.size(), 4);
EXPECT_EQ(nationals[0], 'n');
EXPECT_EQ(nationals[1], 'a');
EXPECT_EQ(nationals[2], 't');
EXPECT_EQ(nationals[3], 's');
}
TEST(dyn_array_tests, contract_violations)
{
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. dyn_array_contract_violations";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
gsl::dyn_array<char> values(3, 'v');
gsl::dyn_array<char> other(3, 'o');
EXPECT_DEATH(values[values.size()], expected);
EXPECT_DEATH((void) *values.end(), expected);
EXPECT_DEATH(++values.end(), expected);
EXPECT_DEATH(--values.begin(), expected);
EXPECT_DEATH((void) (values.begin() == other.begin()), expected);
}
#ifdef _MSC_VER
TEST(dyn_array_tests, unchecked_iterators)
{
gsl::dyn_array<char> values;
const gsl::dyn_array<char> const_values(3, 'v');
EXPECT_TRUE((std::is_same<decltype(const_values._Unchecked_begin()), const char*>::value));
EXPECT_TRUE((std::is_same<decltype(const_values._Unchecked_end()), const char*>::value));
std::size_t count = 0;
for (const auto value : const_values)
{
EXPECT_EQ(value, 'v');
++count;
}
EXPECT_EQ(count, const_values.size());
EXPECT_EQ(values._Unchecked_begin(), nullptr);
EXPECT_EQ(values._Unchecked_end(), nullptr);
}
#endif /* _MSC_VER */
TEST(DynArrayTests, TypeConsistency)
{
static_assert(std::is_same<gsl::dyn_array<int>::value_type, int>::value, "Value type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::reference, int&>::value,
"Reference type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::const_reference, const int&>::value,
"Const reference type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::iterator::value_type, int>::value,
"Iterator value type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::iterator::reference, int&>::value,
"Iterator reference type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::iterator::const_reference, const int&>::value,
"Iterator const reference type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::size_type, std::size_t>::value,
"Size type mismatch");
static_assert(std::is_same<gsl::dyn_array<int>::difference_type, std::ptrdiff_t>::value,
"Difference type mismatch");
}
#if defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201703L)
TEST(dyn_array_tests, deduction_guides)
{
std::vector<char> giants{10};
#if defined(__cpp_lib_containers_ranges) && (__cpp_lib_containers_ranges >= 202202L)
gsl::dyn_array mariners(std::from_range, giants);
#endif /* __cpp_lib_containers_ranges >= 202202L */
gsl::dyn_array cardinals(std::begin(giants), std::end(giants));
}
#endif /* __cpp_deduction_guides >= 201703L */
File diff suppressed because it is too large Load Diff
-7
View File
@@ -14,11 +14,8 @@
//
///////////////////////////////////////////////////////////////////////////////
#include <chrono>
#include <cstdlib> // for std::exit
#include <gsl/span> // for span
#include <iostream>
#include <thread>
int operator_subscript_no_throw() noexcept
{
@@ -45,10 +42,6 @@ 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;
+65 -251
View File
@@ -18,24 +18,19 @@
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#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 <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 "deathTestCommon.h"
using namespace gsl;
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
namespace
{
static constexpr char deathstring[] = "Expected Death";
} //namespace
struct MyBase
{
@@ -61,7 +56,7 @@ template <typename T>
struct CustomPtr
{
CustomPtr(T* p) : p_(p) {}
operator T*() const { return p_; }
operator T*() { return p_; }
bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
T* p_ = nullptr;
};
@@ -69,7 +64,7 @@ struct CustomPtr
template <typename T, typename U>
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -77,7 +72,7 @@ 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)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -85,7 +80,7 @@ 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)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -93,7 +88,7 @@ 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)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -101,7 +96,7 @@ 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)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -109,7 +104,7 @@ 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)
{
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@@ -123,49 +118,23 @@ struct NonCopyableNonMovable
NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
};
namespace
{
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper(not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
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)
{
{
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
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;
// Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10);
@@ -173,12 +142,10 @@ TEST(notnull_tests, TestNotNullConstructors)
#endif
}
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructors";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
{
// from shared pointer
int i = 12;
@@ -190,15 +157,7 @@ TEST(notnull_tests, TestNotNullConstructors)
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr;
EXPECT_DEATH((not_null<decltype(pi)>(pi)), 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);
EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring);
}
{
@@ -255,8 +214,8 @@ TEST(notnull_tests, TestNotNullConstructors)
{
// from returned pointer
EXPECT_DEATH(helper(return_pointer()), expected);
EXPECT_DEATH(helper_const(return_pointer()), expected);
EXPECT_DEATH(helper(return_pointer()), deathstring);
EXPECT_DEATH(helper_const(return_pointer()), deathstring);
}
}
@@ -291,27 +250,6 @@ 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;
@@ -324,46 +262,30 @@ TEST(notnull_tests, TestNotNullCasting)
q = p; // allowed with heterogeneous copy ctor
EXPECT_TRUE(q == p);
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>");
#ifdef CONFIRM_COMPILATION_ERRORS
q = u; // no viable conversion possible between MyBase* and Unrelated*
p = q; // not possible to implicitly convert MyBase* to 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)
{
const auto terminateHandler = std::set_terminate([] {
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), expected);
EXPECT_DEATH(p = not_null<int*>(q), deathstring);
}
TEST(notnull_tests, TestNotNullRawPointerComparison)
@@ -489,18 +411,6 @@ 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)
{
{
@@ -513,18 +423,6 @@ 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;
@@ -536,28 +434,17 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42);
}
{
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::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(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
@@ -565,45 +452,26 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int* p1 = nullptr;
const not_null x{p1};
};
EXPECT_DEATH(workaround_macro(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
int* p = nullptr;
EXPECT_DEATH(helper(not_null{p}), expected);
EXPECT_DEATH(helper_const(not_null{p}), expected);
EXPECT_DEATH(helper(not_null{p}), deathstring);
EXPECT_DEATH(helper_const(not_null{p}), deathstring);
}
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>");
#ifdef CONFIRM_COMPILATION_ERRORS
{
not_null x{nullptr};
helper(not_null{nullptr});
helper_const(not_null{nullptr});
}
#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)
{
{
@@ -616,17 +484,6 @@ 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;
@@ -638,23 +495,10 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42);
}
{
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::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
{
const auto workaround_macro = []() {
@@ -662,7 +506,7 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42);
};
EXPECT_DEATH(workaround_macro(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
@@ -671,66 +515,36 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42);
};
EXPECT_DEATH(workaround_macro(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
int* p = nullptr;
EXPECT_DEATH(helper(make_not_null(p)), expected);
EXPECT_DEATH(helper_const(make_not_null(p)), expected);
EXPECT_DEATH(helper(make_not_null(p)), deathstring);
EXPECT_DEATH(helper_const(make_not_null(p)), deathstring);
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
EXPECT_DEATH(make_not_null(nullptr), expected);
EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
EXPECT_DEATH(make_not_null(nullptr), deathstring);
EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring);
EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring);
}
#endif
}
TEST(notnull_tests, TestStdHash)
{
{
int x = 42;
int y = 99;
not_null<int*> nn{&x};
const not_null<int*> cnn{&x};
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;
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));
}
{
auto x = std::make_shared<int>(42);
auto y = std::make_shared<int>(99);
not_null<std::shared_ptr<int>> nn{x};
const not_null<std::shared_ptr<int>> cnn{x};
std::hash<not_null<std::shared_ptr<int>>> hash_nn;
std::hash<std::shared_ptr<int>> hash_sharedptr;
EXPECT_TRUE(hash_nn(nn) == hash_sharedptr(x));
EXPECT_FALSE(hash_nn(nn) == hash_sharedptr(y));
EXPECT_TRUE(hash_nn(cnn) == hash_sharedptr(x));
}
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
}
+10 -16
View File
@@ -17,11 +17,10 @@
#include <gtest/gtest.h>
#include <gsl/pointers> // for owner
#include <type_traits> // for declval
using namespace gsl;
GSL_SUPPRESS(f.23)
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute
void f(int* i) { *i += 1; }
TEST(owner_tests, basic_test)
@@ -33,17 +32,12 @@ TEST(owner_tests, basic_test)
delete p;
}
#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>>");
TEST(owner_tests, check_pointer_constraint)
{
#ifdef CONFIRM_COMPILATION_ERRORS
{
owner<int> integerTest = 10;
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
}
#endif
}
-119
View File
@@ -1,119 +0,0 @@
#include <gtest/gtest.h>
#include <gsl/pointers>
#include <functional>
#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));
static_assert(noexcept(gsl::swap(a, b)),
"not null unique_ptr should be noexcept-swappable");
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)};
static_assert(noexcept(gsl::swap(a, b)),
"strict not null unique_ptr should be noexcept-swappable");
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");
}
TEST(pointers_test, hash_noexcept_compiles)
{
{
using Key = gsl::not_null<std::shared_ptr<int>>;
static_assert(noexcept(std::hash<Key>{}(std::declval<Key>())),
"gsl::not_null hash operator must be noexcept");
}
{
using Key = gsl::strict_not_null<std::shared_ptr<int>>;
static_assert(noexcept(std::hash<Key>{}(std::declval<Key>())),
"gsl::strict_not_null hash operator must be noexcept");
}
}
} // namespace
+10 -15
View File
@@ -17,7 +17,7 @@
#include <gtest/gtest.h>
#include <gsl/byte> // for byte
#include <gsl/span> // for span, span_iterator, operator==, operator!=
#include <gsl/span> // for span, span_iterator, operator==, operator!=
#include <array> // for array
#include <cstddef> // for ptrdiff_t
@@ -55,16 +55,16 @@ void ArrayConvertibilityCheck()
EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
gsl::span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
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(gsl::span{stl_nullptr}), gsl::span<T*, 3>>::value,
static_assert(std::is_same<decltype(span{stl_nullptr}), span<T*, 3>>::value,
"std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
static_assert(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");
static_assert(
std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<T* const, 3>>::value,
"std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
"3>>::value");
}
#endif
}
@@ -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 represented as std::size_t");
"gsl::dynamic_extent must be respresented 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");
@@ -1005,18 +1005,12 @@ 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>>");
@@ -1026,3 +1020,4 @@ 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
+237 -257
View File
@@ -16,27 +16,27 @@
#include <gtest/gtest.h>
#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at
#include <gsl/span_ext> // for operator==, operator!=, make_span
#include <array> // for array
#include <exception> // for terminate
#include <iostream> // for cerr
#include <vector> // for vector
#include <array> // for array
#include <iostream> // for cerr
#include <vector> // for vector
using namespace std;
using namespace gsl;
#include "deathTestCommon.h"
namespace
{
static constexpr char deathstring[] = "Expected Death";
} // namespace
TEST(span_ext_test, make_span_from_pointer_length_constructor)
{
const auto terminateHandler = std::set_terminate([] {
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<gsl::span<int>::size_type>(0));
auto s = make_span(p, narrow_cast<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(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
}
@@ -88,293 +88,273 @@ 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
{
gsl::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
{
span<int> s1 = make_span(arr);
static gsl::span<int> s2;
s2 = s1;
static span<int> s2;
s2 = s1;
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
// Known to be broken in gcc 6.4 and 6.5 with optimizations
// Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
EXPECT_TRUE(s1.size() == 4);
EXPECT_TRUE(s2.size() == 0);
#else
EXPECT_TRUE(s1.size() == s2.size());
#endif
}
}
#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)
{
std::vector<int> vec{1, 2, 3, 4, 5};
gsl::span<int> sp{vec};
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);
}
std::vector<int> cvec{1, 2, 3, 4, 5};
gsl::span<int> csp{cvec};
TEST(span_ext_test, iterator_free_functions)
{
int a[] = {1, 2, 3, 4};
span<int> s{a};
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(s.begin()), decltype(begin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(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(std::cbegin(s)), decltype(cbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(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(s.rbegin()), decltype(rbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
TEST(span_ext_test, iterator_free_functions)
{
int a[] = {1, 2, 3, 4};
gsl::span<int> s{a};
EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
EXPECT_TRUE((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.begin() == begin(s));
EXPECT_TRUE(s.end() == end(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.rbegin() == rbegin(s));
EXPECT_TRUE(s.rend() == rend(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.begin() == cbegin(s));
EXPECT_TRUE(s.end() == cend(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));
EXPECT_TRUE(s.rbegin() == crbegin(s));
EXPECT_TRUE(s.rend() == crend(s));
}
EXPECT_TRUE(s.begin() == begin(s));
EXPECT_TRUE(s.end() == end(s));
TEST(span_ext_test, ssize_free_function)
{
int a[] = {1, 2, 3, 4};
span<int> s{a};
EXPECT_TRUE(s.rbegin() == rbegin(s));
EXPECT_TRUE(s.rend() == rend(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.begin() == cbegin(s));
EXPECT_TRUE(s.end() == cend(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.rbegin() == crbegin(s));
EXPECT_TRUE(s.rend() == crend(s));
}
{
int arr[] = {2, 1};
span<int> s1 = arr;
span<int> s2 = arr;
TEST(span_ext_test, ssize_free_function)
{
int a[] = {1, 2, 3, 4};
gsl::span<int> s{a};
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_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
}
{
int arr[] = {2, 1}; // bigger
#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);
}
span<int> s1;
span<int> s2 = arr;
{
int arr[] = {2, 1};
gsl::span<int> s1 = arr;
gsl::span<int> s2 = arr;
EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1);
EXPECT_FALSE(s1 == s2);
EXPECT_FALSE(s2 == s1);
EXPECT_TRUE(s1 < s2);
EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s2 <= s1);
EXPECT_TRUE(s2 > s1);
EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s2 >= s1);
EXPECT_FALSE(s1 >= s2);
}
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 arr1[] = {1, 2};
int arr2[] = {1, 2};
span<int> s1 = arr1;
span<int> s2 = arr2;
{
int arr[] = {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);
}
gsl::span<int> s1;
gsl::span<int> s2 = arr;
{
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);
}
span<int> s1 = {&arr[0], 2}; // shorter
span<int> s2 = arr; // longer
{
int arr1[] = {1, 2};
int arr2[] = {1, 2};
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);
}
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 arr1[] = {1, 2}; // smaller
int arr2[] = {2, 1}; // bigger
{
int arr[] = {1, 2, 3};
span<int> s1 = arr1;
span<int> s2 = arr2;
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
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);
}
}
+910 -1060
View File
File diff suppressed because it is too large Load Diff
+26 -286
View File
@@ -14,190 +14,30 @@
//
///////////////////////////////////////////////////////////////////////////////
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <type_traits> // for declval
#include "deathTestCommon.h"
namespace gsl
{
struct fail_fast;
} // namespace gsl
using namespace gsl;
#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
{
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper(not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper_const(not_null<const int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4)
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool strict_helper_const(strict_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::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;
const int* return_pointer_const() { return nullptr; }
TEST(strict_notnull_tests, TestStrictNotNull)
{
@@ -207,42 +47,20 @@ 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;
@@ -257,21 +75,6 @@ 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;
@@ -288,23 +91,6 @@ 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;
@@ -329,48 +115,25 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
// 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));
strict_not_null<int*> p{nullptr};
}
}
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");
#endif
}
#if defined(__cplusplus) && (__cplusplus >= 201703L)
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
{
const auto terminateHandler = std::set_terminate([] {
std::set_terminate([] {
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
{
int i = 42;
@@ -382,17 +145,6 @@ 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;
@@ -404,24 +156,12 @@ 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(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
@@ -429,14 +169,14 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
const int* p1 = nullptr;
const strict_not_null x{p1};
};
EXPECT_DEATH(workaround_macro(), expected);
EXPECT_DEATH(workaround_macro(), deathstring);
}
{
int* p = nullptr;
EXPECT_DEATH(helper(strict_not_null{p}), expected);
EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
EXPECT_DEATH(helper(strict_not_null{p}), deathstring);
EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring);
}
#ifdef CONFIRM_COMPILATION_ERRORS
+790
View File
@@ -0,0 +1,790 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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/byte> // for byte
#include <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
+8 -26
View File
@@ -16,15 +16,14 @@
#include <gtest/gtest.h>
#include <algorithm> // for move
#include <complex>
#include <cstddef> // for std::ptrdiff_t
#include <cstdint> // for uint32_t, int32_t
#include <gsl/util> // finally, narrow_cast
#include <gsl/narrow> // for narrow, narrowing_error
#include <algorithm> // for move
#include <functional> // for reference_wrapper, _Bind_helper<>::type
#include <gsl/narrow> // for narrow, narrowing_error
#include <gsl/util> // finally, narrow_cast
#include <limits> // for numeric_limits
#include <stdint.h> // for uint32_t, int32_t
#include <type_traits> // for is_same
#include <cstddef> // for std::ptrdiff_t
using namespace gsl;
@@ -33,7 +32,8 @@ 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)
{
@@ -96,7 +96,7 @@ TEST(utils_tests, finally_function_with_bind)
{
int i = 0;
{
auto _ = finally([&i] { return f(i); });
auto _ = finally(std::bind(&f, std::ref(i)));
EXPECT_TRUE(i == 0);
}
EXPECT_TRUE(i == 1);
@@ -112,16 +112,6 @@ 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;
@@ -133,7 +123,6 @@ TEST(utils_tests, narrow_cast)
EXPECT_TRUE(uc == 44);
}
#ifndef GSL_KERNEL_MODE
TEST(utils_tests, narrow)
{
int n = 120;
@@ -155,11 +144,4 @@ TEST(utils_tests, narrow)
n = -42;
EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
EXPECT_TRUE(narrow<std::complex<float>>(std::complex<double>(4, 2)) ==
std::complex<float>(4, 2));
EXPECT_THROW(narrow<std::complex<float>>(std::complex<double>(4.2)), narrowing_error);
EXPECT_TRUE(narrow<int>(float(1)) == 1);
}
#endif // GSL_KERNEL_MODE