├── .clang-format ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── copilot-instructions.md └── workflows │ ├── android.yml │ ├── cmake │ └── action.yml │ ├── cmake_find_package.yml │ ├── compilers.yml │ ├── copilot-setup-steps.yml │ └── ios.yml ├── .gitignore ├── CMakeLists.txt ├── CMakeSettings.json ├── CONTRIBUTING.md ├── GSL.natvis ├── LICENSE ├── README.md ├── SECURITY.md ├── ThirdPartyNotices.txt ├── docs └── headers.md ├── include ├── CMakeLists.txt └── gsl │ ├── algorithm │ ├── assert │ ├── byte │ ├── gsl │ ├── narrow │ ├── pointers │ ├── span │ ├── span_ext │ ├── util │ └── zstring └── tests ├── CMakeLists.txt ├── CMakeLists.txt.in ├── algorithm_tests.cpp ├── assertion_tests.cpp ├── at_tests.cpp ├── byte_tests.cpp ├── constexpr_notnull_tests.cpp ├── deathTestCommon.h ├── no_exception_ensure_tests.cpp ├── notnull_tests.cpp ├── owner_tests.cpp ├── pointers_tests.cpp ├── span_compatibility_tests.cpp ├── span_ext_tests.cpp ├── span_tests.cpp ├── strict_notnull_tests.cpp └── utils_tests.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | ColumnLimit: 100 2 | 3 | UseTab: Never 4 | IndentWidth: 4 5 | AccessModifierOffset: -4 6 | NamespaceIndentation: Inner 7 | 8 | BreakBeforeBraces: Custom 9 | BraceWrapping: 10 | AfterNamespace: true 11 | AfterEnum: true 12 | AfterStruct: true 13 | AfterClass: true 14 | SplitEmptyFunction: false 15 | AfterControlStatement: true 16 | AfterFunction: true 17 | AfterUnion: true 18 | BeforeElse: true 19 | 20 | 21 | AlwaysBreakTemplateDeclarations: true 22 | BreakConstructorInitializersBeforeComma: true 23 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 24 | AllowShortBlocksOnASingleLine: true 25 | AllowShortFunctionsOnASingleLine: All 26 | AllowShortIfStatementsOnASingleLine: true 27 | AllowShortLoopsOnASingleLine: true 28 | 29 | PointerAlignment: Left 30 | AlignConsecutiveAssignments: false 31 | AlignTrailingComments: true 32 | 33 | SpaceAfterCStyleCast: true 34 | CommentPragmas: '^ NO-FORMAT:' 35 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | include/gsl/* linguist-language=C++ 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'Status: Open, Type: Bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | ```c++ 15 | #include 16 | 17 | // your repro here: ... 18 | ``` 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Spec (please complete the following information):** 24 | - OS: [e.g. Windows] 25 | - Compiler: [e.g. MSVC] 26 | - C++ Version: [e.g. C++20] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Instructions for GSL (Guidelines Support Library) 2 | 3 | ## Project Overview 4 | This repository contains the Guidelines Support Library (GSL), a Microsoft implementation of types and functions 5 | suggested for use by the C++ Core Guidelines. It's a header-only C++ library with emphasis on safety, 6 | correctness, and zero overhead. 7 | 8 | ## Coding Standards 9 | 10 | ### General 11 | - Follow C++ Core Guidelines wherever possible 12 | - Use meaningful type, function, and template parameter names 13 | - Keep functions small and focused with clear preconditions/postconditions 14 | - Include comments for complex code, but prefer self-documenting code 15 | - Use the Expects() and Ensures() macros for contract verification 16 | 17 | ### Style Guidelines 18 | - Use 4 spaces for indentation (not tabs) 19 | - Maximum line length of 100 characters 20 | - Follow GSL naming conventions (lowercase with underscores) 21 | - Keep templates clean and readable with appropriate spacing 22 | - Use C++14 features since this is the minimum standard supported 23 | 24 | ### Error Handling 25 | - Use Expects() for preconditions and Ensures() for postconditions 26 | - Design for fail-fast semantics (std::terminate) on contract violations 27 | - Template constraints should use static_assert or SFINAE 28 | - Don't throw exceptions from basic operations 29 | 30 | ### Testing 31 | - Write thorough unit tests for every component using GTest 32 | - Test for all edge cases and error conditions 33 | - Ensure cross-platform compatibility in tests 34 | - Maintain 100% code coverage for changed code 35 | 36 | ## Project-Specific Conventions 37 | 38 | ### Architecture 39 | - All public types must be in the gsl namespace 40 | - Design for zero overhead abstractions when possible 41 | - Respect the distinction between Owners and Views 42 | - Maintain backward compatibility with existing GSL code 43 | 44 | ### Version Control 45 | - Link all PRs to related issues 46 | - Use clear commit messages explaining what and why 47 | - Follow the contribution guidelines documented in CONTRIBUTING.md 48 | - PRs should include appropriate tests with 100% coverage for changed code 49 | 50 | ### Documentation 51 | - Document all public APIs with clarity on preconditions and postconditions 52 | - Keep header comments up-to-date 53 | - Include examples for complex functionality in docs/headers.md 54 | 55 | ## Technology Stack 56 | - C++14 (minimum) for core implementation 57 | - CMake build system (3.14+) 58 | - Google Test for unit testing 59 | - Support for multiple compilers (MSVC, GCC, Clang) 60 | 61 | ## Security Considerations 62 | - Bounds checking is a core principle - enforce it consistently 63 | - Design for safety while minimizing overhead 64 | - Ensure undefined behavior is explicitly detected where possible 65 | 66 | ## Performance Guidelines 67 | - Optimize for both safety and performance 68 | - Constexpr-enable functions wherever possible 69 | - Avoid hidden allocations 70 | - Use noexcept appropriately for move operations and other performance-critical functions 71 | 72 | ## Cross-Platform Support 73 | - Code must work across: 74 | - Windows (MSVC) 75 | - Linux (GCC, Clang) 76 | - macOS (AppleClang) 77 | - Android and iOS where applicable 78 | 79 | ## Copilot Tasks 80 | - You can find the CMake artifacts for C++20 in build-cxx20 and C++14 in build-cxx14. 81 | - Before publishing a PR, verify the following: 82 | - There are no compiler warnings or errors when building the test suite. 83 | - The test suite passes on all supported platforms and compilers. 84 | - The test suite passes for both C++14 and C++20. 85 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: CI_Android 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | branches: [ main ] 12 | 13 | jobs: 14 | Android: 15 | runs-on: macos-latest-large 16 | defaults: 17 | run: 18 | working-directory: build 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Create build directory 23 | run: mkdir -p build 24 | working-directory: . 25 | 26 | - uses: actions/setup-java@v4 27 | with: 28 | java-version: 8 29 | distribution: zulu 30 | 31 | - name: Start Emulator 32 | run: | 33 | echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-24;default;x86_64' 34 | echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-24;default;x86_64' --force 35 | $ANDROID_HOME/emulator/emulator -list-avds 36 | echo "Starting emulator..." 37 | nohup $ANDROID_HOME/emulator/emulator -no-audio -no-snapshot -avd xamarin_android_emulator &> /dev/null & 38 | echo "Emulator starting in background" 39 | 40 | - name: Configure 41 | 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 .. 42 | 43 | - name: Build 44 | run: cmake --build . --parallel 45 | 46 | - name: Wait for emulator ready 47 | timeout-minutes: 2 48 | run: | 49 | $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' 50 | $ANDROID_HOME/platform-tools/adb devices 51 | $ANDROID_HOME/platform-tools/adb shell getprop ro.product.cpu.abi 52 | 53 | - name: Deploy tests 54 | run: | 55 | adb push tests /data/local/tmp 56 | adb shell find /data/local/tmp/tests -maxdepth 1 -exec chmod +x {} \\\; 57 | 58 | - name: Test 59 | run: adb shell find /data/local/tmp/tests -name "*_tests" -maxdepth 1 -exec {} \\\; 60 | -------------------------------------------------------------------------------- /.github/workflows/cmake/action.yml: -------------------------------------------------------------------------------- 1 | name: Composite CMake 2 | inputs: 3 | cmake_generator: 4 | required: false 5 | type: string 6 | default: 'Unix Makefiles' 7 | cmake_build_type: 8 | required: true 9 | type: string 10 | default: '' 11 | cmake_cxx_compiler: 12 | required: false 13 | type: string 14 | gsl_cxx_standard: 15 | required: true 16 | type: number 17 | extra_cmake_args: 18 | required: false 19 | type: string 20 | default: '' 21 | build_cmd: 22 | required: true 23 | type: string 24 | default: 'make' 25 | test_cmd: 26 | required: false 27 | type: string 28 | default: 'make test' 29 | shell: 30 | required: false 31 | type: string 32 | default: 'bash' 33 | 34 | 35 | runs: 36 | using: composite 37 | steps: 38 | - name: Create build directory 39 | run: mkdir build 40 | shell: ${{ inputs.shell }} 41 | 42 | - name: Configure CMake 43 | working-directory: build 44 | 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 }} .. 45 | shell: ${{ inputs.shell }} 46 | 47 | - name: Build 48 | working-directory: build 49 | run: ${{ inputs.build_cmd }} 50 | shell: ${{ inputs.shell }} 51 | 52 | - name: Test 53 | working-directory: build 54 | run: ${{ inputs.test_cmd }} 55 | shell: ${{ inputs.shell }} 56 | 57 | -------------------------------------------------------------------------------- /.github/workflows/cmake_find_package.yml: -------------------------------------------------------------------------------- 1 | name: cmake_find_package 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | cmake-find-package: 10 | name: Build ${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ ubuntu-latest, macos-latest ] 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: lukka/get-cmake@latest 18 | with: 19 | cmakeVersion: 3.14.0 20 | - name: Configure GSL 21 | run: cmake -S . -B build -G "Ninja" -D GSL_TEST=OFF -D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/build/install 22 | - name: Install GSL 23 | run: cmake --build build --target install 24 | - name: Test GSL find_package support 25 | run: cmake -S tests/ -B build/tests_find_package -G "Ninja" -D CMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/build/install -D CMAKE_BUILD_TYPE=Release 26 | -------------------------------------------------------------------------------- /.github/workflows/compilers.yml: -------------------------------------------------------------------------------- 1 | name: Compiler Integration Tests 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | branches: [ main ] 12 | 13 | # These jobs are correlated with the officially supported compilers 14 | # and toolsets. If you change any versions, please update README.md. 15 | 16 | jobs: 17 | gcc: 18 | strategy: 19 | matrix: 20 | gcc_version: [ 12, 13, 14 ] 21 | build_type: [ Debug, Release ] 22 | cxx_version: [ 14, 17, 20, 23 ] 23 | exclude: 24 | # https://github.com/google/googletest/issues/4232 25 | # Looks like GoogleTest is not interested in making version 1.14 26 | # work with gcc-12. 27 | - gcc_version: 12 28 | cxx_version: 20 29 | - gcc_version: 12 30 | cxx_version: 23 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - name: Run CMake (configure, build, test) 36 | uses: ./.github/workflows/cmake 37 | with: 38 | cmake_build_type: ${{ matrix.build_type }} 39 | cmake_cxx_compiler: g++-${{ matrix.gcc_version }} 40 | gsl_cxx_standard: ${{ matrix.cxx_version }} 41 | 42 | clang: 43 | strategy: 44 | matrix: 45 | clang_version: [ 16, 17, 18 ] 46 | build_type: [ Debug, Release ] 47 | cxx_version: [ 14, 17, 20, 23 ] 48 | exclude: 49 | # https://github.com/llvm/llvm-project/issues/93734 50 | # Looks like clang fixed this issue in clang-18, but won't backport 51 | # the fix. 52 | - clang_version: 17 53 | cxx_version: 23 54 | runs-on: ubuntu-latest 55 | steps: 56 | - uses: actions/checkout@v4 57 | 58 | - name: Run CMake (configure, build, test) 59 | uses: ./.github/workflows/cmake 60 | with: 61 | cmake_build_type: ${{ matrix.build_type }} 62 | cmake_cxx_compiler: clang++-${{ matrix.clang_version }} 63 | gsl_cxx_standard: ${{ matrix.cxx_version }} 64 | 65 | xcode: 66 | strategy: 67 | matrix: 68 | xcode_version: [ '15.4' ] 69 | build_type: [ Debug, Release ] 70 | cxx_version: [ 14, 17, 20, 23 ] 71 | runs-on: macos-latest 72 | steps: 73 | - uses: actions/checkout@v4 74 | 75 | - name: select xcode version 76 | run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode_version }}.app 77 | 78 | - name: Run CMake (configure, build, test) 79 | uses: ./.github/workflows/cmake 80 | with: 81 | cmake_build_type: ${{ matrix.build_type }} 82 | cmake_cxx_compiler: clang++ 83 | gsl_cxx_standard: ${{ matrix.cxx_version }} 84 | 85 | VisualStudio: 86 | strategy: 87 | matrix: 88 | generator: [ 'Visual Studio 16 2019', 'Visual Studio 17 2022' ] 89 | image: [ windows-2019, windows-2022 ] 90 | build_type: [ Debug, Release ] 91 | extra_args: [ '', '-T ClangCL' ] 92 | cxx_version: [ 14, 17, 20, 23 ] 93 | exclude: 94 | - generator: 'Visual Studio 17 2022' 95 | image: windows-2019 96 | - generator: 'Visual Studio 16 2019' 97 | image: windows-2022 98 | - generator: 'Visual Studio 16 2019' 99 | cxx_version: 23 100 | runs-on: ${{ matrix.image }} 101 | steps: 102 | - uses: actions/checkout@v4 103 | - uses: microsoft/setup-msbuild@v2 104 | 105 | - name: Run CMake (configure, build, test) 106 | uses: ./.github/workflows/cmake 107 | with: 108 | cmake_generator: ${{ matrix.generator }} 109 | cmake_build_type: ${{ matrix.build_type }} 110 | gsl_cxx_standard: ${{ matrix.cxx_version }} 111 | extra_cmake_args: ${{ matrix.extra_args }} 112 | build_cmd: msbuild GSL.sln 113 | test_cmd: ctest . --output-on-failure --no-compress-output 114 | shell: pwsh 115 | 116 | -------------------------------------------------------------------------------- /.github/workflows/copilot-setup-steps.yml: -------------------------------------------------------------------------------- 1 | name: "Copilot Setup Steps" 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | copilot-setup-steps: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | contents: read 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v4 13 | 14 | - name: Install Build Dependencies 15 | run: sudo apt-get update && sudo apt-get install -y clang cmake make 16 | 17 | - name: Configure CMake (C++14) 18 | run: cmake -B build-cxx14 . -DGSL_CXX_STANDARD=14 -DGSL_TEST=ON -G "Unix Makefiles" 19 | 20 | - name: Configure CMake (C++20) 21 | run: cmake -B build-cxx20 . -DGSL_CXX_STANDARD=20 -DGSL_TEST=ON -G "Unix Makefiles" 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/ios.yml: -------------------------------------------------------------------------------- 1 | name: CI_iOS 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | iOS: 10 | runs-on: macos-latest 11 | defaults: 12 | run: 13 | working-directory: build 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Create build directory 18 | run: mkdir -p build 19 | working-directory: . 20 | 21 | - name: Configure 22 | run: | 23 | cmake \ 24 | -Werror=dev \ 25 | -GXcode \ 26 | -DCMAKE_SYSTEM_NAME=iOS \ 27 | "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ 28 | -DCMAKE_OSX_DEPLOYMENT_TARGET=9 \ 29 | -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \ 30 | "-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \ 31 | -DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \ 32 | -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \ 33 | .. 34 | 35 | - name: Build 36 | run: cmake --build . --parallel `sysctl -n hw.ncpu` --config Release -- -sdk iphonesimulator 37 | 38 | - name: Start simulator 39 | run: | 40 | RUNTIME=`xcrun simctl list runtimes iOS -j|jq '.runtimes|last.identifier'` 41 | UDID=`xcrun simctl list devices iPhone available -j|jq -r ".devices[$RUNTIME]|last.udid"` 42 | xcrun simctl bootstatus $UDID -b 43 | 44 | - name: Test 45 | run: | 46 | for TEST in `find tests/Release-iphonesimulator -depth 1 -name "*.app"` 47 | do 48 | xcrun simctl install booted $TEST 49 | TEST_ID=`plutil -convert json -o - $TEST/Info.plist|jq -r ".CFBundleIdentifier"` 50 | xcrun simctl launch --console booted $TEST_ID 51 | xcrun simctl uninstall booted $TEST_ID 52 | done 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeFiles 2 | build*/ 3 | tests/CMakeFiles 4 | tests/Debug 5 | *.opensdf 6 | *.sdf 7 | tests/*tests.dir 8 | *.vcxproj 9 | *.vcxproj.filters 10 | *.sln 11 | *.tlog 12 | Testing/Temporary/*.* 13 | CMakeCache.txt 14 | *.suo 15 | .vs/ 16 | .vscode/ 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14...3.16) 2 | 3 | project(GSL VERSION 4.2.0 LANGUAGES CXX) 4 | 5 | add_library(GSL INTERFACE) 6 | add_library(Microsoft.GSL::GSL ALIAS GSL) 7 | 8 | # https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html 9 | string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL) 10 | 11 | option(GSL_INSTALL "Generate and install GSL target" ${PROJECT_IS_TOP_LEVEL}) 12 | option(GSL_TEST "Build and perform GSL tests" ${PROJECT_IS_TOP_LEVEL}) 13 | 14 | # The implementation generally assumes a platform that implements C++14 support 15 | target_compile_features(GSL INTERFACE "cxx_std_14") 16 | 17 | # Setup include directory 18 | add_subdirectory(include) 19 | 20 | target_sources(GSL INTERFACE $) 21 | 22 | if (GSL_TEST) 23 | enable_testing() 24 | add_subdirectory(tests) 25 | endif() 26 | 27 | if (GSL_INSTALL) 28 | include(GNUInstallDirs) 29 | include(CMakePackageConfigHelpers) 30 | 31 | install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/gsl" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 32 | 33 | set(export_name "Microsoft.GSLConfig") 34 | set(namespace "Microsoft.GSL::") 35 | set(cmake_files_install_dir ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL) 36 | 37 | install(TARGETS GSL EXPORT ${export_name} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 38 | install(EXPORT ${export_name} NAMESPACE ${namespace} DESTINATION ${cmake_files_install_dir}) 39 | export(TARGETS GSL NAMESPACE ${namespace} FILE ${export_name}.cmake) 40 | 41 | set(gls_config_version "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake") 42 | 43 | write_basic_package_version_file(${gls_config_version} COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT) 44 | 45 | install(FILES ${gls_config_version} DESTINATION ${cmake_files_install_dir}) 46 | 47 | install(FILES GSL.natvis DESTINATION ${cmake_files_install_dir}) 48 | endif() 49 | -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "inheritEnvironments": [ 8 | "msvc_x64_x64" 9 | ], 10 | "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", 11 | "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", 12 | "cmakeCommandArgs": "-DGSL_CXX_STANDARD=17", 13 | "buildCommandArgs": "-v", 14 | "ctestCommandArgs": "", 15 | "codeAnalysisRuleset": "CppCoreCheckRules.ruleset" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to the Guidelines Support Library 2 | 3 | The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the 4 | [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines). GSL design changes are made only as a result of modifications to the Guidelines. 5 | 6 | GSL is accepting contributions that improve or refine any of the types in this library as well as ports to other platforms. Changes should have an issue 7 | tracking the suggestion that has been approved by the maintainers. Your pull request should include a link to the bug that you are fixing. If you've submitted 8 | a PR, please post a comment in the associated issue to avoid duplication of effort. 9 | 10 | ## Legal 11 | You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us and the community permission to 12 | use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. 13 | 14 | Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. 15 | 16 | ## Housekeeping 17 | Your pull request should: 18 | 19 | * Include a description of what your change intends to do 20 | * Be a child commit of a reasonably recent commit in the **main** branch 21 | * Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR) 22 | * It is desirable, but not necessary, for the tests to pass at each commit. Please see [README.md](./README.md) for instructions to build the test suite. 23 | * Have clear commit messages 24 | * e.g. "Fix issue", "Add tests for type", etc. 25 | * Include appropriate tests 26 | * Tests should include reasonable permutations of the target fix/change 27 | * Include baseline changes with your change 28 | * All changed code must have 100% code coverage 29 | * To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration 30 | -------------------------------------------------------------------------------- /GSL.natvis: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | {{ invoke = {invoke_}, action = {f_} }} 10 | 11 | invoke_ 12 | f_ 13 | 14 | 15 | 16 | 17 | 18 | {{ extent = {storage_.size_} }} 19 | 20 | 21 | storage_.size_ 22 | storage_.data_ 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | value = {*ptr_} 31 | 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Microsoft Corporation. All rights reserved. 2 | 3 | This code is licensed under the MIT License (MIT). 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GSL: Guidelines Support Library 2 | [![CI](https://github.com/Microsoft/GSL/actions/workflows/compilers.yml/badge.svg)](https://github.com/microsoft/GSL/actions/workflows/compilers.yml?query=branch%3Amain) 3 | [![vcpkg](https://img.shields.io/vcpkg/v/ms-gsl)](https://vcpkg.io/en/package/ms-gsl) 4 | 5 | The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the 6 | [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org). 7 | This repo contains Microsoft's implementation of GSL. 8 | 9 | The entire implementation is provided inline in the headers under the [gsl](./include/gsl) directory. The implementation generally assumes a platform that implements C++14 support. 10 | 11 | While some types have been broken out into their own headers (e.g. [gsl/span](./include/gsl/span)), 12 | it is simplest to just include [gsl/gsl](./include/gsl/gsl) and gain access to the entire library. 13 | 14 | > NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to 15 | other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing. 16 | 17 | # Project Code of Conduct 18 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 19 | 20 | # Usage of Third Party Libraries 21 | This project makes use of the [Google Test](https://github.com/google/googletest) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Google Test. 22 | 23 | # Supported features 24 | ## Microsoft GSL implements the following from the C++ Core Guidelines: 25 | 26 | Feature | Supported? | Description 27 | -------------------------------------------------------------------------|:----------:|------------- 28 | [**1. Views**][cg-views] | | 29 | [owner](docs/headers.md#user-content-H-pointers-owner) | ☑ | An alias for a raw pointer 30 | [not_null](docs/headers.md#user-content-H-pointers-not_null) | ☑ | Restricts a pointer/smart pointer to hold non-null values 31 | [span](docs/headers.md#user-content-H-span-span) | ☑ | A view over a contiguous sequence of memory. Based on the standardized version of `std::span`, however `gsl::span` enforces bounds checking. 32 | span_p | ☐ | Spans a range starting from a pointer to the first place for which the predicate is true 33 | [basic_zstring](docs/headers.md#user-content-H-zstring) | ☑ | A pointer to a C-string (zero-terminated array) with a templated char type 34 | [zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char` 35 | [czstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char` 36 | [wzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `wchar_t` 37 | [cwzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const wchar_t` 38 | [u16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char16_t` 39 | [cu16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char16_t` 40 | [u32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t` 41 | [cu32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t` 42 | [**2. Owners**][cg-owners] | | 43 | stack_array | ☐ | A stack-allocated array 44 | dyn_array | ☐ | A heap-allocated array 45 | [**3. Assertions**][cg-assertions] | | 46 | [Expects](docs/headers.md#user-content-H-assert-expects) | ☑ | A precondition assertion; on failure it terminates 47 | [Ensures](docs/headers.md#user-content-H-assert-ensures) | ☑ | A postcondition assertion; on failure it terminates 48 | [**4. Utilities**][cg-utilities] | | 49 | move_owner | ☐ | A helper function that moves one `owner` to the other 50 | [final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a functor on its destruction 51 | [finally](docs/headers.md#user-content-H-util-finally) | ☑ | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action) 52 | [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")]]` 53 | [[implicit]] | ☐ | A "marker" to put on single-argument constructors to explicitly make them non-explicit 54 | [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`) 55 | [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) 56 | [narrow_cast](docs/headers.md#user-content-H-util-narrow_cast) | ☑ | A narrowing cast for values and a synonym for `static_cast` 57 | [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) 58 | [**5. Concepts**][cg-concepts] | ☐ | 59 | 60 | ## The following features do not exist in or have been removed from the C++ Core Guidelines: 61 | Feature | Supported? | Description 62 | -----------------------------------|:----------:|------------- 63 | [strict_not_null](docs/headers.md#user-content-H-pointers-strict_not_null) | ☑ | A stricter version of [not_null](docs/headers.md#user-content-H-pointers-not_null) with explicit constructors 64 | multi_span | ☐ | Deprecated. Multi-dimensional span. 65 | strided_span | ☐ | Deprecated. Support for this type has been discontinued. 66 | basic_string_span | ☐ | Deprecated. Like `span` but for strings with a templated char type 67 | string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char` 68 | cstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char` 69 | wstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `wchar_t` 70 | cwstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const wchar_t` 71 | u16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char16_t` 72 | cu16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char16_t` 73 | u32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char32_t` 74 | cu32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char32_t` 75 | 76 | ## The following features have been adopted by WG21. They are deprecated in GSL. 77 | Feature | Deprecated Since | Notes 78 | ------------------------------------------------------------------|------------------|------ 79 | [unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | C++11 | Use std::unique_ptr instead. 80 | [shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | C++11 | Use std::shared_ptr instead. 81 | [byte](docs/headers.md#user-content-H-byte-byte) | C++17 | Use std::byte instead. 82 | joining_thread | C++20 (Note: Not yet implemented in GSL) | Use std::jthread instead. 83 | 84 | This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library). 85 | 86 | [cg-views]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslview-views 87 | [cg-owners]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslowner-ownership-pointers 88 | [cg-assertions]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslassert-assertions 89 | [cg-utilities]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslutil-utilities 90 | [cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts 91 | 92 | # Quick Start 93 | ## Supported Compilers / Toolsets 94 | The GSL officially supports recent major versions of Visual Studio with both MSVC and LLVM, GCC, Clang, and XCode with Apple-Clang. 95 | For each of these major versions, the GSL officially supports C++14, C++17, C++20, and C++23 (when supported by the compiler). 96 | Below is a table showing the versions currently being tested (also see [.github/workflows/compilers.yml](the workflow).) 97 | 98 | Compiler |Toolset Versions Currently Tested 99 | :------- |--: 100 | GCC | 12, 13, 14 101 | XCode | 14.3.1, 15.4 102 | Clang | 16, 17, 18 103 | Visual Studio with MSVC | VS2019, VS2022 104 | Visual Studio with LLVM | VS2019, VS2022 105 | 106 | --- 107 | If you successfully port GSL to another platform, we would love to hear from you! 108 | - Submit an issue specifying the platform and target. 109 | - Consider contributing your changes by filing a pull request with any necessary changes. 110 | - If at all possible, add a CI/CD step and add the button to the table below! 111 | 112 | Target | CI/CD Status 113 | :------- | -----------: 114 | iOS | [![CI_iOS](https://github.com/microsoft/GSL/workflows/CI_iOS/badge.svg?branch=main)](https://github.com/microsoft/GSL/actions/workflows/ios.yml?query=branch%3Amain) 115 | Android | [![CI_Android](https://github.com/microsoft/GSL/workflows/CI_Android/badge.svg?branch=main)](https://github.com/microsoft/GSL/actions/workflows/android.yml?query=branch%3Amain) 116 | 117 | Note: These CI/CD steps are run with each pull request, however failures in them are non-blocking. 118 | 119 | ## Building the tests 120 | To build the tests, you will require the following: 121 | 122 | * [CMake](http://cmake.org), version 3.14 or later to be installed and in your PATH. 123 | 124 | These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`. 125 | 126 | 1. Create a directory to contain the build outputs for a particular architecture (we name it `c:\GSL\build-x86` in this example). 127 | 128 | cd GSL 129 | md build-x86 130 | cd build-x86 131 | 132 | 2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`). 133 | 134 | cmake -G "Visual Studio 15 2017" c:\GSL 135 | 136 | 3. Build the test suite (in this case, in the Debug configuration, Release is another good choice). 137 | 138 | cmake --build . --config Debug 139 | 140 | 4. Run the test suite. 141 | 142 | ctest -C Debug 143 | 144 | All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types! 145 | 146 | ## Building GSL - Using vcpkg 147 | 148 | You can download and install GSL using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: 149 | 150 | git clone https://github.com/Microsoft/vcpkg.git 151 | cd vcpkg 152 | ./bootstrap-vcpkg.sh 153 | ./vcpkg integrate install 154 | vcpkg install ms-gsl 155 | 156 | The GSL port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. 157 | 158 | ## Using the libraries 159 | As the types are entirely implemented inline in headers, there are no linking requirements. 160 | 161 | You can copy the [gsl](./include/gsl) directory into your source tree so it is available 162 | to your compiler, then include the appropriate headers in your program. 163 | 164 | Alternatively set your compiler's *include path* flag to point to the GSL development folder (`c:\GSL\include` in the example above) or installation folder (after running the install). Eg. 165 | 166 | MSVC++ 167 | 168 | /I c:\GSL\include 169 | 170 | GCC/clang 171 | 172 | -I$HOME/dev/GSL/include 173 | 174 | Include the library using: 175 | 176 | #include 177 | 178 | ## Usage in CMake 179 | 180 | The library provides a Config file for CMake, once installed it can be found via `find_package`. 181 | 182 | Which, when successful, will add library target called `Microsoft.GSL::GSL` which you can use via the usual 183 | `target_link_libraries` mechanism. 184 | 185 | ```cmake 186 | find_package(Microsoft.GSL CONFIG REQUIRED) 187 | 188 | target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL) 189 | ``` 190 | 191 | ### FetchContent 192 | 193 | If you are using CMake version 3.11+ you can use the official [FetchContent module](https://cmake.org/cmake/help/latest/module/FetchContent.html). 194 | This allows you to easily incorporate GSL into your project. 195 | 196 | ```cmake 197 | # NOTE: This example uses CMake version 3.14 (FetchContent_MakeAvailable). 198 | # Since it streamlines the FetchContent process 199 | cmake_minimum_required(VERSION 3.14) 200 | 201 | include(FetchContent) 202 | 203 | FetchContent_Declare(GSL 204 | GIT_REPOSITORY "https://github.com/microsoft/GSL" 205 | GIT_TAG "v4.2.0" 206 | GIT_SHALLOW ON 207 | ) 208 | 209 | FetchContent_MakeAvailable(GSL) 210 | 211 | target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL) 212 | ``` 213 | 214 | ## Debugging visualization support 215 | 216 | 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. 217 | 218 | ## See Also 219 | 220 | For information on [Microsoft Gray Systems Lab (GSL)](https://aka.ms/gsl) of applied data management and system research see . 221 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /ThirdPartyNotices.txt: -------------------------------------------------------------------------------- 1 | 2 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 3 | Do Not Translate or Localize 4 | 5 | GSL: Guidelines Support Library incorporates third party material from the projects listed below. 6 | 7 | ------------------------------------------------------------------------------- 8 | Software: Google Test 9 | Owner: Google Inc. 10 | Source URL: github.com/google/googletest 11 | License: BSD 3 - Clause 12 | Text: 13 | Copyright 2008, Google Inc. 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are 18 | met: 19 | 20 | * Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | * Redistributions in binary form must reproduce the above 23 | copyright notice, this list of conditions and the following disclaimer 24 | in the documentation and/or other materials provided with the 25 | distribution. 26 | * Neither the name of Google Inc. nor the names of its 27 | contributors may be used to endorse or promote products derived from 28 | this software without specific prior written permission. 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | ------------------------------------------------------------------------------- 42 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Add include folders to the library and targets that consume it 2 | # the SYSTEM keyword suppresses warnings for users of the library 3 | # 4 | # By adding this directory as an include directory the user gets a 5 | # namespace effect. 6 | # 7 | # IE: 8 | # #include 9 | if(PROJECT_IS_TOP_LEVEL) 10 | target_include_directories(GSL INTERFACE $) 11 | else() 12 | target_include_directories(GSL SYSTEM INTERFACE $) 13 | endif() 14 | -------------------------------------------------------------------------------- /include/gsl/algorithm: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_ALGORITHM_H 18 | #define GSL_ALGORITHM_H 19 | 20 | #include "./assert" // for Expects 21 | #include "./span" // for dynamic_extent, span 22 | 23 | #include // for copy_n 24 | #include // for ptrdiff_t 25 | #include // for is_assignable 26 | 27 | #ifdef _MSC_VER 28 | #pragma warning(push) 29 | 30 | // turn off some warnings that are noisy about our Expects statements 31 | #pragma warning(disable : 4127) // conditional expression is constant 32 | #pragma warning(disable : 4996) // unsafe use of std::copy_n 33 | 34 | #endif // _MSC_VER 35 | 36 | namespace gsl 37 | { 38 | // Note: this will generate faster code than std::copy using span iterator in older msvc+stl 39 | // not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915) 40 | template 42 | void copy(span src, span dest) 43 | { 44 | static_assert(std::is_assignable::value, 45 | "Elements of source span can not be assigned to elements of destination span"); 46 | static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent || 47 | (SrcExtent <= DestExtent), 48 | "Source range is longer than target range"); 49 | 50 | Expects(dest.size() >= src.size()); 51 | // clang-format off 52 | GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute 53 | // clang-format on 54 | std::copy_n(src.data(), src.size(), dest.data()); 55 | } 56 | 57 | } // namespace gsl 58 | 59 | #ifdef _MSC_VER 60 | #pragma warning(pop) 61 | #endif // _MSC_VER 62 | 63 | #endif // GSL_ALGORITHM_H 64 | -------------------------------------------------------------------------------- /include/gsl/assert: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_ASSERT_H 18 | #define GSL_ASSERT_H 19 | 20 | // 21 | // Temporary until MSVC STL supports no-exceptions mode. 22 | // Currently terminate is a no-op in this mode, so we add termination behavior back 23 | // 24 | #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) 25 | #define GSL_KERNEL_MODE 26 | 27 | #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND 28 | #include 29 | #define RANGE_CHECKS_FAILURE 0 30 | 31 | #if defined(__clang__) 32 | #pragma clang diagnostic push 33 | #pragma clang diagnostic ignored "-Winvalid-noreturn" 34 | #endif // defined(__clang__) 35 | 36 | #else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && 37 | // !_HAS_EXCEPTIONS)) 38 | 39 | #include 40 | 41 | #endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && 42 | // !_HAS_EXCEPTIONS)) 43 | 44 | // 45 | // make suppress attributes parse for some compilers 46 | // Hopefully temporary until suppression standardization occurs 47 | // 48 | #if defined(__clang__) 49 | #define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] 50 | #else 51 | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__) 52 | #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] 53 | #else 54 | #define GSL_SUPPRESS(x) 55 | #endif // _MSC_VER 56 | #endif // __clang__ 57 | 58 | #if defined(__clang__) || defined(__GNUC__) 59 | #define GSL_LIKELY(x) __builtin_expect(!!(x), 1) 60 | #define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0) 61 | 62 | #else 63 | 64 | #define GSL_LIKELY(x) (!!(x)) 65 | #define GSL_UNLIKELY(x) (!!(x)) 66 | #endif // defined(__clang__) || defined(__GNUC__) 67 | 68 | // 69 | // GSL_ASSUME(cond) 70 | // 71 | // Tell the optimizer that the predicate cond must hold. It is unspecified 72 | // whether or not cond is actually evaluated. 73 | // 74 | #ifdef _MSC_VER 75 | #define GSL_ASSUME(cond) __assume(cond) 76 | #elif defined(__GNUC__) 77 | #define GSL_ASSUME(cond) ((cond) ? static_cast(0) : __builtin_unreachable()) 78 | #else 79 | #define GSL_ASSUME(cond) static_cast((cond) ? 0 : 0) 80 | #endif 81 | 82 | // 83 | // GSL.assert: assertions 84 | // 85 | 86 | namespace gsl 87 | { 88 | 89 | namespace details 90 | { 91 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) 92 | 93 | typedef void(__cdecl* terminate_handler)(); 94 | 95 | // clang-format off 96 | GSL_SUPPRESS(f.6) // NO-FORMAT: attribute 97 | // clang-format on 98 | [[noreturn]] inline void __cdecl default_terminate_handler() 99 | { 100 | __fastfail(RANGE_CHECKS_FAILURE); 101 | } 102 | 103 | inline gsl::details::terminate_handler& get_terminate_handler() noexcept 104 | { 105 | static terminate_handler handler = &default_terminate_handler; 106 | return handler; 107 | } 108 | 109 | #endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) 110 | 111 | [[noreturn]] inline void terminate() noexcept 112 | { 113 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) 114 | (*gsl::details::get_terminate_handler())(); 115 | #else 116 | std::terminate(); 117 | #endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) 118 | } 119 | 120 | } // namespace details 121 | } // namespace gsl 122 | 123 | #define GSL_CONTRACT_CHECK(type, cond) \ 124 | (GSL_LIKELY(cond) ? static_cast(0) : gsl::details::terminate()) 125 | 126 | #define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond) 127 | #define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond) 128 | 129 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__) 130 | #pragma clang diagnostic pop 131 | #endif 132 | 133 | #endif // GSL_ASSERT_H 134 | -------------------------------------------------------------------------------- /include/gsl/byte: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_BYTE_H 18 | #define GSL_BYTE_H 19 | 20 | #include "./util" // for GSL_DEPRECATED 21 | 22 | #include 23 | 24 | #ifdef _MSC_VER 25 | 26 | #pragma warning(push) 27 | 28 | // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. 29 | #pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates 30 | // does not always work 31 | 32 | #ifndef GSL_USE_STD_BYTE 33 | // this tests if we are under MSVC and the standard lib has std::byte and it is enabled 34 | #if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603 35 | 36 | #define GSL_USE_STD_BYTE 1 37 | 38 | #else // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603 39 | 40 | #define GSL_USE_STD_BYTE 0 41 | 42 | #endif // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603 43 | #endif // GSL_USE_STD_BYTE 44 | 45 | #else // _MSC_VER 46 | 47 | #ifndef GSL_USE_STD_BYTE 48 | #include /* __cpp_lib_byte */ 49 | // this tests if we are under GCC or Clang with enough -std=c++1z power to get us std::byte 50 | // also check if libc++ version is sufficient (> 5.0) or libstdc++ actually contains std::byte 51 | #if defined(__cplusplus) && (__cplusplus >= 201703L) && \ 52 | (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \ 53 | defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) 54 | 55 | #define GSL_USE_STD_BYTE 1 56 | 57 | #else // defined(__cplusplus) && (__cplusplus >= 201703L) && 58 | // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || 59 | // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) 60 | 61 | #define GSL_USE_STD_BYTE 0 62 | 63 | #endif // defined(__cplusplus) && (__cplusplus >= 201703L) && 64 | // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || 65 | // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) 66 | #endif // GSL_USE_STD_BYTE 67 | 68 | #endif // _MSC_VER 69 | 70 | // Use __may_alias__ attribute on gcc and clang 71 | #if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5) 72 | #define byte_may_alias __attribute__((__may_alias__)) 73 | #else // defined __clang__ || defined __GNUC__ 74 | #define byte_may_alias 75 | #endif // defined __clang__ || defined __GNUC__ 76 | 77 | #if GSL_USE_STD_BYTE 78 | #include 79 | #endif 80 | 81 | namespace gsl 82 | { 83 | #if GSL_USE_STD_BYTE 84 | 85 | namespace impl { 86 | // 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. 87 | // Users of GSL should only use gsl::byte, not gsl::impl::byte. 88 | using byte = std::byte; 89 | } 90 | 91 | using byte GSL_DEPRECATED("Use std::byte instead.") = std::byte; 92 | 93 | using std::to_integer; 94 | 95 | #else // GSL_USE_STD_BYTE 96 | 97 | // This is a simple definition for now that allows 98 | // use of byte within span<> to be standards-compliant 99 | enum class byte_may_alias byte : unsigned char 100 | { 101 | }; 102 | 103 | namespace impl { 104 | // 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. 105 | // Users of GSL should only use gsl::byte, not gsl::impl::byte. 106 | using byte = gsl::byte; 107 | } 108 | 109 | template ::value, bool> = true> 110 | constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept 111 | { 112 | return b = byte(static_cast(b) << shift); 113 | } 114 | 115 | template ::value, bool> = true> 116 | constexpr byte operator<<(byte b, IntegerType shift) noexcept 117 | { 118 | return byte(static_cast(b) << shift); 119 | } 120 | 121 | template ::value, bool> = true> 122 | constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept 123 | { 124 | return b = byte(static_cast(b) >> shift); 125 | } 126 | 127 | template ::value, bool> = true> 128 | constexpr byte operator>>(byte b, IntegerType shift) noexcept 129 | { 130 | return byte(static_cast(b) >> shift); 131 | } 132 | 133 | constexpr byte& operator|=(byte& l, byte r) noexcept 134 | { 135 | return l = byte(static_cast(l) | static_cast(r)); 136 | } 137 | 138 | constexpr byte operator|(byte l, byte r) noexcept 139 | { 140 | return byte(static_cast(l) | static_cast(r)); 141 | } 142 | 143 | constexpr byte& operator&=(byte& l, byte r) noexcept 144 | { 145 | return l = byte(static_cast(l) & static_cast(r)); 146 | } 147 | 148 | constexpr byte operator&(byte l, byte r) noexcept 149 | { 150 | return byte(static_cast(l) & static_cast(r)); 151 | } 152 | 153 | constexpr byte& operator^=(byte& l, byte r) noexcept 154 | { 155 | return l = byte(static_cast(l) ^ static_cast(r)); 156 | } 157 | 158 | constexpr byte operator^(byte l, byte r) noexcept 159 | { 160 | return byte(static_cast(l) ^ static_cast(r)); 161 | } 162 | 163 | constexpr byte operator~(byte b) noexcept { return byte(~static_cast(b)); } 164 | 165 | template ::value, bool> = true> 166 | constexpr IntegerType to_integer(byte b) noexcept 167 | { 168 | return static_cast(b); 169 | } 170 | 171 | #endif // GSL_USE_STD_BYTE 172 | 173 | 174 | template 175 | // NOTE: need suppression since c++14 does not allow "return {t}" 176 | // GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work 177 | constexpr gsl::impl::byte to_byte(T t) noexcept 178 | { 179 | static_assert(std::is_same::value, 180 | "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. " 181 | "If you are calling to_byte with an integer constant use: gsl::to_byte() version."); 182 | return gsl::impl::byte(t); 183 | } 184 | 185 | template 186 | constexpr gsl::impl::byte to_byte() noexcept 187 | { 188 | static_assert(I >= 0 && I <= 255, 189 | "gsl::byte only has 8 bits of storage, values must be in range 0-255"); 190 | return static_cast(I); 191 | } 192 | 193 | } // namespace gsl 194 | 195 | #ifdef _MSC_VER 196 | #pragma warning(pop) 197 | #endif // _MSC_VER 198 | 199 | #endif // GSL_BYTE_H 200 | -------------------------------------------------------------------------------- /include/gsl/gsl: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_GSL_H 18 | #define GSL_GSL_H 19 | 20 | // IWYU pragma: begin_exports 21 | #include "./algorithm" // copy 22 | #include "./assert" // Ensures/Expects 23 | #include "./byte" // byte 24 | #include "./pointers" // owner, not_null 25 | #include "./span" // span 26 | #include "./zstring" // zstring 27 | #include "./util" // finally()/narrow_cast()... 28 | 29 | #ifdef __cpp_exceptions 30 | #include "./narrow" // narrow() 31 | #endif 32 | // IWYU pragma: end_exports 33 | 34 | #endif // GSL_GSL_H 35 | -------------------------------------------------------------------------------- /include/gsl/narrow: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_NARROW_H 18 | #define GSL_NARROW_H 19 | #include "./assert" // for GSL_SUPPRESS 20 | #include "./util" // for narrow_cast 21 | #include // for std::exception 22 | namespace gsl 23 | { 24 | struct narrowing_error : public std::exception 25 | { 26 | const char* what() const noexcept override { return "narrowing_error"; } 27 | }; 28 | 29 | // narrow() : a checked version of narrow_cast() that throws if the cast changed the value 30 | template ::value>::type* = nullptr> 31 | // clang-format off 32 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 33 | GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur 34 | // in the static_cast below, and that gsl::narrow should be used instead. 35 | // Suppress this warning, since gsl::narrow is defined in terms of 36 | // static_cast 37 | // clang-format on 38 | constexpr T narrow(U u) 39 | { 40 | constexpr const bool is_different_signedness = 41 | (std::is_signed::value != std::is_signed::value); 42 | 43 | GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow 44 | GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow 45 | GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior 46 | const T t = narrow_cast(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type 47 | // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms 48 | // that we target (i.e., no hardware trap representations are hit). 49 | 50 | #if defined(__clang__) || defined(__GNUC__) 51 | #pragma GCC diagnostic push 52 | #pragma GCC diagnostic ignored "-Wfloat-equal" 53 | #endif 54 | // Note: NaN will always throw, since NaN != NaN 55 | if (static_cast(t) != u || (is_different_signedness && ((t < T{}) != (u < U{})))) 56 | { 57 | throw narrowing_error{}; 58 | } 59 | #if defined(__clang__) || defined(__GNUC__) 60 | #pragma GCC diagnostic pop 61 | #endif 62 | 63 | return t; 64 | } 65 | 66 | template ::value>::type* = nullptr> 67 | // clang-format off 68 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 69 | // clang-format on 70 | constexpr T narrow(U u) 71 | { 72 | const T t = narrow_cast(u); 73 | 74 | if (static_cast(t) != u) 75 | { 76 | throw narrowing_error{}; 77 | } 78 | 79 | return t; 80 | } 81 | } // namespace gsl 82 | #endif // GSL_NARROW_H 83 | -------------------------------------------------------------------------------- /include/gsl/pointers: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_POINTERS_H 18 | #define GSL_POINTERS_H 19 | 20 | #include "./assert" // for Ensures, Expects 21 | #include "./util" // for GSL_DEPRECATED 22 | 23 | #include // for ptrdiff_t, nullptr_t, size_t 24 | #include // for less, greater 25 | #include // for shared_ptr, unique_ptr, hash 26 | #include // for enable_if_t, is_convertible, is_assignable 27 | #include // for declval, forward 28 | 29 | #if !defined(GSL_NO_IOSTREAMS) 30 | #include // for ostream 31 | #endif // !defined(GSL_NO_IOSTREAMS) 32 | 33 | namespace gsl 34 | { 35 | 36 | namespace details 37 | { 38 | template 39 | struct is_comparable_to_nullptr : std::false_type 40 | { 41 | }; 42 | 43 | template 44 | struct is_comparable_to_nullptr< 45 | T, 46 | std::enable_if_t() != nullptr), bool>::value>> 47 | : std::true_type 48 | { 49 | }; 50 | 51 | // Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value 52 | // of type T. 53 | // 54 | // Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-in) 55 | template 56 | using value_or_reference_return_t = std::conditional_t< 57 | sizeof(T) <= 2*sizeof(void*) && std::is_trivially_copy_constructible::value, 58 | const T, 59 | const T&>; 60 | 61 | } // namespace details 62 | 63 | // 64 | // GSL.owner: ownership pointers 65 | // 66 | template 67 | using shared_ptr GSL_DEPRECATED("Use std::shared_ptr instead") = std::shared_ptr; 68 | 69 | template 70 | using unique_ptr GSL_DEPRECATED("Use std::unique_ptr instead") = std::unique_ptr; 71 | 72 | // 73 | // owner 74 | // 75 | // `gsl::owner` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory. 76 | // Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used 77 | // as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers. 78 | // 79 | // T must be a pointer type 80 | // - disallow construction from any type other than pointer type 81 | // 82 | template ::value, bool> = true> 83 | using owner = T; 84 | 85 | // 86 | // not_null 87 | // 88 | // Restricts a pointer or smart pointer to only hold non-null values. 89 | // 90 | // Has zero size overhead over T. 91 | // 92 | // If T is a pointer (i.e. T == U*) then 93 | // - allow construction from U* 94 | // - disallow construction from nullptr_t 95 | // - disallow default construction 96 | // - ensure construction from null U* fails 97 | // - allow implicit conversion to U* 98 | // 99 | template 100 | class not_null 101 | { 102 | public: 103 | static_assert(details::is_comparable_to_nullptr::value, "T cannot be compared to nullptr."); 104 | 105 | using element_type = T; 106 | 107 | template ::value>> 108 | constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible::value) : ptr_(std::forward(u)) 109 | { 110 | Expects(ptr_ != nullptr); 111 | } 112 | 113 | template ::value>> 114 | constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible::value) : ptr_(std::move(u)) 115 | { 116 | Expects(ptr_ != nullptr); 117 | } 118 | 119 | template ::value>> 120 | constexpr not_null(const not_null& other) noexcept(std::is_nothrow_move_constructible::value) : not_null(other.get()) 121 | {} 122 | 123 | not_null(const not_null& other) = default; 124 | not_null& operator=(const not_null& other) = default; 125 | constexpr details::value_or_reference_return_t get() const 126 | noexcept(noexcept(details::value_or_reference_return_t(std::declval()))) 127 | { 128 | return ptr_; 129 | } 130 | 131 | constexpr operator T() const { return get(); } 132 | constexpr decltype(auto) operator->() const { return get(); } 133 | constexpr decltype(auto) operator*() const { return *get(); } 134 | 135 | // prevents compilation when someone attempts to assign a null pointer constant 136 | not_null(std::nullptr_t) = delete; 137 | not_null& operator=(std::nullptr_t) = delete; 138 | 139 | // unwanted operators...pointers only point to single objects! 140 | not_null& operator++() = delete; 141 | not_null& operator--() = delete; 142 | not_null operator++(int) = delete; 143 | not_null operator--(int) = delete; 144 | not_null& operator+=(std::ptrdiff_t) = delete; 145 | not_null& operator-=(std::ptrdiff_t) = delete; 146 | void operator[](std::ptrdiff_t) const = delete; 147 | 148 | void swap(not_null& other) { std::swap(ptr_, other.ptr_); } 149 | 150 | private: 151 | T ptr_; 152 | }; 153 | 154 | template ::value && std::is_move_constructible::value, bool> = true> 155 | void swap(not_null& a, not_null& b) 156 | { 157 | a.swap(b); 158 | } 159 | 160 | template 161 | auto make_not_null(T&& t) noexcept 162 | { 163 | return not_null>>{std::forward(t)}; 164 | } 165 | 166 | #if !defined(GSL_NO_IOSTREAMS) 167 | template 168 | std::ostream& operator<<(std::ostream& os, const not_null& val) 169 | { 170 | os << val.get(); 171 | return os; 172 | } 173 | #endif // !defined(GSL_NO_IOSTREAMS) 174 | 175 | template 176 | constexpr auto operator==(const not_null& lhs, 177 | const not_null& rhs) noexcept(noexcept(lhs.get() == rhs.get())) 178 | -> decltype(lhs.get() == rhs.get()) 179 | { 180 | return lhs.get() == rhs.get(); 181 | } 182 | 183 | template 184 | constexpr auto operator!=(const not_null& lhs, 185 | const not_null& rhs) noexcept(noexcept(lhs.get() != rhs.get())) 186 | -> decltype(lhs.get() != rhs.get()) 187 | { 188 | return lhs.get() != rhs.get(); 189 | } 190 | 191 | template 192 | constexpr auto operator<(const not_null& lhs, 193 | const not_null& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get()))) 194 | -> decltype(std::less<>{}(lhs.get(), rhs.get())) 195 | { 196 | return std::less<>{}(lhs.get(), rhs.get()); 197 | } 198 | 199 | template 200 | constexpr auto operator<=(const not_null& lhs, 201 | const not_null& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get()))) 202 | -> decltype(std::less_equal<>{}(lhs.get(), rhs.get())) 203 | { 204 | return std::less_equal<>{}(lhs.get(), rhs.get()); 205 | } 206 | 207 | template 208 | constexpr auto operator>(const not_null& lhs, 209 | const not_null& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get()))) 210 | -> decltype(std::greater<>{}(lhs.get(), rhs.get())) 211 | { 212 | return std::greater<>{}(lhs.get(), rhs.get()); 213 | } 214 | 215 | template 216 | constexpr auto operator>=(const not_null& lhs, 217 | const not_null& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get()))) 218 | -> decltype(std::greater_equal<>{}(lhs.get(), rhs.get())) 219 | { 220 | return std::greater_equal<>{}(lhs.get(), rhs.get()); 221 | } 222 | 223 | // more unwanted operators 224 | template 225 | std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; 226 | template 227 | not_null operator-(const not_null&, std::ptrdiff_t) = delete; 228 | template 229 | not_null operator+(const not_null&, std::ptrdiff_t) = delete; 230 | template 231 | not_null operator+(std::ptrdiff_t, const not_null&) = delete; 232 | 233 | 234 | template ().get()), bool = std::is_default_constructible>::value> 235 | struct not_null_hash 236 | { 237 | std::size_t operator()(const T& value) const { return std::hash{}(value.get()); } 238 | }; 239 | 240 | template 241 | struct not_null_hash 242 | { 243 | not_null_hash() = delete; 244 | not_null_hash(const not_null_hash&) = delete; 245 | not_null_hash& operator=(const not_null_hash&) = delete; 246 | }; 247 | 248 | } // namespace gsl 249 | 250 | namespace std 251 | { 252 | template 253 | struct hash> : gsl::not_null_hash> 254 | { 255 | }; 256 | 257 | } // namespace std 258 | 259 | namespace gsl 260 | { 261 | 262 | // 263 | // strict_not_null 264 | // 265 | // Restricts a pointer or smart pointer to only hold non-null values, 266 | // 267 | // - provides a strict (i.e. explicit constructor from T) wrapper of not_null 268 | // - to be used for new code that wishes the design to be cleaner and make not_null 269 | // checks intentional, or in old code that would like to make the transition. 270 | // 271 | // To make the transition from not_null, incrementally replace not_null 272 | // by strict_not_null and fix compilation errors 273 | // 274 | // Expect to 275 | // - remove all unneeded conversions from raw pointer to not_null and back 276 | // - make API clear by specifying not_null in parameters where needed 277 | // - remove unnecessary asserts 278 | // 279 | template 280 | class strict_not_null : public not_null 281 | { 282 | public: 283 | template ::value>> 284 | constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible::value) : not_null(std::forward(u)) 285 | {} 286 | 287 | template ::value>> 288 | constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible::value) : not_null(std::move(u)) 289 | {} 290 | 291 | template ::value>> 292 | constexpr strict_not_null(const not_null& other) noexcept(std::is_nothrow_move_constructible::value) : not_null(other) 293 | {} 294 | 295 | template ::value>> 296 | constexpr strict_not_null(const strict_not_null& other) noexcept(std::is_nothrow_move_constructible::value) : not_null(other) 297 | {} 298 | 299 | // To avoid invalidating the "not null" invariant, the contained pointer is actually copied 300 | // instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions. 301 | strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible::value) = default; 302 | strict_not_null(const strict_not_null& other) = default; 303 | strict_not_null& operator=(const strict_not_null& other) = default; 304 | strict_not_null& operator=(const not_null& other) 305 | { 306 | not_null::operator=(other); 307 | return *this; 308 | } 309 | 310 | // prevents compilation when someone attempts to assign a null pointer constant 311 | strict_not_null(std::nullptr_t) = delete; 312 | strict_not_null& operator=(std::nullptr_t) = delete; 313 | 314 | // unwanted operators...pointers only point to single objects! 315 | strict_not_null& operator++() = delete; 316 | strict_not_null& operator--() = delete; 317 | strict_not_null operator++(int) = delete; 318 | strict_not_null operator--(int) = delete; 319 | strict_not_null& operator+=(std::ptrdiff_t) = delete; 320 | strict_not_null& operator-=(std::ptrdiff_t) = delete; 321 | void operator[](std::ptrdiff_t) const = delete; 322 | }; 323 | 324 | // more unwanted operators 325 | template 326 | std::ptrdiff_t operator-(const strict_not_null&, const strict_not_null&) = delete; 327 | template 328 | strict_not_null operator-(const strict_not_null&, std::ptrdiff_t) = delete; 329 | template 330 | strict_not_null operator+(const strict_not_null&, std::ptrdiff_t) = delete; 331 | template 332 | strict_not_null operator+(std::ptrdiff_t, const strict_not_null&) = delete; 333 | 334 | template 335 | auto make_strict_not_null(T&& t) noexcept 336 | { 337 | return strict_not_null>>{std::forward(t)}; 338 | } 339 | 340 | #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) 341 | 342 | // deduction guides to prevent the ctad-maybe-unsupported warning 343 | template 344 | not_null(T) -> not_null; 345 | template 346 | strict_not_null(T) -> strict_not_null; 347 | 348 | #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) 349 | 350 | } // namespace gsl 351 | 352 | namespace std 353 | { 354 | template 355 | struct hash> : gsl::not_null_hash> 356 | { 357 | }; 358 | 359 | } // namespace std 360 | 361 | #endif // GSL_POINTERS_H 362 | -------------------------------------------------------------------------------- /include/gsl/span_ext: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_SPAN_EXT_H 18 | #define GSL_SPAN_EXT_H 19 | 20 | /////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // File: span_ext 23 | // Purpose: continue offering features that have been cut from the official 24 | // implementation of span. 25 | // While modernizing gsl::span a number of features needed to be removed to 26 | // be compliant with the design of std::span 27 | // 28 | /////////////////////////////////////////////////////////////////////////////// 29 | 30 | #include "./assert" // GSL_KERNEL_MODE 31 | #include "./util" // for narrow_cast, narrow 32 | 33 | #include // for ptrdiff_t, size_t 34 | #include 35 | 36 | #ifndef GSL_KERNEL_MODE 37 | #include // for lexicographical_compare 38 | #endif // GSL_KERNEL_MODE 39 | 40 | namespace gsl 41 | { 42 | 43 | // [span.views.constants], constants 44 | GSL_INLINE constexpr const std::size_t dynamic_extent = narrow_cast(-1); 45 | 46 | template 47 | class span; 48 | 49 | // std::equal and std::lexicographical_compare are not /kernel compatible 50 | // so all comparison operators must be removed for kernel mode. 51 | #ifndef GSL_KERNEL_MODE 52 | 53 | // [span.comparison], span comparison operators 54 | template 55 | constexpr bool operator==(span l, span r) 56 | { 57 | return std::equal(l.begin(), l.end(), r.begin(), r.end()); 58 | } 59 | 60 | template 61 | constexpr bool operator!=(span l, span r) 62 | { 63 | return !(l == r); 64 | } 65 | 66 | template 67 | constexpr bool operator<(span l, span r) 68 | { 69 | return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); 70 | } 71 | 72 | template 73 | constexpr bool operator<=(span l, span r) 74 | { 75 | return !(l > r); 76 | } 77 | 78 | template 79 | constexpr bool operator>(span l, span r) 80 | { 81 | return r < l; 82 | } 83 | 84 | template 85 | constexpr bool operator>=(span l, span r) 86 | { 87 | return !(l < r); 88 | } 89 | 90 | #endif // GSL_KERNEL_MODE 91 | 92 | // 93 | // make_span() - Utility functions for creating spans 94 | // 95 | template 96 | constexpr span make_span(ElementType* ptr, typename span::size_type count) 97 | { 98 | return span(ptr, count); 99 | } 100 | 101 | template 102 | constexpr span make_span(ElementType* firstElem, ElementType* lastElem) 103 | { 104 | return span(firstElem, lastElem); 105 | } 106 | 107 | template 108 | constexpr span make_span(ElementType (&arr)[N]) noexcept 109 | { 110 | return span(arr); 111 | } 112 | 113 | template 114 | constexpr span make_span(Container& cont) 115 | { 116 | return span(cont); 117 | } 118 | 119 | template 120 | constexpr span make_span(const Container& cont) 121 | { 122 | return span(cont); 123 | } 124 | 125 | template 126 | GSL_DEPRECATED("This function is deprecated. See GSL issue #1092.") 127 | constexpr span make_span(Ptr& cont, std::size_t count) 128 | { 129 | return span(cont, count); 130 | } 131 | 132 | template 133 | GSL_DEPRECATED("This function is deprecated. See GSL issue #1092.") 134 | constexpr span make_span(Ptr& cont) 135 | { 136 | return span(cont); 137 | } 138 | 139 | // Specialization of gsl::at for span 140 | template 141 | constexpr ElementType& at(span s, index i) 142 | { 143 | // No bounds checking here because it is done in span::operator[] called below 144 | Ensures(i >= 0); 145 | return s[narrow_cast(i)]; 146 | } 147 | 148 | // [span.obs] Free observer functions 149 | template 150 | constexpr std::ptrdiff_t ssize(const span& s) noexcept 151 | { 152 | return static_cast(s.size()); 153 | } 154 | 155 | // [span.iter] Free functions for begin/end functions 156 | template 157 | constexpr typename span::iterator 158 | begin(const span& s) noexcept 159 | { 160 | return s.begin(); 161 | } 162 | 163 | template 164 | constexpr typename span::iterator 165 | end(const span& s) noexcept 166 | { 167 | return s.end(); 168 | } 169 | 170 | template 171 | constexpr typename span::reverse_iterator 172 | rbegin(const span& s) noexcept 173 | { 174 | return s.rbegin(); 175 | } 176 | 177 | template 178 | constexpr typename span::reverse_iterator 179 | rend(const span& s) noexcept 180 | { 181 | return s.rend(); 182 | } 183 | 184 | template 185 | constexpr typename span::iterator 186 | cbegin(const span& s) noexcept 187 | { 188 | return s.begin(); 189 | } 190 | 191 | template 192 | constexpr typename span::iterator 193 | cend(const span& s) noexcept 194 | { 195 | return s.end(); 196 | } 197 | 198 | template 199 | constexpr typename span::reverse_iterator 200 | crbegin(const span& s) noexcept 201 | { 202 | return s.rbegin(); 203 | } 204 | 205 | template 206 | constexpr typename span::reverse_iterator 207 | crend(const span& s) noexcept 208 | { 209 | return s.rend(); 210 | } 211 | 212 | } // namespace gsl 213 | 214 | #endif // GSL_SPAN_EXT_H 215 | -------------------------------------------------------------------------------- /include/gsl/util: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_UTIL_H 18 | #define GSL_UTIL_H 19 | 20 | #include "./assert" // for Expects 21 | 22 | #include 23 | #include // for ptrdiff_t, size_t 24 | #include // for numeric_limits 25 | #include // for initializer_list 26 | #include // for is_signed, integral_constant 27 | #include // for exchange, forward 28 | 29 | #if defined(__has_include) && __has_include() 30 | #include 31 | #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 32 | #include 33 | #endif // __cpp_lib_span >= 202002L 34 | #endif //__has_include() 35 | 36 | #if defined(_MSC_VER) && !defined(__clang__) 37 | 38 | #pragma warning(push) 39 | #pragma warning(disable : 4127) // conditional expression is constant 40 | 41 | #endif // _MSC_VER 42 | 43 | // Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks 44 | #if defined(__clang__) 45 | #if __has_warning("-Wunsafe-buffer-usage") 46 | #pragma clang diagnostic push 47 | #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" 48 | #endif // __has_warning("-Wunsafe-buffer-usage") 49 | #endif // defined(__clang__) 50 | 51 | #if defined(__cplusplus) && (__cplusplus >= 201703L) 52 | #define GSL_NODISCARD [[nodiscard]] 53 | #else 54 | #define GSL_NODISCARD 55 | #endif // defined(__cplusplus) && (__cplusplus >= 201703L) 56 | 57 | #if defined(__cpp_inline_variables) 58 | #define GSL_INLINE inline 59 | #else 60 | #define GSL_INLINE 61 | #endif 62 | 63 | #if defined(__has_cpp_attribute) 64 | #if __has_cpp_attribute(deprecated) 65 | #define GSL_DEPRECATED(msg) [[deprecated(msg)]] 66 | #endif // __has_cpp_attribute(deprecated) 67 | #endif // defined(__has_cpp_attribute) 68 | 69 | #if !defined(GSL_DEPRECATED) 70 | #if defined(__cplusplus) 71 | #if __cplusplus >= 201309L 72 | #define GSL_DEPRECATED(msg) [[deprecated(msg)]] 73 | #endif // __cplusplus >= 201309L 74 | #endif // defined(__cplusplus) 75 | #endif // !defined(GSL_DEPRECATED) 76 | 77 | #if !defined(GSL_DEPRECATED) 78 | #if defined(_MSC_VER) 79 | #define GSL_DEPRECATED(msg) __declspec(deprecated(msg)) 80 | #elif defined(__GNUC__) 81 | #define GSL_DEPRECATED(msg) __attribute__((deprecated(msg))) 82 | #endif // defined(_MSC_VER) 83 | #endif // !defined(GSL_DEPRECATED) 84 | 85 | #if !defined(GSL_DEPRECATED) 86 | #define GSL_DEPRECATED(msg) 87 | #endif // !defined(GSL_DEPRECATED) 88 | 89 | namespace gsl 90 | { 91 | // 92 | // GSL.util: utilities 93 | // 94 | 95 | // index type for all container indexes/subscripts/sizes 96 | using index = std::ptrdiff_t; 97 | 98 | // final_action allows you to ensure something gets run at the end of a scope 99 | template 100 | class final_action 101 | { 102 | public: 103 | explicit final_action(const F& ff) noexcept : f{ff} { } 104 | explicit final_action(F&& ff) noexcept : f{std::move(ff)} { } 105 | 106 | ~final_action() noexcept { if (invoke) f(); } 107 | 108 | final_action(final_action&& other) noexcept 109 | : f(std::move(other.f)), invoke(std::exchange(other.invoke, false)) 110 | { } 111 | 112 | final_action(const final_action&) = delete; 113 | void operator=(const final_action&) = delete; 114 | void operator=(final_action&&) = delete; 115 | 116 | private: 117 | F f; 118 | bool invoke = true; 119 | }; 120 | 121 | // finally() - convenience function to generate a final_action 122 | template 123 | GSL_NODISCARD auto finally(F&& f) noexcept 124 | { 125 | return final_action>{std::forward(f)}; 126 | } 127 | 128 | // narrow_cast(): a searchable way to do narrowing casts of values 129 | template 130 | // clang-format off 131 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 132 | // clang-format on 133 | constexpr T narrow_cast(U&& u) noexcept 134 | { 135 | return static_cast(std::forward(u)); 136 | } 137 | 138 | // 139 | // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector 140 | // 141 | template 142 | // clang-format off 143 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 144 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 145 | // clang-format on 146 | constexpr T& at(T (&arr)[N], const index i) 147 | { 148 | static_assert(N <= static_cast((std::numeric_limits::max)()), "We only support arrays up to PTRDIFF_MAX bytes."); 149 | Expects(i >= 0 && i < narrow_cast(N)); 150 | return arr[narrow_cast(i)]; 151 | } 152 | 153 | template 154 | // clang-format off 155 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 156 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 157 | // clang-format on 158 | constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) 159 | { 160 | Expects(i >= 0 && i < narrow_cast(cont.size())); 161 | using size_type = decltype(cont.size()); 162 | return cont[narrow_cast(i)]; 163 | } 164 | 165 | template 166 | // clang-format off 167 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 168 | // clang-format on 169 | constexpr T at(const std::initializer_list cont, const index i) 170 | { 171 | Expects(i >= 0 && i < narrow_cast(cont.size())); 172 | return *(cont.begin() + i); 173 | } 174 | 175 | template ::value && std::is_move_constructible::value>> 176 | void swap(T& a, T& b) { std::swap(a, b); } 177 | 178 | #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 179 | template 180 | constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size()]) 181 | { 182 | Expects(i >= 0 && i < narrow_cast(sp.size())); 183 | return sp[gsl::narrow_cast(i)]; 184 | } 185 | #endif // __cpp_lib_span >= 202002L 186 | } // namespace gsl 187 | 188 | #if defined(_MSC_VER) && !defined(__clang__) 189 | 190 | #pragma warning(pop) 191 | 192 | #endif // _MSC_VER 193 | 194 | #if defined(__clang__) 195 | #if __has_warning("-Wunsafe-buffer-usage") 196 | #pragma clang diagnostic pop 197 | #endif // __has_warning("-Wunsafe-buffer-usage") 198 | #endif // defined(__clang__) 199 | 200 | #endif // GSL_UTIL_H 201 | -------------------------------------------------------------------------------- /include/gsl/zstring: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef GSL_ZSTRING_H 18 | #define GSL_ZSTRING_H 19 | 20 | #include "./span_ext" // for dynamic_extent 21 | 22 | #include // for size_t, nullptr_t 23 | 24 | namespace gsl 25 | { 26 | // 27 | // czstring and wzstring 28 | // 29 | // These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays) 30 | // that allow static analysis to help find bugs. 31 | // 32 | // There are no additional features/semantics that we can find a way to add inside the 33 | // type system for these types that will not either incur significant runtime costs or 34 | // (sometimes needlessly) break existing programs when introduced. 35 | // 36 | 37 | template 38 | using basic_zstring = CharT*; 39 | 40 | using czstring = basic_zstring; 41 | 42 | using cwzstring = basic_zstring; 43 | 44 | using cu16zstring = basic_zstring; 45 | 46 | using cu32zstring = basic_zstring; 47 | 48 | using zstring = basic_zstring; 49 | 50 | using wzstring = basic_zstring; 51 | 52 | using u16zstring = basic_zstring; 53 | 54 | using u32zstring = basic_zstring; 55 | 56 | } // namespace gsl 57 | 58 | #endif // GSL_ZSTRING_H 59 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14...3.16) 2 | 3 | project(GSLTests LANGUAGES CXX) 4 | 5 | set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard") 6 | 7 | set(CMAKE_CXX_STANDARD ${GSL_CXX_STANDARD}) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | include(FindPkgConfig) 12 | include(ExternalProject) 13 | 14 | # will make visual studio generated project group files 15 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 16 | 17 | if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20) 18 | add_compile_definitions(FORCE_STD_SPAN_TESTS=1) 19 | endif() 20 | 21 | if(IOS) 22 | add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1) 23 | endif() 24 | 25 | pkg_search_module(GTestMain gtest_main) 26 | if (NOT GTestMain_FOUND) 27 | # No pre-installed GTest is available, try to download it using Git. 28 | find_package(Git REQUIRED QUIET) 29 | 30 | configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) 31 | execute_process( 32 | COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 33 | RESULT_VARIABLE result 34 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download 35 | ) 36 | if(result) 37 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 38 | endif() 39 | 40 | execute_process( 41 | COMMAND ${CMAKE_COMMAND} --build . 42 | RESULT_VARIABLE result 43 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download 44 | ) 45 | if(result) 46 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 47 | endif() 48 | 49 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 50 | set(GTestMain_LIBRARIES gtest_main) 51 | 52 | add_subdirectory( 53 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-src 54 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build 55 | EXCLUDE_FROM_ALL 56 | ) 57 | endif() 58 | 59 | if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 60 | find_package(Microsoft.GSL CONFIG REQUIRED) 61 | enable_testing() 62 | 63 | if (NOT DEFINED Microsoft.GSL_VERSION) 64 | message(FATAL_ERROR "Microsoft.GSL_VERSION not defined!") 65 | endif() 66 | 67 | message(STATUS "Microsoft.GSL_VERSION = ${Microsoft.GSL_VERSION}") 68 | endif() 69 | 70 | if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17)) 71 | set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) 72 | endif() 73 | 74 | include(CheckCXXCompilerFlag) 75 | # this interface adds compile options to how the tests are run 76 | # please try to keep entries ordered =) 77 | add_library(gsl_tests_config INTERFACE) 78 | if(MSVC) # MSVC or simulating MSVC 79 | target_compile_options(gsl_tests_config INTERFACE 80 | ${GSL_CPLUSPLUS_OPT} 81 | /EHsc 82 | /W4 83 | /WX 84 | $<$: 85 | /wd4996 # Use of function or classes marked [[deprecated]] 86 | /wd26409 # CppCoreCheck - GTest 87 | /wd26426 # CppCoreCheck - GTest 88 | /wd26440 # CppCoreCheck - GTest 89 | /wd26446 # CppCoreCheck - prefer gsl::at() 90 | /wd26472 # CppCoreCheck - use gsl::narrow(_cast) 91 | /wd26481 # CppCoreCheck - use span instead of pointer arithmetic 92 | $<$,1920>: # VS2015 93 | /wd4189 # variable is initialized but not referenced 94 | $<$>: # Release, RelWithDebInfo 95 | /wd4702 # Unreachable code 96 | > 97 | > 98 | > 99 | $<$: 100 | -Weverything 101 | -Wfloat-equal 102 | -Wno-c++98-compat 103 | -Wno-c++98-compat-pedantic 104 | -Wno-covered-switch-default # GTest 105 | -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements 106 | -Wno-global-constructors # GTest 107 | -Wno-language-extension-token # GTest gtest-port.h 108 | -Wno-missing-braces 109 | -Wno-missing-prototypes 110 | -Wno-shift-sign-overflow # GTest gtest-port.h 111 | -Wno-undef # GTest 112 | -Wno-used-but-marked-unused # GTest EXPECT_DEATH 113 | -Wno-switch-default # GTest EXPECT_DEATH 114 | $<$: # no support for [[maybe_unused]] 115 | -Wno-unused-member-function 116 | -Wno-unused-variable 117 | $<$,15.0.1>: 118 | -Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning 119 | > 120 | > 121 | > 122 | ) 123 | check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) 124 | if (WARN_RESERVED_ID) 125 | target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier") 126 | endif() 127 | else() 128 | target_compile_options(gsl_tests_config INTERFACE 129 | -fno-strict-aliasing 130 | -Wall 131 | -Wcast-align 132 | -Wconversion 133 | -Wctor-dtor-privacy 134 | -Werror 135 | -Wextra 136 | -Wpedantic 137 | -Wshadow 138 | -Wsign-conversion 139 | -Wfloat-equal 140 | -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements 141 | $<$,$>: 142 | -Weverything 143 | -Wno-c++98-compat 144 | -Wno-c++98-compat-pedantic 145 | -Wno-missing-braces 146 | -Wno-covered-switch-default # GTest 147 | -Wno-global-constructors # GTest 148 | -Wno-missing-prototypes 149 | -Wno-padded 150 | -Wno-switch-default 151 | -Wno-unknown-attributes 152 | -Wno-used-but-marked-unused # GTest EXPECT_DEATH 153 | -Wno-weak-vtables 154 | $<$: # no support for [[maybe_unused]] 155 | -Wno-unused-member-function 156 | -Wno-unused-variable 157 | > 158 | > 159 | $<$: 160 | $<$,4.99>,$,6>>: 161 | $<$:-Wno-undefined-func-template> 162 | > 163 | $<$,$,$>>: 164 | -Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 10.0.0 165 | # and clang 11.0.0. (operator< is being re-written by the compiler 166 | # as operator<=> and raising the warning) 167 | > 168 | > 169 | $<$: 170 | $<$,9.1>,$,10>>: 171 | $<$:-Wno-undefined-func-template> 172 | > 173 | > 174 | $<$: 175 | -Wdouble-promotion # float implicit to double 176 | -Wlogical-op # suspicious uses of logical operators 177 | $<$,6>>: 178 | -Wduplicated-cond # duplicated if-else conditions 179 | -Wmisleading-indentation 180 | -Wnull-dereference 181 | $<$: # no support for [[maybe_unused]] 182 | -Wno-unused-variable 183 | > 184 | > 185 | $<$,7>>: 186 | -Wduplicated-branches # identical if-else branches 187 | > 188 | > 189 | ) 190 | endif(MSVC) 191 | check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER) 192 | if (WARN_UNSAFE_BUFFER) 193 | # This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer" 194 | target_compile_options(gsl_tests_config INTERFACE "-Wno-unsafe-buffer-usage") 195 | endif() 196 | 197 | # for tests to find the gtest header 198 | target_include_directories(gsl_tests_config SYSTEM INTERFACE 199 | googletest/googletest/include 200 | ) 201 | 202 | add_executable(gsl_tests 203 | algorithm_tests.cpp 204 | assertion_tests.cpp 205 | at_tests.cpp 206 | byte_tests.cpp 207 | constexpr_notnull_tests.cpp 208 | notnull_tests.cpp 209 | owner_tests.cpp 210 | pointers_tests.cpp 211 | span_compatibility_tests.cpp 212 | span_ext_tests.cpp 213 | span_tests.cpp 214 | strict_notnull_tests.cpp 215 | 216 | utils_tests.cpp 217 | ) 218 | 219 | target_link_libraries(gsl_tests 220 | Microsoft.GSL::GSL 221 | gsl_tests_config 222 | ${GTestMain_LIBRARIES} 223 | ) 224 | add_test(gsl_tests gsl_tests) 225 | 226 | # No exception tests 227 | 228 | foreach(flag_var 229 | CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE 230 | CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) 231 | STRING (REGEX REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}") 232 | endforeach(flag_var) 233 | 234 | # this interface adds compile options to how the tests are run 235 | # please try to keep entries ordered =) 236 | add_library(gsl_tests_config_noexcept INTERFACE) 237 | if(MSVC) # MSVC or simulating MSVC 238 | target_compile_definitions(gsl_tests_config_noexcept INTERFACE 239 | _HAS_EXCEPTIONS=0 # disable exceptions in the Microsoft STL 240 | ) 241 | target_compile_options(gsl_tests_config_noexcept INTERFACE 242 | ${GSL_CPLUSPLUS_OPT} 243 | /W4 244 | /WX 245 | $<$: 246 | /wd4577 247 | /wd4702 248 | /wd26440 # CppCoreCheck - GTest 249 | /wd26446 # CppCoreCheck - prefer gsl::at() 250 | > 251 | $<$: 252 | -Weverything 253 | -Wfloat-equal 254 | -Wno-c++98-compat 255 | -Wno-c++98-compat-pedantic 256 | -Wno-missing-prototypes 257 | -Wno-unknown-attributes 258 | $<$: 259 | $<$,15.0.1>: 260 | -Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning 261 | > 262 | > 263 | > 264 | ) 265 | check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) 266 | if (WARN_RESERVED_ID) 267 | target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier") 268 | endif() 269 | else() 270 | target_compile_options(gsl_tests_config_noexcept INTERFACE 271 | -fno-exceptions 272 | -fno-strict-aliasing 273 | -Wall 274 | -Wcast-align 275 | -Wconversion 276 | -Wctor-dtor-privacy 277 | -Werror 278 | -Wextra 279 | -Wpedantic 280 | -Wshadow 281 | -Wsign-conversion 282 | -Wfloat-equal 283 | $<$,$>: 284 | -Weverything 285 | -Wno-c++98-compat 286 | -Wno-c++98-compat-pedantic 287 | -Wno-missing-prototypes 288 | -Wno-unknown-attributes 289 | -Wno-weak-vtables 290 | > 291 | $<$: 292 | -Wdouble-promotion # float implicit to double 293 | -Wlogical-op # suspicious uses of logical operators 294 | -Wuseless-cast # casting to its own type 295 | $<$,6>>: 296 | -Wduplicated-cond # duplicated if-else conditions 297 | -Wmisleading-indentation 298 | -Wnull-dereference 299 | > 300 | $<$,7>>: 301 | -Wduplicated-branches # identical if-else branches 302 | > 303 | $<$,8>>: 304 | -Wcast-align=strict # increase alignment (i.e. char* to int*) 305 | > 306 | > 307 | ) 308 | endif(MSVC) 309 | check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER) 310 | if (WARN_UNSAFE_BUFFER) 311 | # This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer" 312 | target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-unsafe-buffer-usage") 313 | endif() 314 | 315 | add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp) 316 | target_link_libraries(gsl_noexcept_tests 317 | Microsoft.GSL::GSL 318 | gsl_tests_config_noexcept 319 | ) 320 | add_test(gsl_noexcept_tests gsl_noexcept_tests) 321 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(googletest-download NONE) 3 | 4 | include(ExternalProject) 5 | ExternalProject_Add(googletest 6 | GIT_REPOSITORY https://github.com/google/googletest.git 7 | GIT_TAG v1.14.0 8 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 9 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 10 | CONFIGURE_COMMAND "" 11 | BUILD_COMMAND "" 12 | INSTALL_COMMAND "" 13 | TEST_COMMAND "" 14 | ) 15 | -------------------------------------------------------------------------------- /tests/algorithm_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include // for array 18 | #include // for size_t 19 | #include // for copy 20 | #include // for span 21 | #include 22 | 23 | #include "deathTestCommon.h" 24 | 25 | namespace gsl 26 | { 27 | struct fail_fast; 28 | } // namespace gsl 29 | 30 | using namespace gsl; 31 | 32 | TEST(algorithm_tests, same_type) 33 | { 34 | // dynamic source and destination span 35 | { 36 | std::array src{1, 2, 3, 4, 5}; 37 | std::array dst{}; 38 | 39 | const span src_span(src); 40 | const span dst_span(dst); 41 | 42 | copy(src_span, dst_span); 43 | copy(src_span, dst_span.subspan(src_span.size())); 44 | 45 | for (std::size_t i = 0; i < src.size(); ++i) 46 | { 47 | EXPECT_TRUE(dst[i] == src[i]); 48 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 49 | } 50 | } 51 | 52 | // static source and dynamic destination span 53 | { 54 | std::array src{1, 2, 3, 4, 5}; 55 | std::array dst{}; 56 | 57 | const span src_span(src); 58 | const span dst_span(dst); 59 | 60 | copy(src_span, dst_span); 61 | copy(src_span, dst_span.subspan(src_span.size())); 62 | 63 | for (std::size_t i = 0; i < src.size(); ++i) 64 | { 65 | EXPECT_TRUE(dst[i] == src[i]); 66 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 67 | } 68 | } 69 | 70 | // dynamic source and static destination span 71 | { 72 | std::array src{1, 2, 3, 4, 5}; 73 | std::array dst{}; 74 | 75 | const gsl::span src_span(src); 76 | const gsl::span dst_span(dst); 77 | 78 | copy(src_span, dst_span); 79 | copy(src_span, dst_span.subspan(src_span.size())); 80 | 81 | for (std::size_t i = 0; i < src.size(); ++i) 82 | { 83 | EXPECT_TRUE(dst[i] == src[i]); 84 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 85 | } 86 | } 87 | 88 | // static source and destination span 89 | { 90 | std::array src{1, 2, 3, 4, 5}; 91 | std::array dst{}; 92 | 93 | const span src_span(src); 94 | const span dst_span(dst); 95 | 96 | copy(src_span, dst_span); 97 | copy(src_span, dst_span.subspan(src_span.size())); 98 | 99 | for (std::size_t i = 0; i < src.size(); ++i) 100 | { 101 | EXPECT_TRUE(dst[i] == src[i]); 102 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 103 | } 104 | } 105 | } 106 | 107 | TEST(algorithm_tests, compatible_type) 108 | { 109 | // dynamic source and destination span 110 | { 111 | std::array src{1, 2, 3, 4, 5}; 112 | std::array dst{}; 113 | 114 | const span src_span(src); 115 | const span dst_span(dst); 116 | 117 | copy(src_span, dst_span); 118 | copy(src_span, dst_span.subspan(src_span.size())); 119 | 120 | for (std::size_t i = 0; i < src.size(); ++i) 121 | { 122 | EXPECT_TRUE(dst[i] == src[i]); 123 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 124 | } 125 | } 126 | 127 | // static source and dynamic destination span 128 | { 129 | std::array src{1, 2, 3, 4, 5}; 130 | std::array dst{}; 131 | 132 | const span src_span(src); 133 | const span dst_span(dst); 134 | 135 | copy(src_span, dst_span); 136 | copy(src_span, dst_span.subspan(src_span.size())); 137 | 138 | for (std::size_t i = 0; i < src.size(); ++i) 139 | { 140 | EXPECT_TRUE(dst[i] == src[i]); 141 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 142 | } 143 | } 144 | 145 | // dynamic source and static destination span 146 | { 147 | std::array src{1, 2, 3, 4, 5}; 148 | std::array dst{}; 149 | 150 | const span src_span(src); 151 | const span dst_span(dst); 152 | 153 | copy(src_span, dst_span); 154 | copy(src_span, dst_span.subspan(src_span.size())); 155 | 156 | for (std::size_t i = 0; i < src.size(); ++i) 157 | { 158 | EXPECT_TRUE(dst[i] == src[i]); 159 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 160 | } 161 | } 162 | 163 | // static source and destination span 164 | { 165 | std::array src{1, 2, 3, 4, 5}; 166 | std::array dst{}; 167 | 168 | const span src_span(src); 169 | const span dst_span(dst); 170 | 171 | copy(src_span, dst_span); 172 | copy(src_span, dst_span.subspan(src_span.size())); 173 | 174 | for (std::size_t i = 0; i < src.size(); ++i) 175 | { 176 | EXPECT_TRUE(dst[i] == src[i]); 177 | EXPECT_TRUE(dst[i + src.size()] == src[i]); 178 | } 179 | } 180 | } 181 | 182 | #ifdef CONFIRM_COMPILATION_ERRORS 183 | TEST(algorithm_tests, incompatible_type) 184 | { 185 | std::array src{1, 2, 3, 4}; 186 | std::array dst{}; 187 | 188 | span src_span_dyn(src); 189 | span src_span_static(src); 190 | span dst_span_dyn(dst); 191 | span dst_span_static(gsl::make_span(dst)); 192 | 193 | // every line should produce a compilation error 194 | copy(src_span_dyn, dst_span_dyn); 195 | copy(src_span_dyn, dst_span_static); 196 | copy(src_span_static, dst_span_dyn); 197 | copy(src_span_static, dst_span_static); 198 | } 199 | #endif 200 | 201 | TEST(algorithm_tests, small_destination_span) 202 | { 203 | const auto terminateHandler = std::set_terminate([] { 204 | std::cerr << "Expected Death. small_destination_span"; 205 | std::abort(); 206 | }); 207 | const auto expected = GetExpectedDeathString(terminateHandler); 208 | 209 | std::array src{1, 2, 3, 4}; 210 | std::array dst{}; 211 | 212 | const span src_span_dyn(src); 213 | const span src_span_static(src); 214 | const span dst_span_dyn(dst); 215 | const span dst_span_static(dst); 216 | 217 | EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected); 218 | EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected); 219 | EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected); 220 | 221 | #ifdef CONFIRM_COMPILATION_ERRORS 222 | copy(src_span_static, dst_span_static); 223 | #endif 224 | } 225 | -------------------------------------------------------------------------------- /tests/assertion_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include "deathTestCommon.h" 18 | #include // for Ensures, Expects 19 | #include 20 | 21 | using namespace gsl; 22 | 23 | namespace 24 | { 25 | 26 | int f(int i) 27 | { 28 | Expects(i > 0 && i < 10); 29 | return i; 30 | } 31 | 32 | int g(int i) 33 | { 34 | i++; 35 | Ensures(i > 0 && i < 10); 36 | return i; 37 | } 38 | } // namespace 39 | 40 | TEST(assertion_tests, expects) 41 | { 42 | const auto terminateHandler = std::set_terminate([] { 43 | std::cerr << "Expected Death. expects"; 44 | std::abort(); 45 | }); 46 | 47 | EXPECT_TRUE(f(2) == 2); 48 | EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler)); 49 | } 50 | 51 | TEST(assertion_tests, ensures) 52 | { 53 | const auto terminateHandler = std::set_terminate([] { 54 | std::cerr << "Expected Death. ensures"; 55 | std::abort(); 56 | }); 57 | 58 | EXPECT_TRUE(g(2) == 3); 59 | EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler)); 60 | } 61 | -------------------------------------------------------------------------------- /tests/at_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #include // for at 20 | 21 | #include // for array 22 | #include // for size_t 23 | #include // for terminate 24 | #include // for initializer_list 25 | #include // for vector 26 | #if defined(__cplusplus) && __cplusplus >= 202002L 27 | #include 28 | #endif // __cplusplus >= 202002L 29 | 30 | #include "deathTestCommon.h" 31 | 32 | TEST(at_tests, static_array) 33 | { 34 | int a[4] = {1, 2, 3, 4}; 35 | const int(&c_a)[4] = a; 36 | 37 | for (int i = 0; i < 4; ++i) 38 | { 39 | EXPECT_TRUE(&gsl::at(a, i) == &a[i]); 40 | EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); 41 | } 42 | 43 | const auto terminateHandler = std::set_terminate([] { 44 | std::cerr << "Expected Death. static_array"; 45 | std::abort(); 46 | }); 47 | const auto expected = GetExpectedDeathString(terminateHandler); 48 | 49 | EXPECT_DEATH(gsl::at(a, -1), expected); 50 | EXPECT_DEATH(gsl::at(a, 4), expected); 51 | EXPECT_DEATH(gsl::at(c_a, -1), expected); 52 | EXPECT_DEATH(gsl::at(c_a, 4), expected); 53 | } 54 | 55 | TEST(at_tests, std_array) 56 | { 57 | std::array a = {1, 2, 3, 4}; 58 | const std::array& c_a = a; 59 | 60 | for (int i = 0; i < 4; ++i) 61 | { 62 | EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); 63 | EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); 64 | } 65 | 66 | const auto terminateHandler = std::set_terminate([] { 67 | std::cerr << "Expected Death. std_array"; 68 | std::abort(); 69 | }); 70 | const auto expected = GetExpectedDeathString(terminateHandler); 71 | 72 | EXPECT_DEATH(gsl::at(a, -1), expected); 73 | EXPECT_DEATH(gsl::at(a, 4), expected); 74 | EXPECT_DEATH(gsl::at(c_a, -1), expected); 75 | EXPECT_DEATH(gsl::at(c_a, 4), expected); 76 | } 77 | 78 | TEST(at_tests, std_vector) 79 | { 80 | std::vector a = {1, 2, 3, 4}; 81 | const std::vector& c_a = a; 82 | 83 | for (int i = 0; i < 4; ++i) 84 | { 85 | EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); 86 | EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); 87 | } 88 | 89 | const auto terminateHandler = std::set_terminate([] { 90 | std::cerr << "Expected Death. std_vector"; 91 | std::abort(); 92 | }); 93 | const auto expected = GetExpectedDeathString(terminateHandler); 94 | 95 | EXPECT_DEATH(gsl::at(a, -1), expected); 96 | EXPECT_DEATH(gsl::at(a, 4), expected); 97 | EXPECT_DEATH(gsl::at(c_a, -1), expected); 98 | EXPECT_DEATH(gsl::at(c_a, 4), expected); 99 | } 100 | 101 | TEST(at_tests, InitializerList) 102 | { 103 | const std::initializer_list a = {1, 2, 3, 4}; 104 | 105 | for (int i = 0; i < 4; ++i) 106 | { 107 | EXPECT_TRUE(gsl::at(a, i) == i + 1); 108 | EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); 109 | } 110 | 111 | const auto terminateHandler = std::set_terminate([] { 112 | std::cerr << "Expected Death. InitializerList"; 113 | std::abort(); 114 | }); 115 | const auto expected = GetExpectedDeathString(terminateHandler); 116 | 117 | EXPECT_DEATH(gsl::at(a, -1), expected); 118 | EXPECT_DEATH(gsl::at(a, 4), expected); 119 | EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected); 120 | EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected); 121 | } 122 | 123 | #if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 124 | TEST(at_tests, std_span) 125 | { 126 | std::vector vec{1, 2, 3, 4, 5}; 127 | std::span sp{vec}; 128 | 129 | std::vector cvec{1, 2, 3, 4, 5}; 130 | std::span csp{cvec}; 131 | 132 | for (gsl::index i = 0; i < gsl::narrow_cast(vec.size()); ++i) 133 | { 134 | EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast(i)]); 135 | EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast(i)]); 136 | } 137 | 138 | const auto terminateHandler = std::set_terminate([] { 139 | std::cerr << "Expected Death. std_span"; 140 | std::abort(); 141 | }); 142 | const auto expected = GetExpectedDeathString(terminateHandler); 143 | 144 | EXPECT_DEATH(gsl::at(sp, -1), expected); 145 | EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast(sp.size())), expected); 146 | EXPECT_DEATH(gsl::at(csp, -1), expected); 147 | EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast(sp.size())), expected); 148 | } 149 | #endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 150 | 151 | #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 152 | static constexpr bool test_constexpr() 153 | { 154 | int a1[4] = {1, 2, 3, 4}; 155 | const int(&c_a1)[4] = a1; 156 | std::array a2 = {1, 2, 3, 4}; 157 | const std::array& c_a2 = a2; 158 | 159 | for (int i = 0; i < 4; ++i) 160 | { 161 | if (&gsl::at(a1, i) != &a1[i]) return false; 162 | if (&gsl::at(c_a1, i) != &a1[i]) return false; 163 | // requires C++17: 164 | // if (&gsl::at(a2, i) != &a2[static_cast(i)]) return false; 165 | if (&gsl::at(c_a2, i) != &c_a2[static_cast(i)]) return false; 166 | if (gsl::at({1, 2, 3, 4}, i) != i + 1) return false; 167 | } 168 | 169 | return true; 170 | } 171 | 172 | static_assert(test_constexpr(), "FAIL"); 173 | #endif 174 | -------------------------------------------------------------------------------- /tests/byte_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #define GSL_USE_STD_BYTE 0 20 | #include // for to_byte, to_integer, byte, operator&, ope... 21 | 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | using namespace gsl; 27 | 28 | namespace 29 | { 30 | int modify_both(gsl::byte& b, int& i) 31 | { 32 | i = 10; 33 | b = to_byte<5>(); 34 | return i; 35 | } 36 | 37 | TEST(byte_tests, construction) 38 | { 39 | { 40 | const gsl::byte b = static_cast(4); 41 | EXPECT_TRUE(static_cast(b) == 4); 42 | } 43 | 44 | { 45 | const gsl::byte b = gsl::byte(12); 46 | EXPECT_TRUE(static_cast(b) == 12); 47 | } 48 | 49 | { 50 | const gsl::byte b = to_byte<12>(); 51 | EXPECT_TRUE(static_cast(b) == 12); 52 | } 53 | { 54 | const unsigned char uc = 12; 55 | const gsl::byte b = to_byte(uc); 56 | EXPECT_TRUE(static_cast(b) == 12); 57 | } 58 | 59 | #if defined(__cplusplus) && (__cplusplus >= 201703L) 60 | { 61 | const gsl::byte b{14}; 62 | EXPECT_TRUE(static_cast(b) == 14); 63 | } 64 | #endif 65 | 66 | #ifdef CONFIRM_COMPILATION_ERRORS 67 | to_byte(char{}); 68 | to_byte(3); 69 | to_byte(3u); 70 | to_byte<-1>(); 71 | to_byte<256u>(); 72 | #endif 73 | } 74 | 75 | TEST(byte_tests, bitwise_operations) 76 | { 77 | const gsl::byte b = to_byte<0xFF>(); 78 | 79 | gsl::byte a = to_byte<0x00>(); 80 | EXPECT_TRUE((b | a) == to_byte<0xFF>()); 81 | EXPECT_TRUE(a == to_byte<0x00>()); 82 | 83 | a |= b; 84 | EXPECT_TRUE(a == to_byte<0xFF>()); 85 | 86 | a = to_byte<0x01>(); 87 | EXPECT_TRUE((b & a) == to_byte<0x01>()); 88 | 89 | a &= b; 90 | EXPECT_TRUE(a == to_byte<0x01>()); 91 | 92 | EXPECT_TRUE((b ^ a) == to_byte<0xFE>()); 93 | 94 | EXPECT_TRUE(a == to_byte<0x01>()); 95 | a ^= b; 96 | EXPECT_TRUE(a == to_byte<0xFE>()); 97 | 98 | a = to_byte<0x01>(); 99 | EXPECT_TRUE(~a == to_byte<0xFE>()); 100 | 101 | a = to_byte<0xFF>(); 102 | EXPECT_TRUE((a << 4) == to_byte<0xF0>()); 103 | EXPECT_TRUE((a >> 4) == to_byte<0x0F>()); 104 | 105 | a <<= 4; 106 | EXPECT_TRUE(a == to_byte<0xF0>()); 107 | a >>= 4; 108 | EXPECT_TRUE(a == to_byte<0x0F>()); 109 | } 110 | 111 | TEST(byte_tests, to_integer) 112 | { 113 | const gsl::byte b = to_byte<0x12>(); 114 | 115 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 116 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 117 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 118 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 119 | 120 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 121 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 122 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 123 | EXPECT_TRUE(0x12 == gsl::to_integer(b)); 124 | 125 | // EXPECT_TRUE(0x12 == gsl::to_integer(b)); // expect compile-time error 126 | // EXPECT_TRUE(0x12 == gsl::to_integer(b)); // expect compile-time error 127 | } 128 | 129 | TEST(byte_tests, aliasing) 130 | { 131 | int i{0}; 132 | const int res = modify_both(reinterpret_cast(i), i); 133 | EXPECT_TRUE(res == i); 134 | } 135 | 136 | #if __cplusplus >= 201703l 137 | using std::void_t; 138 | #else // __cplusplus >= 201703l 139 | template 140 | using void_t = void; 141 | #endif // __cplusplus < 201703l 142 | 143 | template 144 | static constexpr bool LShiftCompilesFor = false; 145 | template 146 | static constexpr bool LShiftCompilesFor< 147 | U, void_t(declval(), declval()))>> = true; 148 | static_assert(!LShiftCompilesFor, "!LShiftCompilesFor"); 149 | 150 | template 151 | static constexpr bool RShiftCompilesFor = false; 152 | template 153 | static constexpr bool RShiftCompilesFor< 154 | U, void_t> (declval(), declval()))>> = true; 155 | static_assert(!RShiftCompilesFor, "!RShiftCompilesFor"); 156 | 157 | template 158 | static constexpr bool LShiftAssignCompilesFor = false; 159 | template 160 | static constexpr bool LShiftAssignCompilesFor< 161 | U, void_t(declval(), declval()))>> = true; 162 | static_assert(!LShiftAssignCompilesFor, "!LShiftAssignCompilesFor"); 163 | 164 | template 165 | static constexpr bool RShiftAssignCompilesFor = false; 166 | template 167 | static constexpr bool RShiftAssignCompilesFor< 168 | U, void_t>= (declval(), declval()))>> = true; 169 | static_assert(!RShiftAssignCompilesFor, "!RShiftAssignCompilesFor"); 170 | 171 | template 172 | static constexpr bool ToIntegerCompilesFor = false; 173 | template 174 | static constexpr bool 175 | ToIntegerCompilesFor(gsl::byte{}))>> = true; 176 | static_assert(!ToIntegerCompilesFor, "!ToIntegerCompilesFor"); 177 | 178 | } // namespace 179 | -------------------------------------------------------------------------------- /tests/constexpr_notnull_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2025 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include // for not_null 18 | #include 19 | 20 | #include // for declval 21 | 22 | using namespace gsl; 23 | 24 | namespace 25 | { 26 | constexpr bool comparison_test(const int* ptr1, const int* ptr2) 27 | { 28 | const not_null p1(ptr1); 29 | const not_null p1_same(ptr1); 30 | const not_null p2(ptr2); 31 | 32 | // Testing operator== 33 | const bool eq_result = (p1 == p1_same); // Should be true 34 | const bool neq_result = (p1 != p2); // Should be true 35 | 36 | // Testing operator<= and operator>= 37 | const bool le_result = (p1 <= p1_same); // Should be true 38 | const bool ge_result = (p1 >= p1_same); // Should be true 39 | 40 | // The exact comparison results will depend on pointer ordering, 41 | // but we can verify that the basic equality checks work as expected 42 | return eq_result && neq_result && le_result && ge_result; 43 | } 44 | 45 | constexpr bool workaround_test(const int* ptr1, const int* ptr2) 46 | { 47 | const not_null p1(ptr1); 48 | const not_null p1_same(ptr1); 49 | const not_null p2(ptr2); 50 | 51 | // Using .get() to compare 52 | const bool eq_result = (p1.get() == p1_same.get()); // Should be true 53 | const bool neq_result = (p1.get() != p2.get()); // Should be true 54 | 55 | return eq_result && neq_result; 56 | } 57 | } // namespace 58 | 59 | constexpr int test_value1 = 1; 60 | constexpr int test_value2 = 2; 61 | 62 | static_assert(comparison_test(&test_value1, &test_value2), "not_null comparison operators should be constexpr"); 63 | static_assert(workaround_test(&test_value1, &test_value2), "not_null .get() comparison workaround should work"); 64 | 65 | TEST(notnull_constexpr_tests, TestNotNullConstexprComparison) 66 | { 67 | // This test simply verifies that the constexpr functions compile and run 68 | // If we got here, it means the constexpr comparison operators are working 69 | static const int value1 = 1; 70 | static const int value2 = 2; 71 | EXPECT_TRUE(comparison_test(&value1, &value2)); 72 | EXPECT_TRUE(workaround_test(&value1, &value2)); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /tests/deathTestCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | constexpr char deathstring[] = "Expected Death"; 5 | constexpr char failed_set_terminate_deathstring[] = ".*"; 6 | 7 | // This prevents a failed call to set_terminate from failing the test suite. 8 | constexpr const char* GetExpectedDeathString(std::terminate_handler handle) 9 | { 10 | return handle ? deathstring : failed_set_terminate_deathstring; 11 | } 12 | -------------------------------------------------------------------------------- /tests/no_exception_ensure_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | #include // for std::exit 19 | #include // for span 20 | #include 21 | #include 22 | 23 | int operator_subscript_no_throw() noexcept 24 | { 25 | int arr[10]; 26 | const gsl::span sp{arr}; 27 | return sp[11]; 28 | } 29 | 30 | [[noreturn]] void test_terminate() { std::exit(0); } 31 | 32 | void setup_termination_handler() noexcept 33 | { 34 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) 35 | 36 | auto& handler = gsl::details::get_terminate_handler(); 37 | handler = &test_terminate; 38 | 39 | #else 40 | 41 | std::set_terminate(test_terminate); 42 | 43 | #endif 44 | } 45 | 46 | int main() noexcept 47 | { 48 | std::cout << "Running main() from " __FILE__ "\n"; 49 | #if defined(IOS_PROCESS_DELAY_WORKAROUND) 50 | std::this_thread::sleep_for(std::chrono::seconds(1)); 51 | #endif 52 | setup_termination_handler(); 53 | operator_subscript_no_throw(); 54 | return -1; 55 | } 56 | -------------------------------------------------------------------------------- /tests/notnull_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #include // for not_null, operator<, operator<=, operator> 20 | 21 | #include // for addressof 22 | #include // for uint16_t 23 | #include // for shared_ptr, make_shared, operator<, opera... 24 | #include // for operator<<, ostringstream, basic_ostream:... 25 | #include // for basic_string, operator==, string, operator<< 26 | #include // for declval 27 | #include // for type_info 28 | #include // for variant, monostate, get 29 | 30 | #include "deathTestCommon.h" 31 | using namespace gsl; 32 | 33 | #if __cplusplus >= 201703l 34 | using std::void_t; 35 | #else // __cplusplus >= 201703l 36 | template 37 | using void_t = void; 38 | #endif // __cplusplus < 201703l 39 | 40 | struct MyBase 41 | { 42 | }; 43 | struct MyDerived : public MyBase 44 | { 45 | }; 46 | struct Unrelated 47 | { 48 | }; 49 | 50 | // stand-in for a user-defined ref-counted class 51 | template 52 | struct RefCounted 53 | { 54 | RefCounted(T* p) : p_(p) {} 55 | operator T*() { return p_; } 56 | T* p_; 57 | }; 58 | 59 | // user defined smart pointer with comparison operators returning non bool value 60 | template 61 | struct CustomPtr 62 | { 63 | CustomPtr(T* p) : p_(p) {} 64 | operator T*() const { return p_; } 65 | bool operator!=(std::nullptr_t) const { return p_ != nullptr; } 66 | T* p_ = nullptr; 67 | }; 68 | 69 | template 70 | std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) 71 | { 72 | // clang-format off 73 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 74 | // clang-format on 75 | return reinterpret_cast(lhs.p_) == reinterpret_cast(rhs.p_) ? "true" 76 | : "false"; 77 | } 78 | 79 | template 80 | std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) 81 | { 82 | // clang-format off 83 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 84 | // clang-format on 85 | return reinterpret_cast(lhs.p_) != reinterpret_cast(rhs.p_) ? "true" 86 | : "false"; 87 | } 88 | 89 | template 90 | std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) 91 | { 92 | // clang-format off 93 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 94 | // clang-format on 95 | return reinterpret_cast(lhs.p_) < reinterpret_cast(rhs.p_) ? "true" 96 | : "false"; 97 | } 98 | 99 | template 100 | std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) 101 | { 102 | // clang-format off 103 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 104 | // clang-format on 105 | return reinterpret_cast(lhs.p_) > reinterpret_cast(rhs.p_) ? "true" 106 | : "false"; 107 | } 108 | 109 | template 110 | std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) 111 | { 112 | // clang-format off 113 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 114 | // clang-format on 115 | return reinterpret_cast(lhs.p_) <= reinterpret_cast(rhs.p_) ? "true" 116 | : "false"; 117 | } 118 | 119 | template 120 | std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) 121 | { 122 | // clang-format off 123 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 124 | // clang-format on 125 | return reinterpret_cast(lhs.p_) >= reinterpret_cast(rhs.p_) ? "true" 126 | : "false"; 127 | } 128 | 129 | struct NonCopyableNonMovable 130 | { 131 | NonCopyableNonMovable() = default; 132 | NonCopyableNonMovable(const NonCopyableNonMovable&) = delete; 133 | NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete; 134 | NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; 135 | NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; 136 | }; 137 | 138 | namespace 139 | { 140 | // clang-format off 141 | GSL_SUPPRESS(f .4) // NO-FORMAT: attribute 142 | // clang-format on 143 | bool helper(not_null p) { return *p == 12; } 144 | // clang-format off 145 | GSL_SUPPRESS(f .4) // NO-FORMAT: attribute 146 | // clang-format on 147 | bool helper_const(not_null p) { return *p == 12; } 148 | 149 | int* return_pointer() { return nullptr; } 150 | } // namespace 151 | 152 | template 153 | static constexpr bool CtorCompilesFor_A = false; 154 | template 155 | static constexpr bool 156 | CtorCompilesFor_A{std::declval()})>> = true; 157 | 158 | template 159 | static constexpr bool CtorCompilesFor_B = false; 160 | template 161 | static constexpr bool CtorCompilesFor_B{N})>> = true; 162 | 163 | template 164 | static constexpr bool DefaultCtorCompilesFor = false; 165 | template 166 | static constexpr bool DefaultCtorCompilesFor{})>> = true; 167 | 168 | template 169 | static constexpr bool CtorCompilesFor_C = false; 170 | template 171 | static constexpr bool 172 | CtorCompilesFor_C{std::declval>()})>> = 173 | true; 174 | 175 | TEST(notnull_tests, TestNotNullConstructors) 176 | { 177 | { 178 | static_assert(CtorCompilesFor_A, "CtorCompilesFor_A"); 179 | static_assert(!CtorCompilesFor_A, "!CtorCompilesFor_A"); 180 | static_assert(!CtorCompilesFor_B, "!CtorCompilesFor_B"); 181 | static_assert(!DefaultCtorCompilesFor, "!DefaultCtorCompilesFor"); 182 | static_assert(!CtorCompilesFor_C, "CtorCompilesFor_C"); 183 | 184 | #ifdef CONFIRM_COMPILATION_ERRORS 185 | // Forbid non-nullptr assignable types 186 | not_null> f(std::vector{1}); 187 | not_null z(10); 188 | not_null> y({1, 2}); 189 | #endif 190 | } 191 | 192 | const auto terminateHandler = std::set_terminate([] { 193 | std::cerr << "Expected Death. TestNotNullConstructors"; 194 | std::abort(); 195 | }); 196 | const auto expected = GetExpectedDeathString(terminateHandler); 197 | 198 | { 199 | // from shared pointer 200 | int i = 12; 201 | auto rp = RefCounted(&i); 202 | not_null p(rp); 203 | EXPECT_TRUE(p.get() == &i); 204 | 205 | not_null> x( 206 | std::make_shared(10)); // shared_ptr is nullptr assignable 207 | 208 | int* pi = nullptr; 209 | EXPECT_DEATH((not_null(pi)), expected); 210 | } 211 | 212 | { 213 | // from unique pointer 214 | not_null> x( 215 | std::make_unique(10)); // unique_ptr is nullptr assignable 216 | 217 | EXPECT_DEATH((not_null>(std::unique_ptr{})), expected); 218 | } 219 | 220 | { 221 | // from pointer to local 222 | int t = 42; 223 | 224 | not_null x = &t; 225 | helper(&t); 226 | helper_const(&t); 227 | 228 | EXPECT_TRUE(*x == 42); 229 | } 230 | 231 | { 232 | // from raw pointer 233 | // from not_null pointer 234 | 235 | int t = 42; 236 | int* p = &t; 237 | 238 | not_null x = p; 239 | helper(p); 240 | helper_const(p); 241 | helper(x); 242 | helper_const(x); 243 | 244 | EXPECT_TRUE(*x == 42); 245 | } 246 | 247 | { 248 | // from raw const pointer 249 | // from not_null const pointer 250 | 251 | int t = 42; 252 | const int* cp = &t; 253 | 254 | not_null x = cp; 255 | helper_const(cp); 256 | helper_const(x); 257 | 258 | EXPECT_TRUE(*x == 42); 259 | } 260 | 261 | { 262 | // from not_null const pointer, using auto 263 | int t = 42; 264 | const int* cp = &t; 265 | 266 | auto x = not_null{cp}; 267 | 268 | EXPECT_TRUE(*x == 42); 269 | } 270 | 271 | { 272 | // from returned pointer 273 | 274 | EXPECT_DEATH(helper(return_pointer()), expected); 275 | EXPECT_DEATH(helper_const(return_pointer()), expected); 276 | } 277 | } 278 | 279 | template 280 | void ostream_helper(T v) 281 | { 282 | not_null p(&v); 283 | { 284 | std::ostringstream os; 285 | std::ostringstream ref; 286 | os << static_cast(p); 287 | ref << static_cast(&v); 288 | EXPECT_TRUE(os.str() == ref.str()); 289 | } 290 | { 291 | std::ostringstream os; 292 | std::ostringstream ref; 293 | os << *p; 294 | ref << v; 295 | EXPECT_TRUE(os.str() == ref.str()); 296 | } 297 | } 298 | 299 | TEST(notnull_tests, TestNotNullostream) 300 | { 301 | ostream_helper(17); 302 | ostream_helper(21.5f); 303 | ostream_helper(3.4566e-7); 304 | ostream_helper('c'); 305 | ostream_helper(0x0123u); 306 | ostream_helper("cstring"); 307 | ostream_helper("string"); 308 | } 309 | 310 | template 311 | static constexpr bool AssignmentCompilesFor = false; 312 | template 313 | static constexpr bool 314 | AssignmentCompilesFor&>().operator=( 316 | std::declval&>()))>> = true; 317 | 318 | template 319 | static constexpr bool SCastCompilesFor = false; 320 | template 321 | static constexpr bool 322 | SCastCompilesFor(std::declval&>()))>> = 323 | true; 324 | 325 | template 326 | static constexpr bool RCastCompilesFor = false; 327 | template 328 | static constexpr bool RCastCompilesFor< 329 | U, V, void_t(std::declval&>()))>> = true; 330 | 331 | TEST(notnull_tests, TestNotNullCasting) 332 | { 333 | MyBase base; 334 | MyDerived derived; 335 | Unrelated unrelated; 336 | not_null u{&unrelated}; 337 | (void) u; 338 | not_null p{&derived}; 339 | not_null q(&base); 340 | q = p; // allowed with heterogeneous copy ctor 341 | EXPECT_TRUE(q == p); 342 | 343 | static_assert(AssignmentCompilesFor, 344 | "AssignmentCompilesFor"); 345 | static_assert(!AssignmentCompilesFor, 346 | "!AssignmentCompilesFor"); 347 | static_assert(!AssignmentCompilesFor, 348 | "!AssignmentCompilesFor"); 349 | static_assert(!AssignmentCompilesFor, 350 | "!AssignmentCompilesFor"); 351 | 352 | static_assert(SCastCompilesFor, "SCastCompilesFor"); 353 | static_assert(SCastCompilesFor, "SCastCompilesFor"); 354 | static_assert(!SCastCompilesFor, "!SCastCompilesFor"); 355 | static_assert(!SCastCompilesFor, 356 | "!SCastCompilesFor"); 357 | static_assert(!RCastCompilesFor, 358 | "!SCastCompilesFor"); 359 | static_assert(!RCastCompilesFor, 360 | "!SCastCompilesFor"); 361 | 362 | not_null t(reinterpret_cast(p.get())); 363 | EXPECT_TRUE(reinterpret_cast(p.get()) == reinterpret_cast(t.get())); 364 | 365 | (void) static_cast(p); 366 | (void) static_cast(p); 367 | } 368 | 369 | TEST(notnull_tests, TestNotNullAssignment) 370 | { 371 | const auto terminateHandler = std::set_terminate([] { 372 | std::cerr << "Expected Death. TestNotNullAssignmentd"; 373 | std::abort(); 374 | }); 375 | const auto expected = GetExpectedDeathString(terminateHandler); 376 | 377 | int i = 12; 378 | not_null p(&i); 379 | EXPECT_TRUE(helper(p)); 380 | 381 | int* q = nullptr; 382 | EXPECT_DEATH(p = not_null(q), expected); 383 | } 384 | 385 | TEST(notnull_tests, TestNotNullRawPointerComparison) 386 | { 387 | int ints[2] = {42, 43}; 388 | int* p1 = &ints[0]; 389 | const int* p2 = &ints[1]; 390 | 391 | using NotNull1 = not_null; 392 | using NotNull2 = not_null; 393 | 394 | EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == true); 395 | EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == false); 396 | 397 | EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == false); 398 | EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == true); 399 | 400 | EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == false); 401 | EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 402 | EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 403 | 404 | EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == false); 405 | EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 406 | EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 407 | 408 | EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == true); 409 | EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 410 | EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 411 | } 412 | 413 | TEST(notnull_tests, TestNotNullDereferenceOperator) 414 | { 415 | { 416 | auto sp1 = std::make_shared(); 417 | 418 | using NotNullSp1 = not_null; 419 | EXPECT_TRUE(typeid(*sp1) == typeid(*NotNullSp1(sp1))); 420 | EXPECT_TRUE(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); 421 | } 422 | 423 | { 424 | int ints[1] = {42}; 425 | CustomPtr p1(&ints[0]); 426 | 427 | using NotNull1 = not_null; 428 | EXPECT_TRUE(typeid(*NotNull1(p1)) == typeid(*p1)); 429 | EXPECT_TRUE(*NotNull1(p1) == 42); 430 | *NotNull1(p1) = 43; 431 | EXPECT_TRUE(ints[0] == 43); 432 | } 433 | 434 | { 435 | int v = 42; 436 | gsl::not_null p(&v); 437 | EXPECT_TRUE(typeid(*p) == typeid(*(&v))); 438 | *p = 43; 439 | EXPECT_TRUE(v == 43); 440 | } 441 | } 442 | 443 | TEST(notnull_tests, TestNotNullSharedPtrComparison) 444 | { 445 | auto sp1 = std::make_shared(42); 446 | auto sp2 = std::make_shared(43); 447 | 448 | using NotNullSp1 = not_null; 449 | using NotNullSp2 = not_null; 450 | 451 | EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); 452 | EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); 453 | 454 | EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); 455 | EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); 456 | 457 | EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); 458 | EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); 459 | EXPECT_TRUE((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); 460 | 461 | EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); 462 | EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); 463 | EXPECT_TRUE((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); 464 | 465 | EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); 466 | EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); 467 | EXPECT_TRUE((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); 468 | 469 | EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); 470 | EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); 471 | EXPECT_TRUE((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); 472 | } 473 | 474 | TEST(notnull_tests, TestNotNullCustomPtrComparison) 475 | { 476 | int ints[2] = {42, 43}; 477 | CustomPtr p1(&ints[0]); 478 | CustomPtr p2(&ints[1]); 479 | 480 | using NotNull1 = not_null; 481 | using NotNull2 = not_null; 482 | 483 | EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == "true"); 484 | EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == "false"); 485 | 486 | EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == "false"); 487 | EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == "true"); 488 | 489 | EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == "false"); 490 | EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 491 | EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 492 | 493 | EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == "false"); 494 | EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 495 | EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 496 | 497 | EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == "true"); 498 | EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 499 | EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 500 | 501 | EXPECT_TRUE((NotNull1(p1) >= NotNull1(p1)) == "true"); 502 | EXPECT_TRUE((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); 503 | EXPECT_TRUE((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); 504 | } 505 | 506 | #if defined(__cplusplus) && (__cplusplus >= 201703L) 507 | 508 | template 509 | static constexpr bool TypeDeductionCtorCompilesFor = false; 510 | template 511 | static constexpr bool 512 | TypeDeductionCtorCompilesFor()})>> = true; 513 | 514 | template 515 | static constexpr bool TypeDeductionHelperCompilesFor = false; 516 | template 517 | static constexpr bool 518 | TypeDeductionHelperCompilesFor()}))>> = true; 519 | 520 | TEST(notnull_tests, TestNotNullConstructorTypeDeduction) 521 | { 522 | { 523 | int i = 42; 524 | 525 | not_null x{&i}; 526 | helper(not_null{&i}); 527 | helper_const(not_null{&i}); 528 | 529 | EXPECT_TRUE(*x == 42); 530 | } 531 | 532 | { 533 | const int i = 42; 534 | 535 | not_null x{&i}; 536 | static_assert(TypeDeductionHelperCompilesFor, "TypeDeductionHelperCompilesFor"); 537 | static_assert(!TypeDeductionHelperCompilesFor, 538 | "!TypeDeductionHelperCompilesFor"); 539 | helper_const(not_null{&i}); 540 | 541 | EXPECT_TRUE(*x == 42); 542 | } 543 | 544 | { 545 | int i = 42; 546 | int* p = &i; 547 | 548 | not_null x{p}; 549 | helper(not_null{p}); 550 | helper_const(not_null{p}); 551 | 552 | EXPECT_TRUE(*x == 42); 553 | } 554 | 555 | { 556 | const int i = 42; 557 | const int* p = &i; 558 | 559 | not_null x{p}; 560 | helper_const(not_null{p}); 561 | 562 | EXPECT_TRUE(*x == 42); 563 | } 564 | 565 | const auto terminateHandler = std::set_terminate([] { 566 | std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; 567 | std::abort(); 568 | }); 569 | const auto expected = GetExpectedDeathString(terminateHandler); 570 | 571 | { 572 | auto workaround_macro = []() { 573 | int* p1 = nullptr; 574 | const not_null x{p1}; 575 | }; 576 | EXPECT_DEATH(workaround_macro(), expected); 577 | } 578 | 579 | { 580 | auto workaround_macro = []() { 581 | const int* p1 = nullptr; 582 | const not_null x{p1}; 583 | }; 584 | EXPECT_DEATH(workaround_macro(), expected); 585 | } 586 | 587 | { 588 | int* p = nullptr; 589 | 590 | EXPECT_DEATH(helper(not_null{p}), expected); 591 | EXPECT_DEATH(helper_const(not_null{p}), expected); 592 | } 593 | 594 | static_assert(TypeDeductionCtorCompilesFor, "TypeDeductionCtorCompilesFor"); 595 | #if defined(_MSC_VER) && !defined(__clang__) 596 | // Fails on gcc, clang, xcode, VS clang with 597 | // "error : no type named 'type' in 'std::enable_if'; 'enable_if' cannot be used to 598 | // disable this declaration" 599 | static_assert(!TypeDeductionCtorCompilesFor, 600 | "!TypeDeductionCtorCompilesFor"); 601 | static_assert(!TypeDeductionHelperCompilesFor, 602 | "!TypeDeductionHelperCompilesFor"); 603 | #endif 604 | } 605 | 606 | TEST(notnull_tests, TestVariantEmplace) 607 | { 608 | int i = 0; 609 | std::variant> v; 610 | v.emplace>(&i); 611 | 612 | EXPECT_FALSE(v.valueless_by_exception()); 613 | EXPECT_TRUE(v.index() == 1); 614 | EXPECT_TRUE(std::get>(v) == &i); 615 | } 616 | #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) 617 | 618 | template 619 | static constexpr bool HelperCompilesFor = false; 620 | template 621 | static constexpr bool HelperCompilesFor()))>> = true; 622 | 623 | TEST(notnull_tests, TestMakeNotNull) 624 | { 625 | { 626 | int i = 42; 627 | 628 | const auto x = make_not_null(&i); 629 | helper(make_not_null(&i)); 630 | helper_const(make_not_null(&i)); 631 | 632 | EXPECT_TRUE(*x == 42); 633 | } 634 | 635 | { 636 | const int i = 42; 637 | 638 | const auto x = make_not_null(&i); 639 | static_assert(HelperCompilesFor>, 640 | "HelperCompilesFor>"); 641 | helper_const(make_not_null(&i)); 642 | 643 | EXPECT_TRUE(*x == 42); 644 | } 645 | 646 | { 647 | int i = 42; 648 | int* p = &i; 649 | 650 | const auto x = make_not_null(p); 651 | helper(make_not_null(p)); 652 | helper_const(make_not_null(p)); 653 | 654 | EXPECT_TRUE(*x == 42); 655 | } 656 | 657 | { 658 | const int i = 42; 659 | const int* p = &i; 660 | 661 | const auto x = make_not_null(p); 662 | static_assert(!HelperCompilesFor>, 663 | "!HelperCompilesFor>"); 664 | helper_const(make_not_null(p)); 665 | 666 | EXPECT_TRUE(*x == 42); 667 | } 668 | 669 | const auto terminateHandler = std::set_terminate([] { 670 | std::cerr << "Expected Death. TestMakeNotNull"; 671 | std::abort(); 672 | }); 673 | const auto expected = GetExpectedDeathString(terminateHandler); 674 | 675 | { 676 | const auto workaround_macro = []() { 677 | int* p1 = nullptr; 678 | const auto x = make_not_null(p1); 679 | EXPECT_TRUE(*x == 42); 680 | }; 681 | EXPECT_DEATH(workaround_macro(), expected); 682 | } 683 | 684 | { 685 | const auto workaround_macro = []() { 686 | const int* p1 = nullptr; 687 | const auto x = make_not_null(p1); 688 | EXPECT_TRUE(*x == 42); 689 | }; 690 | EXPECT_DEATH(workaround_macro(), expected); 691 | } 692 | 693 | { 694 | int* p = nullptr; 695 | 696 | EXPECT_DEATH(helper(make_not_null(p)), expected); 697 | EXPECT_DEATH(helper_const(make_not_null(p)), expected); 698 | } 699 | 700 | #ifdef CONFIRM_COMPILATION_ERRORS 701 | { 702 | EXPECT_DEATH(make_not_null(nullptr), expected); 703 | EXPECT_DEATH(helper(make_not_null(nullptr)), expected); 704 | EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected); 705 | } 706 | #endif 707 | } 708 | 709 | TEST(notnull_tests, TestStdHash) 710 | { 711 | { 712 | int x = 42; 713 | int y = 99; 714 | not_null nn{&x}; 715 | const not_null cnn{&x}; 716 | 717 | std::hash> hash_nn; 718 | std::hash hash_intptr; 719 | 720 | EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x)); 721 | EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y)); 722 | EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr)); 723 | } 724 | 725 | { 726 | const int x = 42; 727 | const int y = 99; 728 | not_null nn{&x}; 729 | const not_null cnn{&x}; 730 | 731 | std::hash> hash_nn; 732 | std::hash hash_intptr; 733 | 734 | EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x)); 735 | EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y)); 736 | EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr)); 737 | } 738 | } 739 | -------------------------------------------------------------------------------- /tests/owner_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #include // for owner 20 | #include // for declval 21 | 22 | using namespace gsl; 23 | 24 | GSL_SUPPRESS(f .23) // NO-FORMAT: attribute 25 | void f(int* i) { *i += 1; } 26 | 27 | TEST(owner_tests, basic_test) 28 | { 29 | owner p = new int(120); 30 | EXPECT_TRUE(*p == 120); 31 | f(p); 32 | EXPECT_TRUE(*p == 121); 33 | delete p; 34 | } 35 | 36 | #if __cplusplus >= 201703l 37 | using std::void_t; 38 | #else // __cplusplus >= 201703l 39 | template 40 | using void_t = void; 41 | #endif // __cplusplus < 201703l 42 | 43 | template 44 | static constexpr bool OwnerCompilesFor = false; 45 | template 46 | static constexpr bool OwnerCompilesFor{})>> = 47 | true; 48 | static_assert(OwnerCompilesFor, "OwnerCompilesFor"); 49 | static_assert(!OwnerCompilesFor, "!OwnerCompilesFor"); 50 | static_assert(!OwnerCompilesFor>, "!OwnerCompilesFor>"); 51 | -------------------------------------------------------------------------------- /tests/pointers_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #if __cplusplus >= 201703l 10 | using std::void_t; 11 | #else // __cplusplus >= 201703l 12 | template 13 | using void_t = void; 14 | #endif // __cplusplus < 201703l 15 | 16 | namespace 17 | { 18 | // Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped. 19 | struct NotMoveAssignableCustomPtr 20 | { 21 | NotMoveAssignableCustomPtr() = default; 22 | NotMoveAssignableCustomPtr(const NotMoveAssignableCustomPtr&) = default; 23 | NotMoveAssignableCustomPtr& operator=(const NotMoveAssignableCustomPtr&) = default; 24 | NotMoveAssignableCustomPtr(NotMoveAssignableCustomPtr&&) = default; 25 | NotMoveAssignableCustomPtr& operator=(NotMoveAssignableCustomPtr&&) = delete; 26 | 27 | bool operator!=(std::nullptr_t) const { return true; } 28 | 29 | int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded 30 | }; 31 | 32 | template 33 | static constexpr bool SwapCompilesFor = false; 34 | template 35 | static constexpr bool 36 | SwapCompilesFor(std::declval&>(), 37 | std::declval&>()))>> = true; 38 | 39 | TEST(pointers_test, swap) 40 | { 41 | // taken from gh-1129: 42 | { 43 | gsl::not_null> a(std::make_unique(0)); 44 | gsl::not_null> b(std::make_unique(1)); 45 | 46 | EXPECT_TRUE(*a == 0); 47 | EXPECT_TRUE(*b == 1); 48 | 49 | gsl::swap(a, b); 50 | 51 | EXPECT_TRUE(*a == 1); 52 | EXPECT_TRUE(*b == 0); 53 | 54 | // Make sure our custom ptr can be used with not_null. The shared_pr is to prevent "unused" 55 | // compiler warnings. 56 | const auto shared_custom_ptr{std::make_shared()}; 57 | gsl::not_null c{*shared_custom_ptr}; 58 | EXPECT_TRUE(c.get() != nullptr); 59 | } 60 | 61 | { 62 | gsl::strict_not_null> a{std::make_unique(0)}; 63 | gsl::strict_not_null> b{std::make_unique(1)}; 64 | 65 | EXPECT_TRUE(*a == 0); 66 | EXPECT_TRUE(*b == 1); 67 | 68 | gsl::swap(a, b); 69 | 70 | EXPECT_TRUE(*a == 1); 71 | EXPECT_TRUE(*b == 0); 72 | } 73 | 74 | { 75 | gsl::not_null> a{std::make_unique(0)}; 76 | gsl::strict_not_null> b{std::make_unique(1)}; 77 | 78 | EXPECT_TRUE(*a == 0); 79 | EXPECT_TRUE(*b == 1); 80 | 81 | gsl::swap(a, b); 82 | 83 | EXPECT_TRUE(*a == 1); 84 | EXPECT_TRUE(*b == 0); 85 | } 86 | 87 | static_assert(!SwapCompilesFor, 88 | "!SwapCompilesFor"); 89 | } 90 | 91 | TEST(pointers_test, member_types) 92 | { 93 | static_assert(std::is_same::element_type, int*>::value, 94 | "check member type: element_type"); 95 | } 96 | 97 | } // namespace 98 | -------------------------------------------------------------------------------- /tests/span_ext_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #include // for span and span_ext 20 | #include // for narrow_cast, at 21 | 22 | #include // for array 23 | #include // for terminate 24 | #include // for cerr 25 | #include // for vector 26 | 27 | using namespace std; 28 | using namespace gsl; 29 | 30 | #include "deathTestCommon.h" 31 | 32 | TEST(span_ext_test, make_span_from_pointer_length_constructor) 33 | { 34 | const auto terminateHandler = std::set_terminate([] { 35 | std::cerr << "Expected Death. from_pointer_length_constructor"; 36 | std::abort(); 37 | }); 38 | const auto expected = GetExpectedDeathString(terminateHandler); 39 | 40 | int arr[4] = {1, 2, 3, 4}; 41 | 42 | { 43 | auto s = make_span(&arr[0], 2); 44 | EXPECT_TRUE(s.size() == 2); 45 | EXPECT_TRUE(s.data() == &arr[0]); 46 | EXPECT_TRUE(s[0] == 1); 47 | EXPECT_TRUE(s[1] == 2); 48 | } 49 | 50 | { 51 | int* p = nullptr; 52 | auto s = make_span(p, narrow_cast::size_type>(0)); 53 | EXPECT_TRUE(s.size() == 0); 54 | EXPECT_TRUE(s.data() == nullptr); 55 | } 56 | 57 | { 58 | int* p = nullptr; 59 | auto workaround_macro = [=]() { make_span(p, 2); }; 60 | EXPECT_DEATH(workaround_macro(), expected); 61 | } 62 | } 63 | 64 | TEST(span_ext_test, make_span_from_pointer_pointer_construction) 65 | { 66 | int arr[4] = {1, 2, 3, 4}; 67 | 68 | { 69 | auto s = make_span(&arr[0], &arr[2]); 70 | EXPECT_TRUE(s.size() == 2); 71 | EXPECT_TRUE(s.data() == &arr[0]); 72 | EXPECT_TRUE(s[0] == 1); 73 | EXPECT_TRUE(s[1] == 2); 74 | } 75 | 76 | { 77 | auto s = make_span(&arr[0], &arr[0]); 78 | EXPECT_TRUE(s.size() == 0); 79 | EXPECT_TRUE(s.data() == &arr[0]); 80 | } 81 | 82 | { 83 | int* p = nullptr; 84 | auto s = make_span(p, p); 85 | EXPECT_TRUE(s.size() == 0); 86 | EXPECT_TRUE(s.data() == nullptr); 87 | } 88 | } 89 | 90 | TEST(span_ext_test, make_span_from_array_constructor) 91 | { 92 | int arr[5] = {1, 2, 3, 4, 5}; 93 | int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; 94 | int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; 95 | 96 | { 97 | const auto s = make_span(arr); 98 | EXPECT_TRUE(s.size() == 5); 99 | EXPECT_TRUE(s.data() == std::addressof(arr[0])); 100 | } 101 | 102 | { 103 | const auto s = make_span(std::addressof(arr2d[0]), 1); 104 | EXPECT_TRUE(s.size() == 1); 105 | EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); 106 | } 107 | 108 | { 109 | const auto s = make_span(std::addressof(arr3d[0]), 1); 110 | EXPECT_TRUE(s.size() == 1); 111 | EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); 112 | } 113 | } 114 | 115 | TEST(span_ext_test, make_span_from_dynamic_array_constructor) 116 | { 117 | double(*arr)[3][4] = new double[100][3][4]; 118 | 119 | { 120 | auto s = make_span(&arr[0][0][0], 10); 121 | EXPECT_TRUE(s.size() == 10); 122 | EXPECT_TRUE(s.data() == &arr[0][0][0]); 123 | } 124 | 125 | delete[] arr; 126 | } 127 | 128 | TEST(span_ext_test, make_span_from_std_array_constructor) 129 | { 130 | std::array arr = {1, 2, 3, 4}; 131 | 132 | { 133 | auto s = make_span(arr); 134 | EXPECT_TRUE(s.size() == arr.size()); 135 | EXPECT_TRUE(s.data() == arr.data()); 136 | } 137 | 138 | // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 139 | { 140 | gsl::span s1 = make_span(arr); 141 | 142 | static gsl::span s2; 143 | s2 = s1; 144 | 145 | #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ 146 | __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) 147 | // Known to be broken in gcc 6.4 and 6.5 with optimizations 148 | // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 149 | EXPECT_TRUE(s1.size() == 4); 150 | EXPECT_TRUE(s2.size() == 0); 151 | #else 152 | EXPECT_TRUE(s1.size() == s2.size()); 153 | #endif 154 | } 155 | } 156 | 157 | TEST(span_ext_test, make_span_from_const_std_array_constructor) 158 | { 159 | const std::array arr = {1, 2, 3, 4}; 160 | 161 | { 162 | auto s = make_span(arr); 163 | EXPECT_TRUE(s.size() == arr.size()); 164 | EXPECT_TRUE(s.data() == arr.data()); 165 | } 166 | } 167 | 168 | TEST(span_ext_test, make_span_from_std_array_const_constructor) 169 | { 170 | std::array arr = {1, 2, 3, 4}; 171 | 172 | { 173 | auto s = make_span(arr); 174 | EXPECT_TRUE(s.size() == arr.size()); 175 | EXPECT_TRUE(s.data() == arr.data()); 176 | } 177 | } 178 | 179 | TEST(span_ext_test, make_span_from_container_constructor) 180 | { 181 | std::vector v = {1, 2, 3}; 182 | const std::vector cv = v; 183 | 184 | { 185 | auto s = make_span(v); 186 | EXPECT_TRUE(s.size() == v.size()); 187 | EXPECT_TRUE(s.data() == v.data()); 188 | 189 | auto cs = make_span(cv); 190 | EXPECT_TRUE(cs.size() == cv.size()); 191 | EXPECT_TRUE(cs.data() == cv.data()); 192 | } 193 | } 194 | 195 | TEST(span_test, interop_with_gsl_at) 196 | { 197 | std::vector vec{1, 2, 3, 4, 5}; 198 | gsl::span sp{vec}; 199 | 200 | std::vector cvec{1, 2, 3, 4, 5}; 201 | gsl::span csp{cvec}; 202 | 203 | for (gsl::index i = 0; i < gsl::narrow_cast(vec.size()); ++i) 204 | { 205 | EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast(i)]); 206 | EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast(i)]); 207 | } 208 | 209 | const auto terminateHandler = std::set_terminate([] { 210 | std::cerr << "Expected Death. interop_with_gsl_at"; 211 | std::abort(); 212 | }); 213 | const auto expected = GetExpectedDeathString(terminateHandler); 214 | 215 | EXPECT_DEATH(gsl::at(sp, -1), expected); 216 | EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast(sp.size())), expected); 217 | EXPECT_DEATH(gsl::at(csp, -1), expected); 218 | EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast(sp.size())), expected); 219 | } 220 | 221 | TEST(span_ext_test, iterator_free_functions) 222 | { 223 | int a[] = {1, 2, 3, 4}; 224 | gsl::span s{a}; 225 | 226 | EXPECT_TRUE((std::is_same::value)); 227 | EXPECT_TRUE((std::is_same::value)); 228 | 229 | EXPECT_TRUE((std::is_same::value)); 230 | EXPECT_TRUE((std::is_same::value)); 231 | 232 | EXPECT_TRUE((std::is_same::value)); 233 | EXPECT_TRUE((std::is_same::value)); 234 | 235 | EXPECT_TRUE((std::is_same::value)); 236 | EXPECT_TRUE((std::is_same::value)); 237 | 238 | EXPECT_TRUE(s.begin() == begin(s)); 239 | EXPECT_TRUE(s.end() == end(s)); 240 | 241 | EXPECT_TRUE(s.rbegin() == rbegin(s)); 242 | EXPECT_TRUE(s.rend() == rend(s)); 243 | 244 | EXPECT_TRUE(s.begin() == cbegin(s)); 245 | EXPECT_TRUE(s.end() == cend(s)); 246 | 247 | EXPECT_TRUE(s.rbegin() == crbegin(s)); 248 | EXPECT_TRUE(s.rend() == crend(s)); 249 | } 250 | 251 | TEST(span_ext_test, ssize_free_function) 252 | { 253 | int a[] = {1, 2, 3, 4}; 254 | gsl::span s{a}; 255 | 256 | EXPECT_FALSE((std::is_same::value)); 257 | EXPECT_TRUE(s.size() == static_cast(ssize(s))); 258 | } 259 | 260 | #ifndef GSL_KERNEL_MODE 261 | TEST(span_ext_test, comparison_operators) 262 | { 263 | { 264 | gsl::span s1; 265 | gsl::span s2; 266 | EXPECT_TRUE(s1 == s2); 267 | EXPECT_FALSE(s1 != s2); 268 | EXPECT_FALSE(s1 < s2); 269 | EXPECT_TRUE(s1 <= s2); 270 | EXPECT_FALSE(s1 > s2); 271 | EXPECT_TRUE(s1 >= s2); 272 | EXPECT_TRUE(s2 == s1); 273 | EXPECT_FALSE(s2 != s1); 274 | EXPECT_FALSE(s2 != s1); 275 | EXPECT_TRUE(s2 <= s1); 276 | EXPECT_FALSE(s2 > s1); 277 | EXPECT_TRUE(s2 >= s1); 278 | } 279 | 280 | { 281 | int arr[] = {2, 1}; 282 | gsl::span s1 = arr; 283 | gsl::span s2 = arr; 284 | 285 | EXPECT_TRUE(s1 == s2); 286 | EXPECT_FALSE(s1 != s2); 287 | EXPECT_FALSE(s1 < s2); 288 | EXPECT_TRUE(s1 <= s2); 289 | EXPECT_FALSE(s1 > s2); 290 | EXPECT_TRUE(s1 >= s2); 291 | EXPECT_TRUE(s2 == s1); 292 | EXPECT_FALSE(s2 != s1); 293 | EXPECT_FALSE(s2 < s1); 294 | EXPECT_TRUE(s2 <= s1); 295 | EXPECT_FALSE(s2 > s1); 296 | EXPECT_TRUE(s2 >= s1); 297 | } 298 | 299 | { 300 | int arr[] = {2, 1}; // bigger 301 | 302 | gsl::span s1; 303 | gsl::span s2 = arr; 304 | 305 | EXPECT_TRUE(s1 != s2); 306 | EXPECT_TRUE(s2 != s1); 307 | EXPECT_FALSE(s1 == s2); 308 | EXPECT_FALSE(s2 == s1); 309 | EXPECT_TRUE(s1 < s2); 310 | EXPECT_FALSE(s2 < s1); 311 | EXPECT_TRUE(s1 <= s2); 312 | EXPECT_FALSE(s2 <= s1); 313 | EXPECT_TRUE(s2 > s1); 314 | EXPECT_FALSE(s1 > s2); 315 | EXPECT_TRUE(s2 >= s1); 316 | EXPECT_FALSE(s1 >= s2); 317 | } 318 | 319 | { 320 | int arr1[] = {1, 2}; 321 | int arr2[] = {1, 2}; 322 | gsl::span s1 = arr1; 323 | gsl::span s2 = arr2; 324 | 325 | EXPECT_TRUE(s1 == s2); 326 | EXPECT_FALSE(s1 != s2); 327 | EXPECT_FALSE(s1 < s2); 328 | EXPECT_TRUE(s1 <= s2); 329 | EXPECT_FALSE(s1 > s2); 330 | EXPECT_TRUE(s1 >= s2); 331 | EXPECT_TRUE(s2 == s1); 332 | EXPECT_FALSE(s2 != s1); 333 | EXPECT_FALSE(s2 < s1); 334 | EXPECT_TRUE(s2 <= s1); 335 | EXPECT_FALSE(s2 > s1); 336 | EXPECT_TRUE(s2 >= s1); 337 | } 338 | 339 | { 340 | int arr[] = {1, 2, 3}; 341 | 342 | gsl::span s1 = {&arr[0], 2}; // shorter 343 | gsl::span s2 = arr; // longer 344 | 345 | EXPECT_TRUE(s1 != s2); 346 | EXPECT_TRUE(s2 != s1); 347 | EXPECT_FALSE(s1 == s2); 348 | EXPECT_FALSE(s2 == s1); 349 | EXPECT_TRUE(s1 < s2); 350 | EXPECT_FALSE(s2 < s1); 351 | EXPECT_TRUE(s1 <= s2); 352 | EXPECT_FALSE(s2 <= s1); 353 | EXPECT_TRUE(s2 > s1); 354 | EXPECT_FALSE(s1 > s2); 355 | EXPECT_TRUE(s2 >= s1); 356 | EXPECT_FALSE(s1 >= s2); 357 | } 358 | 359 | { 360 | int arr1[] = {1, 2}; // smaller 361 | int arr2[] = {2, 1}; // bigger 362 | 363 | gsl::span s1 = arr1; 364 | gsl::span s2 = arr2; 365 | 366 | EXPECT_TRUE(s1 != s2); 367 | EXPECT_TRUE(s2 != s1); 368 | EXPECT_FALSE(s1 == s2); 369 | EXPECT_FALSE(s2 == s1); 370 | EXPECT_TRUE(s1 < s2); 371 | EXPECT_FALSE(s2 < s1); 372 | EXPECT_TRUE(s1 <= s2); 373 | EXPECT_FALSE(s2 <= s1); 374 | EXPECT_TRUE(s2 > s1); 375 | EXPECT_FALSE(s1 > s2); 376 | EXPECT_TRUE(s2 >= s1); 377 | EXPECT_FALSE(s1 >= s2); 378 | } 379 | } 380 | #endif // GSL_KERNEL_MODE 381 | -------------------------------------------------------------------------------- /tests/strict_notnull_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include // for not_null, operator<, operator<=, operator> 18 | #include 19 | 20 | #include // for declval 21 | 22 | #include "deathTestCommon.h" 23 | 24 | using namespace gsl; 25 | 26 | #if __cplusplus >= 201703l 27 | using std::void_t; 28 | #else // __cplusplus >= 201703l 29 | template 30 | using void_t = void; 31 | #endif // __cplusplus < 201703l 32 | 33 | // stand-in for a user-defined ref-counted class 34 | template 35 | struct RefCounted 36 | { 37 | RefCounted(T* p) : p_(p) {} 38 | operator T*() { return p_; } 39 | T* p_; 40 | }; 41 | 42 | namespace 43 | { 44 | // clang-format off 45 | GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 46 | // clang-format on 47 | bool helper(not_null p) { return *p == 12; } 48 | 49 | // clang-format off 50 | GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 51 | // clang-format on 52 | bool helper_const(not_null p) { return *p == 12; } 53 | 54 | // clang-format off 55 | GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 56 | // clang-format on 57 | bool strict_helper(strict_not_null p) { return *p == 12; } 58 | 59 | // clang-format off 60 | GSL_SUPPRESS(f.4) // NO-FORMAT: attribute 61 | // clang-format on 62 | bool strict_helper_const(strict_not_null p) { return *p == 12; } 63 | 64 | int* return_pointer() { return nullptr; } 65 | } // namespace 66 | 67 | template 68 | static constexpr bool CtorCompilesFor_A = false; 69 | template 70 | static constexpr bool 71 | CtorCompilesFor_A{std::declval()})>> = true; 72 | 73 | template 74 | static constexpr bool CtorCompilesFor_B = false; 75 | template 76 | static constexpr bool CtorCompilesFor_B{N})>> = true; 77 | 78 | template 79 | static constexpr bool DefaultCtorCompilesFor = false; 80 | template 81 | static constexpr bool DefaultCtorCompilesFor{})>> = true; 82 | 83 | template 84 | static constexpr bool CtorCompilesFor_C = false; 85 | template 86 | static constexpr bool CtorCompilesFor_C< 87 | U, void_t{std::declval>()})>> = true; 88 | 89 | TEST(strict_notnull_tests, TestStrictNotNullConstructors) 90 | { 91 | { 92 | static_assert(CtorCompilesFor_A, "CtorCompilesFor_A"); 93 | static_assert(!CtorCompilesFor_A, "!CtorCompilesFor_A"); 94 | static_assert(!CtorCompilesFor_B, "!CtorCompilesFor_B"); 95 | static_assert(!DefaultCtorCompilesFor, "!DefaultCtorCompilesFor"); 96 | static_assert(!CtorCompilesFor_C, "CtorCompilesFor_C"); 97 | #ifdef CONFIRM_COMPILATION_ERRORS 98 | // Forbid non-nullptr assignable types 99 | strict_not_null> f(std::vector{1}); 100 | strict_not_null z(10); 101 | strict_not_null> y({1, 2}); 102 | #endif 103 | } 104 | 105 | const auto terminateHandler = std::set_terminate([] { 106 | std::cerr << "Expected Death. TestNotNullConstructors"; 107 | std::abort(); 108 | }); 109 | const auto expected = GetExpectedDeathString(terminateHandler); 110 | 111 | { 112 | // from shared pointer 113 | int i = 12; 114 | auto rp = RefCounted(&i); 115 | strict_not_null p(rp); 116 | EXPECT_TRUE(p.get() == &i); 117 | 118 | strict_not_null> x( 119 | std::make_shared(10)); // shared_ptr is nullptr assignable 120 | 121 | int* pi = nullptr; 122 | EXPECT_DEATH((strict_not_null(pi)), expected); 123 | } 124 | 125 | { 126 | // from unique pointer 127 | strict_not_null> x( 128 | std::make_unique(10)); // unique_ptr is nullptr assignable 129 | 130 | EXPECT_DEATH((strict_not_null>(std::unique_ptr{})), expected); 131 | } 132 | 133 | { 134 | // from pointer to local 135 | int t = 42; 136 | 137 | strict_not_null x{&t}; 138 | helper(&t); 139 | helper_const(&t); 140 | 141 | EXPECT_TRUE(*x == 42); 142 | } 143 | 144 | { 145 | // from raw pointer 146 | // from strict_not_null pointer 147 | 148 | int t = 42; 149 | int* p = &t; 150 | 151 | strict_not_null x{p}; 152 | helper(p); 153 | helper_const(p); 154 | helper(x); 155 | helper_const(x); 156 | 157 | EXPECT_TRUE(*x == 42); 158 | } 159 | 160 | { 161 | // from raw const pointer 162 | // from strict_not_null const pointer 163 | 164 | int t = 42; 165 | const int* cp = &t; 166 | 167 | strict_not_null x{cp}; 168 | helper_const(cp); 169 | helper_const(x); 170 | 171 | EXPECT_TRUE(*x == 42); 172 | } 173 | 174 | { 175 | // from strict_not_null const pointer, using auto 176 | int t = 42; 177 | const int* cp = &t; 178 | 179 | auto x = strict_not_null{cp}; 180 | 181 | EXPECT_TRUE(*x == 42); 182 | } 183 | 184 | { 185 | // from returned pointer 186 | 187 | EXPECT_DEATH(helper(return_pointer()), expected); 188 | EXPECT_DEATH(helper_const(return_pointer()), expected); 189 | } 190 | } 191 | 192 | template 193 | static constexpr bool StrictHelperCompilesFor = false; 194 | template 195 | static constexpr bool 196 | StrictHelperCompilesFor()))>> = true; 197 | 198 | 199 | template 200 | static constexpr bool StrictHelperConstCompilesFor = false; 201 | template 202 | static constexpr bool 203 | StrictHelperConstCompilesFor()))>> = 204 | true; 205 | 206 | 207 | template 208 | static constexpr bool HelperCompilesFor = false; 209 | template 210 | static constexpr bool HelperCompilesFor()))>> = true; 211 | 212 | TEST(strict_notnull_tests, TestStrictNotNull) 213 | { 214 | { 215 | // raw ptr <-> strict_not_null 216 | int x = 42; 217 | 218 | #ifdef CONFIRM_COMPILATION_ERRORS 219 | strict_not_null snn = &x; 220 | #endif 221 | static_assert(!StrictHelperCompilesFor, "!StrictHelperCompilesFor"); 222 | static_assert(!StrictHelperConstCompilesFor, 223 | "!StrictHelperCompilesFor"); 224 | 225 | const strict_not_null snn1{&x}; 226 | 227 | static_assert(StrictHelperCompilesFor>, 228 | "StrictHelperCompilesFor>"); 229 | helper(snn1); 230 | helper_const(snn1); 231 | 232 | EXPECT_TRUE(*snn1 == 42); 233 | } 234 | 235 | { 236 | // raw ptr <-> strict_not_null 237 | const int x = 42; 238 | 239 | #ifdef CONFIRM_COMPILATION_ERRORS 240 | strict_not_null snn = &x; 241 | #endif 242 | static_assert(!StrictHelperCompilesFor, "!StrictHelperFor"); 243 | static_assert(!StrictHelperConstCompilesFor, 244 | "!StrictHelperCompilesFor"); 245 | 246 | const strict_not_null snn1{&x}; 247 | 248 | static_assert(!HelperCompilesFor>, 249 | "!HelperCompilesFor>"); 250 | static_assert(StrictHelperConstCompilesFor>, 251 | "StrictHelperCompilesFor>"); 252 | helper_const(snn1); 253 | 254 | EXPECT_TRUE(*snn1 == 42); 255 | } 256 | 257 | { 258 | // strict_not_null -> strict_not_null 259 | int x = 42; 260 | 261 | strict_not_null snn1{&x}; 262 | const strict_not_null snn2{&x}; 263 | 264 | strict_helper(snn1); 265 | strict_helper_const(snn1); 266 | strict_helper_const(snn2); 267 | 268 | EXPECT_TRUE(snn1 == snn2); 269 | } 270 | 271 | { 272 | // strict_not_null -> strict_not_null 273 | const int x = 42; 274 | 275 | strict_not_null snn1{&x}; 276 | const strict_not_null snn2{&x}; 277 | 278 | static_assert(!StrictHelperCompilesFor>, 279 | "!StrictHelperCompilesFor>"); 280 | strict_helper_const(snn1); 281 | strict_helper_const(snn2); 282 | 283 | EXPECT_TRUE(snn1 == snn2); 284 | } 285 | 286 | { 287 | // strict_not_null -> not_null 288 | int x = 42; 289 | 290 | strict_not_null snn{&x}; 291 | 292 | const not_null nn1 = snn; 293 | const not_null nn2{snn}; 294 | 295 | helper(snn); 296 | helper_const(snn); 297 | 298 | EXPECT_TRUE(snn == nn1); 299 | EXPECT_TRUE(snn == nn2); 300 | } 301 | 302 | { 303 | // strict_not_null -> not_null 304 | const int x = 42; 305 | 306 | strict_not_null snn{&x}; 307 | 308 | const not_null nn1 = snn; 309 | const not_null nn2{snn}; 310 | 311 | static_assert(!HelperCompilesFor>, 312 | "!HelperCompilesFor>"); 313 | helper_const(snn); 314 | 315 | EXPECT_TRUE(snn == nn1); 316 | EXPECT_TRUE(snn == nn2); 317 | } 318 | 319 | { 320 | // not_null -> strict_not_null 321 | int x = 42; 322 | 323 | not_null nn{&x}; 324 | 325 | const strict_not_null snn1{nn}; 326 | const strict_not_null snn2{nn}; 327 | 328 | strict_helper(nn); 329 | strict_helper_const(nn); 330 | 331 | EXPECT_TRUE(snn1 == nn); 332 | EXPECT_TRUE(snn2 == nn); 333 | 334 | std::hash> hash_snn; 335 | std::hash> hash_nn; 336 | 337 | EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn)); 338 | EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn)); 339 | EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2)); 340 | EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn)); 341 | } 342 | 343 | { 344 | // not_null -> strict_not_null 345 | const int x = 42; 346 | 347 | not_null nn{&x}; 348 | 349 | const strict_not_null snn1{nn}; 350 | const strict_not_null snn2{nn}; 351 | 352 | static_assert(!StrictHelperCompilesFor>, 353 | "!StrictHelperCompilesFor>"); 354 | strict_helper_const(nn); 355 | 356 | EXPECT_TRUE(snn1 == nn); 357 | EXPECT_TRUE(snn2 == nn); 358 | 359 | std::hash> hash_snn; 360 | std::hash> hash_nn; 361 | 362 | EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn)); 363 | EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn)); 364 | EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2)); 365 | EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn)); 366 | } 367 | } 368 | 369 | TEST(pointers_test, member_types) 370 | { 371 | // make sure `element_type` is inherited from `gsl::not_null` 372 | static_assert(std::is_same::element_type, int*>::value, 373 | "check member type: element_type"); 374 | } 375 | 376 | #if defined(__cplusplus) && (__cplusplus >= 201703L) 377 | 378 | TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) 379 | { 380 | const auto terminateHandler = std::set_terminate([] { 381 | std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; 382 | std::abort(); 383 | }); 384 | const auto expected = GetExpectedDeathString(terminateHandler); 385 | 386 | { 387 | int i = 42; 388 | 389 | strict_not_null x{&i}; 390 | helper(strict_not_null{&i}); 391 | helper_const(strict_not_null{&i}); 392 | 393 | EXPECT_TRUE(*x == 42); 394 | } 395 | 396 | { 397 | const int i = 42; 398 | 399 | strict_not_null x{&i}; 400 | static_assert(!HelperCompilesFor>, 401 | "!HelperCompilesFor>"); 402 | helper_const(strict_not_null{&i}); 403 | 404 | EXPECT_TRUE(*x == 42); 405 | } 406 | 407 | { 408 | int i = 42; 409 | int* p = &i; 410 | 411 | strict_not_null x{p}; 412 | helper(strict_not_null{p}); 413 | helper_const(strict_not_null{p}); 414 | 415 | EXPECT_TRUE(*x == 42); 416 | } 417 | 418 | { 419 | const int i = 42; 420 | const int* p = &i; 421 | 422 | strict_not_null x{p}; 423 | static_assert(!HelperCompilesFor>, 424 | "!HelperCompilesFor>"); 425 | helper_const(strict_not_null{p}); 426 | 427 | EXPECT_TRUE(*x == 42); 428 | } 429 | 430 | { 431 | auto workaround_macro = []() { 432 | int* p1 = nullptr; 433 | const strict_not_null x{p1}; 434 | }; 435 | EXPECT_DEATH(workaround_macro(), expected); 436 | } 437 | 438 | { 439 | auto workaround_macro = []() { 440 | const int* p1 = nullptr; 441 | const strict_not_null x{p1}; 442 | }; 443 | EXPECT_DEATH(workaround_macro(), expected); 444 | } 445 | 446 | { 447 | int* p = nullptr; 448 | 449 | EXPECT_DEATH(helper(strict_not_null{p}), expected); 450 | EXPECT_DEATH(helper_const(strict_not_null{p}), expected); 451 | } 452 | 453 | #ifdef CONFIRM_COMPILATION_ERRORS 454 | { 455 | strict_not_null x{nullptr}; 456 | helper(strict_not_null{nullptr}); 457 | helper_const(strict_not_null{nullptr}); 458 | } 459 | #endif 460 | } 461 | #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) 462 | -------------------------------------------------------------------------------- /tests/utils_tests.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 | // 5 | // This code is licensed under the MIT License (MIT). 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 | // THE SOFTWARE. 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | 19 | #include // for move 20 | #include 21 | #include // for std::ptrdiff_t 22 | #include // for uint32_t, int32_t 23 | #include // for reference_wrapper, _Bind_helper<>::type 24 | #include // for narrow, narrowing_error 25 | #include // finally, narrow_cast 26 | #include // for numeric_limits 27 | #include // for is_same 28 | 29 | using namespace gsl; 30 | 31 | namespace 32 | { 33 | void f(int& i) { i += 1; } 34 | static int j = 0; 35 | void g() { j += 1; } 36 | } // namespace 37 | 38 | TEST(utils_tests, sanity_check_for_gsl_index_typedef) 39 | { 40 | static_assert(std::is_same::value, 41 | "gsl::index represents wrong arithmetic type"); 42 | } 43 | 44 | TEST(utils_tests, finally_lambda) 45 | { 46 | int i = 0; 47 | { 48 | auto _ = finally([&]() { f(i); }); 49 | EXPECT_TRUE(i == 0); 50 | } 51 | EXPECT_TRUE(i == 1); 52 | } 53 | 54 | TEST(utils_tests, finally_lambda_move) 55 | { 56 | int i = 0; 57 | { 58 | auto _1 = finally([&]() { f(i); }); 59 | { 60 | auto _2 = std::move(_1); 61 | EXPECT_TRUE(i == 0); 62 | } 63 | EXPECT_TRUE(i == 1); 64 | { 65 | auto _2 = std::move(_1); 66 | EXPECT_TRUE(i == 1); 67 | } 68 | EXPECT_TRUE(i == 1); 69 | } 70 | EXPECT_TRUE(i == 1); 71 | } 72 | 73 | TEST(utils_tests, finally_const_lvalue_lambda) 74 | { 75 | int i = 0; 76 | { 77 | const auto const_lvalue_lambda = [&]() { f(i); }; 78 | auto _ = finally(const_lvalue_lambda); 79 | EXPECT_TRUE(i == 0); 80 | } 81 | EXPECT_TRUE(i == 1); 82 | } 83 | 84 | TEST(utils_tests, finally_mutable_lvalue_lambda) 85 | { 86 | int i = 0; 87 | { 88 | auto mutable_lvalue_lambda = [&]() { f(i); }; 89 | auto _ = finally(mutable_lvalue_lambda); 90 | EXPECT_TRUE(i == 0); 91 | } 92 | EXPECT_TRUE(i == 1); 93 | } 94 | 95 | TEST(utils_tests, finally_function_with_bind) 96 | { 97 | int i = 0; 98 | { 99 | auto _ = finally([&i] { return f(i); }); 100 | EXPECT_TRUE(i == 0); 101 | } 102 | EXPECT_TRUE(i == 1); 103 | } 104 | 105 | TEST(utils_tests, finally_function_ptr) 106 | { 107 | j = 0; 108 | { 109 | auto _ = finally(&g); 110 | EXPECT_TRUE(j == 0); 111 | } 112 | EXPECT_TRUE(j == 1); 113 | } 114 | 115 | TEST(utils_tests, finally_function) 116 | { 117 | j = 0; 118 | { 119 | auto _ = finally(g); 120 | EXPECT_TRUE(j == 0); 121 | } 122 | EXPECT_TRUE(j == 1); 123 | } 124 | 125 | TEST(utils_tests, narrow_cast) 126 | { 127 | int n = 120; 128 | char c = narrow_cast(n); 129 | EXPECT_TRUE(c == 120); 130 | 131 | n = 300; 132 | unsigned char uc = narrow_cast(n); 133 | EXPECT_TRUE(uc == 44); 134 | } 135 | 136 | #ifndef GSL_KERNEL_MODE 137 | TEST(utils_tests, narrow) 138 | { 139 | int n = 120; 140 | const char c = narrow(n); 141 | EXPECT_TRUE(c == 120); 142 | 143 | n = 300; 144 | EXPECT_THROW(narrow(n), narrowing_error); 145 | 146 | const auto int32_max = std::numeric_limits::max(); 147 | const auto int32_min = std::numeric_limits::min(); 148 | 149 | EXPECT_TRUE(narrow(int32_t(0)) == 0); 150 | EXPECT_TRUE(narrow(int32_t(1)) == 1); 151 | EXPECT_TRUE(narrow(int32_max) == static_cast(int32_max)); 152 | 153 | EXPECT_THROW(narrow(int32_t(-1)), narrowing_error); 154 | EXPECT_THROW(narrow(int32_min), narrowing_error); 155 | 156 | n = -42; 157 | EXPECT_THROW(narrow(n), narrowing_error); 158 | 159 | EXPECT_TRUE( 160 | narrow>(std::complex(4, 2)) == std::complex(4, 2)); 161 | EXPECT_THROW(narrow>(std::complex(4.2)), narrowing_error); 162 | 163 | EXPECT_TRUE(narrow(float(1)) == 1); 164 | } 165 | #endif // GSL_KERNEL_MODE 166 | --------------------------------------------------------------------------------