forked from microsoft/GSL
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e0943d20d | |||
| 2d343b0440 | |||
| c21970972b | |||
| 466e4ebaa5 | |||
| 3325bbd33d | |||
| 2828399820 | |||
| c5fbb81ad4 | |||
| 7fabaa499d | |||
| 4742bc192a | |||
| ec729d63a7 | |||
| 7f4fc9388b | |||
| 355982daf6 | |||
| 50aaf2efbb | |||
| 7b6b8013b1 | |||
| 1cdb8d295e | |||
| c832885f15 | |||
| 16a60199df | |||
| fcd55ee924 | |||
| b8ac820fe1 | |||
| 272463043e | |||
| 8a0e3d8a9b | |||
| aed09c41b6 | |||
| 4b190d2e2a | |||
| ddae9d72b6 | |||
| 74d2bb79d4 | |||
| f8ec309118 | |||
| 87f9d76886 | |||
| 82ba6c77ce | |||
| 32511b8de4 | |||
| 84b2ca1352 | |||
| ce2a959e02 | |||
| 11fe02d1ac | |||
| 3275f9ccb9 | |||
| b206bd163b | |||
| b39e7e4b09 | |||
| 2e0d1ba48c | |||
| 1b4d42ca2e | |||
| caae4dd0f8 | |||
| f1a494cfd2 | |||
| 77b2f4f3b8 |
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'Status: Open, Type: Bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
```c++
|
||||
#include <gsl>
|
||||
|
||||
// your repro here: ...
|
||||
```
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Spec (please complete the following information):**
|
||||
- OS: [e.g. Windows]
|
||||
- Compiler: [e.g. MSVC]
|
||||
- C++ Version: [e.g. C++20]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,84 @@
|
||||
# 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.
|
||||
@@ -1,4 +1,9 @@
|
||||
name: CI_Android
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
@@ -7,39 +12,43 @@ on:
|
||||
|
||||
jobs:
|
||||
Android:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-latest-large
|
||||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
working-directory: .
|
||||
|
||||
- name: Start emulator
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 8
|
||||
distribution: zulu
|
||||
|
||||
- name: Start Emulator
|
||||
run: |
|
||||
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-24;default;x86_64'
|
||||
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-24;default;x86_64' --force
|
||||
$ANDROID_HOME/emulator/emulator -list-avds
|
||||
echo "Starting emulator"
|
||||
# Start emulator in background
|
||||
nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot > /dev/null 2>&1 &
|
||||
echo "Emulator starting"
|
||||
echo "Starting emulator..."
|
||||
nohup $ANDROID_HOME/emulator/emulator -no-audio -no-snapshot -avd xamarin_android_emulator &> /dev/null &
|
||||
echo "Emulator starting in background"
|
||||
|
||||
- name: Configure
|
||||
run: cmake -Werror=dev -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_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --parallel
|
||||
|
||||
- name: Wait for emulator ready
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 10; done; input keyevent 82'
|
||||
$ANDROID_HOME/platform-tools/adb devices
|
||||
$ANDROID_HOME/platform-tools/adb shell getprop ro.product.cpu.abi
|
||||
echo "Emulator started"
|
||||
|
||||
- name: Deploy tests
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Composite CMake
|
||||
inputs:
|
||||
cmake_generator:
|
||||
required: false
|
||||
type: string
|
||||
default: 'Unix Makefiles'
|
||||
cmake_build_type:
|
||||
required: true
|
||||
type: string
|
||||
default: ''
|
||||
cmake_cxx_compiler:
|
||||
required: false
|
||||
type: string
|
||||
gsl_cxx_standard:
|
||||
required: true
|
||||
type: number
|
||||
extra_cmake_args:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
build_cmd:
|
||||
required: true
|
||||
type: string
|
||||
default: 'make'
|
||||
test_cmd:
|
||||
required: false
|
||||
type: string
|
||||
default: 'make test'
|
||||
shell:
|
||||
required: false
|
||||
type: string
|
||||
default: 'bash'
|
||||
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create build directory
|
||||
run: mkdir build
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: build
|
||||
run: cmake -G "${{ inputs.cmake_generator }}" -DCMAKE_BUILD_TYPE=${{ inputs.cmake_build_type }} -DCMAKE_CXX_COMPILER=${{ inputs.cmake_cxx_compiler }} -DGSL_CXX_STANDARD=${{ inputs.gsl_cxx_standard }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ inputs.extra_cmake_args }} ..
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: ${{ inputs.build_cmd }}
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
- name: Test
|
||||
working-directory: build
|
||||
run: ${{ inputs.test_cmd }}
|
||||
shell: ${{ inputs.shell }}
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-latest ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.14.0
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
name: Compiler Integration Tests
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
# These jobs are correlated with the officially supported compilers
|
||||
# and toolsets. If you change any versions, please update README.md.
|
||||
|
||||
jobs:
|
||||
gcc:
|
||||
strategy:
|
||||
matrix:
|
||||
gcc_version: [ 12, 13, 14 ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
# https://github.com/google/googletest/issues/4232
|
||||
# Looks like GoogleTest is not interested in making version 1.14
|
||||
# work with gcc-12.
|
||||
- gcc_version: 12
|
||||
cxx_version: 20
|
||||
- gcc_version: 12
|
||||
cxx_version: 23
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: g++-${{ matrix.gcc_version }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
clang:
|
||||
strategy:
|
||||
matrix:
|
||||
clang_version: [ 16, 17, 18 ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
# https://github.com/llvm/llvm-project/issues/93734
|
||||
# Looks like clang fixed this issue in clang-18, but won't backport
|
||||
# the fix.
|
||||
- clang_version: 17
|
||||
cxx_version: 23
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: clang++-${{ matrix.clang_version }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
xcode:
|
||||
strategy:
|
||||
matrix:
|
||||
xcode_version: [ '15.4' ]
|
||||
build_type: [ Debug, Release ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: select xcode version
|
||||
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode_version }}.app
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
cmake_cxx_compiler: clang++
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
|
||||
VisualStudio:
|
||||
strategy:
|
||||
matrix:
|
||||
generator: [ 'Visual Studio 16 2019', 'Visual Studio 17 2022' ]
|
||||
image: [ windows-2019, windows-2022 ]
|
||||
build_type: [ Debug, Release ]
|
||||
extra_args: [ '', '-T ClangCL' ]
|
||||
cxx_version: [ 14, 17, 20, 23 ]
|
||||
exclude:
|
||||
- generator: 'Visual Studio 17 2022'
|
||||
image: windows-2019
|
||||
- generator: 'Visual Studio 16 2019'
|
||||
image: windows-2022
|
||||
- generator: 'Visual Studio 16 2019'
|
||||
cxx_version: 23
|
||||
runs-on: ${{ matrix.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Run CMake (configure, build, test)
|
||||
uses: ./.github/workflows/cmake
|
||||
with:
|
||||
cmake_generator: ${{ matrix.generator }}
|
||||
cmake_build_type: ${{ matrix.build_type }}
|
||||
gsl_cxx_standard: ${{ matrix.cxx_version }}
|
||||
extra_cmake_args: ${{ matrix.extra_args }}
|
||||
build_cmd: msbuild GSL.sln
|
||||
test_cmd: ctest . --output-on-failure --no-compress-output
|
||||
shell: pwsh
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
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@v4
|
||||
|
||||
- name: Install Build Dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y clang cmake make
|
||||
|
||||
- name: Configure CMake (C++14)
|
||||
run: cmake -B build-cxx14 . -DGSL_CXX_STANDARD=14 -DGSL_TEST=ON -G "Unix Makefiles"
|
||||
|
||||
- name: Configure CMake (C++20)
|
||||
run: cmake -B build-cxx20 . -DGSL_CXX_STANDARD=20 -DGSL_TEST=ON -G "Unix Makefiles"
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
CMakeFiles
|
||||
build
|
||||
build*/
|
||||
tests/CMakeFiles
|
||||
tests/Debug
|
||||
*.opensdf
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.14...3.16)
|
||||
|
||||
project(GSL VERSION 4.0.0 LANGUAGES CXX)
|
||||
project(GSL VERSION 4.2.0 LANGUAGES CXX)
|
||||
|
||||
add_library(GSL INTERFACE)
|
||||
add_library(Microsoft.GSL::GSL ALIAS GSL)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# GSL: Guidelines Support Library
|
||||
[](https://dev.azure.com/cppstat/GSL/_build/latest?definitionId=1&branchName=main)
|
||||
[](https://github.com/microsoft/GSL/actions/workflows/compilers.yml?query=branch%3Amain)
|
||||
[](https://vcpkg.io/en/package/ms-gsl)
|
||||
|
||||
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org).
|
||||
@@ -39,8 +40,6 @@ span_p | &
|
||||
[u32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t`
|
||||
[cu32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t`
|
||||
[**2. Owners**][cg-owners] | |
|
||||
[unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | ☑ | An alias to `std::unique_ptr`
|
||||
[shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | ☑ | An alias to `std::shared_ptr`
|
||||
stack_array | ☐ | A stack-allocated array
|
||||
dyn_array | ☐ | A heap-allocated array
|
||||
[**3. Assertions**][cg-assertions] | |
|
||||
@@ -48,13 +47,11 @@ dyn_array | &
|
||||
[Ensures](docs/headers.md#user-content-H-assert-ensures) | ☑ | A postcondition assertion; on failure it terminates
|
||||
[**4. Utilities**][cg-utilities] | |
|
||||
move_owner | ☐ | A helper function that moves one `owner` to the other
|
||||
[byte](docs/headers.md#user-content-H-byte-byte) | ☑ | Either an alias to `std::byte` or a byte type
|
||||
[final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a functor on its destruction
|
||||
[finally](docs/headers.md#user-content-H-util-finally) | ☑ | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action)
|
||||
[GSL_SUPPRESS](docs/headers.md#user-content-H-assert-gsl_suppress) | ☑ | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
|
||||
[[implicit]] | ☐ | A "marker" to put on single-argument constructors to explicitly make them non-explicit
|
||||
[index](docs/headers.md#user-content-H-util-index) | ☑ | A type to use for all container and array indexing (currently an alias for `std::ptrdiff_t`)
|
||||
joining_thread | ☐ | A RAII style version of `std::thread` that joins
|
||||
[narrow](docs/headers.md#user-content-H-narrow-narrow) | ☑ | A checked version of `narrow_cast`; it can throw [narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error)
|
||||
[narrow_cast](docs/headers.md#user-content-H-util-narrow_cast) | ☑ | A narrowing cast for values and a synonym for `static_cast`
|
||||
[narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error) | ☑ | A custom exception type thrown by [narrow](docs/headers.md#user-content-H-narrow-narrow)
|
||||
@@ -76,6 +73,14 @@ cu16string_span | ☐ | Deprecated. An alias to `basic
|
||||
u32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char32_t`
|
||||
cu32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char32_t`
|
||||
|
||||
## The following features have been adopted by WG21. They are deprecated in GSL.
|
||||
Feature | Deprecated Since | Notes
|
||||
------------------------------------------------------------------|------------------|------
|
||||
[unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | C++11 | Use std::unique_ptr instead.
|
||||
[shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | C++11 | Use std::shared_ptr instead.
|
||||
[byte](docs/headers.md#user-content-H-byte-byte) | C++17 | Use std::byte instead.
|
||||
joining_thread | C++20 (Note: Not yet implemented in GSL) | Use std::jthread instead.
|
||||
|
||||
This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library).
|
||||
|
||||
[cg-views]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslview-views
|
||||
@@ -86,24 +91,17 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp
|
||||
|
||||
# Quick Start
|
||||
## Supported Compilers / Toolsets
|
||||
The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang.
|
||||
Within these two major versions, we try to target the latest minor updates / revisions (although this may be affected by
|
||||
delays between a toolchain's release and when it becomes widely available for use).
|
||||
Below is a table showing the versions currently being tested.
|
||||
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).)
|
||||
|
||||
Compiler |Toolset Versions Currently Tested
|
||||
:------- |--:
|
||||
XCode | 13.2.1 & 12.5.1
|
||||
GCC | 11[^1] & 10[^2]
|
||||
Clang | 12[^2] & 11[^2]
|
||||
Visual Studio with MSVC | VS2022[^3] & VS2019[^4]
|
||||
Visual Studio with LLVM | VS2022[^3] & VS2019[^4]
|
||||
|
||||
|
||||
[^1]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26).
|
||||
[^2]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#language-and-runtime).
|
||||
[^3]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022).
|
||||
[^4]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019).
|
||||
GCC | 12, 13, 14
|
||||
XCode | 14.3.1, 15.4
|
||||
Clang | 16, 17, 18
|
||||
Visual Studio with MSVC | VS2019, VS2022
|
||||
Visual Studio with LLVM | VS2019, VS2022
|
||||
|
||||
---
|
||||
If you successfully port GSL to another platform, we would love to hear from you!
|
||||
@@ -113,8 +111,8 @@ If you successfully port GSL to another platform, we would love to hear from you
|
||||
|
||||
Target | CI/CD Status
|
||||
:------- | -----------:
|
||||
iOS | 
|
||||
Android | 
|
||||
iOS | [](https://github.com/microsoft/GSL/actions/workflows/ios.yml?query=branch%3Amain)
|
||||
Android | [](https://github.com/microsoft/GSL/actions/workflows/android.yml?query=branch%3Amain)
|
||||
|
||||
Note: These CI/CD steps are run with each pull request, however failures in them are non-blocking.
|
||||
|
||||
@@ -192,7 +190,7 @@ target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
|
||||
|
||||
### FetchContent
|
||||
|
||||
If you are using CMake version 3.11+ you can use the offical [FetchContent module](https://cmake.org/cmake/help/latest/module/FetchContent.html).
|
||||
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
|
||||
@@ -204,7 +202,7 @@ include(FetchContent)
|
||||
|
||||
FetchContent_Declare(GSL
|
||||
GIT_REPOSITORY "https://github.com/microsoft/GSL"
|
||||
GIT_TAG "v4.0.0"
|
||||
GIT_TAG "v4.2.0"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
|
||||
@@ -216,3 +214,7 @@ 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>.
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
trigger:
|
||||
- main
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
stages:
|
||||
- stage: GCC
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: gcc
|
||||
image: ubuntu-20.04
|
||||
compilerVersions: [ 11, 10 ]
|
||||
setupfile: 'setup_gcc.yml'
|
||||
|
||||
- stage: Clang
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: clang
|
||||
image: ubuntu-20.04
|
||||
compilerVersions: [ 12, 11 ]
|
||||
setupfile: 'setup_clang.yml'
|
||||
|
||||
- stage: Xcode
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'Xcode'
|
||||
image: macOS-11
|
||||
compilerVersions: [ '12.5.1', '13.2.1' ]
|
||||
setupfile: 'setup_apple.yml'
|
||||
|
||||
- stage: VS_MSVC
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2019 (MSVC)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2019
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2022 (MSVC)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2022
|
||||
|
||||
- stage: VS_LLVM
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2019 (LLVM)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2019
|
||||
extraCmakeArgs: '-T ClangCL'
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2022 (LLVM)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2022
|
||||
extraCmakeArgs: '-T ClangCL'
|
||||
+64
-19
@@ -91,16 +91,16 @@ See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily r
|
||||
### Non-member functions
|
||||
|
||||
```cpp
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
|
||||
```
|
||||
|
||||
@@ -133,6 +133,13 @@ constexpr byte operator~(byte b) noexcept;
|
||||
|
||||
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.
|
||||
|
||||
```cpp
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr IntegerType to_integer(byte b) noexcept;
|
||||
```
|
||||
|
||||
Convert the given `byte` value to an integral type.
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
constexpr byte to_byte(T t) noexcept;
|
||||
@@ -217,6 +224,14 @@ When a nullptr check fails, `std::terminate` is called.
|
||||
|
||||
See [F.23: Use a `not_null<T>` to indicate that “null” is not a valid value](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr)
|
||||
|
||||
#### Member Types
|
||||
|
||||
```cpp
|
||||
using element_type = T;
|
||||
```
|
||||
|
||||
The type of the pointer or smart pointer that is managed by this object.
|
||||
|
||||
#### Member functions
|
||||
|
||||
##### Construct/Copy
|
||||
@@ -287,6 +302,12 @@ void operator[](std::ptrdiff_t) const = delete;
|
||||
|
||||
Array index operator is explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow treating them as an array.
|
||||
|
||||
```cpp
|
||||
void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
|
||||
```
|
||||
|
||||
Swaps contents with another `gsl::not_null` object.
|
||||
|
||||
#### Non-member functions
|
||||
|
||||
```cpp
|
||||
@@ -296,6 +317,13 @@ auto make_not_null(T&& t) noexcept;
|
||||
|
||||
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
|
||||
|
||||
```cpp
|
||||
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
|
||||
void swap(not_null<T>& a, not_null<T>& b);
|
||||
```
|
||||
|
||||
Swaps the contents of two `gsl::not_null` objects.
|
||||
|
||||
```cpp
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
@@ -384,22 +412,36 @@ The `gsl::span` is based on the standardized version of `std::span` which was ad
|
||||
deprecate `gsl::span` when `std::span` finished standardization, however that plan changed when the runtime bounds checking
|
||||
was removed from `std::span`'s design.
|
||||
|
||||
The only difference between `gsl::span` and `std::span` is that `gsl::span` strictly enforces runtime bounds checking.
|
||||
Any violations of the bounds check results in termination of the program.
|
||||
Like `gsl::span`, `gsl::span`'s iterators also differ from `std::span`'s iterator in that all access operations are bounds checked.
|
||||
The key differences between `gsl::span` and `std::span` are:
|
||||
- `gsl::span` strictly enforces runtime bounds checking for all access operations
|
||||
- Any violations of the bounds check results in termination of the program
|
||||
- `gsl::span`'s iterators also perform bounds checking, unlike `std::span`'s iterators
|
||||
|
||||
#### Which version of span should I use?
|
||||
|
||||
##### Use `gsl::span` if
|
||||
The following table compares the different span implementations to help you choose which one is best for your project:
|
||||
|
||||
- you want to guarantee bounds safety in your project.
|
||||
- All data accessing operations use bounds checking to ensure you are only accessing valid memory.
|
||||
- your project uses C++14 or C++17.
|
||||
- `std::span` is not available as it was not introduced into the STL until C++20.
|
||||
| Feature/Version | `std::span` (C++20/23) | Hardened `std::span` (C++26) | `gsl::span` |
|
||||
|-----------------|------------------------|------------------------------|-------------|
|
||||
| **C++ Standard** | Requires C++20 or later | Requires C++26 or backported implementation | Works with C++14 or later |
|
||||
| **Element Access** | No bounds checking | Bounds checking | Bounds checking |
|
||||
| **Iterator Safety** | No bounds checking | Implementation-defined, may depend on vendor | Full bounds checking |
|
||||
| **Error Behavior** | Undefined behavior on invalid access | Implementation-defined, may be configurable | Always calls [`std::terminate()`](https://en.cppreference.com/w/cpp/error/terminate) via [gsl::details::terminate()](https://github.com/microsoft/GSL/blob/main/include/gsl/assert#L111-L118) |
|
||||
| **Performance** | Fastest (no checking) | Varies by implementation and configuration | May have performance impact from bounds checking |
|
||||
|
||||
##### Use `std::span` if
|
||||
**Recommendations:**
|
||||
|
||||
- your project is C++20 and you need the performance offered by `std::span`.
|
||||
- **C++14 & C++17 projects**: Use `gsl::span` as `std::span` is not available.
|
||||
- **C++20 & C++23 projects**:
|
||||
- Use `gsl::span` if safety is your priority.
|
||||
- Use `std::span` if performance is critical and you're confident in your index calculations.
|
||||
- **C++26 projects**:
|
||||
- Use `gsl::span` if you need guaranteed iterator safety across all platforms.
|
||||
- Use hardened `std::span` if you want standard library compliance and acceptable safety.
|
||||
|
||||
**Implementation notes for hardened `std::span` in C++26:**
|
||||
- For MSVC: See [Microsoft STL Hardening](https://github.com/microsoft/STL/wiki/STL-Hardening)
|
||||
- For Clang/LLVM: See [libc++ Hardening](https://libcxx.llvm.org/Hardening.html)
|
||||
|
||||
#### Types
|
||||
|
||||
@@ -656,10 +698,6 @@ template <class Container>
|
||||
constexpr span<typename Container::value_type> make_span(Container& cont);
|
||||
template <class Container>
|
||||
constexpr span<const typename Container::value_type> make_span(const Container& cont);
|
||||
template <class Ptr>
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count);
|
||||
template <class Ptr>
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont);
|
||||
```
|
||||
|
||||
Utility function for creating a `span` with [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) from
|
||||
@@ -804,7 +842,7 @@ void operator=(const final_action&) = delete;
|
||||
void operator=(final_action&&) = delete;
|
||||
```
|
||||
|
||||
Move construction is allowed. Copy construction is deleted. Copy and move assignment are also explicitely deleted.
|
||||
Move construction is allowed. Copy construction is deleted. Copy and move assignment are also explicitly deleted.
|
||||
|
||||
#### <a name="H-util-finally" />Non-member functions
|
||||
```cpp
|
||||
@@ -851,3 +889,10 @@ constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size
|
||||
This overload returns a reference to the `i`s element of the `std::span` `sp`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
For [`gsl::at`](#user-content-H-span_ext-at) for [`gsl::span`](#user-content-H-span-span) see header [`span_ext`](#user-content-H-span_ext).
|
||||
|
||||
```cpp
|
||||
template <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
|
||||
void swap(T& a, T& b);
|
||||
```
|
||||
|
||||
Swaps the contents of two objects. Exists only to specialize `gsl::swap<T>(gsl::not_null<T>&, gsl::not_null<T>&)`.
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#ifndef GSL_ALGORITHM_H
|
||||
#define GSL_ALGORITHM_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
#include "span" // for dynamic_extent, span
|
||||
#include "./assert" // for Expects
|
||||
#include "./span" // for dynamic_extent, span
|
||||
|
||||
#include <algorithm> // for copy_n
|
||||
#include <cstddef> // for ptrdiff_t
|
||||
|
||||
+30
-19
@@ -17,10 +17,10 @@
|
||||
#ifndef GSL_BYTE_H
|
||||
#define GSL_BYTE_H
|
||||
|
||||
#include "./util" // for GSL_DEPRECATED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// VS2017 15.8 added support for the __cpp_lib_byte definition
|
||||
// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(push)
|
||||
@@ -31,18 +31,15 @@
|
||||
|
||||
#ifndef GSL_USE_STD_BYTE
|
||||
// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
|
||||
#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \
|
||||
(defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
|
||||
#define GSL_USE_STD_BYTE 1
|
||||
|
||||
#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
|
||||
// 201603)
|
||||
#else // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
|
||||
#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
|
||||
// 201603)
|
||||
#endif // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
#else // _MSC_VER
|
||||
@@ -85,7 +82,14 @@ namespace gsl
|
||||
{
|
||||
#if GSL_USE_STD_BYTE
|
||||
|
||||
using std::byte;
|
||||
namespace impl {
|
||||
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
|
||||
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
|
||||
using byte = std::byte;
|
||||
}
|
||||
|
||||
using byte GSL_DEPRECATED("Use std::byte instead.") = std::byte;
|
||||
|
||||
using std::to_integer;
|
||||
|
||||
#else // GSL_USE_STD_BYTE
|
||||
@@ -96,25 +100,31 @@ enum class byte_may_alias byte : unsigned char
|
||||
{
|
||||
};
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
namespace impl {
|
||||
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
|
||||
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
|
||||
using byte = gsl::byte;
|
||||
}
|
||||
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) >> shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) >> shift);
|
||||
@@ -152,7 +162,7 @@ constexpr byte operator^(byte l, byte r) noexcept
|
||||
|
||||
constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
|
||||
constexpr IntegerType to_integer(byte b) noexcept
|
||||
{
|
||||
return static_cast<IntegerType>(b);
|
||||
@@ -160,23 +170,24 @@ constexpr IntegerType to_integer(byte b) noexcept
|
||||
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
|
||||
template <typename T>
|
||||
// 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(T t) noexcept
|
||||
constexpr gsl::impl::byte to_byte(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 contant use: gsl::to_byte<t>() version.");
|
||||
return byte(t);
|
||||
"If you are calling to_byte with an integer constant use: gsl::to_byte<t>() version.");
|
||||
return gsl::impl::byte(t);
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr byte to_byte() noexcept
|
||||
constexpr gsl::impl::byte to_byte() noexcept
|
||||
{
|
||||
static_assert(I >= 0 && I <= 255,
|
||||
"gsl::byte only has 8 bits of storage, values must be in range 0-255");
|
||||
return static_cast<byte>(I);
|
||||
return static_cast<gsl::impl::byte>(I);
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
+10
-8
@@ -17,16 +17,18 @@
|
||||
#ifndef GSL_GSL_H
|
||||
#define GSL_GSL_H
|
||||
|
||||
#include "algorithm" // copy
|
||||
#include "assert" // Ensures/Expects
|
||||
#include "byte" // byte
|
||||
#include "pointers" // owner, not_null
|
||||
#include "span" // span
|
||||
#include "zstring" // zstring
|
||||
#include "util" // finally()/narrow_cast()...
|
||||
// IWYU pragma: begin_exports
|
||||
#include "./algorithm" // copy
|
||||
#include "./assert" // Ensures/Expects
|
||||
#include "./byte" // byte
|
||||
#include "./pointers" // owner, not_null
|
||||
#include "./span" // span
|
||||
#include "./zstring" // zstring
|
||||
#include "./util" // finally()/narrow_cast()...
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
#include "narrow" // narrow()
|
||||
#include "./narrow" // narrow()
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif // GSL_GSL_H
|
||||
|
||||
+4
-6
@@ -16,8 +16,8 @@
|
||||
|
||||
#ifndef GSL_NARROW_H
|
||||
#define GSL_NARROW_H
|
||||
#include "assert" // for GSL_SUPPRESS
|
||||
#include "util" // for narrow_cast
|
||||
#include "./assert" // for GSL_SUPPRESS
|
||||
#include "./util" // for narrow_cast
|
||||
#include <exception> // for std::exception
|
||||
namespace gsl
|
||||
{
|
||||
@@ -30,13 +30,12 @@ struct narrowing_error : public std::exception
|
||||
template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
|
||||
GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
|
||||
// in the static_cast below, and that gsl::narrow should be used instead.
|
||||
// Suppress this warning, since gsl::narrow is defined in terms of
|
||||
// static_cast
|
||||
// clang-format on
|
||||
constexpr T narrow(U u) noexcept(false)
|
||||
constexpr T narrow(U u)
|
||||
{
|
||||
constexpr const bool is_different_signedness =
|
||||
(std::is_signed<T>::value != std::is_signed<U>::value);
|
||||
@@ -67,9 +66,8 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
|
||||
template <class T, class U, typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
|
||||
// clang-format on
|
||||
constexpr T narrow(U u) noexcept(false)
|
||||
constexpr T narrow(U u)
|
||||
{
|
||||
const T t = narrow_cast<T>(u);
|
||||
|
||||
|
||||
+33
-20
@@ -17,14 +17,14 @@
|
||||
#ifndef GSL_POINTERS_H
|
||||
#define GSL_POINTERS_H
|
||||
|
||||
#include "assert" // for Ensures, Expects
|
||||
#include "./assert" // for Ensures, Expects
|
||||
#include "./util" // for GSL_DEPRECATED
|
||||
|
||||
#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 <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
|
||||
#include <utility> // for declval, forward
|
||||
|
||||
#if !defined(GSL_NO_IOSTREAMS)
|
||||
#include <iosfwd> // for ostream
|
||||
@@ -54,7 +54,7 @@ namespace details
|
||||
// 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,
|
||||
sizeof(T) <= 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
|
||||
const T,
|
||||
const T&>;
|
||||
|
||||
@@ -63,8 +63,11 @@ namespace details
|
||||
//
|
||||
// GSL.owner: ownership pointers
|
||||
//
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
template <typename... Ts>
|
||||
using shared_ptr GSL_DEPRECATED("Use std::shared_ptr instead") = std::shared_ptr<Ts...>;
|
||||
|
||||
template <typename... Ts>
|
||||
using unique_ptr GSL_DEPRECATED("Use std::unique_ptr instead") = std::unique_ptr<Ts...>;
|
||||
|
||||
//
|
||||
// owner
|
||||
@@ -76,7 +79,7 @@ using std::unique_ptr;
|
||||
// T must be a pointer type
|
||||
// - disallow construction from any type other than pointer type
|
||||
//
|
||||
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
|
||||
template <class T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
using owner = T;
|
||||
|
||||
//
|
||||
@@ -99,6 +102,8 @@ class not_null
|
||||
public:
|
||||
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
|
||||
|
||||
using element_type = T;
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
|
||||
{
|
||||
@@ -118,7 +123,7 @@ public:
|
||||
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&>()}))
|
||||
noexcept(noexcept(details::value_or_reference_return_t<T>(std::declval<T&>())))
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
@@ -140,10 +145,18 @@ public:
|
||||
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
|
||||
void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
|
||||
|
||||
private:
|
||||
T ptr_;
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
|
||||
void swap(not_null<T>& a, not_null<T>& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_not_null(T&& t) noexcept
|
||||
{
|
||||
@@ -160,7 +173,7 @@ std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
|
||||
#endif // !defined(GSL_NO_IOSTREAMS)
|
||||
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
constexpr auto operator==(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
|
||||
-> decltype(lhs.get() == rhs.get())
|
||||
{
|
||||
@@ -168,7 +181,7 @@ auto operator==(const not_null<T>& lhs,
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator!=(const not_null<T>& lhs,
|
||||
constexpr auto operator!=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
|
||||
-> decltype(lhs.get() != rhs.get())
|
||||
{
|
||||
@@ -176,7 +189,7 @@ auto operator!=(const not_null<T>& lhs,
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<(const not_null<T>& lhs,
|
||||
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()))
|
||||
{
|
||||
@@ -184,7 +197,7 @@ auto operator<(const not_null<T>& lhs,
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<=(const not_null<T>& lhs,
|
||||
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()))
|
||||
{
|
||||
@@ -192,7 +205,7 @@ auto operator<=(const not_null<T>& lhs,
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>(const not_null<T>& lhs,
|
||||
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()))
|
||||
{
|
||||
@@ -200,7 +213,7 @@ auto operator>(const not_null<T>& lhs,
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>=(const not_null<T>& lhs,
|
||||
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()))
|
||||
{
|
||||
@@ -268,19 +281,19 @@ class strict_not_null : public not_null<T>
|
||||
{
|
||||
public:
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr explicit strict_not_null(U&& u) : not_null<T>(std::forward<U>(u))
|
||||
constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::forward<U>(u))
|
||||
{}
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr explicit strict_not_null(T u) : not_null<T>(u)
|
||||
constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::move(u))
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const not_null<U>& other) : not_null<T>(other)
|
||||
constexpr strict_not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const strict_not_null<U>& other) : not_null<T>(other)
|
||||
constexpr strict_not_null(const strict_not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
// To avoid invalidating the "not null" invariant, the contained pointer is actually copied
|
||||
|
||||
+40
-21
@@ -17,10 +17,10 @@
|
||||
#ifndef GSL_SPAN_H
|
||||
#define GSL_SPAN_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
#include "byte" // for byte
|
||||
#include "span_ext" // for span specialization of gsl::at and other span-related extensions
|
||||
#include "util" // for narrow_cast
|
||||
#include "./assert" // for Expects
|
||||
#include "./byte" // for gsl::impl::byte
|
||||
#include "./span_ext" // for span specialization of gsl::at and other span-related extensions
|
||||
#include "./util" // for narrow_cast
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
|
||||
@@ -42,7 +42,7 @@
|
||||
#pragma warning(disable : 4702) // unreachable code
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
|
||||
#pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
|
||||
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
|
||||
|
||||
#endif // _MSC_VER
|
||||
@@ -53,7 +53,7 @@
|
||||
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||
|
||||
// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
|
||||
// GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
|
||||
// While there is a conversion from signed to unsigned, it happens at
|
||||
// compiletime, so the compiler wouldn't have to warn indiscriminately, but
|
||||
// could check if the source value actually doesn't fit into the target type
|
||||
@@ -63,6 +63,14 @@
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -132,7 +140,9 @@ namespace details
|
||||
|
||||
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
|
||||
{
|
||||
@@ -141,21 +151,18 @@ namespace details
|
||||
|
||||
constexpr reference operator*() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
return *current_;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
return current_;
|
||||
}
|
||||
constexpr span_iterator& operator++() noexcept
|
||||
{
|
||||
Expects(begin_ && current_ && end_);
|
||||
Expects(current_ < end_);
|
||||
Expects(current_ != end_);
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
@@ -172,8 +179,7 @@ namespace details
|
||||
|
||||
constexpr span_iterator& operator--() noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ < current_);
|
||||
Expects(begin_ != current_);
|
||||
--current_;
|
||||
return *this;
|
||||
}
|
||||
@@ -576,6 +582,8 @@ public:
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const noexcept
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"first() cannot extract more elements from a span than it contains.");
|
||||
Expects(Count <= size());
|
||||
return span<element_type, Count>{data(), Count};
|
||||
}
|
||||
@@ -586,6 +594,8 @@ public:
|
||||
// clang-format on
|
||||
constexpr span<element_type, Count> last() const noexcept
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"last() cannot extract more elements from a span than it contains.");
|
||||
Expects(Count <= size());
|
||||
return span<element_type, Count>{data() + (size() - Count), Count};
|
||||
}
|
||||
@@ -597,6 +607,9 @@ public:
|
||||
constexpr auto subspan() const noexcept ->
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
||||
{
|
||||
static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
|
||||
Count <= Extent - Offset)),
|
||||
"subspan() cannot extract more elements from a span than it contains.");
|
||||
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
|
||||
using type =
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
|
||||
@@ -811,28 +824,28 @@ namespace details
|
||||
|
||||
// [span.objectrep], views of object representation
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
using type = span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return type{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||
return type{reinterpret_cast<const gsl::impl::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent,
|
||||
std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
|
||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
using type = span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||
return type{reinterpret_cast<gsl::impl::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
@@ -846,4 +859,10 @@ as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
#pragma GCC diagnostic pop
|
||||
#endif // __GNUC__ > 6
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wunsafe-buffer-usage")
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __has_warning("-Wunsafe-buffer-usage")
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#endif // GSL_SPAN_H
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "assert" // GSL_KERNEL_MODE
|
||||
#include "util" // for narrow_cast, narrow
|
||||
#include "./assert" // GSL_KERNEL_MODE
|
||||
#include "./util" // for narrow_cast, narrow
|
||||
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <utility>
|
||||
@@ -123,14 +123,14 @@ constexpr span<const typename Container::value_type> make_span(const Container&
|
||||
}
|
||||
|
||||
template <class Ptr>
|
||||
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
|
||||
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>
|
||||
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
|
||||
GSL_DEPRECATED("This function is deprecated. See GSL issue #1092.")
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
|
||||
{
|
||||
return span<typename Ptr::element_type>(cont);
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#pragma message( \
|
||||
"This header will soon be removed. Use <gsl/zstring> instead of <gsl/string_span>")
|
||||
#include "zstring"
|
||||
+44
-1
@@ -17,7 +17,7 @@
|
||||
#ifndef GSL_UTIL_H
|
||||
#define GSL_UTIL_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
#include "./assert" // for Expects
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
@@ -40,6 +40,14 @@
|
||||
|
||||
#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
|
||||
@@ -52,6 +60,32 @@
|
||||
#define GSL_INLINE
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
#if __has_cpp_attribute(deprecated)
|
||||
#define GSL_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#endif // __has_cpp_attribute(deprecated)
|
||||
#endif // defined(__has_cpp_attribute)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#if defined(__cplusplus)
|
||||
#if __cplusplus >= 201309L
|
||||
#define GSL_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#endif // __cplusplus >= 201309L
|
||||
#endif // defined(__cplusplus)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#if defined(_MSC_VER)
|
||||
#define GSL_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#elif defined(__GNUC__)
|
||||
#define GSL_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#endif // defined(_MSC_VER)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
#if !defined(GSL_DEPRECATED)
|
||||
#define GSL_DEPRECATED(msg)
|
||||
#endif // !defined(GSL_DEPRECATED)
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
@@ -138,6 +172,9 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
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()])
|
||||
@@ -154,4 +191,10 @@ 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
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
#ifndef GSL_ZSTRING_H
|
||||
#define GSL_ZSTRING_H
|
||||
|
||||
#include "span_ext" // for dynamic_extent
|
||||
#include "./span_ext" // for dynamic_extent
|
||||
|
||||
#include <cstddef> // for size_t, nullptr_t
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
parameters:
|
||||
CXXVersions: [ 14, 17, 20 ]
|
||||
buildTypes: [ 'Debug', 'Release' ]
|
||||
image: ''
|
||||
|
||||
compiler: ''
|
||||
compilerVersions: ["default"] # if default value, simply uses whatever version is on the machine.
|
||||
# the text of this default value doesn't actually matter.
|
||||
setupfile: ''
|
||||
extraCmakeArgs: ''
|
||||
|
||||
jobs:
|
||||
- ${{ each compilerVersion in parameters.compilerVersions }}:
|
||||
- ${{ each CXXVersion in parameters.CXXVersions }}:
|
||||
- ${{ each buildType in parameters.buildTypes }}:
|
||||
- job:
|
||||
displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.image }}
|
||||
continueOnError: false
|
||||
|
||||
steps:
|
||||
- ${{ if not(eq(parameters.setupfile, '')) }}:
|
||||
- template: ${{ parameters.setupfile }}
|
||||
parameters:
|
||||
version: ${{ compilerVersion }}
|
||||
|
||||
- task: CMake@1
|
||||
name: Configure
|
||||
inputs:
|
||||
workingDirectory: build
|
||||
cmakeArgs: '-DGSL_CXX_STANDARD=${{ CXXVersion }} -DCMAKE_BUILD_TYPE=${{ buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ parameters.extraCmakeArgs }} .. '
|
||||
|
||||
- task: CMake@1
|
||||
name: Build
|
||||
inputs:
|
||||
workingDirectory: build
|
||||
cmakeArgs: '--build . '
|
||||
|
||||
- script: ctest . --output-on-failure --no-compress-output
|
||||
name: CTest
|
||||
workingDirectory: build
|
||||
failOnStderr: true
|
||||
@@ -1,9 +0,0 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
if [ "${{ parameters.version }}" != "default" ]; then sudo xcode-select -switch /Applications/Xcode_${{ parameters.version }}.app; fi
|
||||
|
||||
displayName: "Setup Xcode Version"
|
||||
failOnStderr: true
|
||||
@@ -1,13 +0,0 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
echo "##vso[task.setvariable variable=CXX;]${CXX}"
|
||||
echo "##vso[task.setvariable variable=CC;]${CC}"
|
||||
|
||||
displayName: "Setup Clang Version"
|
||||
failOnStderr: true
|
||||
env:
|
||||
CC: clang-${{ parameters.version }}
|
||||
CXX: clang++-${{ parameters.version }}
|
||||
@@ -1,14 +0,0 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
echo "##vso[task.setvariable variable=CXX;]${CXX}"
|
||||
echo "##vso[task.setvariable variable=CC;]${CC}"
|
||||
if [ "${{ parameters.version }}" = "11" ]; then sudo apt-get install $CXX; fi
|
||||
|
||||
displayName: "Setup GCC Version"
|
||||
failOnStderr: true
|
||||
env:
|
||||
CC: gcc-${{ parameters.version }}
|
||||
CXX: g++-${{ parameters.version }}
|
||||
+14
-10
@@ -110,6 +110,7 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
-Wno-shift-sign-overflow # GTest gtest-port.h
|
||||
-Wno-undef # GTest
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
-Wno-switch-default # GTest EXPECT_DEATH
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
|
||||
-Wno-unused-member-function
|
||||
-Wno-unused-variable
|
||||
@@ -123,11 +124,6 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
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()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config INTERFACE
|
||||
-fno-strict-aliasing
|
||||
@@ -151,6 +147,7 @@ else()
|
||||
-Wno-global-constructors # GTest
|
||||
-Wno-missing-prototypes
|
||||
-Wno-padded
|
||||
-Wno-switch-default
|
||||
-Wno-unknown-attributes
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
-Wno-weak-vtables
|
||||
@@ -191,6 +188,11 @@ 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
|
||||
@@ -202,8 +204,10 @@ add_executable(gsl_tests
|
||||
assertion_tests.cpp
|
||||
at_tests.cpp
|
||||
byte_tests.cpp
|
||||
constexpr_notnull_tests.cpp
|
||||
notnull_tests.cpp
|
||||
owner_tests.cpp
|
||||
pointers_tests.cpp
|
||||
span_compatibility_tests.cpp
|
||||
span_ext_tests.cpp
|
||||
span_tests.cpp
|
||||
@@ -262,11 +266,6 @@ if(MSVC) # MSVC or simulating MSVC
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
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()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE
|
||||
-fno-exceptions
|
||||
@@ -307,6 +306,11 @@ 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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 1b18723e874b256c1e39378c6774a90701d70f7a
|
||||
GIT_TAG v1.14.0
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
|
||||
@@ -188,7 +188,7 @@ TEST(algorithm_tests, incompatible_type)
|
||||
span<int> src_span_dyn(src);
|
||||
span<int, 4> src_span_static(src);
|
||||
span<int*> dst_span_dyn(dst);
|
||||
span<int*, 4> dst_span_static(dst);
|
||||
span<int*, 4> dst_span_static(gsl::make_span(dst));
|
||||
|
||||
// every line should produce a compilation error
|
||||
copy(src_span_dyn, dst_span_dyn);
|
||||
|
||||
+57
-13
@@ -16,8 +16,12 @@
|
||||
|
||||
#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;
|
||||
|
||||
@@ -33,28 +37,28 @@ int modify_both(gsl::byte& b, int& i)
|
||||
TEST(byte_tests, construction)
|
||||
{
|
||||
{
|
||||
const byte b = static_cast<byte>(4);
|
||||
const gsl::byte b = static_cast<gsl::byte>(4);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
|
||||
}
|
||||
|
||||
{
|
||||
const byte b = byte(12);
|
||||
const gsl::byte b = gsl::byte(12);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
{
|
||||
const byte b = to_byte<12>();
|
||||
const gsl::byte b = to_byte<12>();
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
{
|
||||
const unsigned char uc = 12;
|
||||
const byte b = to_byte(uc);
|
||||
const gsl::byte b = to_byte(uc);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
{
|
||||
const byte b{14};
|
||||
const gsl::byte b{14};
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
|
||||
}
|
||||
#endif
|
||||
@@ -63,14 +67,16 @@ TEST(byte_tests, construction)
|
||||
to_byte(char{});
|
||||
to_byte(3);
|
||||
to_byte(3u);
|
||||
to_byte<-1>();
|
||||
to_byte<256u>();
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(byte_tests, bitwise_operations)
|
||||
{
|
||||
const byte b = to_byte<0xFF>();
|
||||
const gsl::byte b = to_byte<0xFF>();
|
||||
|
||||
byte a = to_byte<0x00>();
|
||||
gsl::byte a = to_byte<0x00>();
|
||||
EXPECT_TRUE((b | a) == to_byte<0xFF>());
|
||||
EXPECT_TRUE(a == to_byte<0x00>());
|
||||
|
||||
@@ -104,7 +110,7 @@ TEST(byte_tests, bitwise_operations)
|
||||
|
||||
TEST(byte_tests, to_integer)
|
||||
{
|
||||
const byte b = to_byte<0x12>();
|
||||
const gsl::byte b = to_byte<0x12>();
|
||||
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<char>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<short>(b));
|
||||
@@ -123,12 +129,50 @@ TEST(byte_tests, to_integer)
|
||||
TEST(byte_tests, aliasing)
|
||||
{
|
||||
int i{0};
|
||||
const int res = modify_both(reinterpret_cast<byte&>(i), i);
|
||||
const int res = modify_both(reinterpret_cast<gsl::byte&>(i), i);
|
||||
EXPECT_TRUE(res == i);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
#endif
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool LShiftCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool LShiftCompilesFor<
|
||||
U, void_t<decltype(gsl::operator<< <float>(declval<gsl::byte>(), declval<U>()))>> = true;
|
||||
static_assert(!LShiftCompilesFor<float>, "!LShiftCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool RShiftCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool RShiftCompilesFor<
|
||||
U, void_t<decltype(gsl::operator>> <U>(declval<gsl::byte>(), declval<U>()))>> = true;
|
||||
static_assert(!RShiftCompilesFor<float>, "!RShiftCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool LShiftAssignCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool LShiftAssignCompilesFor<
|
||||
U, void_t<decltype(gsl::operator<<= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
|
||||
static_assert(!LShiftAssignCompilesFor<float>, "!LShiftAssignCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool RShiftAssignCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool RShiftAssignCompilesFor<
|
||||
U, void_t<decltype(gsl::operator>>= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
|
||||
static_assert(!RShiftAssignCompilesFor<float>, "!RShiftAssignCompilesFor<float>");
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool ToIntegerCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
ToIntegerCompilesFor<U, void_t<decltype(gsl::to_integer<U>(gsl::byte{}))>> = true;
|
||||
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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));
|
||||
}
|
||||
|
||||
+127
-37
@@ -18,17 +18,25 @@
|
||||
|
||||
#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 <typeinfo> // for type_info
|
||||
#include <variant> // for variant, monostate, get
|
||||
#include <algorithm> // for addressof
|
||||
#include <cstdint> // for uint16_t
|
||||
#include <memory> // for shared_ptr, make_shared, operator<, opera...
|
||||
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
|
||||
#include <string> // for basic_string, operator==, string, operator<<
|
||||
#include <type_traits> // for declval
|
||||
#include <typeinfo> // for type_info
|
||||
#include <variant> // for variant, monostate, get
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
using namespace gsl;
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
struct MyBase
|
||||
{
|
||||
};
|
||||
@@ -141,16 +149,39 @@ bool helper_const(not_null<const int*> p) { return *p == 12; }
|
||||
int* return_pointer() { return nullptr; }
|
||||
} // namespace
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_A = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_A<U, void_t<decltype(gsl::not_null<void*>{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, int N, typename = void>
|
||||
static constexpr bool CtorCompilesFor_B = false;
|
||||
template <typename U, int N>
|
||||
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::not_null<U>{N})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool DefaultCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::not_null<U>{})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_C = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_C<U, void_t<decltype(gsl::not_null<U*>{std::declval<std::unique_ptr<U>>()})>> =
|
||||
true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructors)
|
||||
{
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
not_null<int*> p = nullptr; // yay...does not compile!
|
||||
not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
|
||||
not_null<int*> p2; // yay...does not compile!
|
||||
std::unique_ptr<int> up = std::make_unique<int>(120);
|
||||
not_null<int*> p3 = up;
|
||||
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
|
||||
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
|
||||
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
|
||||
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
|
||||
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
// Forbid non-nullptr assignable types
|
||||
not_null<std::vector<int>> f(std::vector<int>{1});
|
||||
not_null<int> z(10);
|
||||
@@ -178,6 +209,14 @@ TEST(notnull_tests, TestNotNullConstructors)
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
// from pointer to local
|
||||
int t = 42;
|
||||
@@ -268,6 +307,27 @@ TEST(notnull_tests, TestNotNullostream)
|
||||
ostream_helper<std::string>("string");
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool AssignmentCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool
|
||||
AssignmentCompilesFor<U, V,
|
||||
void_t<decltype(std::declval<gsl::not_null<U*>&>().operator=(
|
||||
std::declval<gsl::not_null<V*>&>()))>> = true;
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool SCastCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool
|
||||
SCastCompilesFor<U, V, void_t<decltype(static_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> =
|
||||
true;
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool RCastCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool RCastCompilesFor<
|
||||
U, V, void_t<decltype(reinterpret_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> = true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullCasting)
|
||||
{
|
||||
MyBase base;
|
||||
@@ -280,15 +340,30 @@ TEST(notnull_tests, TestNotNullCasting)
|
||||
q = p; // allowed with heterogeneous copy ctor
|
||||
EXPECT_TRUE(q == p);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
q = u; // no viable conversion possible between MyBase* and Unrelated*
|
||||
p = q; // not possible to implicitly convert MyBase* to MyDerived*
|
||||
static_assert(AssignmentCompilesFor<MyBase, MyDerived>,
|
||||
"AssignmentCompilesFor<MyBase, MyDerived>");
|
||||
static_assert(!AssignmentCompilesFor<MyBase, Unrelated>,
|
||||
"!AssignmentCompilesFor<MyBase, Unrelated>");
|
||||
static_assert(!AssignmentCompilesFor<Unrelated, MyDerived>,
|
||||
"!AssignmentCompilesFor<Unrelated, MyDerived>");
|
||||
static_assert(!AssignmentCompilesFor<MyDerived, MyBase>,
|
||||
"!AssignmentCompilesFor<MyDerived, MyBase>");
|
||||
|
||||
static_assert(SCastCompilesFor<MyDerived, MyDerived>, "SCastCompilesFor<MyDerived, MyDerived>");
|
||||
static_assert(SCastCompilesFor<MyBase, MyDerived>, "SCastCompilesFor<MyBase, MyDerived>");
|
||||
static_assert(!SCastCompilesFor<MyDerived, MyBase>, "!SCastCompilesFor<MyDerived, MyBase>");
|
||||
static_assert(!SCastCompilesFor<Unrelated, MyDerived>,
|
||||
"!SCastCompilesFor<Unrelated, MyDerived>");
|
||||
static_assert(!RCastCompilesFor<MyDerived, MyDerived>,
|
||||
"!SCastCompilesFor<MyDerived, MyDerived>");
|
||||
static_assert(!RCastCompilesFor<Unrelated, MyDerived>,
|
||||
"!SCastCompilesFor<Unrelated, MyDerived>");
|
||||
|
||||
not_null<Unrelated*> r = p;
|
||||
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
|
||||
#endif
|
||||
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
|
||||
EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
|
||||
|
||||
(void) static_cast<MyDerived*>(p);
|
||||
(void) static_cast<MyBase*>(p);
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullAssignment)
|
||||
@@ -430,6 +505,18 @@ TEST(notnull_tests, TestNotNullCustomPtrComparison)
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool TypeDeductionCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
TypeDeductionCtorCompilesFor<U, void_t<decltype(not_null{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool TypeDeductionHelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
TypeDeductionHelperCompilesFor<U, void_t<decltype(helper(not_null{std::declval<U>()}))>> = true;
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
{
|
||||
{
|
||||
@@ -446,9 +533,9 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
const int i = 42;
|
||||
|
||||
not_null x{&i};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(not_null{&i});
|
||||
#endif
|
||||
static_assert(TypeDeductionHelperCompilesFor<int*>, "TypeDeductionHelperCompilesFor<int*>");
|
||||
static_assert(!TypeDeductionHelperCompilesFor<const int*>,
|
||||
"!TypeDeductionHelperCompilesFor<const int*>");
|
||||
helper_const(not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
@@ -470,9 +557,6 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
const int* p = &i;
|
||||
|
||||
not_null x{p};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(not_null{p});
|
||||
#endif
|
||||
helper_const(not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
@@ -507,12 +591,15 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
EXPECT_DEATH(helper_const(not_null{p}), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
not_null x{nullptr};
|
||||
helper(not_null{nullptr});
|
||||
helper_const(not_null{nullptr});
|
||||
}
|
||||
static_assert(TypeDeductionCtorCompilesFor<void*>, "TypeDeductionCtorCompilesFor<void*>");
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// Fails on gcc, clang, xcode, VS clang with
|
||||
// "error : no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to
|
||||
// disable this declaration"
|
||||
static_assert(!TypeDeductionCtorCompilesFor<std::nullptr_t>,
|
||||
"!TypeDeductionCtorCompilesFor<std::nullptr_t>");
|
||||
static_assert(!TypeDeductionHelperCompilesFor<std::nullptr_t>,
|
||||
"!TypeDeductionHelperCompilesFor<std::nullptr_t>");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -528,6 +615,11 @@ TEST(notnull_tests, TestVariantEmplace)
|
||||
}
|
||||
#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)
|
||||
{
|
||||
{
|
||||
@@ -544,9 +636,8 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
const int i = 42;
|
||||
|
||||
const auto x = make_not_null(&i);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(make_not_null(&i));
|
||||
#endif
|
||||
static_assert(HelperCompilesFor<gsl::not_null<int*>>,
|
||||
"HelperCompilesFor<gsl::not_null<int*>>");
|
||||
helper_const(make_not_null(&i));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
@@ -568,9 +659,8 @@ TEST(notnull_tests, TestMakeNotNull)
|
||||
const int* p = &i;
|
||||
|
||||
const auto x = make_not_null(p);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(make_not_null(p));
|
||||
#endif
|
||||
static_assert(!HelperCompilesFor<gsl::not_null<const int*>>,
|
||||
"!HelperCompilesFor<gsl::not_null<const int*>>");
|
||||
helper_const(make_not_null(p));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
|
||||
+16
-9
@@ -17,6 +17,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers> // for owner
|
||||
#include <type_traits> // for declval
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
@@ -32,12 +33,18 @@ TEST(owner_tests, basic_test)
|
||||
delete p;
|
||||
}
|
||||
|
||||
TEST(owner_tests, check_pointer_constraint)
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
owner<int> integerTest = 10;
|
||||
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool OwnerCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> =
|
||||
true;
|
||||
static_assert(OwnerCompilesFor<int*>, "OwnerCompilesFor<int*>");
|
||||
static_assert(!OwnerCompilesFor<int>, "!OwnerCompilesFor<int>");
|
||||
static_assert(!OwnerCompilesFor<std::shared_ptr<int>>, "!OwnerCompilesFor<std::shared_ptr<int>>");
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers>
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
namespace
|
||||
{
|
||||
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
|
||||
struct NotMoveAssignableCustomPtr
|
||||
{
|
||||
NotMoveAssignableCustomPtr() = default;
|
||||
NotMoveAssignableCustomPtr(const NotMoveAssignableCustomPtr&) = default;
|
||||
NotMoveAssignableCustomPtr& operator=(const NotMoveAssignableCustomPtr&) = default;
|
||||
NotMoveAssignableCustomPtr(NotMoveAssignableCustomPtr&&) = default;
|
||||
NotMoveAssignableCustomPtr& operator=(NotMoveAssignableCustomPtr&&) = delete;
|
||||
|
||||
bool operator!=(std::nullptr_t) const { return true; }
|
||||
|
||||
int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
|
||||
};
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool SwapCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
|
||||
std::declval<gsl::not_null<U>&>()))>> = true;
|
||||
|
||||
TEST(pointers_test, swap)
|
||||
{
|
||||
// taken from gh-1129:
|
||||
{
|
||||
gsl::not_null<std::unique_ptr<int>> a(std::make_unique<int>(0));
|
||||
gsl::not_null<std::unique_ptr<int>> b(std::make_unique<int>(1));
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
|
||||
// Make sure our custom ptr can be used with not_null. The shared_pr is to prevent "unused"
|
||||
// compiler warnings.
|
||||
const auto shared_custom_ptr{std::make_shared<NotMoveAssignableCustomPtr>()};
|
||||
gsl::not_null<NotMoveAssignableCustomPtr> c{*shared_custom_ptr};
|
||||
EXPECT_TRUE(c.get() != nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
gsl::strict_not_null<std::unique_ptr<int>> a{std::make_unique<int>(0)};
|
||||
gsl::strict_not_null<std::unique_ptr<int>> b{std::make_unique<int>(1)};
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
}
|
||||
|
||||
{
|
||||
gsl::not_null<std::unique_ptr<int>> a{std::make_unique<int>(0)};
|
||||
gsl::strict_not_null<std::unique_ptr<int>> b{std::make_unique<int>(1)};
|
||||
|
||||
EXPECT_TRUE(*a == 0);
|
||||
EXPECT_TRUE(*b == 1);
|
||||
|
||||
gsl::swap(a, b);
|
||||
|
||||
EXPECT_TRUE(*a == 1);
|
||||
EXPECT_TRUE(*b == 0);
|
||||
}
|
||||
|
||||
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
|
||||
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
|
||||
}
|
||||
|
||||
TEST(pointers_test, member_types)
|
||||
{
|
||||
static_assert(std::is_same<gsl::not_null<int*>::element_type, int*>::value,
|
||||
"check member type: element_type");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -519,7 +519,7 @@ TEST(span_compatibility_tests, assertion_tests)
|
||||
|
||||
// assertions for span's definition
|
||||
static_assert(std::is_same<decltype(gsl::dynamic_extent), const std::size_t>::value,
|
||||
"gsl::dynamic_extent must be respresented as std::size_t");
|
||||
"gsl::dynamic_extent must be represented as std::size_t");
|
||||
static_assert(gsl::dynamic_extent == static_cast<std::size_t>(-1),
|
||||
"gsl::dynamic_extent must be defined as the max value of std::size_t");
|
||||
|
||||
@@ -1005,12 +1005,18 @@ static_assert(std::is_convertible<const std::array<int, 3>&, gsl::span<const int
|
||||
"std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>");
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool AsWritableBytesCompilesFor = false;
|
||||
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
|
||||
AsWritableBytesCompilesFor<U, ::void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
|
||||
|
||||
static_assert(AsWritableBytesCompilesFor<gsl::span<int>>,
|
||||
"AsWritableBytesCompilesFor<gsl::span<int>>");
|
||||
@@ -1020,4 +1026,3 @@ static_assert(!AsWritableBytesCompilesFor<gsl::span<const int>>,
|
||||
"!AsWritableBytesCompilesFor<gsl::span<const int>>");
|
||||
static_assert(!AsWritableBytesCompilesFor<gsl::span<const int, 9>>,
|
||||
"!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
|
||||
#endif // __cplusplus >= 201703l
|
||||
|
||||
+347
-304
@@ -48,6 +48,13 @@
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
#if __cplusplus >= 201703l
|
||||
using std::void_t;
|
||||
#else // __cplusplus >= 201703l
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
#endif // __cplusplus < 201703l
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -62,8 +69,7 @@ struct AddressOverloaded
|
||||
#if (__cplusplus > 201402L)
|
||||
[[maybe_unused]]
|
||||
#endif
|
||||
AddressOverloaded
|
||||
operator&() const
|
||||
AddressOverloaded operator&() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -216,6 +222,12 @@ TEST(span_test, from_pointer_length_constructor)
|
||||
|
||||
TEST(span_test, from_pointer_pointer_construction)
|
||||
{
|
||||
// const auto terminateHandler = std::set_terminate([] {
|
||||
// std::cerr << "Expected Death. from_pointer_pointer_construction";
|
||||
// std::abort();
|
||||
// });
|
||||
// const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
int arr[4] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
@@ -245,19 +257,11 @@ TEST(span_test, from_pointer_pointer_construction)
|
||||
EXPECT_TRUE(s.data() == &arr[0]);
|
||||
}
|
||||
|
||||
// this will fail the std::distance() precondition, which asserts on MSVC debug builds
|
||||
//{
|
||||
//{ // this test succeeds on all platforms, gsl::span is more relaxed than std::span where this would be UB
|
||||
// auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; };
|
||||
// EXPECT_DEATH(workaround_macro(), expected);
|
||||
//}
|
||||
|
||||
// this will fail the std::distance() precondition, which asserts on MSVC debug builds
|
||||
//{
|
||||
// int* p = nullptr;
|
||||
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
|
||||
// EXPECT_DEATH(workaround_macro(), expected);
|
||||
//}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
span<int> s{p, p};
|
||||
@@ -271,19 +275,21 @@ TEST(span_test, from_pointer_pointer_construction)
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == nullptr);
|
||||
}
|
||||
|
||||
// this will fail the std::distance() precondition, which asserts on MSVC debug builds
|
||||
//{
|
||||
// int* p = nullptr;
|
||||
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
|
||||
// EXPECT_DEATH(workaround_macro(), expected);
|
||||
//}
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool CtorCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool CtorCompilesFor<U, V, void_t<decltype(U{std::declval<V>()})>> = true;
|
||||
|
||||
TEST(span_test, from_array_constructor)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
|
||||
static_assert(!CtorCompilesFor<span<int, 6>, int[5]>, "!CtorCompilesFor<span<int, 6>, int[5]>");
|
||||
static_assert(!CtorCompilesFor<span<int, 0>, int[5]>, "!CtorCompilesFor<span<int, 0>, int[5]>");
|
||||
static_assert(!CtorCompilesFor<span<int>, int[2][3]>, "!CtorCompilesFor<span<int>, int[2][3]>");
|
||||
|
||||
{
|
||||
const span<int> s{arr};
|
||||
EXPECT_TRUE(s.size() == 5);
|
||||
@@ -298,70 +304,28 @@ TEST(span_test, from_array_constructor)
|
||||
|
||||
int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<int, 6> s{arr};
|
||||
}
|
||||
static_assert(!CtorCompilesFor<span<int, 0>, int[2][3]>,
|
||||
"!CtorCompilesFor<span<int, 0>, int[2][3]>");
|
||||
static_assert(!CtorCompilesFor<span<int, 6>, int[2][3]>,
|
||||
"!CtorCompilesFor<span<int, 6>, int[2][3]>");
|
||||
|
||||
{
|
||||
span<int, 0> s{arr};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == &arr[0]);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s{arr2d};
|
||||
EXPECT_TRUE(s.size() == 6);
|
||||
EXPECT_TRUE(s.data() == &arr2d[0][0]);
|
||||
EXPECT_TRUE(s[0] == 1);
|
||||
EXPECT_TRUE(s[5] == 6);
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 0> s{arr2d};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == &arr2d[0][0]);
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 6> s{arr2d};
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const span<int[3]> s{std::addressof(arr2d[0]), 1};
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
|
||||
}
|
||||
|
||||
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
int arr3d[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<int> s{arr3d};
|
||||
EXPECT_TRUE(s.size() == 12);
|
||||
EXPECT_TRUE(s.data() == &arr3d[0][0][0]);
|
||||
EXPECT_TRUE(s[0] == 1);
|
||||
EXPECT_TRUE(s[11] == 12);
|
||||
}
|
||||
static_assert(!CtorCompilesFor<span<int>, int[2][3][2]>,
|
||||
"!CtorCompilesFor<span<int>, int[2][3][2]>");
|
||||
static_assert(!CtorCompilesFor<span<int, 0>, int[2][3][2]>,
|
||||
"!CtorCompilesFor<span<int, 0>, int[2][3][2]>");
|
||||
static_assert(!CtorCompilesFor<span<int, 11>, int[2][3][2]>,
|
||||
"!CtorCompilesFor<span<int, 11>, int[2][3][2]>");
|
||||
static_assert(!CtorCompilesFor<span<int, 12>, int[2][3][2]>,
|
||||
"!CtorCompilesFor<span<int, 12>, int[2][3][2]>");
|
||||
|
||||
{
|
||||
span<int, 0> s{arr3d};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == &arr3d[0][0][0]);
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 11> s{arr3d};
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 12> s{arr3d};
|
||||
EXPECT_TRUE(s.size() == 12);
|
||||
EXPECT_TRUE(s.data() == &arr3d[0][0][0]);
|
||||
EXPECT_TRUE(s[0] == 1);
|
||||
EXPECT_TRUE(s[5] == 6);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const span<int[3][2]> s{std::addressof(arr3d[0]), 1};
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
@@ -389,6 +353,13 @@ TEST(span_test, from_dynamic_array_constructor)
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename = void>
|
||||
static constexpr bool ConversionCompilesFor = false;
|
||||
template <typename U, typename V>
|
||||
static constexpr bool
|
||||
ConversionCompilesFor<U, V, void_t<decltype(std::declval<void (*)(U)>()(std::declval<V>()))>> =
|
||||
true;
|
||||
|
||||
TEST(span_test, from_std_array_constructor)
|
||||
{
|
||||
std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
@@ -428,43 +399,31 @@ TEST(span_test, from_std_array_constructor)
|
||||
EXPECT_TRUE(ao_arr.data() == fs.data());
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<int, 2> s{arr};
|
||||
EXPECT_TRUE(s.size() == 2);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
static_assert(!CtorCompilesFor<span<int, 2>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<int, 2>, std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>");
|
||||
|
||||
span<const int, 2> cs{arr};
|
||||
EXPECT_TRUE(cs.size() == 2);
|
||||
EXPECT_TRUE(cs.data() == arr.data());
|
||||
}
|
||||
static_assert(!CtorCompilesFor<span<int, 0>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<int, 0>, std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>");
|
||||
|
||||
{
|
||||
span<int, 0> s{arr};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
static_assert(!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>");
|
||||
|
||||
span<const int, 0> cs{arr};
|
||||
EXPECT_TRUE(cs.size() == 0);
|
||||
EXPECT_TRUE(cs.data() == arr.data());
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 5> s{arr};
|
||||
}
|
||||
|
||||
{
|
||||
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
|
||||
auto take_a_span = [](span<int> s) { static_cast<void>(s); };
|
||||
// try to take a temporary std::array
|
||||
take_a_span(get_an_array());
|
||||
}
|
||||
#if !defined(_MSC_VER) || (_MSC_VER > 1943) || (__cplusplus >= 201703L)
|
||||
// Fails on "Visual Studio 16 2019/Visual Studio 17 2022, windows-2019/2022, Debug/Release, 14".
|
||||
static_assert(!ConversionCompilesFor<span<int>, std::array<int, 4>>,
|
||||
"!ConversionCompilesFor<span<int>, std::array<int, 4>>");
|
||||
#endif
|
||||
|
||||
{
|
||||
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
|
||||
auto take_a_span = [](span<const int> s) { static_cast<void>(s); };
|
||||
auto take_a_span = [](span<const int>) {};
|
||||
// try to take a temporary std::array
|
||||
static_assert(ConversionCompilesFor<span<const int>, std::array<int, 4>>,
|
||||
"ConversionCompilesFor<span<const int>, std::array<int, 4>>");
|
||||
take_a_span(get_an_array());
|
||||
}
|
||||
}
|
||||
@@ -493,23 +452,12 @@ TEST(span_test, from_const_std_array_constructor)
|
||||
EXPECT_TRUE(s.data() == ao_arr.data());
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<const int, 2> s{arr};
|
||||
EXPECT_TRUE(s.size() == 2);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
{
|
||||
span<const int, 0> s{arr};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
{
|
||||
span<const int, 5> s{arr};
|
||||
}
|
||||
#endif
|
||||
static_assert(!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>");
|
||||
|
||||
{
|
||||
auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; };
|
||||
@@ -535,27 +483,14 @@ TEST(span_test, from_std_array_const_constructor)
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<const int, 2> s{arr};
|
||||
EXPECT_TRUE(s.size() == 2);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
{
|
||||
span<const int, 0> s{arr};
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
{
|
||||
span<const int, 5> s{arr};
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 4> s{arr};
|
||||
}
|
||||
#endif
|
||||
static_assert(!CtorCompilesFor<span<const int, 2>, const std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 2>, const std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<const int, 0>, const std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 0>, const std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<const int, 5>, const std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<const int, 5>, const std::array<int, 4>&>");
|
||||
static_assert(!CtorCompilesFor<span<int, 5>, const std::array<int, 4>&>,
|
||||
"!CtorCompilesFor<span<int, 5>, const std::array<int, 4>&>");
|
||||
}
|
||||
|
||||
TEST(span_test, from_container_constructor)
|
||||
@@ -577,32 +512,28 @@ TEST(span_test, from_container_constructor)
|
||||
const std::string cstr = "hello";
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
span<char> s{str};
|
||||
EXPECT_TRUE(s.size() == str.size());
|
||||
EXPECT_TRUE(s.data() == str.data()));
|
||||
#endif
|
||||
span<const char> cs{str};
|
||||
EXPECT_TRUE(cs.size() == str.size());
|
||||
EXPECT_TRUE(cs.data() == str.data());
|
||||
static_assert(CtorCompilesFor<span<char>, std::string&> == (__cplusplus >= 201703L),
|
||||
"CtorCompilesFor<span<char>, std::string&> == (__cplusplus >= 201703L)");
|
||||
|
||||
span<const char> cs{str};
|
||||
EXPECT_TRUE(cs.size() == str.size());
|
||||
EXPECT_TRUE(cs.data() == str.data());
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
span<char> s{cstr};
|
||||
#endif
|
||||
static_assert(!CtorCompilesFor<span<char>, const std::string&>,
|
||||
"!CtorCompilesFor<span<char>, const std::string&>");
|
||||
|
||||
span<const char> cs{cstr};
|
||||
EXPECT_TRUE(cs.size() == cstr.size());
|
||||
EXPECT_TRUE(cs.data() == cstr.data());
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
auto get_temp_vector = []() -> std::vector<int> { return {}; };
|
||||
auto use_span = [](span<int> s) { static_cast<void>(s); };
|
||||
use_span(get_temp_vector());
|
||||
#endif
|
||||
}
|
||||
#if !defined(_MSC_VER) || (_MSC_VER > 1943) || (__cplusplus >= 201703L)
|
||||
// Fails on "Visual Studio 16 2019/Visual Studio 17 2022, windows-2019/2022, Debug/Release, 14".
|
||||
static_assert(!ConversionCompilesFor<span<int>, std::vector<int>>,
|
||||
"!ConversionCompilesFor<span<int>, std::vector<int>>");
|
||||
#endif // !defined(_MSC_VER) || (_MSC_VER > 1942) || (__cplusplus >= 201703L)
|
||||
|
||||
{
|
||||
auto get_temp_vector = []() -> std::vector<int> { return {}; };
|
||||
@@ -610,13 +541,8 @@ TEST(span_test, from_container_constructor)
|
||||
use_span(get_temp_vector());
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
auto get_temp_string = []() -> std::string { return {}; };
|
||||
auto use_span = [](span<char> s) { static_cast<void>(s); };
|
||||
use_span(get_temp_string());
|
||||
#endif
|
||||
}
|
||||
static_assert(!ConversionCompilesFor<span<char>, std::string>,
|
||||
"!ConversionCompilesFor<span<char>, std::string>");
|
||||
|
||||
{
|
||||
auto get_temp_string = []() -> std::string { return {}; };
|
||||
@@ -624,13 +550,10 @@ TEST(span_test, from_container_constructor)
|
||||
use_span(get_temp_string());
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
auto get_temp_vector = []() -> const std::vector<int> { return {}; };
|
||||
auto use_span = [](span<const char> s) { static_cast<void>(s); };
|
||||
use_span(get_temp_vector());
|
||||
#endif
|
||||
}
|
||||
static_assert(!ConversionCompilesFor<span<const char>, const std::vector<int>>,
|
||||
"!ConversionCompilesFor<span<const char>, const std::vector<int>>");
|
||||
static_assert(!ConversionCompilesFor<span<char>, const std::string>,
|
||||
"!ConversionCompilesFor<span<char>, const std::string>");
|
||||
|
||||
{
|
||||
auto get_temp_string = []() -> const std::string { return {}; };
|
||||
@@ -638,12 +561,8 @@ TEST(span_test, from_container_constructor)
|
||||
use_span(get_temp_string());
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
std::map<int, int> m;
|
||||
span<int> s{m};
|
||||
#endif
|
||||
}
|
||||
static_assert(!CtorCompilesFor<span<int>, std::map<int, int>&>,
|
||||
"!CtorCompilesFor<span<int>, std::map<int, int>&>");
|
||||
}
|
||||
|
||||
TEST(span_test, from_convertible_span_constructor)
|
||||
@@ -695,52 +614,20 @@ TEST(span_test, from_convertible_span_constructor)
|
||||
EXPECT_DEATH(T{avd}, expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
std::array<DerivedClass, 2> arr{};
|
||||
span<DerivedClass> avd{arr};
|
||||
span<const DerivedClass, 2> avcd = avd;
|
||||
static_cast<void>(avcd);
|
||||
}
|
||||
|
||||
{
|
||||
std::array<DerivedClass, 2> arr{};
|
||||
span<DerivedClass, 2> avd{arr};
|
||||
span<const DerivedClass, 1> avcd = avd;
|
||||
static_cast<void>(avcd);
|
||||
}
|
||||
|
||||
{
|
||||
std::array<DerivedClass, 2> arr{};
|
||||
span<DerivedClass, 2> avd{arr};
|
||||
span<const DerivedClass, 3> avcd = avd;
|
||||
static_cast<void>(avcd);
|
||||
}
|
||||
|
||||
{
|
||||
span<DerivedClass> avd;
|
||||
span<BaseClass> avb = avd;
|
||||
static_cast<void>(avb);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
span<unsigned int> s2 = s;
|
||||
static_cast<void>(s2);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
span<const unsigned int> s2 = s;
|
||||
static_cast<void>(s2);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
span<short> s2 = s;
|
||||
static_cast<void>(s2);
|
||||
}
|
||||
#endif
|
||||
static_assert(!ConversionCompilesFor<span<const DerivedClass, 2>, span<DerivedClass>&>,
|
||||
"!ConversionCompilesFor<span<const DerivedClass, 2>, span<DerivedClass>&>");
|
||||
static_assert(!ConversionCompilesFor<span<const DerivedClass, 1>, span<DerivedClass, 2>&>,
|
||||
"!ConversionCompilesFor<span<const DerivedClass, 1>, span<DerivedClass, 2>&>");
|
||||
static_assert(!ConversionCompilesFor<span<const DerivedClass, 3>, span<DerivedClass, 2>&>,
|
||||
"!ConversionCompilesFor<span<const DerivedClass, 3>, span<DerivedClass, 2>&>");
|
||||
static_assert(!ConversionCompilesFor<span<BaseClass, 3>, span<DerivedClass>&>,
|
||||
"!ConversionCompilesFor<span<BaseClass, 3>, span<DerivedClass>&>");
|
||||
static_assert(!ConversionCompilesFor<span<unsigned int>, span<int>&>,
|
||||
"!ConversionCompilesFor<span<unsigned int>, span<int>&>");
|
||||
static_assert(!ConversionCompilesFor<span<const unsigned int>, span<int>&>,
|
||||
"!ConversionCompilesFor<span<const unsigned int>, span<int>&>");
|
||||
static_assert(!ConversionCompilesFor<span<short>, span<int>&>,
|
||||
"!ConversionCompilesFor<span<short>, span<int>&>");
|
||||
}
|
||||
|
||||
TEST(span_test, copy_move_and_assignment)
|
||||
@@ -800,10 +687,9 @@ TEST(span_test, first)
|
||||
{
|
||||
span<int, 5> av = arr;
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
EXPECT_TRUE(av.first<6>().size() == 6);
|
||||
EXPECT_TRUE(av.first<-1>().size() == -1);
|
||||
(void) av.first<6>();
|
||||
#endif
|
||||
EXPECT_DEATH(av.first(6).size(), expected);
|
||||
EXPECT_DEATH(av.first(6), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -844,9 +730,9 @@ TEST(span_test, last)
|
||||
{
|
||||
span<int, 5> av = arr;
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
EXPECT_TRUE(av.last<6>().size() == 6);
|
||||
(void) av.last<6>();
|
||||
#endif
|
||||
EXPECT_DEATH(av.last(6).size(), expected);
|
||||
EXPECT_DEATH(av.last(6), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -871,6 +757,9 @@ TEST(span_test, subspan)
|
||||
EXPECT_TRUE((av.subspan<2, 2>().size()) == 2);
|
||||
EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2);
|
||||
EXPECT_TRUE(av.subspan(2, 2).size() == 2);
|
||||
|
||||
EXPECT_TRUE((av.subspan<2, 3>().size()) == 3);
|
||||
EXPECT_TRUE(decltype(av.subspan<2, 3>())::extent == 3);
|
||||
EXPECT_TRUE(av.subspan(2, 3).size() == 3);
|
||||
}
|
||||
|
||||
@@ -887,8 +776,12 @@ TEST(span_test, subspan)
|
||||
EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5);
|
||||
EXPECT_TRUE(av.subspan(0, 5).size() == 5);
|
||||
|
||||
EXPECT_DEATH(av.subspan(0, 6).size(), expected);
|
||||
EXPECT_DEATH(av.subspan(1, 5).size(), expected);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
(void) av.subspan<0, 6>();
|
||||
(void) av.subspan<1, 5>();
|
||||
#endif
|
||||
EXPECT_DEATH(av.subspan(0, 6), expected);
|
||||
EXPECT_DEATH(av.subspan(1, 5), expected);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -896,14 +789,22 @@ TEST(span_test, subspan)
|
||||
EXPECT_TRUE((av.subspan<4, 0>().size()) == 0);
|
||||
EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0);
|
||||
EXPECT_TRUE(av.subspan(4, 0).size() == 0);
|
||||
|
||||
EXPECT_TRUE((av.subspan<5, 0>().size()) == 0);
|
||||
EXPECT_TRUE(decltype(av.subspan<5, 0>())::extent == 0);
|
||||
EXPECT_TRUE(av.subspan(5, 0).size() == 0);
|
||||
EXPECT_DEATH(av.subspan(6, 0).size(), expected);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
(void) av.subspan<6, 0>();
|
||||
#endif
|
||||
EXPECT_DEATH(av.subspan(6, 0), expected);
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 5> av = arr;
|
||||
EXPECT_TRUE(av.subspan<1>().size() == 4);
|
||||
EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4);
|
||||
EXPECT_TRUE(av.subspan(1).size() == 4);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -911,35 +812,58 @@ TEST(span_test, subspan)
|
||||
EXPECT_TRUE((av.subspan<0, 0>().size()) == 0);
|
||||
EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0);
|
||||
EXPECT_TRUE(av.subspan(0, 0).size() == 0);
|
||||
EXPECT_DEATH((av.subspan<1, 0>().size()), expected);
|
||||
|
||||
EXPECT_DEATH((av.subspan<1, 0>()), expected);
|
||||
EXPECT_DEATH((av.subspan(1, 0)), expected);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> av;
|
||||
EXPECT_TRUE((av.subspan<0>().size()) == 0);
|
||||
EXPECT_TRUE(decltype(av.subspan<0>())::extent == dynamic_extent);
|
||||
EXPECT_TRUE(av.subspan(0).size() == 0);
|
||||
EXPECT_DEATH(av.subspan(1).size(), expected);
|
||||
|
||||
EXPECT_DEATH(av.subspan<1>(), expected);
|
||||
EXPECT_TRUE(decltype(av.subspan<1>())::extent == dynamic_extent);
|
||||
EXPECT_DEATH(av.subspan(1), expected);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> av = arr;
|
||||
EXPECT_TRUE(av.subspan(0).size() == 5);
|
||||
EXPECT_TRUE(av.subspan<0>().size() == 5);
|
||||
EXPECT_TRUE(av.subspan(1).size() == 4);
|
||||
EXPECT_TRUE(av.subspan<1>().size() == 4);
|
||||
EXPECT_TRUE(av.subspan(4).size() == 1);
|
||||
EXPECT_TRUE(av.subspan<4>().size() == 1);
|
||||
EXPECT_TRUE(av.subspan(5).size() == 0);
|
||||
EXPECT_DEATH(av.subspan(6).size(), expected);
|
||||
EXPECT_TRUE(av.subspan<5>().size() == 0);
|
||||
EXPECT_DEATH(av.subspan(6), expected);
|
||||
EXPECT_DEATH(av.subspan<6>(), expected);
|
||||
const auto av2 = av.subspan(1);
|
||||
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
|
||||
const auto av3 = av.subspan<1>();
|
||||
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av3[i] == static_cast<int>(i) + 2);
|
||||
}
|
||||
|
||||
{
|
||||
span<int, 5> av = arr;
|
||||
EXPECT_TRUE(av.subspan(0).size() == 5);
|
||||
EXPECT_TRUE(av.subspan<0>().size() == 5);
|
||||
EXPECT_TRUE(av.subspan(1).size() == 4);
|
||||
EXPECT_TRUE(av.subspan<1>().size() == 4);
|
||||
EXPECT_TRUE(av.subspan(4).size() == 1);
|
||||
EXPECT_TRUE(av.subspan<4>().size() == 1);
|
||||
EXPECT_TRUE(av.subspan(5).size() == 0);
|
||||
EXPECT_DEATH(av.subspan(6).size(), expected);
|
||||
EXPECT_TRUE(av.subspan<5>().size() == 0);
|
||||
EXPECT_DEATH(av.subspan(6), expected);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
EXPECT_DEATH(av.subspan<6>(), expected);
|
||||
#endif
|
||||
const auto av2 = av.subspan(1);
|
||||
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
|
||||
const auto av3 = av.subspan<1>();
|
||||
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av3[i] == static_cast<int>(i) + 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,9 +1038,21 @@ TEST(span_test, rbegin_rend)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool AsWritableBytesCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(std::declval<U>()))>> = true;
|
||||
|
||||
TEST(span_test, as_bytes)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
|
||||
static_assert(AsWritableBytesCompilesFor<span<int>>, "AsWriteableBytesCompilesFor<span<int>>");
|
||||
// you should not be able to get writeable bytes for const objects
|
||||
static_assert(!AsWritableBytesCompilesFor<span<const int>>,
|
||||
"!AsWriteableBytesCompilesFor<span<const int>>");
|
||||
|
||||
{
|
||||
const span<const int> s = a;
|
||||
EXPECT_TRUE(s.size() == 4);
|
||||
@@ -1147,17 +1083,6 @@ TEST(span_test, as_writable_bytes)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
// you should not be able to get writeable bytes for const objects
|
||||
span<const int> s = a;
|
||||
EXPECT_TRUE(s.size() == 4);
|
||||
span<const byte> bs = as_writable_bytes(s);
|
||||
EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
|
||||
EXPECT_TRUE(bs.size() == s.size_bytes());
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
const auto bs = as_writable_bytes(s);
|
||||
@@ -1197,30 +1122,15 @@ TEST(span_test, fixed_size_conversions)
|
||||
static_cast<void>(s);
|
||||
}
|
||||
|
||||
// initialization or assignment to static span that REDUCES size is NOT ok
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<int, 2> s = arr;
|
||||
}
|
||||
{
|
||||
span<int, 2> s2 = s4;
|
||||
static_cast<void>(s2);
|
||||
}
|
||||
#endif
|
||||
// initialization or assignment to static span that REDUCES size is NOT ok
|
||||
static_assert(!ConversionCompilesFor<span<int, 2>, int[4]>,
|
||||
"!ConversionCompilesFor<span<int, 2>, int[4]>");
|
||||
static_assert(!ConversionCompilesFor<span<int, 2>, span<int, 4>>,
|
||||
"!ConversionCompilesFor<span<int, 2>, span<int, 4>>");
|
||||
|
||||
// even when done dynamically
|
||||
{
|
||||
/*
|
||||
// this now results in a compile-time error, rather than runtime.
|
||||
// There is no suitable conversion from dynamic span to fixed span.
|
||||
span<int> s = arr;
|
||||
auto f = [&]() {
|
||||
const span<int, 2> s2 = s;
|
||||
static_cast<void>(s2);
|
||||
};
|
||||
EXPECT_DEATH(f(), expected);
|
||||
*/
|
||||
}
|
||||
static_assert(!ConversionCompilesFor<span<int, 2>, span<int>>,
|
||||
"!ConversionCompilesFor<span<int, 2>, span<int>>");
|
||||
|
||||
// but doing so explicitly is ok
|
||||
|
||||
@@ -1234,32 +1144,24 @@ TEST(span_test, fixed_size_conversions)
|
||||
static_cast<void>(s1);
|
||||
}
|
||||
|
||||
/*
|
||||
// this is not a legal operation in std::span, so we are no longer supporting it
|
||||
// conversion from span<int, 4> to span<int, dynamic_extent> via call to `first`
|
||||
// then convert from span<int, dynamic_extent> to span<int, 1>
|
||||
// The dynamic to fixed extents are not supported in the standard
|
||||
// to make this work, span<int, 1> would need to be span<int>.
|
||||
{
|
||||
|
||||
// NB: implicit conversion to span<int,1> from span<int>
|
||||
span<int, 1> s1 = s4.first(1);
|
||||
static_cast<void>(s1);
|
||||
}
|
||||
*/
|
||||
// this is not a legal operation in std::span, so we are no longer supporting it
|
||||
// conversion from span<int, 4> to span<int, dynamic_extent> via call to `first`
|
||||
// then convert from span<int, dynamic_extent> to span<int, 1>
|
||||
// The dynamic to fixed extents are not supported in the standard
|
||||
// to make this work, span<int, 1> would need to be span<int>.
|
||||
static_assert(!ConversionCompilesFor<span<int, 1>, span<int>>,
|
||||
"!ConversionCompilesFor<span<int, 1>, span<int>>");
|
||||
|
||||
// initialization or assignment to static span that requires size INCREASE is not ok.
|
||||
int arr2[2] = {1, 2};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
span<int, 4> s3 = arr2;
|
||||
}
|
||||
{
|
||||
span<int, 2> s2 = arr2;
|
||||
span<int, 4> s4a = s2;
|
||||
}
|
||||
#endif
|
||||
static_assert(!ConversionCompilesFor<span<int, 4>, int[2]>,
|
||||
"!ConversionCompilesFor<span<int, 4>, int[2]>");
|
||||
static_assert(!ConversionCompilesFor<span<int, 2>, int[2]>,
|
||||
"!ConversionCompilesFor<span<int, 2>, int[2]>");
|
||||
static_assert(!ConversionCompilesFor<span<int, 4>, span<int, 2>>,
|
||||
"!ConversionCompilesFor<span<int, 4>, span<int, 2>>");
|
||||
|
||||
{
|
||||
auto f = [&]() {
|
||||
const span<int, 4> _s4{arr2, 2};
|
||||
@@ -1268,16 +1170,11 @@ TEST(span_test, fixed_size_conversions)
|
||||
EXPECT_DEATH(f(), expected);
|
||||
}
|
||||
|
||||
/*
|
||||
// This no longer compiles. There is no suitable conversion from dynamic span to a fixed size
|
||||
span.
|
||||
// this should fail - we are trying to assign a small dynamic span to a fixed_size larger one
|
||||
span<int> av = arr2; auto f = [&]() {
|
||||
const span<int, 4> _s4 = av;
|
||||
static_cast<void>(_s4);
|
||||
};
|
||||
EXPECT_DEATH(f(), expected);
|
||||
*/
|
||||
// This no longer compiles. There is no suitable conversion from dynamic span to a fixed size
|
||||
// span.
|
||||
// this should fail - we are trying to assign a small dynamic span to a fixed_size larger one
|
||||
static_assert(!ConversionCompilesFor<span<int, 4>, span<int>>,
|
||||
"!ConversionCompilesFor<span<int, 4>, span<int>>");
|
||||
}
|
||||
|
||||
TEST(span_test, interop_with_std_regex)
|
||||
@@ -1376,8 +1273,154 @@ TEST(span_test, msvc_compile_error_PR1100)
|
||||
int arr[]{1, 7, 2, 9};
|
||||
gsl::span sp{arr, std::size(arr)};
|
||||
std::ranges::sort(sp);
|
||||
for (const auto& e : sp) {
|
||||
(void)e;
|
||||
}
|
||||
for (const auto& e : sp) { (void) e; }
|
||||
}
|
||||
#endif // defined(__cpp_lib_span) && defined(__cpp_lib_ranges)
|
||||
|
||||
TEST(span_test, empty_span)
|
||||
{
|
||||
span<int> s{};
|
||||
EXPECT_TRUE(s.empty());
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == nullptr);
|
||||
|
||||
span<const int> cs{};
|
||||
EXPECT_TRUE(cs.empty());
|
||||
EXPECT_TRUE(cs.size() == 0);
|
||||
EXPECT_TRUE(cs.data() == nullptr);
|
||||
}
|
||||
|
||||
TEST(span_test, conversions)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
|
||||
#if defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)
|
||||
span s = arr;
|
||||
span cs = s;
|
||||
#else
|
||||
span<int, 5> s = arr;
|
||||
span<int, 5> cs = s;
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(cs.size() == s.size());
|
||||
EXPECT_TRUE(cs.data() == s.data());
|
||||
|
||||
span<int, 5> fs = s;
|
||||
EXPECT_TRUE(fs.size() == s.size());
|
||||
EXPECT_TRUE(fs.data() == s.data());
|
||||
|
||||
span<const int, 5> cfs = s;
|
||||
EXPECT_TRUE(cfs.size() == s.size());
|
||||
EXPECT_TRUE(cfs.data() == s.data());
|
||||
}
|
||||
|
||||
TEST(span_test, comparison_operators)
|
||||
{
|
||||
int arr1[3] = {1, 2, 3};
|
||||
int arr2[3] = {1, 2, 3};
|
||||
int arr3[3] = {4, 5, 6};
|
||||
|
||||
span<int> s1 = arr1;
|
||||
span<int> s2 = arr2;
|
||||
span<int> s3 = arr3;
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 == s3);
|
||||
EXPECT_TRUE(s1 != s3);
|
||||
EXPECT_TRUE(s1 < s3);
|
||||
EXPECT_FALSE(s3 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_TRUE(s1 <= s3);
|
||||
EXPECT_FALSE(s3 <= s1);
|
||||
EXPECT_TRUE(s3 > s1);
|
||||
EXPECT_FALSE(s1 > s3);
|
||||
EXPECT_TRUE(s3 >= s1);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_FALSE(s1 >= s3);
|
||||
}
|
||||
|
||||
// ...existing code...
|
||||
|
||||
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
|
||||
#include <span> // for std::span
|
||||
|
||||
TEST(span_test, compare_empty_span)
|
||||
{
|
||||
gsl::span<int> gsl_s{};
|
||||
std::span<int> std_s{};
|
||||
|
||||
EXPECT_TRUE(gsl_s.empty());
|
||||
EXPECT_TRUE(std_s.empty());
|
||||
EXPECT_EQ(gsl_s.size(), std_s.size());
|
||||
EXPECT_EQ(gsl_s.data(), std_s.data());
|
||||
}
|
||||
|
||||
TEST(span_test, compare_subspan)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
gsl::span gsl_s = arr;
|
||||
std::span std_s = arr;
|
||||
|
||||
auto gsl_sub1 = gsl_s.subspan(1);
|
||||
auto std_sub1 = std_s.subspan(1);
|
||||
EXPECT_EQ(gsl_sub1.size(), std_sub1.size());
|
||||
EXPECT_EQ(gsl_sub1.data(), std_sub1.data());
|
||||
|
||||
auto gsl_sub2 = gsl_s.subspan(1, 2);
|
||||
auto std_sub2 = std_s.subspan(1, 2);
|
||||
EXPECT_EQ(gsl_sub2.size(), std_sub2.size());
|
||||
EXPECT_EQ(gsl_sub2.data(), std_sub2.data());
|
||||
}
|
||||
|
||||
TEST(span_test, compare_conversions)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
gsl::span gsl_s = arr;
|
||||
std::span std_s = arr;
|
||||
|
||||
gsl::span gsl_cs = gsl_s;
|
||||
std::span std_cs = std_s;
|
||||
EXPECT_EQ(gsl_cs.size(), std_cs.size());
|
||||
EXPECT_EQ(gsl_cs.data(), std_cs.data());
|
||||
|
||||
gsl::span<int, 5> gsl_fs = gsl_s;
|
||||
std::span<int, 5> std_fs = std_s;
|
||||
EXPECT_EQ(gsl_fs.size(), std_fs.size());
|
||||
EXPECT_EQ(gsl_fs.data(), std_fs.data());
|
||||
|
||||
gsl::span<const int, 5> gsl_cfs = gsl_s;
|
||||
std::span<const int, 5> std_cfs = std_s;
|
||||
EXPECT_EQ(gsl_cfs.size(), std_cfs.size());
|
||||
EXPECT_EQ(gsl_cfs.data(), std_cfs.data());
|
||||
}
|
||||
|
||||
TEST(span_test, deduction_guides)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
std::array<int, 5> std_arr = {1, 2, 3, 4, 5};
|
||||
std::vector<int> vec = {1, 2, 3, 4, 5};
|
||||
|
||||
// Test deduction guides for gsl::span
|
||||
gsl::span gsl_s1 = arr;
|
||||
gsl::span gsl_s2 = std_arr;
|
||||
gsl::span gsl_s3 = vec;
|
||||
|
||||
// Test deduction guides for std::span (for sanity checks)
|
||||
std::span std_s1 = arr;
|
||||
std::span std_s2 = std_arr;
|
||||
std::span std_s3 = vec;
|
||||
|
||||
// Compare sizes
|
||||
EXPECT_EQ(gsl_s1.size(), std_s1.size());
|
||||
EXPECT_EQ(gsl_s2.size(), std_s2.size());
|
||||
EXPECT_EQ(gsl_s3.size(), std_s3.size());
|
||||
|
||||
// Compare data pointers
|
||||
EXPECT_EQ(gsl_s1.data(), std_s1.data());
|
||||
EXPECT_EQ(gsl_s2.data(), std_s2.data());
|
||||
EXPECT_EQ(gsl_s3.data(), std_s3.data());
|
||||
}
|
||||
|
||||
#endif // defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
|
||||
+191
-34
@@ -17,10 +17,28 @@
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <type_traits> // for declval
|
||||
|
||||
#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
|
||||
|
||||
// stand-in for a user-defined ref-counted class
|
||||
template <typename T>
|
||||
struct RefCounted
|
||||
{
|
||||
RefCounted(T* p) : p_(p) {}
|
||||
operator T*() { return p_; }
|
||||
T* p_;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
@@ -43,12 +61,154 @@ GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
int* return_pointer() { return nullptr; }
|
||||
const int* return_pointer_const() { return nullptr; }
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_A = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
CtorCompilesFor_A<U, void_t<decltype(gsl::strict_not_null<void*>{std::declval<U>()})>> = true;
|
||||
|
||||
template <typename U, int N, typename = void>
|
||||
static constexpr bool CtorCompilesFor_B = false;
|
||||
template <typename U, int N>
|
||||
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::strict_not_null<U>{N})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool DefaultCtorCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::strict_not_null<U>{})>> = true;
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool CtorCompilesFor_C = false;
|
||||
template <typename U>
|
||||
static constexpr bool CtorCompilesFor_C<
|
||||
U, void_t<decltype(gsl::strict_not_null<U*>{std::declval<std::unique_ptr<U>>()})>> = true;
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNullConstructors)
|
||||
{
|
||||
{
|
||||
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
|
||||
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
|
||||
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
|
||||
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
|
||||
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
// Forbid non-nullptr assignable types
|
||||
strict_not_null<std::vector<int>> f(std::vector<int>{1});
|
||||
strict_not_null<int> z(10);
|
||||
strict_not_null<std::vector<int>> y({1, 2});
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructors";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
// from shared pointer
|
||||
int i = 12;
|
||||
auto rp = RefCounted<int>(&i);
|
||||
strict_not_null<int*> p(rp);
|
||||
EXPECT_TRUE(p.get() == &i);
|
||||
|
||||
strict_not_null<std::shared_ptr<int>> x(
|
||||
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
|
||||
|
||||
int* pi = nullptr;
|
||||
EXPECT_DEATH((strict_not_null<decltype(pi)>(pi)), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from unique pointer
|
||||
strict_not_null<std::unique_ptr<int>> x(
|
||||
std::make_unique<int>(10)); // unique_ptr<int> is nullptr assignable
|
||||
|
||||
EXPECT_DEATH((strict_not_null<std::unique_ptr<int>>(std::unique_ptr<int>{})), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from pointer to local
|
||||
int t = 42;
|
||||
|
||||
strict_not_null<int*> x{&t};
|
||||
helper(&t);
|
||||
helper_const(&t);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw pointer
|
||||
// from strict_not_null pointer
|
||||
|
||||
int t = 42;
|
||||
int* p = &t;
|
||||
|
||||
strict_not_null<int*> x{p};
|
||||
helper(p);
|
||||
helper_const(p);
|
||||
helper(x);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw const pointer
|
||||
// from strict_not_null const pointer
|
||||
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
strict_not_null<const int*> x{cp};
|
||||
helper_const(cp);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from strict_not_null const pointer, using auto
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
auto x = strict_not_null<const int*>{cp};
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from returned pointer
|
||||
|
||||
EXPECT_DEATH(helper(return_pointer()), expected);
|
||||
EXPECT_DEATH(helper_const(return_pointer()), expected);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool StrictHelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
StrictHelperCompilesFor<U, void_t<decltype(strict_helper(std::declval<U>()))>> = true;
|
||||
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool StrictHelperConstCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool
|
||||
StrictHelperConstCompilesFor<U, void_t<decltype(strict_helper_const(std::declval<U>()))>> =
|
||||
true;
|
||||
|
||||
|
||||
template <typename U, typename = void>
|
||||
static constexpr bool HelperCompilesFor = false;
|
||||
template <typename U>
|
||||
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
{
|
||||
{
|
||||
@@ -57,14 +217,15 @@ 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);
|
||||
|
||||
@@ -77,17 +238,17 @@ 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<const int*>, "!StrictHelperFor<const int*>");
|
||||
static_assert(!StrictHelperConstCompilesFor<const int*>,
|
||||
"!StrictHelperCompilesFor<const int*>");
|
||||
|
||||
const strict_not_null<const int*> snn1{&x};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(snn1);
|
||||
#endif
|
||||
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);
|
||||
@@ -114,9 +275,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
strict_not_null<const int*> snn1{&x};
|
||||
const strict_not_null<const int*> snn2{&x};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_helper(snn1);
|
||||
#endif
|
||||
static_assert(!StrictHelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!StrictHelperCompilesFor<strict_not_null<const int*>>");
|
||||
strict_helper_const(snn1);
|
||||
strict_helper_const(snn2);
|
||||
|
||||
@@ -148,9 +308,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
const not_null<const int*> nn1 = snn;
|
||||
const not_null<const int*> nn2{snn};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(snn);
|
||||
#endif
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(snn);
|
||||
|
||||
EXPECT_TRUE(snn == nn1);
|
||||
@@ -190,9 +349,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
const strict_not_null<const int*> snn1{nn};
|
||||
const strict_not_null<const int*> snn2{nn};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_helper(nn);
|
||||
#endif
|
||||
static_assert(!StrictHelperCompilesFor<not_null<const int*>>,
|
||||
"!StrictHelperCompilesFor<not_null<const int*>>");
|
||||
strict_helper_const(nn);
|
||||
|
||||
EXPECT_TRUE(snn1 == nn);
|
||||
@@ -206,12 +364,13 @@ TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
strict_not_null<int*> p{nullptr};
|
||||
}
|
||||
#endif
|
||||
TEST(pointers_test, member_types)
|
||||
{
|
||||
// make sure `element_type` is inherited from `gsl::not_null`
|
||||
static_assert(std::is_same<gsl::strict_not_null<int*>::element_type, int*>::value,
|
||||
"check member type: element_type");
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
@@ -238,9 +397,8 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
const int i = 42;
|
||||
|
||||
strict_not_null x{&i};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(strict_not_null{&i});
|
||||
#endif
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(strict_not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
@@ -262,9 +420,8 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
const int* p = &i;
|
||||
|
||||
strict_not_null x{p};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(strict_not_null{p});
|
||||
#endif
|
||||
static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
|
||||
"!HelperCompilesFor<strict_not_null<const int*>>");
|
||||
helper_const(strict_not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
|
||||
Reference in New Issue
Block a user