pax_global_header00006660000000000000000000000064135646033750014526gustar00rootroot0000000000000052 comment=7e99e76c9761d0d0b0848b91f8648830670ee872 GSL-2.1.0/000077500000000000000000000000001356460337500121535ustar00rootroot00000000000000GSL-2.1.0/.clang-format000066400000000000000000000014101356460337500145220ustar00rootroot00000000000000ColumnLimit: 100 UseTab: Never IndentWidth: 4 AccessModifierOffset: -4 NamespaceIndentation: Inner BreakBeforeBraces: Custom BraceWrapping: AfterNamespace: true AfterEnum: true AfterStruct: true AfterClass: true SplitEmptyFunction: false AfterControlStatement: true AfterFunction: true AfterUnion: true BeforeElse: true AlwaysBreakTemplateDeclarations: true BreakConstructorInitializersBeforeComma: true ConstructorInitializerAllOnOneLineOrOnePerLine: true AllowShortBlocksOnASingleLine: true AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true PointerAlignment: Left AlignConsecutiveAssignments: false AlignTrailingComments: true SpaceAfterCStyleCast: true CommentPragmas: '^ NO-FORMAT:' GSL-2.1.0/.gitignore000066400000000000000000000002611356460337500141420ustar00rootroot00000000000000CMakeFiles build tests/CMakeFiles tests/Debug *.opensdf *.sdf tests/*tests.dir *.vcxproj *.vcxproj.filters *.sln *.tlog Testing/Temporary/*.* CMakeCache.txt *.suo .vs/ .vscode/ GSL-2.1.0/.travis.yml000066400000000000000000000223621356460337500142710ustar00rootroot00000000000000# Based on https://github.com/ldionne/hana/blob/master/.travis.yml language: cpp sudo: false notifications: email: false # Use Linux unless specified otherwise os: linux dist: trusty cache: directories: - ${TRAVIS_BUILD_DIR}/deps matrix: include: ########################################################################## # Clang on OSX # Travis seems to take longer to start OSX instances, # so leave this first for the overall build to be faster ########################################################################## # XCode 8.3 - env: COMPILER=clang++ BUILD_TYPE=Debug GSL_CXX_STANDARD=14 os: osx osx_image: xcode8.3 compiler: clang - env: COMPILER=clang++ BUILD_TYPE=Release GSL_CXX_STANDARD=14 os: osx osx_image: xcode8.3 compiler: clang # XCode 9.1 - env: COMPILER=clang++ BUILD_TYPE=Debug GSL_CXX_STANDARD=14 os: osx osx_image: xcode9.1 compiler: clang - env: COMPILER=clang++ BUILD_TYPE=Release GSL_CXX_STANDARD=14 os: osx osx_image: xcode9.1 compiler: clang ########################################################################## # Clang on Linux ########################################################################## # Clang 3.6 - env: COMPILER=clang++-3.6 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang36 apt: packages: - clang-3.6 - g++-5 sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.6 - env: COMPILER=clang++-3.6 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang36 # Clang 3.7 - env: COMPILER=clang++-3.7 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang37 apt: packages: - clang-3.7 - g++-5 sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.7 - env: COMPILER=clang++-3.7 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang37 # Clang 3.8 - env: COMPILER=clang++-3.8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang38 apt: packages: - clang-3.8 - g++-5 sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.8 - env: COMPILER=clang++-3.8 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang38 # Clang 3.9 - env: COMPILER=clang++-3.9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang39 apt: packages: - clang-3.9 - g++-5 sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.9 - env: COMPILER=clang++-3.9 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang39 # Clang 4.0 - env: COMPILER=clang++-4.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang40 apt: packages: - clang-4.0 - g++-5 sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-4.0 - env: COMPILER=clang++-4.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang40 # Clang 5.0 - env: COMPILER=clang++-5.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang50 apt: packages: - clang-5.0 - g++-7 sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-5.0 - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: COMPILER=clang++-5.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang50 - env: COMPILER=clang++-5.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 addons: *clang50 - env: COMPILER=clang++-5.0 BUILD_TYPE=Release GSL_CXX_STANDARD=17 addons: *clang50 # Clang 6.0 - env: COMPILER=clang++-6.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang60 apt: packages: - clang-6.0 - g++-7 sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-6.0 - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: COMPILER=clang++-6.0 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang60 # Clang 6.0 c++17 - env: COMPILER=clang++-6.0 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 addons: *clang60 - env: COMPILER=clang++-6.0 BUILD_TYPE=Release GSL_CXX_STANDARD=17 addons: *clang60 # Clang 7.0 - env: COMPILER=clang++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &clang70 apt: packages: - clang-7 - g++-7 sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-7 - env: COMPILER=clang++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *clang70 # Clang 7.0 c++17 - env: COMPILER=clang++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 addons: *clang70 - env: COMPILER=clang++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=17 addons: *clang70 ########################################################################## # GCC on Linux ########################################################################## # GCC 5 - env: COMPILER=g++-5 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &gcc5 apt: packages: g++-5 sources: - ubuntu-toolchain-r-test - env: COMPILER=g++-5 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *gcc5 # GCC 6 - env: COMPILER=g++-6 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &gcc6 apt: packages: g++-6 sources: - ubuntu-toolchain-r-test - env: COMPILER=g++-6 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *gcc6 # GCC 7 - env: COMPILER=g++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 addons: &gcc7 apt: packages: g++-7 sources: - ubuntu-toolchain-r-test - env: COMPILER=g++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=14 addons: *gcc7 # GCC 7 c++17 - env: COMPILER=g++-7 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 addons: *gcc7 - env: COMPILER=g++-7 BUILD_TYPE=Release GSL_CXX_STANDARD=17 addons: *gcc7 install: # Set the ${CXX} variable properly - export CXX=${COMPILER} - ${CXX} --version # Dependencies required by the CI are installed in ${TRAVIS_BUILD_DIR}/deps/ - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" - mkdir -p "${DEPS_DIR}" - cd "${DEPS_DIR}" # Travis machines have 2 cores - JOBS=2 ############################################################################ # Install a recent CMake (unless already installed on OS X) ############################################################################ - CMAKE_VERSION=3.7.2 - | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then CMAKE_URL="https://cmake.org/files/v${CMAKE_VERSION%.[0-9]}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz" mkdir cmake && travis_retry wget --no-check-certificate -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake export PATH=${DEPS_DIR}/cmake/bin:${PATH} else brew install cmake || brew upgrade cmake fi - cmake --version ############################################################################ # [linux]: Install the right version of libc++ ############################################################################ - | LLVM_INSTALL=${DEPS_DIR}/llvm/install # if in linux and compiler clang and llvm not installed if [[ "${TRAVIS_OS_NAME}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL})" ]]; then if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1"; elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1"; elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1"; fi LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi (cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL}) (cd llvm/build/projects/libcxx && make install -j2) (cd llvm/build/projects/libcxxabi && make install -j2) export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1" export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi" export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib" fi before_script: # have CMake to generate build files - cd "${TRAVIS_BUILD_DIR}" - mkdir build && cd build - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DGSL_CXX_STANDARD=$GSL_CXX_STANDARD script: # build and run tests - cmake --build . -- -j${JOBS} - ctest --output-on-failure -j${JOBS} GSL-2.1.0/CMakeLists.txt000066400000000000000000000055761356460337500147300ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.3) project(GSL CXX) include(ExternalProject) find_package(Git) # creates a library GSL which is an interface (header files only) add_library(GSL INTERFACE) # determine whether this is a standalone project or included by other projects set(GSL_STANDALONE_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(GSL_STANDALONE_PROJECT ON) endif () set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard") set(GSL_CXX_STD "cxx_std_${GSL_CXX_STANDARD}") if (MSVC) set(GSL_CXX_STD_OPT "-std:c++${GSL_CXX_STANDARD}") else() set(GSL_CXX_STD_OPT "-std=c++${GSL_CXX_STANDARD}") endif() # when minimum version required is 3.8.0 remove if below # both branches do exactly the same thing if (CMAKE_VERSION VERSION_LESS 3.7.9) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("${GSL_CXX_STD_OPT}" COMPILER_SUPPORTS_CXX_STANDARD) if(COMPILER_SUPPORTS_CXX_STANDARD) target_compile_options(GSL INTERFACE "${GSL_CXX_STD_OPT}") else() message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no c++${GSL_CXX_STANDARD} support. Please use a different C++ compiler.") endif() else () target_compile_features(GSL INTERFACE "${GSL_CXX_STD}") # on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default) set(CMAKE_CXX_EXTENSIONS OFF) endif() # add definitions to the library and targets that consume it target_compile_definitions(GSL INTERFACE $<$: # remove unnecessary warnings about unchecked iterators _SCL_SECURE_NO_WARNINGS # remove deprecation warnings about std::uncaught_exception() (from catch) _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING > ) # add include folders to the library and targets that consume it # the SYSTEM keyword suppresses warnings for users of the library if(GSL_STANDALONE_PROJECT) target_include_directories(GSL INTERFACE $ ) else() target_include_directories(GSL SYSTEM INTERFACE $ ) endif() if (CMAKE_VERSION VERSION_GREATER 3.7.8) if (MSVC_IDE) option(VS_ADD_NATIVE_VISUALIZERS "Configure project to use Visual Studio native visualizers" TRUE) else() set(VS_ADD_NATIVE_VISUALIZERS FALSE CACHE INTERNAL "Native visualizers are Visual Studio extension" FORCE) endif() # add natvis file to the library so it will automatically be loaded into Visual Studio if(VS_ADD_NATIVE_VISUALIZERS) target_sources(GSL INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/GSL.natvis ) endif() endif() install( DIRECTORY include/gsl DESTINATION include ) option(GSL_TEST "Generate tests." ${GSL_STANDALONE_PROJECT}) if (GSL_TEST) enable_testing() add_subdirectory(tests) endif () GSL-2.1.0/CMakeSettings.json000066400000000000000000000010411356460337500155430ustar00rootroot00000000000000{ "configurations": [ { "name": "x64-Debug", "generator": "Ninja", "configurationType": "Debug", "inheritEnvironments": [ "msvc_x64_x64" ], "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", "cmakeCommandArgs": "-DGSL_CXX_STANDARD=17", "buildCommandArgs": "-v", "ctestCommandArgs": "", "codeAnalysisRuleset": "CppCoreCheckRules.ruleset" } ] }GSL-2.1.0/CONTRIBUTING.md000066400000000000000000000037241356460337500144120ustar00rootroot00000000000000## Contributing to the Guidelines Support Library The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines). GSL design changes are made only as a result of modifications to the Guidelines. 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 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 a PR, please post a comment in the associated issue to avoid duplication of effort. ## Legal You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us and the community permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. ## Housekeeping Your pull request should: * Include a description of what your change intends to do * Be a child commit of a reasonably recent commit in the **master** branch * Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR) * It is desirable, but not necessary, for the tests to pass at each commit. Please see [README.md](./README.md) for instructions to build the test suite. * Have clear commit messages * e.g. "Fix issue", "Add tests for type", etc. * Include appropriate tests * Tests should include reasonable permutations of the target fix/change * Include baseline changes with your change * All changed code must have 100% code coverage * To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration GSL-2.1.0/GSL.natvis000066400000000000000000000071031356460337500140270ustar00rootroot00000000000000 {_Data._What,nasb} {{ invoke = {invoke_}, action = {f_} }} invoke_ f_ {{ extent = {storage_.size_} }} storage_.size_ storage_.data_ {{ extent = {extent} }} extent storage_.data_ {span_.storage_.data_,[span_.storage_.size_]na} span_.storage_.size_ span_.storage_.size_ span_.storage_.data_ {span_.storage_.data_,[span_.extent]na} span_.extent span_.extent span_.storage_.data_ {span_.storage_.data_,[span_.storage_.size_]na} span_.storage_.size_ span_.storage_.size_ span_.storage_.data_ {span_.storage_.data_,[span_.extent]na} span_.extent span_.extent span_.storage_.data_ value = {*ptr_} GSL-2.1.0/LICENSE000066400000000000000000000022051356460337500131570ustar00rootroot00000000000000Copyright (c) 2015 Microsoft Corporation. All rights reserved. This code is licensed under the MIT License (MIT). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. GSL-2.1.0/README.md000066400000000000000000000117711356460337500134410ustar00rootroot00000000000000# GSL: Guidelines Support Library [![Build Status](https://travis-ci.org/Microsoft/GSL.svg?branch=master)](https://travis-ci.org/Microsoft/GSL) [![Build status](https://ci.appveyor.com/api/projects/status/github/Microsoft/GSL?svg=true)](https://ci.appveyor.com/project/neilmacintosh/GSL) The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org). This repo contains Microsoft's implementation of GSL. The library includes types like `span`, `string_span`, `owner<>` and others. The entire implementation is provided inline in the headers under the [gsl](./include/gsl) directory. The implementation generally assumes a platform that implements C++14 support. There are specific workarounds to support MSVC 2015. While some types have been broken out into their own headers (e.g. [gsl/span](./include/gsl/span)), it is simplest to just include [gsl/gsl](./include/gsl/gsl) and gain access to the entire library. > NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing. # Project Code of Conduct 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. # Usage of Third Party Libraries This project makes use of the [Catch](https://github.com/philsquared/catch) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Catch. # Quick Start ## Supported Platforms The test suite that exercises GSL has been built and passes successfully on the following platforms:1) * Windows using Visual Studio 2015 * Windows using Visual Studio 2017 * Windows using Clang/LLVM 3.6 * Windows using Clang/LLVM 7.0.0 * Windows using GCC 5.1 * Windows using Intel C++ Compiler 18.0 * GNU/Linux using Clang/LLVM 3.6-3.9 * GNU/Linux using Clang/LLVM 4.0 * GNU/Linux using Clang/LLVM 5.0 * GNU/Linux using Clang/LLVM 6.0 * GNU/Linux using Clang/LLVM 7.0 * GNU/Linux using GCC 5.1 * OS X Mojave 10.14.4 using Apple LLVM version 10.0.0 (10.0.1.10010046) * OS X Mojave 10.14.3 using Apple LLVM version 10.0.0 (clang-1000.11.45.5) * OS X Yosemite using Xcode with Apple Clang 7.0.0.7000072 * OS X Yosemite using GCC-5.2.0 * OS X Sierra 10.12.4 using Apple LLVM version 8.1.0 (Clang-802.0.42) * OS X El Capitan (10.11) using Xcode with AppleClang 8.0.0.8000042 * OS X High Sierra 10.13.2 (17C88) using Apple LLVM version 9.0.0 (clang-900.0.39.2) * FreeBSD 10.x with Clang/LLVM 3.6 > If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider contributing any changes that were necessary back to this project to benefit the wider community. 1) For `gsl::byte` to work correctly with Clang and GCC you might have to use the ` -fno-strict-aliasing` compiler option. ## Building the tests To build the tests, you will require the following: * [CMake](http://cmake.org), version 3.1.3 or later to be installed and in your PATH. These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`. 1. Create a directory to contain the build outputs for a particular architecture (we name it c:\GSL\build-x86 in this example). cd GSL md build-x86 cd build-x86 2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`). cmake -G "Visual Studio 14 2015" c:\GSL 3. Build the test suite (in this case, in the Debug configuration, Release is another good choice). cmake --build . --config Debug 4. Run the test suite. ctest -C Debug All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types! ## Using the libraries As the types are entirely implemented inline in headers, there are no linking requirements. You can copy the [gsl](./include/gsl) directory into your source tree so it is available to your compiler, then include the appropriate headers in your program. 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. MSVC++ /I c:\GSL\include GCC/clang -I$HOME/dev/GSL/include Include the library using: #include ## Debugging visualization support For Visual Studio users, the file [GSL.natvis](./GSL.natvis) in the root directory of the repository can be added to your project if you would like more helpful visualization of GSL types in the Visual Studio debugger than would be offered by default. GSL-2.1.0/ThirdPartyNotices.txt000066400000000000000000000036771356460337500163500ustar00rootroot00000000000000 THIRD-PARTY SOFTWARE NOTICES AND INFORMATION Do Not Translate or Localize GSL: Guidelines Support Library incorporates third party material from the projects listed below. The original copyright notice and the license under which Microsoft received such third party material are set forth below. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. 1. Catch (https://github.com/philsquared/Catch) %% Catch NOTICES, INFORMATION, AND LICENSE BEGIN HERE ========================================= Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========================================= END OF Catch NOTICES, INFORMATION, AND LICENSE GSL-2.1.0/appveyor.yml000066400000000000000000000103221356460337500145410ustar00rootroot00000000000000shallow_clone: true platform: - x86 - x64 configuration: - Debug - Release image: - Visual Studio 2015 - Visual Studio 2017 - Visual Studio 2019 environment: NINJA_TAG: v1.8.2 NINJA_SHA512: 9B9CE248240665FCD6404B989F3B3C27ED9682838225E6DC9B67B551774F251E4FF8A207504F941E7C811E7A8BE1945E7BCB94472A335EF15E23A0200A32E6D5 NINJA_PATH: C:\Tools\ninja\ninja-%NINJA_TAG% VCVAR2015: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat' VCVAR2017: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat' VCVAR2019: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat' matrix: - GSL_CXX_STANDARD: 14 USE_TOOLSET: MSVC USE_GENERATOR: MSBuild - GSL_CXX_STANDARD: 17 USE_TOOLSET: MSVC USE_GENERATOR: MSBuild - GSL_CXX_STANDARD: 14 USE_TOOLSET: LLVM USE_GENERATOR: Ninja - GSL_CXX_STANDARD: 17 USE_TOOLSET: LLVM USE_GENERATOR: Ninja matrix: exclude: - image: Visual Studio 2015 GSL_CXX_STANDARD: 17 - image: Visual Studio 2015 USE_TOOLSET: LLVM USE_GENERATOR: MSBuild cache: - C:\cmake-3.14.4-win32-x86 - C:\Tools\ninja install: - ps: | if (![IO.File]::Exists("$env:NINJA_PATH\ninja.exe")) { Start-FileDownload ` "https://github.com/ninja-build/ninja/releases/download/$env:NINJA_TAG/ninja-win.zip" $hash = (Get-FileHash ninja-win.zip -Algorithm SHA512).Hash if ($env:NINJA_SHA512 -eq $hash) { 7z e -y -bso0 ninja-win.zip -o"$env:NINJA_PATH" } else { Write-Warning "Ninja download hash changed!"; Write-Output "$hash" } } if ([IO.File]::Exists("$env:NINJA_PATH\ninja.exe")) { $env:PATH = "$env:NINJA_PATH;$env:PATH" } else { Write-Warning "Failed to find ninja.exe in expected location." } if ($env:USE_TOOLSET -ne "LLVM") { if (![IO.File]::Exists("C:\cmake-3.14.0-win32-x86\bin\cmake.exe")) { Start-FileDownload 'https://cmake.org/files/v3.14/cmake-3.14.4-win32-x86.zip' 7z x -y -bso0 cmake-3.14.4-win32-x86.zip -oC:\ } $env:PATH="C:\cmake-3.14.4-win32-x86\bin;$env:PATH" } before_build: - ps: | if ("$env:USE_GENERATOR" -eq "Ninja") { $GeneratorFlags = '-k 10' $Architecture = $env:PLATFORM if ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2015") { $env:VCVARSALL = "`"$env:VCVAR2015`" $Architecture" } elseif ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2017") { $env:VCVARSALL = "`"$env:VCVAR2017`" $Architecture" } else { $env:VCVARSALL = "`"$env:VCVAR2019`" $Architecture" } $env:CMakeGenFlags = "-G Ninja -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD" } else { $GeneratorFlags = '/m /v:minimal' if ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2015") { $Generator = 'Visual Studio 14 2015' } elseif ("$env:APPVEYOR_BUILD_WORKER_IMAGE" -eq "Visual Studio 2017") { $Generator = 'Visual Studio 15 2017' } else { $Generator = 'Visual Studio 16 2019' } if ("$env:PLATFORM" -eq "x86") { $Architecture = "Win32" } else { $Architecture = "x64" } if ("$env:USE_TOOLSET" -eq "LLVM") { $env:CMakeGenFlags = "-G `"$Generator`" -A $Architecture -T llvm -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD" } else { $env:CMakeGenFlags = "-G `"$Generator`" -A $Architecture -DGSL_CXX_STANDARD=$env:GSL_CXX_STANDARD" } } if ("$env:USE_TOOLSET" -eq "LLVM") { $env:CC = "clang-cl" $env:CXX = "clang-cl" if ("$env:PLATFORM" -eq "x86") { $env:CFLAGS = "-m32"; $env:CXXFLAGS = "-m32"; } else { $env:CFLAGS = "-m64"; $env:CXXFLAGS = "-m64"; } } $env:CMakeBuildFlags = "--config $env:CONFIGURATION -- $GeneratorFlags" - mkdir build - cd build - if %USE_GENERATOR%==Ninja (call %VCVARSALL%) - echo %CMakeGenFlags% - cmake .. %CMakeGenFlags% build_script: - echo %CMakeBuildFlags% - cmake --build . %CMakeBuildFlags% test_script: - ctest -j2 deploy: off GSL-2.1.0/include/000077500000000000000000000000001356460337500135765ustar00rootroot00000000000000GSL-2.1.0/include/gsl/000077500000000000000000000000001356460337500143635ustar00rootroot00000000000000GSL-2.1.0/include/gsl/gsl000066400000000000000000000023311356460337500150720ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_GSL_H #define GSL_GSL_H #include // copy #include // Ensures/Expects #include // byte #include // finally()/narrow()/narrow_cast()... #include // multi_span, strided_span... #include // owner, not_null #include // span #include // zstring, string_span, zstring_builder... #endif // GSL_GSL_H GSL-2.1.0/include/gsl/gsl_algorithm000066400000000000000000000044121356460337500171420ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_ALGORITHM_H #define GSL_ALGORITHM_H #include // for Expects #include // for dynamic_extent, span #include // for copy_n #include // for ptrdiff_t #include // for is_assignable #ifdef _MSC_VER #pragma warning(push) // turn off some warnings that are noisy about our Expects statements #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4996) // unsafe use of std::copy_n #endif // _MSC_VER namespace gsl { // Note: this will generate faster code than std::copy using span iterator in older msvc+stl // not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915) template void copy(span src, span dest) { static_assert(std::is_assignable::value, "Elements of source span can not be assigned to elements of destination span"); static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent || (SrcExtent <= DestExtent), "Source range is longer than target range"); Expects(dest.size() >= src.size()); GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute std::copy_n(src.data(), src.size(), dest.data()); } } // namespace gsl #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER #endif // GSL_ALGORITHM_H GSL-2.1.0/include/gsl/gsl_assert000066400000000000000000000123361356460337500164610ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_CONTRACTS_H #define GSL_CONTRACTS_H #include #include // for logic_error // // make suppress attributes parse for some compilers // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) #define GSL_SUPPRESS(x) [[gsl::suppress("x")]] #else #if defined(_MSC_VER) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) #endif // _MSC_VER #endif // __clang__ // // Temporary until MSVC STL supports no-exceptions mode. // Currently terminate is a no-op in this mode, so we add termination behavior back // #if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #include #define RANGE_CHECKS_FAILURE 0 #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winvalid-noreturn" #endif #endif // // There are three configuration options for this GSL implementation's behavior // when pre/post conditions on the GSL types are violated: // // 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default) // 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown // 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens // #if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) || defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) || \ defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)) #define GSL_TERMINATE_ON_CONTRACT_VIOLATION #endif #define GSL_STRINGIFY_DETAIL(x) #x #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) #if defined(__clang__) || defined(__GNUC__) #define GSL_LIKELY(x) __builtin_expect(!!(x), 1) #define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define GSL_LIKELY(x) (!!(x)) #define GSL_UNLIKELY(x) (!!(x)) #endif // // GSL_ASSUME(cond) // // Tell the optimizer that the predicate cond must hold. It is unspecified // whether or not cond is actually evaluated. // #ifdef _MSC_VER #define GSL_ASSUME(cond) __assume(cond) #elif defined(__GNUC__) #define GSL_ASSUME(cond) ((cond) ? static_cast(0) : __builtin_unreachable()) #else #define GSL_ASSUME(cond) static_cast((cond) ? 0 : 0) #endif // // GSL.assert: assertions // namespace gsl { struct fail_fast : public std::logic_error { explicit fail_fast(char const* const message) : std::logic_error(message) {} }; namespace details { #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) typedef void (__cdecl *terminate_handler)(); GSL_SUPPRESS(f.6) // NO-FORMAT: attribute [[noreturn]] inline void __cdecl default_terminate_handler() { __fastfail(RANGE_CHECKS_FAILURE); } inline gsl::details::terminate_handler& get_terminate_handler() noexcept { static terminate_handler handler = &default_terminate_handler; return handler; } #endif [[noreturn]] inline void terminate() noexcept { #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) (*gsl::details::get_terminate_handler())(); #else std::terminate(); #endif } #if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) template [[noreturn]] void throw_exception(Exception&&) noexcept { gsl::details::terminate(); } #else template [[noreturn]] void throw_exception(Exception&& exception) { throw std::forward(exception); } #endif // GSL_TERMINATE_ON_CONTRACT_VIOLATION } // namespace details } // namespace gsl #if defined(GSL_THROW_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) \ (GSL_LIKELY(cond) ? static_cast(0) \ : gsl::details::throw_exception(gsl::fail_fast( \ "GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__)))) #elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) \ (GSL_LIKELY(cond) ? static_cast(0) : gsl::details::terminate()) #elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond) #endif // GSL_THROW_ON_CONTRACT_VIOLATION #define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond) #define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond) #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__) #pragma clang diagnostic pop #endif #endif // GSL_CONTRACTS_H GSL-2.1.0/include/gsl/gsl_byte000066400000000000000000000147251356460337500161270ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_BYTE_H #define GSL_BYTE_H // // make suppress attributes work for some compilers // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) #define GSL_SUPPRESS(x) [[gsl::suppress("x")]] #else #if defined(_MSC_VER) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) #endif // _MSC_VER #endif // __clang__ #include // VS2017 15.8 added support for the __cpp_lib_byte definition // To do: drop _HAS_STD_BYTE when support for pre 15.8 expires #ifdef _MSC_VER #pragma warning(push) // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. #pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates does not always work #ifndef GSL_USE_STD_BYTE // this tests if we are under MSVC and the standard lib has std::byte and it is enabled #if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603) #define GSL_USE_STD_BYTE 1 #else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603) #define GSL_USE_STD_BYTE 0 #endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603) #endif // GSL_USE_STD_BYTE #else // _MSC_VER #ifndef GSL_USE_STD_BYTE #include /* __cpp_lib_byte */ // this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte // also check if libc++ version is sufficient (> 5.0) or libstc++ actually contains std::byte #if defined(__cplusplus) && (__cplusplus >= 201703L) && \ (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \ defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #define GSL_USE_STD_BYTE 1 #else // defined(__cplusplus) && (__cplusplus >= 201703L) && // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #define GSL_USE_STD_BYTE 0 #endif //defined(__cplusplus) && (__cplusplus >= 201703L) && // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #endif // GSL_USE_STD_BYTE #endif // _MSC_VER // Use __may_alias__ attribute on gcc and clang #if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5) #define byte_may_alias __attribute__((__may_alias__)) #else // defined __clang__ || defined __GNUC__ #define byte_may_alias #endif // defined __clang__ || defined __GNUC__ namespace gsl { #if GSL_USE_STD_BYTE using std::byte; using std::to_integer; #else // GSL_USE_STD_BYTE // This is a simple definition for now that allows // use of byte within span<> to be standards-compliant enum class byte_may_alias byte : unsigned char { }; template ::value>> constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept { return b = byte(static_cast(b) << shift); } template ::value>> constexpr byte operator<<(byte b, IntegerType shift) noexcept { return byte(static_cast(b) << shift); } template ::value>> constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept { return b = byte(static_cast(b) >> shift); } template ::value>> constexpr byte operator>>(byte b, IntegerType shift) noexcept { return byte(static_cast(b) >> shift); } constexpr byte& operator|=(byte& l, byte r) noexcept { return l = byte(static_cast(l) | static_cast(r)); } constexpr byte operator|(byte l, byte r) noexcept { return byte(static_cast(l) | static_cast(r)); } constexpr byte& operator&=(byte& l, byte r) noexcept { return l = byte(static_cast(l) & static_cast(r)); } constexpr byte operator&(byte l, byte r) noexcept { return byte(static_cast(l) & static_cast(r)); } constexpr byte& operator^=(byte& l, byte r) noexcept { return l = byte(static_cast(l) ^ static_cast(r)); } constexpr byte operator^(byte l, byte r) noexcept { return byte(static_cast(l) ^ static_cast(r)); } constexpr byte operator~(byte b) noexcept { return byte(~static_cast(b)); } template ::value>> constexpr IntegerType to_integer(byte b) noexcept { return static_cast(b); } #endif // GSL_USE_STD_BYTE template constexpr byte to_byte_impl(T t) noexcept { static_assert( E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. " "If you are calling to_byte with an integer contant use: gsl::to_byte() version."); return static_cast(t); } template <> // NOTE: need suppression since c++14 does not allow "return {t}" // GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work constexpr byte to_byte_impl(unsigned char t) noexcept { return byte(t); } template constexpr byte to_byte(T t) noexcept { return to_byte_impl::value, T>(t); } template constexpr byte to_byte() noexcept { static_assert(I >= 0 && I <= 255, "gsl::byte only has 8 bits of storage, values must be in range 0-255"); return static_cast(I); } } // namespace gsl #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER #endif // GSL_BYTE_H GSL-2.1.0/include/gsl/gsl_util000066400000000000000000000115251356460337500161340ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_UTIL_H #define GSL_UTIL_H #include // for Expects #include #include // for ptrdiff_t, size_t #include // for exception #include // for initializer_list #include // for is_signed, integral_constant #include // for exchange, forward #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ #endif // _MSC_VER < 1910 #endif // _MSC_VER #if (defined(_MSC_VER) && _MSC_VER < 1910) || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ < 6) #define GSL_CONSTEXPR_NARROW 0 #else #define GSL_CONSTEXPR_NARROW 1 #endif namespace gsl { // // GSL.util: utilities // // index type for all container indexes/subscripts/sizes using index = std::ptrdiff_t; // final_action allows you to ensure something gets run at the end of a scope template class final_action { public: explicit final_action(F f) noexcept : f_(std::move(f)) {} final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) {} final_action(const final_action&) = delete; final_action& operator=(const final_action&) = delete; final_action& operator=(final_action&&) = delete; GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws ~final_action() noexcept { if (invoke_) f_(); } private: F f_; bool invoke_{true}; }; // finally() - convenience function to generate a final_action template final_action finally(const F& f) noexcept { return final_action(f); } template final_action finally(F&& f) noexcept { return final_action(std::forward(f)); } // narrow_cast(): a searchable way to do narrowing casts of values template GSL_SUPPRESS(type.1) // NO-FORMAT: attribute constexpr T narrow_cast(U&& u) noexcept { return static_cast(std::forward(u)); } struct narrowing_error : public std::exception { }; namespace details { template struct is_same_signedness : public std::integral_constant::value == std::is_signed::value> { }; } // namespace details // narrow() : a checked version of narrow_cast() that throws if the cast changed the value template GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) #if GSL_CONSTEXPR_NARROW constexpr #endif T narrow(U u) noexcept(false) { T t = narrow_cast(u); if (static_cast(t) != u) gsl::details::throw_exception(narrowing_error()); if (!details::is_same_signedness::value && ((t < T{}) != (u < U{}))) gsl::details::throw_exception(narrowing_error()); return t; } // // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector // template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr T& at(T (&arr)[N], const index i) { Expects(i >= 0 && i < narrow_cast(N)); return arr[narrow_cast(i)]; } template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { Expects(i >= 0 && i < narrow_cast(cont.size())); using size_type = decltype(cont.size()); return cont[narrow_cast(i)]; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr T at(const std::initializer_list cont, const index i) { Expects(i >= 0 && i < narrow_cast(cont.size())); return *(cont.begin() + i); } } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER < 1910 #undef constexpr #pragma pop_macro("constexpr") #endif // _MSC_VER < 1910 #pragma warning(pop) #endif // _MSC_VER #endif // GSL_UTIL_H GSL-2.1.0/include/gsl/multi_span000066400000000000000000002477341356460337500165020ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_MULTI_SPAN_H #define GSL_MULTI_SPAN_H #include // for Expects #include // for byte #include // for narrow_cast #include // for transform, lexicographical_compare #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for PTRDIFF_MAX #include // for divides, multiplies, minus, negate, plus #include // for initializer_list #include // for iterator, random_access_iterator_tag #include // for numeric_limits #include #include #include #include // for basic_string #include // for enable_if_t, remove_cv_t, is_same, is_co... #include #if defined(_MSC_VER) && !defined(__clang__) // turn off some warnings that are noisy about our Expects statements #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4702) // unreachable code // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor #pragma warning(disable : 26473) // in some instantiations we cast to the same type #pragma warning(disable : 26490) // TODO: bug in parser - attributes and templates #pragma warning(disable : 26465) // TODO: bug - suppression does not work on template functions #pragma warning(disable : 4996) // use of function or classes marked [[deprecated]] #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ #endif // _MSC_VER < 1910 #endif // _MSC_VER #if __clang__ || __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) // While there is a conversion from signed to unsigned, it happens at // compiletime, so the compiler wouldn't have to warn indiscriminently, but // could check if the source value actually doesn't fit into the target type // and only warn in those cases. #if defined(__GNUC__) && __GNUC__ > 6 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #endif namespace gsl { /* ** begin definitions of index and bounds */ namespace details { template struct [[deprecated]] SizeTypeTraits { static const SizeType max_value = std::numeric_limits::max(); }; template class [[deprecated]] are_integral : public std::integral_constant { }; template class [[deprecated]] are_integral : public std::integral_constant::value && are_integral::value> { }; } // namespace details template class [[deprecated]] multi_span_index final { static_assert(Rank > 0, "Rank must be greater than 0!"); template friend class multi_span_index; public: static const std::size_t rank = Rank; using value_type = std::ptrdiff_t; using size_type = value_type; using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; constexpr multi_span_index() noexcept {} constexpr multi_span_index(const value_type(&values)[Rank]) noexcept { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::copy(values, values + Rank, elems); } template ::value>> constexpr multi_span_index(Ts... ds) noexcept : elems{narrow_cast(ds)...} {} constexpr multi_span_index(const multi_span_index& other) noexcept = default; constexpr multi_span_index& operator=(const multi_span_index& rhs) noexcept = default; // Preconditions: component_idx < rank GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr reference operator[](std::size_t component_idx) { Expects(component_idx < Rank); // Component index must be less than rank return elems[component_idx]; } // Preconditions: component_idx < rank GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr const_reference operator[](std::size_t component_idx) const { Expects(component_idx < Rank); // Component index must be less than rank return elems[component_idx]; } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute constexpr bool operator==(const multi_span_index& rhs) const { return std::equal(elems, elems + rank, rhs.elems); } constexpr bool operator!=(const multi_span_index& rhs) const { return !(*this == rhs); } constexpr multi_span_index operator+() const noexcept { return *this; } constexpr multi_span_index operator-() const { multi_span_index ret = *this; std::transform(ret, ret + rank, ret, std::negate{}); return ret; } constexpr multi_span_index operator+(const multi_span_index& rhs) const { multi_span_index ret = *this; ret += rhs; return ret; } constexpr multi_span_index operator-(const multi_span_index& rhs) const { multi_span_index ret = *this; ret -= rhs; return ret; } constexpr multi_span_index& operator+=(const multi_span_index& rhs) { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); return *this; } constexpr multi_span_index& operator-=(const multi_span_index& rhs) { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); return *this; } constexpr multi_span_index operator*(value_type v) const { multi_span_index ret = *this; ret *= v; return ret; } constexpr multi_span_index operator/(value_type v) const { multi_span_index ret = *this; ret /= v; return ret; } friend constexpr multi_span_index operator*(value_type v, const multi_span_index& rhs) { return rhs * v; } constexpr multi_span_index& operator*=(value_type v) { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); return *this; } constexpr multi_span_index& operator/=(value_type v) { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); return *this; } private: value_type elems[Rank] = {}; }; #if !defined(_MSC_VER) || _MSC_VER >= 1910 struct [[deprecated]] static_bounds_dynamic_range_t { template ::value>> constexpr operator T() const noexcept { return narrow_cast(-1); } }; constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept { return true; } constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept { return false; } template ::value>> constexpr bool operator==(static_bounds_dynamic_range_t, T other) noexcept { return narrow_cast(-1) == other; } template ::value>> constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept { return right == left; } template ::value>> constexpr bool operator!=(static_bounds_dynamic_range_t, T other) noexcept { return narrow_cast(-1) != other; } template ::value>> constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept { return right != left; } constexpr static_bounds_dynamic_range_t dynamic_range{}; #else const std::ptrdiff_t dynamic_range = -1; #endif struct [[deprecated]] generalized_mapping_tag { }; struct[[deprecated]] contiguous_mapping_tag : generalized_mapping_tag{}; namespace details { template struct [[deprecated]] LessThan { static const bool value = Left < Right; }; template struct [[deprecated]] BoundsRanges { using size_type = std::ptrdiff_t; static const size_type Depth = 0; static const size_type DynamicNum = 0; static const size_type CurrentRange = 1; static const size_type TotalSize = 1; // TODO : following signature is for work around VS bug template constexpr BoundsRanges(const OtherRange&, bool /* firstLevel */) {} constexpr BoundsRanges(const std::ptrdiff_t* const) {} constexpr BoundsRanges() noexcept = default; template constexpr void serialize(T&) const {} template constexpr size_type linearize(const T&) const { return 0; } template constexpr size_type contains(const T&) const { return -1; } constexpr size_type elementNum(std::size_t) const noexcept { return 0; } constexpr size_type totalSize() const noexcept { return TotalSize; } constexpr bool operator==(const BoundsRanges&) const noexcept { return true; } }; template struct[[deprecated]] BoundsRanges : BoundsRanges { using Base = BoundsRanges; using size_type = std::ptrdiff_t; static const std::size_t Depth = Base::Depth + 1; static const std::size_t DynamicNum = Base::DynamicNum + 1; static const size_type CurrentRange = dynamic_range; static const size_type TotalSize = dynamic_range; private: size_type m_bound; public: GSL_SUPPRESS( f.23) // NO-FORMAT: attribute // this pointer type is cannot be assigned nullptr - issue in not_null GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize()) { Expects(0 <= *arr); } constexpr BoundsRanges() noexcept : m_bound(0) {} template constexpr BoundsRanges(const BoundsRanges& other, bool /* firstLevel */ = true) : Base(static_cast&>(other), false) , m_bound(other.totalSize()) {} template constexpr void serialize(T & arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); } template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type linearize(const T& arr) const { const size_type index = this->Base::totalSize() * arr[Dim]; Expects(index < m_bound); return index + this->Base::template linearize(arr); } template constexpr size_type contains(const T& arr) const { const ptrdiff_t last = this->Base::template contains(arr); if (last == -1) return -1; const ptrdiff_t cur = this->Base::totalSize() * arr[Dim]; return cur < m_bound ? cur + last : -1; } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type totalSize() const noexcept { return m_bound; } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); else return elementNum(); } constexpr bool operator==(const BoundsRanges& rhs) const noexcept { return m_bound == rhs.m_bound && static_cast(*this) == static_cast(rhs); } }; template struct[[deprecated]] BoundsRanges : BoundsRanges { using Base = BoundsRanges; using size_type = std::ptrdiff_t; static const std::size_t Depth = Base::Depth + 1; static const std::size_t DynamicNum = Base::DynamicNum; static const size_type CurrentRange = CurRange; static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize; constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {} constexpr BoundsRanges() = default; template constexpr BoundsRanges(const BoundsRanges& other, bool firstLevel = true) : Base(static_cast&>(other), false) { GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) firstLevel; } template constexpr void serialize(T & arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); } template constexpr size_type linearize(const T& arr) const { GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute const ptrdiff_t d = arr[Dim]; return this->Base::totalSize() * d + this->Base::template linearize(arr); } template constexpr size_type contains(const T& arr) const { if (arr[Dim] >= CurrentRange) return -1; const size_type last = this->Base::template contains(arr); if (last == -1) return -1; return this->Base::totalSize() * arr[Dim] + last; } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type elementNum() const noexcept { return CurrentRange; } GSL_SUPPRESS( c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used constexpr size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); else return elementNum(); } constexpr bool operator==(const BoundsRanges& rhs) const noexcept { return static_cast(*this) == static_cast(rhs); } }; template struct[[deprecated]] BoundsRangeConvertible : public std::integral_constant= TargetType::TotalSize || TargetType::TotalSize == dynamic_range || SourceType::TotalSize == dynamic_range || TargetType::TotalSize == 0)>{}; template struct [[deprecated]] TypeListIndexer { const TypeChain& obj_; constexpr TypeListIndexer(const TypeChain& obj) : obj_(obj) {} template constexpr const TypeChain& getObj(std::true_type) { return obj_; } template constexpr auto getObj(std::false_type) ->decltype(TypeListIndexer(static_cast(obj_)).template get()) { return TypeListIndexer(static_cast(obj_)).template get(); } template constexpr auto get()->decltype(getObj(std::integral_constant())) { return getObj(std::integral_constant()); } }; template constexpr TypeListIndexer createTypeListIndexer(const TypeChain& obj) { return TypeListIndexer(obj); } template 1), typename Ret = std::enable_if_t>> constexpr Ret shift_left(const multi_span_index& other) noexcept { Ret ret{}; for (std::size_t i = 0; i < Rank - 1; ++i) { GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute ret[i] = other[i + 1]; } return ret; } } // namespace details template class [[deprecated]] bounds_iterator; template class [[deprecated]] static_bounds { public: static_bounds(const details::BoundsRanges&) {} }; template class[[deprecated]] static_bounds { using MyRanges = details::BoundsRanges; MyRanges m_ranges; constexpr static_bounds(const MyRanges& range) noexcept : m_ranges(range) {} template friend class static_bounds; public: static const std::size_t rank = MyRanges::Depth; static const std::size_t dynamic_rank = MyRanges::DynamicNum; static const std::ptrdiff_t static_size = MyRanges::TotalSize; using size_type = std::ptrdiff_t; using index_type = multi_span_index; using const_index_type = std::add_const_t; using iterator = bounds_iterator; using const_iterator = bounds_iterator; using difference_type = std::ptrdiff_t; using sliced_type = static_bounds; using mapping_type = contiguous_mapping_tag; constexpr static_bounds() /*noexcept*/ = default; template struct BoundsRangeConvertible2; template > static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type)->Ret; template static auto helpBoundsRangeConvertible(SourceType, TargetType, ...)->std::false_type; template struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible( SourceType(), TargetType(), std::integral_constant())) { }; template struct BoundsRangeConvertible2 : std::true_type { }; template struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible( SourceType(), TargetType(), std::integral_constant::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>())) { }; template struct BoundsRangeConvertible : std::true_type { }; template , details::BoundsRanges>::value>> constexpr static_bounds(const static_bounds& other) : m_ranges(other.m_ranges) { Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges::DynamicNum == 0) || MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize()); } constexpr static_bounds(std::initializer_list il) : m_ranges(il.begin()) { // Size of the initializer list must match the rank of the array Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size()); // Size of the range must be less than the max element of the size type Expects(m_ranges.totalSize() <= PTRDIFF_MAX); } constexpr sliced_type slice() const noexcept { return sliced_type{static_cast&>(m_ranges)}; } constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; } constexpr size_type size() const noexcept { return m_ranges.totalSize(); } constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); } constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); } constexpr bool contains(const index_type& idx) const noexcept { return m_ranges.contains(idx) != -1; } constexpr size_type operator[](std::size_t idx) const noexcept { return m_ranges.elementNum(idx); } template constexpr size_type extent() const noexcept { static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)"); return details::createTypeListIndexer(m_ranges).template get().elementNum(); } template constexpr size_type extent(IntType dim) const { static_assert(std::is_integral::value, "Dimension parameter must be supplied as an integral type."); auto real_dim = narrow_cast(dim); Expects(real_dim < rank); return m_ranges.elementNum(real_dim); } constexpr index_type index_bounds() const noexcept { size_type extents[rank] = {}; m_ranges.serialize(extents); return {extents}; } template constexpr bool operator==(const static_bounds& rhs) const noexcept { return this->size() == rhs.size(); } template constexpr bool operator!=(const static_bounds& rhs) const noexcept { return !(*this == rhs); } constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); } constexpr const_iterator end() const noexcept { return const_iterator(*this, this->index_bounds()); } }; template class [[deprecated]] strided_bounds { template friend class strided_bounds; public: static const std::size_t rank = Rank; using value_type = std::ptrdiff_t; using reference = std::add_lvalue_reference_t; using const_reference = std::add_const_t; using size_type = value_type; using difference_type = value_type; using index_type = multi_span_index; using const_index_type = std::add_const_t; using iterator = bounds_iterator; using const_iterator = bounds_iterator; static const value_type dynamic_rank = rank; static const value_type static_size = dynamic_range; using sliced_type = std::conditional_t, void>; using mapping_type = generalized_mapping_tag; constexpr strided_bounds(const strided_bounds&) noexcept = default; constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default; constexpr strided_bounds(const value_type(&values)[rank], index_type strides) : m_extents(values), m_strides(std::move(strides)) {} constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept : m_extents(extents), m_strides(strides) {} constexpr index_type strides() const noexcept { return m_strides; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type total_size() const noexcept { size_type ret = 0; for (std::size_t i = 0; i < rank; ++i) { ret += (m_extents[i] - 1) * m_strides[i]; } return ret + 1; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type size() const noexcept { size_type ret = 1; for (std::size_t i = 0; i < rank; ++i) { ret *= m_extents[i]; } return ret; } constexpr bool contains(const index_type& idx) const noexcept { for (std::size_t i = 0; i < rank; ++i) { if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; } return true; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type linearize(const index_type& idx) const { size_type ret = 0; for (std::size_t i = 0; i < rank; i++) { Expects(idx[i] < m_extents[i]); // index is out of bounds of the array ret += idx[i] * m_strides[i]; } return ret; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type stride() const noexcept { return m_strides[0]; } template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const { return {details::shift_left(m_extents), details::shift_left(m_strides)}; } template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); return m_extents[Dim]; } constexpr index_type index_bounds() const noexcept { return m_extents; } constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; } constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; } private: index_type m_extents; index_type m_strides; }; template struct[[deprecated]] is_bounds : std::integral_constant{}; template struct[[deprecated]] is_bounds> : std::integral_constant{}; template struct[[deprecated]] is_bounds> : std::integral_constant{}; template class [[deprecated]] bounds_iterator { public: static const std::size_t rank = IndexType::rank; using iterator_category = std::random_access_iterator_tag; using value_type = IndexType; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; using index_type = value_type; using index_size_type = typename IndexType::value_type; template explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept : boundary_(bnd.index_bounds()), curr_(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } constexpr reference operator*() const noexcept { return curr_; } constexpr pointer operator->() const noexcept { return &curr_; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr bounds_iterator& operator++() noexcept { for (std::size_t i = rank; i-- > 0;) { if (curr_[i] < boundary_[i] - 1) { curr_[i]++; return *this; } curr_[i] = 0; } // If we're here we've wrapped over - set to past-the-end. curr_ = boundary_; return *this; } constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bounds_iterator& operator--() { if (!less(curr_, boundary_)) { // if at the past-the-end, set to last element for (std::size_t i = 0; i < rank; ++i) { curr_[i] = boundary_[i] - 1; } return *this; } for (std::size_t i = rank; i-- > 0;) { if (curr_[i] >= 1) { curr_[i]--; return *this; } curr_[i] = boundary_[i] - 1; } // If we're here the preconditions were violated // "pre: there exists s such that r == ++s" Expects(false); return *this; } constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{*this}; return ret += n; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bounds_iterator& operator+=(difference_type n) { auto linear_idx = linearize(curr_) + n; std::remove_const_t stride = 0; stride[rank - 1] = 1; for (std::size_t i = rank - 1; i-- > 0;) { stride[i] = stride[i + 1] * boundary_[i + 1]; } for (std::size_t i = 0; i < rank; ++i) { curr_[i] = linear_idx / stride[i]; linear_idx = linear_idx % stride[i]; } // index is out of bounds of the array Expects(!less(curr_, index_type{}) && !less(boundary_, curr_)); return *this; } constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{*this}; return ret -= n; } constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return linearize(curr_) - linearize(rhs.curr_); } constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); } constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr_ == rhs.curr_; } constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } constexpr bool operator<(const bounds_iterator& rhs) const noexcept { return less(curr_, rhs.curr_); } constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } void swap(bounds_iterator & rhs) noexcept { std::swap(boundary_, rhs.boundary_); std::swap(curr_, rhs.curr_); } private: GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bool less(index_type & one, index_type & other) const noexcept { for (std::size_t i = 0; i < rank; ++i) { if (one[i] < other[i]) return true; } return false; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end index_size_type multiplier = 1; index_size_type res = 0; if (!less(idx, boundary_)) { res = 1; for (std::size_t i = rank; i-- > 0;) { res += (idx[i] - 1) * multiplier; multiplier *= boundary_[i]; } } else { for (std::size_t i = rank; i-- > 0;) { res += idx[i] * multiplier; multiplier *= boundary_[i]; } } return res; } value_type boundary_; std::remove_const_t curr_; }; template bounds_iterator operator+(typename bounds_iterator::difference_type n, const bounds_iterator& rhs) noexcept { return rhs + n; } namespace details { template constexpr std::enable_if_t< std::is_same::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { return bnd.strides(); } // Make a stride vector from bounds, assuming contiguous memory. template constexpr std::enable_if_t< std::is_same::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); typename Bounds::size_type stride[Bounds::rank] = {}; stride[Bounds::rank - 1] = 1; for (std::size_t i = 1; i < Bounds::rank; ++i) { GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; } return {stride}; } template void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest) { static_assert(is_bounds::value && is_bounds::value, "The src type and dest type must be bounds"); static_assert(std::is_same::value, "The source type must be a contiguous bounds"); static_assert(BoundsDest::static_size == dynamic_range || BoundsSrc::static_size == dynamic_range || BoundsDest::static_size == BoundsSrc::static_size, "The source bounds must have same size as dest bounds"); Expects(src.size() == dest.size()); } } // namespace details template class [[deprecated]] contiguous_span_iterator; template class [[deprecated]] general_span_iterator; template struct [[deprecated]] dim_t { static const std::ptrdiff_t value = DimSize; }; template <> struct [[deprecated]] dim_t { static const std::ptrdiff_t value = dynamic_range; const std::ptrdiff_t dvalue; constexpr dim_t(std::ptrdiff_t size) noexcept : dvalue(size) {} }; template = 0)>> constexpr dim_t dim() noexcept { return dim_t(); } template > constexpr dim_t dim(std::ptrdiff_t n) noexcept { return dim_t<>(n); } template class [[deprecated("gsl::multi_span is deprecated because it is not in the C++ Core Guidelines")]] multi_span; template class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span; namespace details { template struct [[deprecated]] SpanTypeTraits { using value_type = T; using size_type = std::size_t; }; template struct [[deprecated]] SpanTypeTraits< Traits, typename std::is_reference::type> { using value_type = typename Traits::span_traits::value_type; using size_type = typename Traits::span_traits::size_type; }; template struct [[deprecated]] SpanArrayTraits { using type = multi_span; using value_type = T; using bounds_type = static_bounds; using pointer = T*; using reference = T&; }; template struct [[deprecated]] SpanArrayTraits : SpanArrayTraits { }; template BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size { Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX); return BoundsType{totalSize}; } template BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size { Expects(BoundsType::static_size <= totalSize); return {}; } template BoundsType newBoundsHelper(std::ptrdiff_t totalSize) { static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1"); return newBoundsHelperImpl( totalSize, std::integral_constant()); } struct [[deprecated]] Sep { }; template T static_as_multi_span_helper(Sep, Args... args) { return T{narrow_cast(args)...}; } template std::enable_if_t< !std::is_same>::value && !std::is_same::value, T> static_as_multi_span_helper(Arg, Args... args) { return static_as_multi_span_helper(args...); } template T static_as_multi_span_helper(dim_t val, Args... args) { return static_as_multi_span_helper(args..., val.dvalue); } template struct [[deprecated]] static_as_multi_span_static_bounds_helper { using type = static_bounds<(Dimensions::value)...>; }; template struct [[deprecated]] is_multi_span_oracle : std::false_type { }; template struct [[deprecated]] is_multi_span_oracle> : std::true_type { }; template struct [[deprecated]] is_multi_span_oracle> : std::true_type { }; template struct [[deprecated]] is_multi_span : is_multi_span_oracle> { }; } // namespace details template class [[deprecated("gsl::multi_span is deprecated because it is not in the C++ Core Guidelines")]] multi_span { // TODO do we still need this? template friend class multi_span; public: using bounds_type = static_bounds; static const std::size_t Rank = bounds_type::rank; using size_type = typename bounds_type::size_type; using index_type = typename bounds_type::index_type; using value_type = ValueType; using const_value_type = std::add_const_t; using pointer = std::add_pointer_t; using reference = std::add_lvalue_reference_t; using iterator = contiguous_span_iterator; using const_span = multi_span; using const_iterator = contiguous_span_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using sliced_type = std::conditional_t>; private: pointer data_; bounds_type bounds_; friend iterator; friend const_iterator; public: // default constructor - same as constructing from nullptr_t GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive constexpr multi_span() noexcept : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), "Default construction of multi_span only possible " "for dynamic or fixed, zero-length spans."); } // construct from nullptr - get an empty multi_span GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive constexpr multi_span(std::nullptr_t) noexcept : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), "nullptr_t construction of multi_span only possible " "for dynamic or fixed, zero-length spans."); } // construct from nullptr with size of 0 (helps with template function calls) template ::value>> // GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive // TODO: parser bug constexpr multi_span(std::nullptr_t, IntType size) : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), "nullptr_t construction of multi_span only possible " "for dynamic or fixed, zero-length spans."); Expects(size == 0); } // construct from a single element GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive constexpr multi_span(reference data) noexcept : multi_span(&data, bounds_type{1}) { static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 || bounds_type::static_size == 1, "Construction from a single element only possible " "for dynamic or fixed spans of length 0 or 1."); } // prevent constructing from temporaries for single-elements constexpr multi_span(value_type &&) = delete; // construct from pointer + length GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive constexpr multi_span(pointer ptr, size_type size) : multi_span(ptr, bounds_type{size}) {} // construct from pointer + length - multidimensional constexpr multi_span(pointer data, bounds_type bounds) : data_(data), bounds_(std::move(bounds)) { Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); } // construct from begin,end pointer pair template ::value && details::LessThan::value>> constexpr multi_span(pointer begin, Ptr end) : multi_span(begin, details::newBoundsHelper(static_cast(end) - begin)) { Expects(begin != nullptr && end != nullptr && begin <= static_cast(end)); } // construct from n-dimensions static array template > constexpr multi_span(T(&arr)[N]) : multi_span(reinterpret_cast(arr), bounds_type{typename Helper::bounds_type{}}) { static_assert(std::is_convertible::value, "Cannot convert from source type to target multi_span type."); static_assert(std::is_convertible::value, "Cannot construct a multi_span from an array with fewer elements."); } // construct from n-dimensions dynamic array (e.g. new int[m][4]) // (precedence will be lower than the 1-dimension pointer) template > constexpr multi_span(T* const& data, size_type size) : multi_span(reinterpret_cast(data), typename Helper::bounds_type{size}) { static_assert(std::is_convertible::value, "Cannot convert from source type to target multi_span type."); } // construct from std::array template constexpr multi_span(std::array & arr) : multi_span(arr.data(), bounds_type{static_bounds{}}) { static_assert( std::is_convertible(*)[]>::value, "Cannot convert from source type to target multi_span type."); static_assert(std::is_convertible, bounds_type>::value, "You cannot construct a multi_span from a std::array of smaller size."); } // construct from const std::array template constexpr multi_span(const std::array& arr) : multi_span(arr.data(), bounds_type{static_bounds{}}) { static_assert( std::is_convertible(*)[]>::value, "Cannot convert from source type to target multi_span type."); static_assert(std::is_convertible, bounds_type>::value, "You cannot construct a multi_span from a std::array of smaller size."); } // prevent constructing from temporary std::array template constexpr multi_span(std::array && arr) = delete; // construct from containers // future: could use contiguous_iterator_traits to identify only contiguous containers // type-requirements: container must have .size(), operator[] which are value_type compatible template ::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> constexpr multi_span(Cont & cont) : multi_span(static_cast(cont.data()), details::newBoundsHelper(narrow_cast(cont.size()))) {} // prevent constructing from temporary containers template ::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> explicit constexpr multi_span(Cont && cont) = delete; // construct from a convertible multi_span template , typename = std::enable_if_t::value && std::is_convertible::value>> constexpr multi_span(multi_span other) : data_(other.data_), bounds_(other.bounds_) {} // trivial copy and move constexpr multi_span(const multi_span&) = default; constexpr multi_span(multi_span &&) = default; // trivial assignment constexpr multi_span& operator=(const multi_span&) = default; constexpr multi_span& operator=(multi_span&&) = default; // first() - extract the first Count elements into a new multi_span template constexpr multi_span first() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Count is out of bounds."); Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); return {this->data(), Count}; } // first() - extract the first count elements into a new multi_span constexpr multi_span first(size_type count) const { Expects(count >= 0 && count <= this->size()); return {this->data(), count}; } // last() - extract the last Count elements into a new multi_span template constexpr multi_span last() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Count is out of bounds."); Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); return {this->data() + this->size() - Count, Count}; } // last() - extract the last count elements into a new multi_span constexpr multi_span last(size_type count) const { Expects(count >= 0 && count <= this->size()); return {this->data() + this->size() - count, count}; } // subspan() - create a subview of Count elements starting at Offset template constexpr multi_span subspan() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(Offset >= 0, "Offset must be >= 0."); static_assert(bounds_type::static_size == dynamic_range || ((Offset <= bounds_type::static_size) && Count <= bounds_type::static_size - Offset), "You must describe a sub-range within bounds of the multi_span."); Expects(bounds_type::static_size != dynamic_range || (Offset <= this->size() && Count <= this->size() - Offset)); return {this->data() + Offset, Count}; } // subspan() - create a subview of count elements starting at offset // supplying dynamic_range for count will consume all available elements from offset constexpr multi_span subspan(size_type offset, size_type count = dynamic_range) const { Expects((offset >= 0 && offset <= this->size()) && (count == dynamic_range || (count <= this->size() - offset))); return {this->data() + offset, count == dynamic_range ? this->length() - offset : count}; } // section - creates a non-contiguous, strided multi_span from a contiguous one constexpr strided_span section(index_type origin, index_type extents) const { const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return {&this->operator[](origin), size, strided_bounds{extents, details::make_stride(bounds())}}; } // length of the multi_span in elements constexpr size_type size() const noexcept { return bounds_.size(); } // length of the multi_span in elements constexpr size_type length() const noexcept { return this->size(); } // length of the multi_span in bytes constexpr size_type size_bytes() const noexcept { return narrow_cast(sizeof(value_type)) * this->size(); } // length of the multi_span in bytes constexpr size_type length_bytes() const noexcept { return this->size_bytes(); } constexpr bool empty() const noexcept { return this->size() == 0; } static constexpr std::size_t rank() { return Rank; } template constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "Dimension should be less than rank (dimension count starts from 0)."); return bounds_.template extent(); } template constexpr size_type extent(IntType dim) const { return bounds_.extent(dim); } constexpr bounds_type bounds() const noexcept { return bounds_; } constexpr pointer data() const noexcept { return data_; } template constexpr reference operator()(FirstIndex idx) { return this->operator[](narrow_cast(idx)); } template constexpr reference operator()(FirstIndex firstIndex, OtherIndices... indices) { const index_type idx = {narrow_cast(firstIndex), narrow_cast(indices)...}; return this->operator[](idx); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](const index_type& idx) const { return data_[bounds_.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr Ret operator[](size_type idx) const { Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array const size_type ridx = idx * bounds_.stride(); // index is out of bounds of the underlying data Expects(ridx < bounds_.total_size()); return Ret{data_ + ridx, bounds_.slice()}; } constexpr iterator begin() const noexcept { return iterator{this, true}; } constexpr iterator end() const noexcept { return iterator{this, false}; } GSL_SUPPRESS(type.1) // NO-FORMAT: attribute constexpr const_iterator cbegin() const noexcept { return const_iterator{reinterpret_cast(this), true}; } constexpr const_iterator cend() const noexcept { return const_iterator{reinterpret_cast(this), false}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } template , std::remove_cv_t>::value>> constexpr bool operator==(const multi_span& other) const { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); } template , std::remove_cv_t>::value>> constexpr bool operator!=(const multi_span& other) const { return !(*this == other); } template , std::remove_cv_t>::value>> constexpr bool operator<(const multi_span& other) const { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } template , std::remove_cv_t>::value>> constexpr bool operator<=(const multi_span& other) const { return !(other < *this); } template , std::remove_cv_t>::value>> constexpr bool operator>(const multi_span& other) const noexcept { return (other < *this); } template , std::remove_cv_t>::value>> constexpr bool operator>=(const multi_span& other) const { return !(*this < other); } }; // // Free functions for manipulating spans // // reshape a multi_span into a different dimensionality // DimCount and Enabled here are workarounds for a bug in MSVC 2015 template 0), typename = std::enable_if_t> constexpr auto as_multi_span(SpanType s, Dimensions2... dims) -> multi_span { static_assert(details::is_multi_span::value, "Variadic as_multi_span() is for reshaping existing spans."); using BoundsType = typename multi_span::bounds_type; const auto tobounds = details::static_as_multi_span_helper(dims..., details::Sep{}); details::verifyBoundsReshape(s.bounds(), tobounds); return {s.data(), tobounds}; } // convert a multi_span to a multi_span template multi_span as_bytes(multi_span s) noexcept { static_assert(std::is_trivial>::value, "The value_type of multi_span must be a trivial type."); return {reinterpret_cast(s.data()), s.size_bytes()}; } // convert a multi_span to a multi_span (a writeable byte multi_span) // this is not currently a portable function that can be relied upon to work // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template multi_span as_writeable_bytes(multi_span s) noexcept { static_assert(std::is_trivial>::value, "The value_type of multi_span must be a trivial type."); return {reinterpret_cast(s.data()), s.size_bytes()}; } // convert a multi_span to a multi_span // this is not currently a portable function that can be relied upon to work // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template constexpr auto as_multi_span(multi_span s) -> multi_span< const U, static_cast( multi_span::bounds_type::static_size != dynamic_range ? (static_cast( multi_span::bounds_type::static_size) / sizeof(U)) : dynamic_range)> { using ConstByteSpan = multi_span; static_assert( std::is_trivial>::value && (ConstByteSpan::bounds_type::static_size == dynamic_range || ConstByteSpan::bounds_type::static_size % narrow_cast(sizeof(U)) == 0), "Target type must be a trivial type and its size must match the byte array size"); Expects((s.size_bytes() % narrow_cast(sizeof(U))) == 0 && (s.size_bytes() / narrow_cast(sizeof(U))) < PTRDIFF_MAX); return {reinterpret_cast(s.data()), s.size_bytes() / narrow_cast(sizeof(U))}; } // convert a multi_span to a multi_span // this is not currently a portable function that can be relied upon to work // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template constexpr auto as_multi_span(multi_span s) -> multi_span( multi_span::bounds_type::static_size != dynamic_range ? static_cast( multi_span::bounds_type::static_size) / sizeof(U) : dynamic_range)> { using ByteSpan = multi_span; static_assert(std::is_trivial>::value && (ByteSpan::bounds_type::static_size == dynamic_range || ByteSpan::bounds_type::static_size % sizeof(U) == 0), "Target type must be a trivial type and its size must match the byte array size"); Expects((s.size_bytes() % sizeof(U)) == 0); return {reinterpret_cast(s.data()), s.size_bytes() / narrow_cast(sizeof(U))}; } template constexpr auto as_multi_span(T* const& ptr, dim_t... args) -> multi_span, Dimensions...> { return {reinterpret_cast*>(ptr), details::static_as_multi_span_helper>(args..., details::Sep{})}; } template constexpr auto as_multi_span(T* arr, std::ptrdiff_t len) -> typename details::SpanArrayTraits::type { return {reinterpret_cast*>(arr), len}; } template constexpr auto as_multi_span(T (&arr)[N]) -> typename details::SpanArrayTraits::type { return {arr}; } template constexpr multi_span as_multi_span(const std::array& arr) { return {arr}; } template constexpr multi_span as_multi_span(const std::array&&) = delete; template constexpr multi_span as_multi_span(std::array& arr) { return {arr}; } template constexpr multi_span as_multi_span(T* begin, T* end) { return {begin, end}; } template constexpr auto as_multi_span(Cont& arr) -> std::enable_if_t< !details::is_multi_span>::value, multi_span, dynamic_range>> { Expects(arr.size() < PTRDIFF_MAX); return {arr.data(), narrow_cast(arr.size())}; } template constexpr auto as_multi_span(Cont&& arr) -> std::enable_if_t< !details::is_multi_span>::value, multi_span, dynamic_range>> = delete; // from basic_string which doesn't have nonconst .data() member like other contiguous containers template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr auto as_multi_span(std::basic_string& str) -> multi_span { Expects(str.size() < PTRDIFF_MAX); return {&str[0], narrow_cast(str.size())}; } // strided_span is an extension that is not strictly part of the GSL at this time. // It is kept here while the multidimensional interface is still being defined. template class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span { public: using bounds_type = strided_bounds; using size_type = typename bounds_type::size_type; using index_type = typename bounds_type::index_type; using value_type = ValueType; using const_value_type = std::add_const_t; using pointer = std::add_pointer_t; using reference = std::add_lvalue_reference_t; using iterator = general_span_iterator; using const_strided_span = strided_span; using const_iterator = general_span_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using sliced_type = std::conditional_t>; private: pointer data_; bounds_type bounds_; friend iterator; friend const_iterator; template friend class strided_span; public: // from raw data constexpr strided_span(pointer ptr, size_type size, bounds_type bounds) : data_(ptr), bounds_(std::move(bounds)) { Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0); // Bounds cross data boundaries Expects(this->bounds().total_size() <= size); GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) size; } // from static array of size N template constexpr strided_span(value_type (&values)[N], bounds_type bounds) : strided_span(values, N, std::move(bounds)) {} // from array view template ::value, typename = std::enable_if_t> constexpr strided_span(multi_span av, bounds_type bounds) : strided_span(av.data(), av.bounds().total_size(), std::move(bounds)) {} // convertible template ::value>> constexpr strided_span(const strided_span& other) : data_(other.data_), bounds_(other.bounds_) {} // convert from bytes template constexpr strided_span< typename std::enable_if::value, OtherValueType>::type, Rank> as_strided_span() const { static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes"); auto d = narrow_cast(sizeof(OtherValueType) / sizeof(value_type)); const size_type size = this->bounds().total_size() / d; GSL_SUPPRESS(type.3) // NO-FORMAT: attribute return {const_cast(reinterpret_cast(this->data())), size, bounds_type{resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)}}; } constexpr strided_span section(index_type origin, index_type extents) const { const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return {&this->operator[](origin), size, bounds_type{extents, details::make_stride(bounds())}}; } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](const index_type& idx) const { return data_[bounds_.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr Ret operator[](size_type idx) const { Expects(idx < bounds_.size()); // index is out of bounds of the array const size_type ridx = idx * bounds_.stride(); // index is out of bounds of the underlying data Expects(ridx < bounds_.total_size()); return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()}; } constexpr bounds_type bounds() const noexcept { return bounds_; } template constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than Rank (dimension count starts from 0)"); return bounds_.template extent(); } constexpr size_type size() const noexcept { return bounds_.size(); } constexpr pointer data() const noexcept { return data_; } constexpr bool empty() const noexcept { return this->size() == 0; } constexpr explicit operator bool() const noexcept { return data_ != nullptr; } constexpr iterator begin() const { return iterator{this, true}; } constexpr iterator end() const { return iterator{this, false}; } constexpr const_iterator cbegin() const { return const_iterator{reinterpret_cast(this), true}; } constexpr const_iterator cend() const { return const_iterator{reinterpret_cast(this), false}; } constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; } constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; } constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; } template , std::remove_cv_t>::value>> constexpr bool operator==(const strided_span& other) const { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); } template , std::remove_cv_t>::value>> constexpr bool operator!=(const strided_span& other) const { return !(*this == other); } template , std::remove_cv_t>::value>> constexpr bool operator<(const strided_span& other) const { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } template , std::remove_cv_t>::value>> constexpr bool operator<=(const strided_span& other) const { return !(other < *this); } template , std::remove_cv_t>::value>> constexpr bool operator>(const strided_span& other) const { return (other < *this); } template , std::remove_cv_t>::value>> constexpr bool operator>=(const strided_span& other) const { return !(*this < other); } private: static index_type resize_extent(const index_type& extent, std::ptrdiff_t d) { // The last dimension of the array needs to contain a multiple of new type elements GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0)); index_type ret = extent; ret[Rank - 1] /= d; return ret; } template > static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = nullptr) { // Only strided arrays with regular strides can be resized GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(strides[Rank - 1] == 1); return strides; } template 1), typename = std::enable_if_t> GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) { // Only strided arrays with regular strides can be resized Expects(strides[Rank - 1] == 1); // The strides must have contiguous chunks of // memory that can contain a multiple of new type elements Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0)); for (std::size_t i = Rank - 1; i > 0; --i) { // Only strided arrays with regular strides can be resized Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0)); } index_type ret = strides / d; ret[Rank - 1] = 1; return ret; } }; template class [[deprecated]] contiguous_span_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = typename Span::value_type; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; private: template friend class multi_span; pointer data_; const Span* m_validator; GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute void validateThis() const { // iterator is out of range of the array Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size()); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator(const Span* container, bool isbegin) : data_(isbegin ? container->data_ : container->data_ + container->size()) , m_validator(container) {} public: reference operator*() const { validateThis(); return *data_; } pointer operator->() const { validateThis(); return data_; } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator& operator++() noexcept { ++data_; return *this; } contiguous_span_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator& operator--() noexcept { --data_; return *this; } contiguous_span_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } contiguous_span_iterator operator+(difference_type n) const noexcept { contiguous_span_iterator ret{*this}; return ret += n; } contiguous_span_iterator& operator+=(difference_type n) noexcept { data_ += n; return *this; } contiguous_span_iterator operator-(difference_type n) const noexcept { contiguous_span_iterator ret{*this}; return ret -= n; } contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; } difference_type operator-(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ - rhs.data_; } reference operator[](difference_type n) const { return *(*this + n); } bool operator==(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ == rhs.data_; } bool operator!=(const contiguous_span_iterator& rhs) const { return !(*this == rhs); } bool operator<(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ < rhs.data_; } bool operator<=(const contiguous_span_iterator& rhs) const { return !(rhs < *this); } bool operator>(const contiguous_span_iterator& rhs) const { return rhs < *this; } bool operator>=(const contiguous_span_iterator& rhs) const { return !(rhs > *this); } void swap(contiguous_span_iterator & rhs) noexcept { std::swap(data_, rhs.data_); std::swap(m_validator, rhs.m_validator); } }; template contiguous_span_iterator operator+(typename contiguous_span_iterator::difference_type n, const contiguous_span_iterator& rhs) noexcept { return rhs + n; } template class [[deprecated]] general_span_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = typename Span::value_type; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; private: template friend class strided_span; const Span* m_container; typename Span::bounds_type::iterator m_itr; general_span_iterator(const Span* container, bool isbegin) : m_container(container) , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) {} public: reference operator*() noexcept { return (*m_container)[*m_itr]; } pointer operator->() noexcept { return &(*m_container)[*m_itr]; } general_span_iterator& operator++() noexcept { ++m_itr; return *this; } general_span_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } general_span_iterator& operator--() noexcept { --m_itr; return *this; } general_span_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } general_span_iterator operator+(difference_type n) const noexcept { general_span_iterator ret{*this}; return ret += n; } general_span_iterator& operator+=(difference_type n) noexcept { m_itr += n; return *this; } general_span_iterator operator-(difference_type n) const noexcept { general_span_iterator ret{*this}; return ret -= n; } general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } difference_type operator-(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr - rhs.m_itr; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute value_type operator[](difference_type n) const { return (*m_container)[m_itr[n]]; } bool operator==(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr == rhs.m_itr; } bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); } bool operator<(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr < rhs.m_itr; } bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); } bool operator>(const general_span_iterator& rhs) const { return rhs < *this; } bool operator>=(const general_span_iterator& rhs) const { return !(rhs > *this); } void swap(general_span_iterator & rhs) noexcept { std::swap(m_itr, rhs.m_itr); std::swap(m_container, rhs.m_container); } }; template general_span_iterator operator+(typename general_span_iterator::difference_type n, const general_span_iterator& rhs) noexcept { return rhs + n; } } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER < 1910 #undef constexpr #pragma pop_macro("constexpr") #endif // _MSC_VER < 1910 #pragma warning(pop) #endif // _MSC_VER #if defined(__GNUC__) && __GNUC__ > 6 #pragma GCC diagnostic pop #endif // __GNUC__ > 6 #if __clang__ || __GNUC__ #pragma GCC diagnostic pop #endif #endif // GSL_MULTI_SPAN_H GSL-2.1.0/include/gsl/pointers000066400000000000000000000223241356460337500161540ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_POINTERS_H #define GSL_POINTERS_H #include // for Ensures, Expects #include // for forward #include // for ptrdiff_t, nullptr_t, ostream, size_t #include // for shared_ptr, unique_ptr #include // for hash #include // for enable_if_t, is_convertible, is_assignable #if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) #pragma push_macro("constexpr") #define constexpr /*constexpr*/ #endif // defined(_MSC_VER) && _MSC_VER < 1910 namespace gsl { // // GSL.owner: ownership pointers // using std::unique_ptr; using std::shared_ptr; // // owner // // owner is designed as a bridge for code that must deal directly with owning pointers for some reason // // T must be a pointer type // - disallow construction from any type other than pointer type // template ::value>> using owner = T; // // not_null // // Restricts a pointer or smart pointer to only hold non-null values. // // Has zero size overhead over T. // // If T is a pointer (i.e. T == U*) then // - allow construction from U* // - disallow construction from nullptr_t // - disallow default construction // - ensure construction from null U* fails // - allow implicit conversion to U* // template class not_null { public: static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); template ::value>> constexpr not_null(U&& u) : ptr_(std::forward(u)) { Expects(ptr_ != nullptr); } template ::value>> constexpr not_null(T u) : ptr_(u) { Expects(ptr_ != nullptr); } template ::value>> constexpr not_null(const not_null& other) : not_null(other.get()) { } not_null(not_null&& other) = default; not_null(const not_null& other) = default; not_null& operator=(const not_null& other) = default; constexpr T get() const { Ensures(ptr_ != nullptr); return ptr_; } constexpr operator T() const { return get(); } constexpr T operator->() const { return get(); } constexpr decltype(auto) operator*() const { return *get(); } // prevents compilation when someone attempts to assign a null pointer constant not_null(std::nullptr_t) = delete; not_null& operator=(std::nullptr_t) = delete; // unwanted operators...pointers only point to single objects! not_null& operator++() = delete; not_null& operator--() = delete; not_null operator++(int) = delete; not_null operator--(int) = delete; not_null& operator+=(std::ptrdiff_t) = delete; not_null& operator-=(std::ptrdiff_t) = delete; void operator[](std::ptrdiff_t) const = delete; private: T ptr_; }; template auto make_not_null(T&& t) { return not_null>>{std::forward(t)}; } template std::ostream& operator<<(std::ostream& os, const not_null& val) { os << val.get(); return os; } template auto operator==(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() == rhs.get()) { return lhs.get() == rhs.get(); } template auto operator!=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() != rhs.get()) { return lhs.get() != rhs.get(); } template auto operator<(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() < rhs.get()) { return lhs.get() < rhs.get(); } template auto operator<=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() <= rhs.get()) { return lhs.get() <= rhs.get(); } template auto operator>(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() > rhs.get()) { return lhs.get() > rhs.get(); } template auto operator>=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() >= rhs.get()) { return lhs.get() >= rhs.get(); } // more unwanted operators template std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; template not_null operator-(const not_null&, std::ptrdiff_t) = delete; template not_null operator+(const not_null&, std::ptrdiff_t) = delete; template not_null operator+(std::ptrdiff_t, const not_null&) = delete; } // namespace gsl namespace std { template struct hash> { std::size_t operator()(const gsl::not_null& value) const { return hash{}(value); } }; } // namespace std namespace gsl { // // strict_not_null // // Restricts a pointer or smart pointer to only hold non-null values, // // - provides a strict (i.e. explicit constructor from T) wrapper of not_null // - to be used for new code that wishes the design to be cleaner and make not_null // checks intentional, or in old code that would like to make the transition. // // To make the transition from not_null, incrementally replace not_null // by strict_not_null and fix compilation errors // // Expect to // - remove all unneeded conversions from raw pointer to not_null and back // - make API clear by specifying not_null in parameters where needed // - remove unnecessary asserts // template class strict_not_null: public not_null { public: template ::value>> constexpr explicit strict_not_null(U&& u) : not_null(std::forward(u)) {} template ::value>> constexpr explicit strict_not_null(T u) : not_null(u) {} template ::value>> constexpr strict_not_null(const not_null& other) : not_null(other) {} template ::value>> constexpr strict_not_null(const strict_not_null& other) : not_null(other) {} strict_not_null(strict_not_null&& other) = default; strict_not_null(const strict_not_null& other) = default; strict_not_null& operator=(const strict_not_null& other) = default; strict_not_null& operator=(const not_null& other) { not_null::operator=(other); return *this; } // prevents compilation when someone attempts to assign a null pointer constant strict_not_null(std::nullptr_t) = delete; strict_not_null& operator=(std::nullptr_t) = delete; // unwanted operators...pointers only point to single objects! strict_not_null& operator++() = delete; strict_not_null& operator--() = delete; strict_not_null operator++(int) = delete; strict_not_null operator--(int) = delete; strict_not_null& operator+=(std::ptrdiff_t) = delete; strict_not_null& operator-=(std::ptrdiff_t) = delete; void operator[](std::ptrdiff_t) const = delete; }; // more unwanted operators template std::ptrdiff_t operator-(const strict_not_null&, const strict_not_null&) = delete; template strict_not_null operator-(const strict_not_null&, std::ptrdiff_t) = delete; template strict_not_null operator+(const strict_not_null&, std::ptrdiff_t) = delete; template strict_not_null operator+(std::ptrdiff_t, const strict_not_null&) = delete; template auto make_strict_not_null(T&& t) { return strict_not_null>>{std::forward(t)}; } #if ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) // deduction guides to prevent the ctad-maybe-unsupported warning template not_null(T) -> not_null; template strict_not_null(T) -> strict_not_null; #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) } // namespace gsl namespace std { template struct hash> { std::size_t operator()(const gsl::strict_not_null& value) const { return hash{}(value); } }; } // namespace std #if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) #undef constexpr #pragma pop_macro("constexpr") #endif // defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) #endif // GSL_POINTERS_H GSL-2.1.0/include/gsl/span000066400000000000000000000650021356460337500152520ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_SPAN_H #define GSL_SPAN_H #include // for Expects #include // for byte #include // for narrow_cast, narrow #include // for lexicographical_compare #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... #include #include #include // for enable_if_t, declval, is_convertible, inte... #include #include // for std::addressof #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) // turn off some warnings that are noisy about our Expects statements #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4702) // unreachable code // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor #pragma warning(disable : 26446) // parser bug does not allow attributes on some templates #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND #endif // _MSC_VER < 1910 #endif // _MSC_VER // See if we have enough C++17 power to use a static constexpr data member // without needing an out-of-line definition #if !(defined(__cplusplus) && (__cplusplus >= 201703L)) #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) // While there is a conversion from signed to unsigned, it happens at // compiletime, so the compiler wouldn't have to warn indiscriminently, but // could check if the source value actually doesn't fit into the target type // and only warn in those cases. #if defined(__GNUC__) && __GNUC__ > 6 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #endif namespace gsl { // [views.constants], constants constexpr const std::ptrdiff_t dynamic_extent = -1; template class span; // implementation details namespace details { template struct is_span_oracle : std::false_type { }; template struct is_span_oracle> : std::true_type { }; template struct is_span : public is_span_oracle> { }; template struct is_std_array_oracle : std::false_type { }; template struct is_std_array_oracle> : std::true_type { }; template struct is_std_array : public is_std_array_oracle> { }; template struct is_allowed_extent_conversion : public std::integral_constant { }; template struct is_allowed_element_type_conversion : public std::integral_constant::value> { }; template class span_iterator { using element_type_ = typename Span::element_type; public: #ifdef _MSC_VER // Tell Microsoft standard library that span_iterators are checked. using _Unchecked_type = typename Span::pointer; #endif using iterator_category = std::random_access_iterator_tag; using value_type = std::remove_cv_t; using difference_type = typename Span::index_type; using reference = std::conditional_t&; using pointer = std::add_pointer_t; span_iterator() = default; constexpr span_iterator(const Span* span, difference_type idx) noexcept : span_(span), index_(idx) {} friend span_iterator; template * = nullptr> constexpr span_iterator(const span_iterator& other) noexcept : span_iterator(other.span_, other.index_) {} GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator*() const { Expects(index_ != span_->size()); return *(span_->data() + index_); } constexpr pointer operator->() const { Expects(index_ != span_->size()); return span_->data() + index_; } constexpr span_iterator& operator++() { Expects(0 <= index_ && index_ != span_->size()); ++index_; return *this; } constexpr span_iterator operator++(int) { auto ret = *this; ++(*this); return ret; } constexpr span_iterator& operator--() { Expects(index_ != 0 && index_ <= span_->size()); --index_; return *this; } constexpr span_iterator operator--(int) { auto ret = *this; --(*this); return ret; } constexpr span_iterator operator+(difference_type n) const { auto ret = *this; return ret += n; } friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) { return rhs + n; } constexpr span_iterator& operator+=(difference_type n) { Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); index_ += n; return *this; } constexpr span_iterator operator-(difference_type n) const { auto ret = *this; return ret -= n; } constexpr span_iterator& operator-=(difference_type n) { return *this += -n; } constexpr difference_type operator-(span_iterator rhs) const { Expects(span_ == rhs.span_); return index_ - rhs.index_; } constexpr reference operator[](difference_type n) const { return *(*this + n); } constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept { return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; } constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept { return !(lhs == rhs); } constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept { return lhs.index_ < rhs.index_; } constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept { return !(rhs < lhs); } constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept { return rhs < lhs; } constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept { return !(rhs > lhs); } #ifdef _MSC_VER // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ // to unwrap span_iterator to a pointer type after a range check in STL // algorithm calls friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept { // test that [lhs, rhs) forms a valid range inside an STL algorithm Expects(lhs.span_ == rhs.span_ // range spans have to match && lhs.index_ <= rhs.index_); // range must not be transposed } constexpr void _Verify_offset(const difference_type n) const noexcept { // test that the iterator *this + n is a valid range in an STL // algorithm call Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw // pointer return span_->data() + index_; } // Tell the STL that span_iterator should not be unwrapped if it can't // validate in advance, even in release / optimized builds: #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) static constexpr const bool _Unwrap_when_unverified = false; #else static constexpr bool _Unwrap_when_unverified = false; #endif GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped index_ = p - span_->data(); } #endif protected: const Span* span_ = nullptr; std::ptrdiff_t index_ = 0; }; template class extent_type { public: using index_type = std::ptrdiff_t; static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); constexpr extent_type() noexcept {} template constexpr extent_type(extent_type ext) { static_assert(Other == Ext || Other == dynamic_extent, "Mismatch between fixed-size extent and size of initializing data."); Expects(ext.size() == Ext); } constexpr extent_type(index_type size) { Expects(size == Ext); } constexpr index_type size() const noexcept { return Ext; } }; template <> class extent_type { public: using index_type = std::ptrdiff_t; template explicit constexpr extent_type(extent_type ext) : size_(ext.size()) {} explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } constexpr index_type size() const noexcept { return size_; } private: index_type size_; }; template struct calculate_subspan_type { using type = span; }; } // namespace details // [span], class template span template class span { public: // constants and types using element_type = ElementType; using value_type = std::remove_cv_t; using index_type = std::ptrdiff_t; using pointer = element_type*; using reference = element_type&; using iterator = details::span_iterator, false>; using const_iterator = details::span_iterator, true>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using size_type = index_type; #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) static constexpr const index_type extent{Extent}; #else static constexpr index_type extent{Extent}; #endif // [span.cons], span constructors, copy, assignment, and destructor template " SFINAE, // since "std::enable_if_t" is ill-formed when Extent is greater than 0. class = std::enable_if_t<(Dependent || Extent <= 0)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} constexpr span(pointer firstElem, pointer lastElem) : storage_(firstElem, std::distance(firstElem, lastElem)) {} template constexpr span(element_type (&arr)[N]) noexcept : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) {} template 0)>> constexpr span(std::array, N>& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) { } constexpr span(std::array, 0>&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) { } template 0)>> constexpr span(const std::array, N>& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) { } constexpr span(const std::array, 0>&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) { } // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. template ::value && !details::is_std_array::value && std::is_convertible::value && std::is_convertible().data())>::value>> constexpr span(Container& cont) : span(cont.data(), narrow(cont.size())) {} template ::value && !details::is_span::value && std::is_convertible::value && std::is_convertible().data())>::value>> constexpr span(const Container& cont) : span(cont.data(), narrow(cont.size())) {} constexpr span(const span& other) noexcept = default; template < class OtherElementType, std::ptrdiff_t OtherExtent, class = std::enable_if_t< details::is_allowed_extent_conversion::value && details::is_allowed_element_type_conversion::value>> constexpr span(const span& other) : storage_(other.data(), details::extent_type(other.size())) {} ~span() noexcept = default; constexpr span& operator=(const span& other) noexcept = default; // [span.sub], span subviews template constexpr span first() const { Expects(Count >= 0 && Count <= size()); return {data(), Count}; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr span last() const { Expects(Count >= 0 && size() - Count >= 0); return {data() + (size() - Count), Count}; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr auto subspan() const -> typename details::calculate_subspan_type::type { Expects((Offset >= 0 && size() - Offset >= 0) && (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } constexpr span first(index_type count) const { Expects(count >= 0 && count <= size()); return {data(), count}; } constexpr span last(index_type count) const { return make_subspan(size() - count, dynamic_extent, subspan_selector{}); } constexpr span subspan(index_type offset, index_type count = dynamic_extent) const { return make_subspan(offset, count, subspan_selector{}); } // [span.obs], span observers constexpr index_type size() const noexcept { return storage_.size(); } constexpr index_type size_bytes() const noexcept { return size() * narrow_cast(sizeof(element_type)); } constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const { Expects(CheckRange(idx, storage_.size())); return data()[idx]; } constexpr reference at(index_type idx) const { return this->operator[](idx); } constexpr reference operator()(index_type idx) const { return this->operator[](idx); } constexpr pointer data() const noexcept { return storage_.data(); } // [span.iter], span iterator support constexpr iterator begin() const noexcept { return {this, 0}; } constexpr iterator end() const noexcept { return {this, size()}; } constexpr const_iterator cbegin() const noexcept { return {this, 0}; } constexpr const_iterator cend() const noexcept { return {this, size()}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } #ifdef _MSC_VER // Tell MSVC how to unwrap spans in range-based-for constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return data() + size(); } #endif // _MSC_VER private: static constexpr bool CheckRange(index_type idx, index_type size) noexcept { // Optimization: // // idx >= 0 && idx < size // => // static_cast(idx) < static_cast(size) // // because size >=0 by span construction, and negative idx will // wrap around to a value always greater than size when casted. // check if we have enough space to wrap around #if defined(__cpp_if_constexpr) if constexpr (sizeof(index_type) <= sizeof(size_t)) #else if (sizeof(index_type) <= sizeof(size_t)) #endif { return narrow_cast(idx) < narrow_cast(size); } else { return idx >= 0 && idx < size; } } // Needed to remove unnecessary null check in subspans struct KnownNotNull { pointer p; }; // this implementation detail class lets us take advantage of the // empty base class optimization to pay for only storage of a single // pointer in the case of fixed-size spans template class storage_type : public ExtentType { public: // KnownNotNull parameter is needed to remove unnecessary null check // in subspans and constructors from arrays template constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) { Expects(ExtentType::size() >= 0); } template constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { Expects(ExtentType::size() >= 0); Expects(data || ExtentType::size() == 0); } constexpr pointer data() const noexcept { return data_; } private: pointer data_; }; storage_type> storage_; // The rest is needed to remove unnecessary null check // in subspans and constructors from arrays constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} template class subspan_selector { }; template span make_subspan(index_type offset, index_type count, subspan_selector) const { const span tmp(*this); return tmp.subspan(offset, count); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute span make_subspan(index_type offset, index_type count, subspan_selector) const { Expects(offset >= 0 && size() - offset >= 0); if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } Expects(count >= 0 && size() - offset >= count); return {KnownNotNull{data() + offset}, count}; } }; #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) template constexpr const typename span::index_type span::extent; #endif // [span.comparison], span comparison operators template constexpr bool operator==(span l, span r) { return std::equal(l.begin(), l.end(), r.begin(), r.end()); } template constexpr bool operator!=(span l, span r) { return !(l == r); } template constexpr bool operator<(span l, span r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } template constexpr bool operator<=(span l, span r) { return !(l > r); } template constexpr bool operator>(span l, span r) { return r < l; } template constexpr bool operator>=(span l, span r) { return !(l < r); } namespace details { // if we only supported compilers with good constexpr support then // this pair of classes could collapse down to a constexpr function // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as // constexpr // and so will fail compilation of the template template struct calculate_byte_size : std::integral_constant(sizeof(ElementType) * static_cast(Extent))> { }; template struct calculate_byte_size : std::integral_constant { }; } // namespace details // [span.objectrep], views of object representation template span::value> as_bytes(span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } template ::value>> span::value> as_writeable_bytes(span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } // // make_span() - Utility functions for creating spans // template constexpr span make_span(ElementType* ptr, typename span::index_type count) { return span(ptr, count); } template constexpr span make_span(ElementType* firstElem, ElementType* lastElem) { return span(firstElem, lastElem); } template constexpr span make_span(ElementType (&arr)[N]) noexcept { return span(arr); } template constexpr span make_span(Container& cont) { return span(cont); } template constexpr span make_span(const Container& cont) { return span(cont); } template constexpr span make_span(Ptr& cont, std::ptrdiff_t count) { return span(cont, count); } template constexpr span make_span(Ptr& cont) { return span(cont); } // Specialization of gsl::at for span template constexpr ElementType& at(span s, index i) { // No bounds checking here because it is done in span::operator[] called below return s[i]; } } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER < 1910 #undef constexpr #pragma pop_macro("constexpr") #endif // _MSC_VER < 1910 #pragma warning(pop) #endif // _MSC_VER #if defined(__GNUC__) && __GNUC__ > 6 #pragma GCC diagnostic pop #endif // __GNUC__ > 6 #endif // GSL_SPAN_H GSL-2.1.0/include/gsl/string_span000066400000000000000000000651531356460337500166470ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifndef GSL_STRING_SPAN_H #define GSL_STRING_SPAN_H #include // for Ensures, Expects #include // for narrow_cast #include // for operator!=, operator==, dynamic_extent #include // for equal, lexicographical_compare #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for PTRDIFF_MAX #include #include // for basic_string, allocator, char_traits #include // for declval, is_convertible, enable_if_t, add_... #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. #pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates #pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ #endif // _MSC_VER < 1910 #endif // _MSC_VER namespace gsl { // // czstring and wzstring // // These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays) // that allow static analysis to help find bugs. // // There are no additional features/semantics that we can find a way to add inside the // type system for these types that will not either incur significant runtime costs or // (sometimes needlessly) break existing programs when introduced. // template using basic_zstring = CharT*; template using czstring = basic_zstring; template using cwzstring = basic_zstring; template using cu16zstring = basic_zstring; template using cu32zstring = basic_zstring; template using zstring = basic_zstring; template using wzstring = basic_zstring; template using u16zstring = basic_zstring; template using u32zstring = basic_zstring; namespace details { template std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n) { if (str == nullptr || n <= 0) return 0; const span str_span{str, n}; std::ptrdiff_t len = 0; while (len < n && str_span[len]) len++; return len; } } // namespace details // // ensure_sentinel() // // Provides a way to obtain an span from a contiguous sequence // that ends with a (non-inclusive) sentinel value. // // Will fail-fast if sentinel cannot be found before max elements are examined. // template span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) { Ensures(seq != nullptr); GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work auto cur = seq; Ensures(cur != nullptr); // workaround for removing the warning GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work while ((cur - seq) < max && *cur != Sentinel) ++cur; Ensures(*cur == Sentinel); return {seq, cur - seq}; } // // ensure_z - creates a span for a zero terminated strings. // Will fail fast if a null-terminator cannot be found before // the limit of size_type. // template span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX) { return ensure_sentinel(sz, max); } template span ensure_z(CharT (&sz)[N]) { return ensure_z(&sz[0], narrow_cast(N)); } template span::type, dynamic_extent> ensure_z(Cont& cont) { return ensure_z(cont.data(), narrow_cast(cont.size())); } template class basic_string_span; namespace details { template struct is_basic_string_span_oracle : std::false_type { }; template struct is_basic_string_span_oracle> : std::true_type { }; template struct is_basic_string_span : is_basic_string_span_oracle> { }; } // namespace details // // string_span and relatives // template class basic_string_span { public: using element_type = CharT; using value_type = std::remove_cv_t; using pointer = std::add_pointer_t; using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; using impl_type = span; using index_type = typename impl_type::index_type; using iterator = typename impl_type::iterator; using const_iterator = typename impl_type::const_iterator; using reverse_iterator = typename impl_type::reverse_iterator; using const_reverse_iterator = typename impl_type::const_reverse_iterator; using size_type = index_type; // default (empty) constexpr basic_string_span() noexcept = default; // copy constexpr basic_string_span(const basic_string_span& other) noexcept = default; // assign constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} // From static arrays - if 0-terminated, remove 0 from the view // All other containers allow 0s within the length, so we do not remove them template constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr)) {} template > constexpr basic_string_span(std::array& arr) noexcept : span_(arr) {} template > constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) {} // Container signature should work for basic_string after C++17 version exists template // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr basic_string_span(std::basic_string& str) : span_(&str[0], narrow_cast(str.length())) {} template constexpr basic_string_span(const std::basic_string& str) : span_(&str[0], str.length()) {} // from containers. Containers must have a pointer type and data() function signatures template ::value && std::is_convertible::value && std::is_convertible().data())>::value>> constexpr basic_string_span(Container& cont) : span_(cont) {} template ::value && std::is_convertible::value && std::is_convertible().data())>::value>> constexpr basic_string_span(const Container& cont) : span_(cont) {} // from string_span template < class OtherValueType, std::ptrdiff_t OtherExtent, class = std::enable_if_t::impl_type, impl_type>::value>> constexpr basic_string_span(basic_string_span other) : span_(other.data(), other.length()) {} template constexpr basic_string_span first() const { return {span_.template first()}; } constexpr basic_string_span first(index_type count) const { return {span_.first(count)}; } template constexpr basic_string_span last() const { return {span_.template last()}; } constexpr basic_string_span last(index_type count) const { return {span_.last(count)}; } template constexpr basic_string_span subspan() const { return {span_.template subspan()}; } constexpr basic_string_span subspan(index_type offset, index_type count = dynamic_extent) const { return {span_.subspan(offset, count)}; } constexpr reference operator[](index_type idx) const { return span_[idx]; } constexpr reference operator()(index_type idx) const { return span_[idx]; } constexpr pointer data() const { return span_.data(); } constexpr index_type length() const noexcept { return span_.size(); } constexpr index_type size() const noexcept { return span_.size(); } constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } constexpr bool empty() const noexcept { return size() == 0; } constexpr iterator begin() const noexcept { return span_.begin(); } constexpr iterator end() const noexcept { return span_.end(); } constexpr const_iterator cbegin() const noexcept { return span_.cbegin(); } constexpr const_iterator cend() const noexcept { return span_.cend(); } constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } constexpr reverse_iterator rend() const noexcept { return span_.rend(); } constexpr const_reverse_iterator crbegin() const noexcept { return span_.crbegin(); } constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } private: static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) { return {sz, details::string_length(sz, max)}; } template static impl_type remove_z(element_type (&sz)[N]) { return remove_z(&sz[0], narrow_cast(N)); } impl_type span_; }; template using string_span = basic_string_span; template using cstring_span = basic_string_span; template using wstring_span = basic_string_span; template using cwstring_span = basic_string_span; template using u16string_span = basic_string_span; template using cu16string_span = basic_string_span; template using u32string_span = basic_string_span; template using cu32string_span = basic_string_span; // // to_string() allow (explicit) conversions from string_span to string // template std::basic_string::type> to_string(basic_string_span view) { return {view.data(), narrow_cast(view.length())}; } template , typename Allocator = std::allocator, typename gCharT, std::ptrdiff_t Extent> std::basic_string to_basic_string(basic_string_span view) { return {view.data(), narrow_cast(view.length())}; } template basic_string_span::value> as_bytes(basic_string_span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } template ::value>> basic_string_span::value> as_writeable_bytes(basic_string_span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } // zero-terminated string span, used to convert // zero-terminated spans to legacy strings template class basic_zstring_span { public: using value_type = CharT; using const_value_type = std::add_const_t; using pointer = std::add_pointer_t; using const_pointer = std::add_pointer_t; using zstring_type = basic_zstring; using const_zstring_type = basic_zstring; using impl_type = span; using string_span_type = basic_string_span; constexpr basic_zstring_span(impl_type s) : span_(s) { // expects a zero-terminated span Expects(s[s.size() - 1] == '\0'); } // copy constexpr basic_zstring_span(const basic_zstring_span& other) = default; // move constexpr basic_zstring_span(basic_zstring_span&& other) = default; // assign constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; // move assign constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; constexpr bool empty() const noexcept { return span_.size() == 0; } constexpr string_span_type as_string_span() const noexcept { const auto sz = span_.size(); return {span_.data(), sz > 1 ? sz - 1 : 0}; } constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); } constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } private: impl_type span_; }; template using zstring_span = basic_zstring_span; template using wzstring_span = basic_zstring_span; template using u16zstring_span = basic_zstring_span; template using u32zstring_span = basic_zstring_span; template using czstring_span = basic_zstring_span; template using cwzstring_span = basic_zstring_span; template using cu16zstring_span = basic_zstring_span; template using cu32zstring_span = basic_zstring_span; // operator == template ::value || std::is_convertible>>::value>> bool operator==(const gsl::basic_string_span& one, const T& other) { const gsl::basic_string_span> tmp(other); return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); } template ::value && std::is_convertible>>::value>> bool operator==(const T& one, const gsl::basic_string_span& other) { const gsl::basic_string_span> tmp(one); return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); } // operator != template , Extent>>::value>> bool operator!=(gsl::basic_string_span one, const T& other) { return !(one == other); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> bool operator!=(const T& one, gsl::basic_string_span other) { return !(one == other); } // operator< template , Extent>>::value>> bool operator<(gsl::basic_string_span one, const T& other) { const gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> bool operator<(const T& one, gsl::basic_string_span other) { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); } #ifndef _MSC_VER // VS treats temp and const containers as convertible to basic_string_span, // so the cases below are already covered by the previous operators template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator<(gsl::basic_string_span one, const T& other) { gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator<(const T& one, gsl::basic_string_span other) { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); } #endif // operator <= template , Extent>>::value>> bool operator<=(gsl::basic_string_span one, const T& other) { return !(other < one); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> bool operator<=(const T& one, gsl::basic_string_span other) { return !(other < one); } #ifndef _MSC_VER // VS treats temp and const containers as convertible to basic_string_span, // so the cases below are already covered by the previous operators template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator<=(gsl::basic_string_span one, const T& other) { return !(other < one); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator<=(const T& one, gsl::basic_string_span other) { return !(other < one); } #endif // operator> template , Extent>>::value>> bool operator>(gsl::basic_string_span one, const T& other) { return other < one; } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> bool operator>(const T& one, gsl::basic_string_span other) { return other < one; } #ifndef _MSC_VER // VS treats temp and const containers as convertible to basic_string_span, // so the cases below are already covered by the previous operators template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator>(gsl::basic_string_span one, const T& other) { return other < one; } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator>(const T& one, gsl::basic_string_span other) { return other < one; } #endif // operator >= template , Extent>>::value>> bool operator>=(gsl::basic_string_span one, const T& other) { return !(one < other); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> bool operator>=(const T& one, gsl::basic_string_span other) { return !(one < other); } #ifndef _MSC_VER // VS treats temp and const containers as convertible to basic_string_span, // so the cases below are already covered by the previous operators template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator>=(gsl::basic_string_span one, const T& other) { return !(one < other); } template < typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> bool operator>=(const T& one, gsl::basic_string_span other) { return !(one < other); } #endif } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) #if _MSC_VER < 1910 #undef constexpr #pragma pop_macro("constexpr") #endif // _MSC_VER < 1910 #endif // _MSC_VER #endif // GSL_STRING_SPAN_H GSL-2.1.0/tests/000077500000000000000000000000001356460337500133155ustar00rootroot00000000000000GSL-2.1.0/tests/CMakeLists.txt000066400000000000000000000127441356460337500160650ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) project(GSLTests CXX) # will make visual studio generated project group files set_property(GLOBAL PROPERTY USE_FOLDERS ON) list(APPEND CATCH_CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external" "-DNO_SELFTEST=true" ) if(GIT_FOUND) # add catch ExternalProject_Add( catch PREFIX ${CMAKE_BINARY_DIR}/catch GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v2.0.1 CMAKE_ARGS ${CATCH_CMAKE_ARGS} LOG_DOWNLOAD 1 UPDATE_DISCONNECTED 1 ) else() # assume catch is installed in a system directory add_custom_target(catch) endif() if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) endif() # this interface adds compile options to how the tests are run # please try to keep entries ordered =) add_library(gsl_tests_config INTERFACE) if(MSVC) # MSVC or simulating MSVC target_compile_options(gsl_tests_config INTERFACE ${GSL_CPLUSPLUS_OPT} /EHsc /W4 /WX $<$: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-braces -Wno-missing-prototypes -Wno-unknown-attributes $<$:-Wno-unused-member-function> > ) else() target_compile_options(gsl_tests_config INTERFACE -fno-strict-aliasing -Wall -Wcast-align -Wconversion -Wctor-dtor-privacy -Werror -Wextra -Wpedantic -Wshadow -Wsign-conversion $<$,$>: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-braces -Wno-missing-prototypes -Wno-padded -Wno-unknown-attributes $<$:-Wno-unused-member-function> -Wno-weak-vtables > $<$: $<$:-Wno-undefined-func-template> > ) endif(MSVC) # for tests to find the catch header target_include_directories(gsl_tests_config INTERFACE ${CMAKE_BINARY_DIR}/external/include ) # set definitions for tests target_compile_definitions(gsl_tests_config INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION ) # create the main executable for each test. this reduces the compile time # of each test by pre-compiling catch. add_library(test_catch STATIC test.cpp) target_link_libraries(test_catch GSL gsl_tests_config ) add_dependencies(test_catch catch) set_property(TARGET test_catch PROPERTY FOLDER "GSL_tests") function(add_gsl_test name) add_executable(${name} ${name}.cpp) target_link_libraries(${name} GSL test_catch gsl_tests_config ) add_dependencies(${name} catch) add_test( ${name} ${name} ) # group all tests under GSL_tests set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests") endfunction() add_gsl_test(span_tests) add_gsl_test(multi_span_tests) add_gsl_test(strided_span_tests) add_gsl_test(string_span_tests) add_gsl_test(at_tests) add_gsl_test(bounds_tests) add_gsl_test(notnull_tests) add_gsl_test(assertion_tests) add_gsl_test(utils_tests) add_gsl_test(owner_tests) add_gsl_test(byte_tests) add_gsl_test(algorithm_tests) add_gsl_test(strict_notnull_tests) # No exception tests foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) STRING (REGEX REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}") endforeach(flag_var) # this interface adds compile options to how the tests are run # please try to keep entries ordered =) add_library(gsl_tests_config_noexcept INTERFACE) if(MSVC) # MSVC or simulating MSVC target_compile_definitions(gsl_tests_config_noexcept INTERFACE _HAS_EXCEPTIONS=0 ) target_compile_options(gsl_tests_config_noexcept INTERFACE ${GSL_CPLUSPLUS_OPT} /W4 /WX $<$: /wd4577 /wd4702 > $<$: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes -Wno-unknown-attributes > ) else() target_compile_options(gsl_tests_config_noexcept INTERFACE -fno-exceptions -fno-strict-aliasing -Wall -Wcast-align -Wconversion -Wctor-dtor-privacy -Werror -Wextra -Wpedantic -Wshadow -Wsign-conversion $<$,$>: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes -Wno-unknown-attributes -Wno-weak-vtables > ) endif(MSVC) # set definitions for tests target_compile_definitions(gsl_tests_config_noexcept INTERFACE GSL_TERMINATE_ON_CONTRACT_VIOLATION ) function(add_gsl_test_noexcept name) add_executable(${name} ${name}.cpp) target_link_libraries(${name} GSL gsl_tests_config_noexcept ) add_test( ${name} ${name} ) # group all tests under GSL_tests_noexcept set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept") endfunction() add_gsl_test_noexcept(no_exception_throw_tests) add_gsl_test_noexcept(no_exception_ensure_tests) GSL-2.1.0/tests/algorithm_tests.cpp000066400000000000000000000144131356460337500172340ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, CHE... #include // for copy #include // for span #include // for array #include // for size_t namespace gsl { struct fail_fast; } // namespace gsl using namespace std; using namespace gsl; GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("same_type") { // dynamic source and destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // static source and dynamic destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // dynamic source and static destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // static source and destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("compatible_type") { // dynamic source and destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // static source and dynamic destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // dynamic source and static destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } // static source and destination span { std::array src{1, 2, 3, 4, 5}; std::array dst{}; const span src_span(src); const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); for (std::size_t i = 0; i < src.size(); ++i) { CHECK(dst[i] == src[i]); CHECK(dst[i + src.size()] == src[i]); } } } #ifdef CONFIRM_COMPILATION_ERRORS TEST_CASE("incompatible_type") { std::array src{1, 2, 3, 4}; std::array dst{}; span src_span_dyn(src); span src_span_static(src); span dst_span_dyn(dst); span dst_span_static(dst); // every line should produce a compilation error copy(src_span_dyn, dst_span_dyn); copy(src_span_dyn, dst_span_static); copy(src_span_static, dst_span_dyn); copy(src_span_static, dst_span_static); } #endif TEST_CASE("small_destination_span") { std::array src{1, 2, 3, 4}; std::array dst{}; const span src_span_dyn(src); const span src_span_static(src); const span dst_span_dyn(dst); const span dst_span_static(dst); CHECK_THROWS_AS(copy(src_span_dyn, dst_span_dyn), fail_fast); CHECK_THROWS_AS(copy(src_span_dyn, dst_span_static), fail_fast); CHECK_THROWS_AS(copy(src_span_static, dst_span_dyn), fail_fast); #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif } GSL-2.1.0/tests/assertion_tests.cpp000066400000000000000000000026511356460337500172560ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for fail_fast (ptr only), Ensures, Expects using namespace gsl; int f(int i) { Expects(i > 0 && i < 10); return i; } TEST_CASE("expects") { CHECK(f(2) == 2); CHECK_THROWS_AS(f(10), fail_fast); } int g(int i) { i++; Ensures(i > 0 && i < 10); return i; } TEST_CASE("ensures") { CHECK(g(2) == 3); CHECK_THROWS_AS(g(9), fail_fast); } GSL-2.1.0/tests/at_tests.cpp000066400000000000000000000104151356460337500156500ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK_THROW... #include // for at #include // for array #include // for size_t #include // for initializer_list #include // for vector namespace gsl { struct fail_fast; } // namespace gsl using gsl::fail_fast; GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("static_array") { int a[4] = {1, 2, 3, 4}; const int(&c_a)[4] = a; for (int i = 0; i < 4; ++i) { CHECK(&gsl::at(a, i) == &a[i]); CHECK(&gsl::at(c_a, i) == &a[i]); } CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("std_array") { std::array a = {1, 2, 3, 4}; const std::array& c_a = a; for (int i = 0; i < 4; ++i) { CHECK(&gsl::at(a, i) == &a[static_cast(i)]); CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("StdVector") { std::vector a = {1, 2, 3, 4}; const std::vector& c_a = a; for (int i = 0; i < 4; ++i) { CHECK(&gsl::at(a, i) == &a[static_cast(i)]); CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("InitializerList") { const std::initializer_list a = {1, 2, 3, 4}; for (int i = 0; i < 4; ++i) { CHECK(gsl::at(a, i) == i + 1); CHECK(gsl::at({1, 2, 3, 4}, i) == i + 1); } CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, -1), fail_fast); CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, 4), fail_fast); } #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute static constexpr bool test_constexpr() { int a1[4] = {1, 2, 3, 4}; const int(&c_a1)[4] = a1; std::array a2 = {1, 2, 3, 4}; const std::array& c_a2 = a2; for (int i = 0; i < 4; ++i) { if (&gsl::at(a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false; // requires C++17: // if (&gsl::at(a2, i) != &a2[static_cast(i)]) return false; if (&gsl::at(c_a2, i) != &c_a2[static_cast(i)]) return false; if (gsl::at({1, 2, 3, 4}, i) != i + 1) return false; } return true; } static_assert(test_constexpr(), "FAIL"); #endif GSL-2.1.0/tests/bounds_tests.cpp000066400000000000000000000065001356460337500165360ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 4996) // use of function or classes marked [[deprecated]] #endif #if __clang__ || __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include // for AssertionHandler, StringRef, TEST_CASE #include // for static_bounds, static_bounds_dynamic_range_t #include // for ptrdiff_t, size_t namespace gsl { struct fail_fast; } // namespace gsl using namespace std; using namespace gsl; namespace { void use(std::ptrdiff_t&) {} } GSL_SUPPRESS(type.1) // NO-FORMAT: attribute TEST_CASE("basic_bounds") { for (auto point : static_bounds{2}) { for (decltype(point)::size_type j = 0; j < static_cast(decltype(point)::rank); j++) { use(j); use(point[static_cast(j)]); } } } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("bounds_basic") { static_bounds<3, 4, 5> b; const auto a = b.slice(); (void) a; static_bounds<4, dynamic_range, 2> x{4}; x.slice().slice(); } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("arrayview_iterator") { static_bounds<4, dynamic_range, 2> bounds{3}; const auto itr = bounds.begin(); (void) itr; #ifdef CONFIRM_COMPILATION_ERRORS multi_span av(nullptr, bounds); auto itr2 = av.cbegin(); for (auto& v : av) { v = 4; } fill(av.begin(), av.end(), 0); #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("bounds_convertible") { static_bounds<7, 4, 2> b1; static_bounds<7, dynamic_range, 2> b2 = b1; (void) b2; #ifdef CONFIRM_COMPILATION_ERRORS static_bounds<7, dynamic_range, 1> b4 = b2; #endif static_bounds b3 = b1; static_bounds<7, 4, 2> b4 = b3; (void) b4; static_bounds b11; static_bounds b5; static_bounds<34> b6; b5 = static_bounds<20>(); CHECK_THROWS_AS(b6 = b5, fail_fast); b5 = static_bounds<34>(); b6 = b5; CHECK(b5 == b6); CHECK(b5.size() == b6.size()); } #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif #if __clang__ || __GNUC__ #pragma GCC diagnostic pop #endif GSL-2.1.0/tests/byte_tests.cpp000066400000000000000000000066741356460337500162230ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for to_byte, to_integer, byte, operator&, ope... using namespace std; using namespace gsl; namespace { TEST_CASE("construction") { { const byte b = static_cast(4); CHECK(static_cast(b) == 4); } GSL_SUPPRESS(es.49) { const byte b = byte(12); CHECK(static_cast(b) == 12); } { const byte b = to_byte<12>(); CHECK(static_cast(b) == 12); } { const unsigned char uc = 12; const byte b = to_byte(uc); CHECK(static_cast(b) == 12); } #if defined(__cplusplus) && (__cplusplus >= 201703L) { const byte b { 14 }; CHECK(static_cast(b) == 14); } #endif } TEST_CASE("bitwise_operations") { const byte b = to_byte<0xFF>(); byte a = to_byte<0x00>(); CHECK((b | a) == to_byte<0xFF>()); CHECK(a == to_byte<0x00>()); a |= b; CHECK(a == to_byte<0xFF>()); a = to_byte<0x01>(); CHECK((b & a) == to_byte<0x01>()); a &= b; CHECK(a == to_byte<0x01>()); CHECK((b ^ a) == to_byte<0xFE>()); CHECK(a == to_byte<0x01>()); a ^= b; CHECK(a == to_byte<0xFE>()); a = to_byte<0x01>(); CHECK(~a == to_byte<0xFE>()); a = to_byte<0xFF>(); CHECK((a << 4) == to_byte<0xF0>()); CHECK((a >> 4) == to_byte<0x0F>()); a <<= 4; CHECK(a == to_byte<0xF0>()); a >>= 4; CHECK(a == to_byte<0x0F>()); } TEST_CASE("to_integer") { const byte b = to_byte<0x12>(); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); CHECK(0x12 == gsl::to_integer(b)); // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error } int modify_both(gsl::byte & b, int& i) { i = 10; b = to_byte<5>(); return i; } GSL_SUPPRESS(type.1) TEST_CASE("aliasing") { int i{0}; const int res = modify_both(reinterpret_cast(i), i); CHECK(res == i); } } #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif GSL-2.1.0/tests/multi_span_tests.cpp000066400000000000000000001324621356460337500174260ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 4996) // multi_span is in the process of being deprecated. // Suppressing warnings until it is completely removed #endif #if __clang__ || __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for byte #include // for narrow_cast #include // for multi_span, contiguous_span_iterator, dim #include // for fill, for_each #include // for array #include // for ptrdiff_t, size_t #include // for reverse_iterator, begin, end, operator!= #include // for iota #include // for ptrdiff_t #include // for string #include // for vector namespace gsl { struct fail_fast; } // namespace gsl using namespace std; using namespace gsl; namespace { struct BaseClass { }; struct DerivedClass : BaseClass { }; } // namespace GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("default_constructor") { { multi_span s; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { multi_span s; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s; CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile #endif } { multi_span s{}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_nullptr_constructor") { { multi_span s = nullptr; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs = nullptr; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { multi_span s = nullptr; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs = nullptr; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s = nullptr; CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile #endif } { multi_span s{nullptr}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{nullptr}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { multi_span s{nullptr}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{nullptr}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_nullptr_length_constructor") { { multi_span s{nullptr, 0}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{nullptr, 0}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { multi_span s{nullptr, 0}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{nullptr, 0}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { auto workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); auto const_workaround_macro = []() { const multi_span cs{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { auto workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); auto const_workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { multi_span s{nullptr, 0}; CHECK((s.length() == 0 && s.data() == nullptr)); multi_span cs{nullptr, 0}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{nullptr, 0}; CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_element_constructor") { int i = 5; { multi_span s = i; CHECK((s.length() == 1 && s.data() == &i)); CHECK(s[0] == 5); multi_span cs = i; CHECK((cs.length() == 1 && cs.data() == &i)); CHECK(cs[0] == 5); } { #ifdef CONFIRM_COMPILATION_ERRORS const j = 1; multi_span s = j; #endif } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s = i; CHECK((s.length() == 0 && s.data() == &i)); #endif } { multi_span s = i; CHECK((s.length() == 1 && s.data() == &i)); CHECK(s[0] == 5); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s = i; CHECK((s.length() == 2 && s.data() == &i)); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_a_temp = []() -> int { return 4; }; auto use_a_span = [](multi_span s) { (void) s; }; use_a_span(get_a_temp()); #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_length_constructor") { int arr[4] = {1, 2, 3, 4}; { multi_span s{&arr[0], 2}; CHECK((s.length() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { multi_span s{&arr[0], 2}; CHECK((s.length() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { int* p = nullptr; multi_span s{p, 0}; CHECK((s.length() == 0 && s.data() == nullptr)); } { int* p = nullptr; auto workaround_macro = [=]() { const multi_span s{p, 2}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_pointer_constructor") { int arr[4] = {1, 2, 3, 4}; { multi_span s{&arr[0], &arr[2]}; CHECK((s.length() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { multi_span s{&arr[0], &arr[2]}; CHECK((s.length() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { multi_span s{&arr[0], &arr[0]}; CHECK((s.length() == 0 && s.data() == &arr[0])); } { multi_span s{&arr[0], &arr[0]}; CHECK((s.length() == 0 && s.data() == &arr[0])); } { auto workaround_macro = [&]() { const multi_span s{&arr[1], &arr[0]}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; auto workaround_macro = [&]() { const multi_span s{&arr[0], p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; auto workaround_macro = [&]() { const multi_span s{p, p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; auto workaround_macro = [&]() { const multi_span s{&arr[0], p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("from_array_constructor") { int arr[5] = {1, 2, 3, 4, 5}; { multi_span s{arr}; CHECK((s.length() == 5 && s.data() == &arr[0])); } { multi_span s{arr}; CHECK((s.length() == 5 && s.data() == &arr[0])); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr}; #endif } { multi_span s{arr}; CHECK((s.length() == 0 && s.data() == &arr[0])); } int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; { multi_span s{arr2d}; CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); CHECK((s[0] == 1 && s[5] == 6)); } { multi_span s{arr2d}; CHECK((s.length() == 0 && s.data() == &arr2d[0][0])); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr2d}; #endif } { multi_span s{arr2d}; CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); CHECK((s[0] == 1 && s[5] == 6)); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr2d}; #endif } { multi_span s{arr2d[0]}; CHECK((s.length() == 1 && s.data() == &arr2d[0])); } { multi_span s{arr2d}; CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); auto workaround_macro = [&]() { return s[{1, 2}] == 6; }; CHECK(workaround_macro()); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr2d}; #endif } int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; { multi_span s{arr3d}; CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); CHECK((s[0] == 1 && s[11] == 12)); } { multi_span s{arr3d}; CHECK((s.length() == 0 && s.data() == &arr3d[0][0][0])); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr3d}; #endif } { multi_span s{arr3d}; CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); CHECK((s[0] == 1 && s[5] == 6)); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr3d}; #endif } { multi_span s{arr3d[0]}; CHECK((s.length() == 1 && s.data() == &arr3d[0])); } { multi_span s{arr3d}; CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); auto workaround_macro = [&]() { return s[{2, 1, 0}] == 11; }; CHECK(workaround_macro()); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr3d}; #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(i.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("from_dynamic_array_constructor") { double(*arr)[3][4] = new double[100][3][4]; { multi_span s(arr, 10); CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); CHECK_THROWS_AS(s[10][3][4], fail_fast); } { multi_span s(arr, 10); CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); } { multi_span s(arr, 10); CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); } { multi_span s(arr, 0); CHECK((s.length() == 0 && s.data() == &arr[0][0][0])); } delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: Attribute TEST_CASE("from_std_array_constructor") { std::array arr = {1, 2, 3, 4}; { multi_span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); multi_span cs{arr}; CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); multi_span cs{arr}; CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == 2 && s.data() == arr.data())); multi_span cs{arr}; CHECK((cs.size() == 2 && cs.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == 0 && s.data() == arr.data())); multi_span cs{arr}; CHECK((cs.size() == 0 && cs.data() == arr.data())); } // TODO This is currently an unsupported scenario. We will come back to it as we revise // the multidimensional interface and what transformations between dimensionality look like //{ // multi_span s{arr}; // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); //} { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr}; #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_an_array = []() { return std::array{1, 2, 3, 4}; }; auto take_a_span = [](multi_span s) { (void) s; }; // try to take a temporary std::array take_a_span(get_an_array()); #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_const_std_array_constructor") { const std::array arr = {1, 2, 3, 4}; { multi_span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == 2 && s.data() == arr.data())); } { multi_span s{arr}; CHECK((s.size() == 0 && s.data() == arr.data())); } // TODO This is currently an unsupported scenario. We will come back to it as we revise // the multidimensional interface and what transformations between dimensionality look like //{ // multi_span s{arr}; // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); //} { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{arr}; #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; auto take_a_span = [](multi_span s) { (void) s; }; // try to take a temporary std::array take_a_span(get_an_array()); #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_container_constructor") { std::vector v = {1, 2, 3}; const std::vector cv = v; { multi_span s{v}; CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); multi_span cs{v}; CHECK((cs.size() == narrow_cast(v.size()) && cs.data() == v.data())); } std::string str = "hello"; const std::string cstr = "hello"; { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{str}; CHECK((s.size() == narrow_cast(str.size()) && s.data() == str.data())); #endif multi_span cs{str}; CHECK((cs.size() == narrow_cast(str.size()) && cs.data() == str.data())); } { #ifdef CONFIRM_COMPILATION_ERRORS multi_span s{cstr}; #endif multi_span cs{cstr}; CHECK((cs.size() == narrow_cast(cstr.size()) && cs.data() == cstr.data())); } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_vector = []() -> std::vector { return {}; }; auto use_span = [](multi_span s) { (void) s; }; use_span(get_temp_vector()); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_string = []() -> std::string { return {}; }; auto use_span = [](multi_span s) { (void) s; }; use_span(get_temp_string()); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_vector = []() -> const std::vector { return {}; }; auto use_span = [](multi_span s) { (void) s; }; use_span(get_temp_vector()); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_string = []() -> const std::string { return {}; }; auto use_span = [](multi_span s) { (void) s; }; use_span(get_temp_string()); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS std::map m; multi_span s{m}; #endif } } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_convertible_span_constructor") { #ifdef CONFIRM_COMPILATION_ERRORS multi_span av1(nullptr, b1); auto f = [&]() { multi_span av1(nullptr); }; CHECK_THROWS_AS(f(), fail_fast); #endif #ifdef CONFIRM_COMPILATION_ERRORS static_bounds b12(b11); b12 = b11; b11 = b12; multi_span av1 = nullptr; multi_span av2(av1); multi_span av2(av1); #endif multi_span avd; #ifdef CONFIRM_COMPILATION_ERRORS multi_span avb = avd; #endif multi_span avcd = avd; (void) avcd; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("copy_move_and_assignment") { multi_span s1; CHECK(s1.empty()); int arr[] = {3, 4, 5}; multi_span s2 = arr; CHECK((s2.length() == 3 && s2.data() == &arr[0])); s2 = s1; CHECK(s2.empty()); auto get_temp_span = [&]() -> multi_span { return {&arr[1], 2}; }; auto use_span = [&](multi_span s) { CHECK((s.length() == 2 && s.data() == &arr[1])); }; use_span(get_temp_span()); s1 = get_temp_span(); CHECK((s1.length() == 2 && s1.data() == &arr[1])); } template void fn(const Bounds&) { static_assert(Bounds::static_size == 60, "static bounds is wrong size"); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_multi_span_reshape") { int a[3][4][5]; auto av = as_multi_span(a); fn(av.bounds()); auto av2 = as_multi_span(av, dim<60>()); auto av3 = as_multi_span(av2, dim<3>(), dim<4>(), dim<5>()); auto av4 = as_multi_span(av3, dim<4>(), dim(3), dim<5>()); auto av5 = as_multi_span(av4, dim<3>(), dim<4>(), dim<5>()); auto av6 = as_multi_span(av5, dim<12>(), dim(5)); fill(av6.begin(), av6.end(), 1); auto av7 = as_bytes(av6); auto av8 = as_multi_span(av7); CHECK(av8.size() == av6.size()); for (auto i = 0; i < av8.size(); i++) { CHECK(av8[i] == 1); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("first") { int arr[5] = {1, 2, 3, 4, 5}; { multi_span av = arr; CHECK((av.first<2>().bounds() == static_bounds<2>())); CHECK(av.first<2>().length() == 2); CHECK(av.first(2).length() == 2); } { multi_span av = arr; CHECK((av.first<0>().bounds() == static_bounds<0>())); CHECK(av.first<0>().length() == 0); CHECK(av.first(0).length() == 0); } { multi_span av = arr; CHECK((av.first<5>().bounds() == static_bounds<5>())); CHECK(av.first<5>().length() == 5); CHECK(av.first(5).length() == 5); } { multi_span av = arr; #ifdef CONFIRM_COMPILATION_ERRORS CHECK(av.first<6>().bounds() == static_bounds<6>()); CHECK(av.first<6>().length() == 6); CHECK(av.first<-1>().length() == -1); #endif CHECK_THROWS_AS(av.first(6).length(), fail_fast); } { multi_span av; CHECK((av.first<0>().bounds() == static_bounds<0>())); CHECK(av.first<0>().length() == 0); CHECK(av.first(0).length() == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("last") { int arr[5] = {1, 2, 3, 4, 5}; { multi_span av = arr; CHECK((av.last<2>().bounds() == static_bounds<2>())); CHECK(av.last<2>().length() == 2); CHECK(av.last(2).length() == 2); } { multi_span av = arr; CHECK((av.last<0>().bounds() == static_bounds<0>())); CHECK(av.last<0>().length() == 0); CHECK(av.last(0).length() == 0); } { multi_span av = arr; CHECK((av.last<5>().bounds() == static_bounds<5>())); CHECK(av.last<5>().length() == 5); CHECK(av.last(5).length() == 5); } { multi_span av = arr; #ifdef CONFIRM_COMPILATION_ERRORS CHECK((av.last<6>().bounds() == static_bounds<6>())); CHECK(av.last<6>().length() == 6); #endif CHECK_THROWS_AS(av.last(6).length(), fail_fast); } { multi_span av; CHECK((av.last<0>().bounds() == static_bounds<0>())); CHECK(av.last<0>().length() == 0); CHECK(av.last(0).length() == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("subspan") { int arr[5] = {1, 2, 3, 4, 5}; { multi_span av = arr; CHECK((av.subspan<2, 2>().bounds() == static_bounds<2>())); CHECK((av.subspan<2, 2>().length() == 2)); CHECK(av.subspan(2, 2).length() == 2); CHECK(av.subspan(2, 3).length() == 3); } { multi_span av = arr; CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); CHECK((av.subspan<0, 0>().length() == 0)); CHECK(av.subspan(0, 0).length() == 0); } { multi_span av = arr; CHECK((av.subspan<0, 5>().bounds() == static_bounds<5>())); CHECK((av.subspan<0, 5>().length() == 5)); CHECK(av.subspan(0, 5).length() == 5); CHECK_THROWS_AS(av.subspan(0, 6).length(), fail_fast); CHECK_THROWS_AS(av.subspan(1, 5).length(), fail_fast); } { multi_span av = arr; CHECK((av.subspan<5, 0>().bounds() == static_bounds<0>())); CHECK((av.subspan<5, 0>().length() == 0)); CHECK(av.subspan(5, 0).length() == 0); CHECK_THROWS_AS(av.subspan(6, 0).length(), fail_fast); } { multi_span av; CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); CHECK((av.subspan<0, 0>().length() == 0)); CHECK(av.subspan(0, 0).length() == 0); CHECK_THROWS_AS((av.subspan<1, 0>().length()), fail_fast); } { multi_span av; CHECK(av.subspan(0).length() == 0); CHECK_THROWS_AS(av.subspan(1).length(), fail_fast); } { multi_span av = arr; CHECK(av.subspan(0).length() == 5); CHECK(av.subspan(1).length() == 4); CHECK(av.subspan(4).length() == 1); CHECK(av.subspan(5).length() == 0); CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } { multi_span av = arr; CHECK(av.subspan(0).length() == 5); CHECK(av.subspan(1).length() == 4); CHECK(av.subspan(4).length() == 1); CHECK(av.subspan(5).length() == 0); CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("rank") { int arr[2] = {1, 2}; { multi_span s; CHECK(s.rank() == 1); } { multi_span s = arr; CHECK(s.rank() == 1); } int arr2d[1][1] = {}; { multi_span s = arr2d; CHECK(s.rank() == 2); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("extent") { { multi_span s; CHECK(s.extent() == 0); CHECK(s.extent(0) == 0); CHECK_THROWS_AS(s.extent(1), fail_fast); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(s.extent<1>() == 0); #endif } { multi_span s; CHECK(s.extent() == 0); CHECK(s.extent(0) == 0); CHECK_THROWS_AS(s.extent(1), fail_fast); } { int arr2d[1][2] = {}; multi_span s = arr2d; CHECK(s.extent() == 1); CHECK(s.extent<0>() == 1); CHECK(s.extent<1>() == 2); CHECK(s.extent(0) == 1); CHECK(s.extent(1) == 2); CHECK_THROWS_AS(s.extent(3), fail_fast); } { int arr2d[1][2] = {}; multi_span s = arr2d; CHECK(s.extent() == 0); CHECK(s.extent<0>() == 0); CHECK(s.extent<1>() == 2); CHECK(s.extent(0) == 0); CHECK(s.extent(1) == 2); CHECK_THROWS_AS(s.extent(3), fail_fast); } } TEST_CASE("operator_function_call") { int arr[4] = {1, 2, 3, 4}; { multi_span s = arr; CHECK(s(0) == 1); CHECK_THROWS_AS(s(5), fail_fast); } int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; { multi_span s = arr2d; CHECK(s(0, 0) == 1); CHECK(s(0, 1) == 2); CHECK(s(1, 2) == 6); } int arr3d[2][2][2] = {1, 2, 3, 4, 5, 6, 7, 8}; { multi_span s = arr3d; CHECK(s(0, 0, 0) == 1); CHECK(s(1, 1, 1) == 8); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("comparison_operators") { { int arr[10][2]; auto s1 = as_multi_span(arr); multi_span s2 = s1; CHECK(s1 == s2); multi_span s3 = as_multi_span(s1, dim(20)); CHECK((s3 == s2 && s3 == s1)); } { multi_span s1 = nullptr; multi_span s2 = nullptr; CHECK(s1 == s2); CHECK(!(s1 != s2)); CHECK(!(s1 < s2)); CHECK(s1 <= s2); CHECK(!(s1 > s2)); CHECK(s1 >= s2); CHECK(s2 == s1); CHECK(!(s2 != s1)); CHECK(!(s2 < s1)); CHECK(s2 <= s1); CHECK(!(s2 > s1)); CHECK(s2 >= s1); } { int arr[] = {2, 1}; // bigger multi_span s1 = nullptr; multi_span s2 = arr; CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } { int arr1[] = {1, 2}; int arr2[] = {1, 2}; multi_span s1 = arr1; multi_span s2 = arr2; CHECK(s1 == s2); CHECK(!(s1 != s2)); CHECK(!(s1 < s2)); CHECK(s1 <= s2); CHECK(!(s1 > s2)); CHECK(s1 >= s2); CHECK(s2 == s1); CHECK(!(s2 != s1)); CHECK(!(s2 < s1)); CHECK(s2 <= s1); CHECK(!(s2 > s1)); CHECK(s2 >= s1); } { int arr[] = {1, 2, 3}; multi_span s1 = {&arr[0], 2}; // shorter multi_span s2 = arr; // longer CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } { int arr1[] = {1, 2}; // smaller int arr2[] = {2, 1}; // bigger multi_span s1 = arr1; multi_span s2 = arr2; CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(i.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("basics") { auto ptr = as_multi_span(new int[10], 10); fill(ptr.begin(), ptr.end(), 99); for (int num : ptr) { CHECK(num == 99); } delete[] ptr.data(); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("bounds_checks") { int arr[10][2]; auto av = as_multi_span(arr); fill(begin(av), end(av), 0); av[2][0] = 1; av[1][1] = 3; // out of bounds CHECK_THROWS_AS(av[1][3] = 3, fail_fast); CHECK_THROWS_AS((av[{1, 3}] = 3), fail_fast); CHECK_THROWS_AS(av[10][2], fail_fast); CHECK_THROWS_AS((av[{10, 2}]), fail_fast); CHECK_THROWS_AS(av[-1][0], fail_fast); CHECK_THROWS_AS((av[{-1, 0}]), fail_fast); CHECK_THROWS_AS(av[0][-1], fail_fast); CHECK_THROWS_AS((av[{0, -1}]), fail_fast); } void overloaded_func(multi_span exp, int expected_value) { for (auto val : exp) { CHECK(val == expected_value); } } void overloaded_func(multi_span exp, char expected_value) { for (auto val : exp) { CHECK(val == expected_value); } } void fixed_func(multi_span exp, int expected_value) { for (auto val : exp) { CHECK(val == expected_value); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute TEST_CASE("span_parameter_test") { auto data = new int[4][3][5]; auto av = as_multi_span(data, 4); CHECK(av.size() == 60); fill(av.begin(), av.end(), 34); int count = 0; for_each(av.rbegin(), av.rend(), [&](int val) { count += val; }); CHECK(count == 34 * 60); overloaded_func(av, 34); overloaded_func(as_multi_span(av, dim(4), dim(3), dim(5)), 34); // fixed_func(av, 34); delete[] data; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // false positive, checker does not recognize multi_span yet GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute TEST_CASE("md_access") { auto width = 5, height = 20; auto imgSize = width * height; auto image_ptr = new int[narrow_cast(imgSize)][3]; // size check will be done auto image_view = as_multi_span(as_multi_span(image_ptr, imgSize), dim(height), dim(width), dim<3>()); iota(image_view.begin(), image_view.end(), 1); int expected = 0; for (auto i = 0; i < height; i++) { for (auto j = 0; j < width; j++) { CHECK(expected + 1 == image_view[i][j][0]); CHECK(expected + 2 == image_view[i][j][1]); CHECK(expected + 3 == image_view[i][j][2]); auto val = image_view[{i, j, 0}]; CHECK(expected + 1 == val); val = image_view[{i, j, 1}]; CHECK(expected + 2 == val); val = image_view[{i, j, 2}]; CHECK(expected + 3 == val); expected += 3; } } delete[] image_ptr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute GSL_SUPPRESS(i.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute TEST_CASE("as_multi_span") { { int* arr = new int[150]; auto av = as_multi_span(arr, dim<10>(), dim(3), dim<5>()); fill(av.begin(), av.end(), 24); overloaded_func(av, 24); delete[] arr; array stdarr{0}; auto av2 = as_multi_span(stdarr); overloaded_func(as_multi_span(av2, dim(1), dim<3>(), dim<5>()), 0); string str = "ttttttttttttttt"; // size = 15 auto t = str.data(); GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) t; auto av3 = as_multi_span(str); overloaded_func(as_multi_span(av3, dim(1), dim<3>(), dim<5>()), 't'); } { string str; multi_span strspan = as_multi_span(str); (void) strspan; const string cstr; multi_span cstrspan = as_multi_span(cstr); (void) cstrspan; } { int a[3][4][5]; auto av = as_multi_span(a); const int(*b)[4][5]; b = a; auto bv = as_multi_span(b, 3); CHECK(av == bv); const std::array arr = {0.0, 0.0, 0.0}; auto cv = as_multi_span(arr); (void) cv; vector vec(3); auto dv = as_multi_span(vec); (void) dv; #ifdef CONFIRM_COMPILATION_ERRORS auto dv2 = as_multi_span(std::move(vec)); #endif } } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("empty_spans") { { multi_span empty_av(nullptr); CHECK(empty_av.bounds().index_bounds() == multi_span_index<1>{0}); CHECK_THROWS_AS(empty_av[0], fail_fast); CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); for (auto& v : empty_av) { (void) v; CHECK(false); } } { multi_span empty_av = {}; CHECK(empty_av.bounds().index_bounds() == multi_span_index<1>{0}); CHECK_THROWS_AS(empty_av[0], fail_fast); CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); for (auto& v : empty_av) { (void) v; CHECK(false); } } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("index_constructor") { auto arr = new int[8]; for (int i = 0; i < 4; ++i) { arr[2 * i] = 4 + i; arr[2 * i + 1] = i; } multi_span av(arr, 8); ptrdiff_t a[1] = {0}; multi_span_index<1> i = a; CHECK(av[i] == 4); auto av2 = as_multi_span(av, dim<4>(), dim(2)); ptrdiff_t a2[2] = {0, 1}; multi_span_index<2> i2 = a2; CHECK(av2[i2] == 0); CHECK(av2[0][i] == 4); delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("index_constructors") { { // components of the same type multi_span_index<3> i1(0, 1, 2); CHECK(i1[0] == 0); // components of different types std::size_t c0 = 0; std::size_t c1 = 1; multi_span_index<3> i2(c0, c1, 2); CHECK(i2[0] == 0); // from array multi_span_index<3> i3 = {0, 1, 2}; CHECK(i3[0] == 0); // from other index of the same size type multi_span_index<3> i4 = i3; CHECK(i4[0] == 0); // default multi_span_index<3> i7; CHECK(i7[0] == 0); // default multi_span_index<3> i9 = {}; CHECK(i9[0] == 0); } { // components of the same type multi_span_index<1> i1(0); CHECK(i1[0] == 0); // components of different types std::size_t c0 = 0; multi_span_index<1> i2(c0); CHECK(i2[0] == 0); // from array multi_span_index<1> i3 = {0}; CHECK(i3[0] == 0); // from int multi_span_index<1> i4 = 0; CHECK(i4[0] == 0); // from other index of the same size type multi_span_index<1> i5 = i3; CHECK(i5[0] == 0); // default multi_span_index<1> i8; CHECK(i8[0] == 0); // default multi_span_index<1> i9 = {}; CHECK(i9[0] == 0); } #ifdef CONFIRM_COMPILATION_ERRORS { multi_span_index<3> i1(0, 1); multi_span_index<3> i2(0, 1, 2, 3); multi_span_index<3> i3 = {0}; multi_span_index<3> i4 = {0, 1, 2, 3}; multi_span_index<1> i5 = {0, 1}; } #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("index_operations") { ptrdiff_t a[3] = {0, 1, 2}; ptrdiff_t b[3] = {3, 4, 5}; multi_span_index<3> i = a; multi_span_index<3> j = b; CHECK(i[0] == 0); CHECK(i[1] == 1); CHECK(i[2] == 2); { multi_span_index<3> k = i + j; CHECK(i[0] == 0); CHECK(i[1] == 1); CHECK(i[2] == 2); CHECK(k[0] == 3); CHECK(k[1] == 5); CHECK(k[2] == 7); } { multi_span_index<3> k = i * 3; CHECK(i[0] == 0); CHECK(i[1] == 1); CHECK(i[2] == 2); CHECK(k[0] == 0); CHECK(k[1] == 3); CHECK(k[2] == 6); } { multi_span_index<3> k = 3 * i; CHECK(i[0] == 0); CHECK(i[1] == 1); CHECK(i[2] == 2); CHECK(k[0] == 0); CHECK(k[1] == 3); CHECK(k[2] == 6); } { multi_span_index<2> k = details::shift_left(i); CHECK(i[0] == 0); CHECK(i[1] == 1); CHECK(i[2] == 2); CHECK(k[0] == 1); CHECK(k[1] == 2); } } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute void iterate_second_column(multi_span av) { auto length = av.size() / 2; // view to the second column auto section = av.section({0, 1}, {length, 1}); CHECK(section.size() == length); for (auto i = 0; i < section.size(); ++i) { CHECK(section[i][0] == av[i][1]); } for (auto i = 0; i < section.size(); ++i) { auto idx = multi_span_index<2>{i, 0}; // avoid braces inside the CHECK macro CHECK(section[idx] == av[i][1]); } CHECK(section.bounds().index_bounds()[0] == length); CHECK(section.bounds().index_bounds()[1] == 1); for (auto i = 0; i < section.bounds().index_bounds()[0]; ++i) { for (auto j = 0; j < section.bounds().index_bounds()[1]; ++j) { auto idx = multi_span_index<2>{i, j}; // avoid braces inside the CHECK macro CHECK(section[idx] == av[i][1]); } } auto check_sum = 0; for (auto i = 0; i < length; ++i) { check_sum += av[i][1]; } { auto idx = 0; auto sum = 0; for (auto num : section) { CHECK(num == av[idx][1]); sum += num; idx++; } CHECK(sum == check_sum); } { auto idx = length - 1; auto sum = 0; for (auto iter = section.rbegin(); iter != section.rend(); ++iter) { CHECK(*iter == av[idx][1]); sum += *iter; idx--; } CHECK(sum == check_sum); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("span_section_iteration") { int arr[4][2] = {{4, 0}, {5, 1}, {6, 2}, {7, 3}}; // static bounds { multi_span av = arr; iterate_second_column(av); } // first bound is dynamic { multi_span av = arr; iterate_second_column(av); } // second bound is dynamic { multi_span av = arr; iterate_second_column(av); } // both bounds are dynamic { multi_span av = arr; iterate_second_column(av); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("dynamic_span_section_iteration") { auto height = 4, width = 2; auto size = height * width; auto arr = new int[narrow_cast(size)]; for (auto i = 0; i < size; ++i) { arr[i] = i; } auto av = as_multi_span(arr, size); // first bound is dynamic { multi_span av2 = as_multi_span(av, dim(height), dim(width)); iterate_second_column(av2); } // second bound is dynamic { multi_span av2 = as_multi_span(av, dim(height), dim(width)); iterate_second_column(av2); } // both bounds are dynamic { multi_span av2 = as_multi_span(av, dim(height), dim(width)); iterate_second_column(av2); } delete[] arr; } GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(i.11) // NO-FORMAT: attribute TEST_CASE("span_structure_size") { double(*arr)[3][4] = new double[100][3][4]; multi_span av1(arr, 10); struct EffectiveStructure { double* v1; ptrdiff_t v2; }; CHECK(sizeof(av1) == sizeof(EffectiveStructure)); CHECK_THROWS_AS(av1[10][3][4], fail_fast); multi_span av2 = as_multi_span(av1, dim(5), dim<6>(), dim<4>()); (void) av2; delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; // converting to an multi_span from an equal size array is ok multi_span av4 = arr; CHECK(av4.length() == 4); // converting to dynamic_range a_v is always ok { multi_span av = av4; (void) av; } { multi_span av = arr; (void) av; } // initialization or assignment to static multi_span that REDUCES size is NOT ok #ifdef CONFIRM_COMPILATION_ERRORS { multi_span av2 = arr; } { multi_span av2 = av4; } #endif { multi_span av = arr; multi_span av2 = av; (void) av2; } #ifdef CONFIRM_COMPILATION_ERRORS { multi_span av = arr; multi_span av2 = av.as_multi_span(dim<2>(), dim<2>()); } #endif { multi_span av = arr; multi_span av2 = as_multi_span(av, dim(2), dim(2)); auto workaround_macro = [&]() { return av2[{1, 0}] == 2; }; CHECK(workaround_macro()); } // but doing so explicitly is ok // you can convert statically { multi_span av2 = {arr, 2}; (void) av2; } { multi_span av2 = av4.first<1>(); (void) av2; } // ...or dynamically { // NB: implicit conversion to multi_span from multi_span multi_span av2 = av4.first(1); (void) av2; } // initialization or assignment to static multi_span that requires size INCREASE is not ok. int arr2[2] = {1, 2}; #ifdef CONFIRM_COMPILATION_ERRORS { multi_span av4 = arr2; } { multi_span av2 = arr2; multi_span av4 = av2; } #endif { auto f = [&]() { const multi_span av9 = {arr2, 2}; (void) av9; }; CHECK_THROWS_AS(f(), fail_fast); } // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one multi_span av = arr2; auto f = [&]() { const multi_span av2 = av; (void) av2; }; CHECK_THROWS_AS(f(), fail_fast); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; { #ifdef CONFIRM_COMPILATION_ERRORS // you should not be able to get writeable bytes for const objects multi_span av = a; auto wav = av.as_writeable_bytes(); #endif } { multi_span av; auto wav = as_writeable_bytes(av); CHECK(wav.length() == av.length()); CHECK(wav.length() == 0); CHECK(wav.size_bytes() == 0); } { multi_span av = a; auto wav = as_writeable_bytes(av); CHECK(wav.data() == reinterpret_cast(&a[0])); CHECK(static_cast(wav.length()) == sizeof(a)); } } GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator") { int a[] = {1, 2, 3, 4}; { multi_span av = a; auto wav = as_writeable_bytes(av); for (auto& b : wav) { #if defined(__cplusplus) && (__cplusplus >= 201703L) b = byte{0}; #else GSL_SUPPRESS(es.49) b = byte(0); #endif } for (std::size_t i = 0; i < 4; ++i) { CHECK(a[i] == 0); } } { multi_span av = a; for (auto& n : av) { n = 1; } for (std::size_t i = 0; i < 4; ++i) { CHECK(a[i] == 1); } } } #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif #if __clang__ || __GNUC__ #pragma GCC diagnostic pop #endif GSL-2.1.0/tests/no_exception_ensure_tests.cpp000066400000000000000000000026131356460337500213200ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #include // for std::exit #include // for span int operator_subscript_no_throw() noexcept { int arr[10]; const gsl::span sp{arr}; return sp[11]; } [[noreturn]] void test_terminate() { std::exit(0); } void setup_termination_handler() noexcept { #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) auto& handler = gsl::details::get_terminate_handler(); handler = &test_terminate; #else std::set_terminate(test_terminate); #endif } int main() noexcept { setup_termination_handler(); operator_subscript_no_throw(); return -1; } GSL-2.1.0/tests/no_exception_throw_tests.cpp000066400000000000000000000026641356460337500211700ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #include // for std::exit #include // for get_terminate #include // for narrow int narrow_no_throw() { const long long bigNumber = 0x0fffffffffffffff; return gsl::narrow(bigNumber); } [[noreturn]] void test_terminate() { std::exit(0); } void setup_termination_handler() noexcept { #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) auto& handler = gsl::details::get_terminate_handler(); handler = &test_terminate; #else std::set_terminate(test_terminate); #endif } int main() { setup_termination_handler(); narrow_no_throw(); return -1; } GSL-2.1.0/tests/notnull_tests.cpp000066400000000000000000000362141356460337500167440ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch // Fix VS2015 build breaks in Release #pragma warning(disable : 4702) // unreachable code #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for not_null, operator<, operator<=, operator> #include // for addressof #include // for shared_ptr, make_shared, operator<, opera... #include // for operator<<, ostringstream, basic_ostream:... #include // for uint16_t #include // for basic_string, operator==, string, operator<< #include // for type_info namespace gsl { struct fail_fast; } // namespace gsl using namespace gsl; struct MyBase { }; struct MyDerived : public MyBase { }; struct Unrelated { }; // stand-in for a user-defined ref-counted class template struct RefCounted { RefCounted(T* p) : p_(p) {} operator T*() { return p_; } T* p_; }; // user defined smart pointer with comparison operators returning non bool value template struct CustomPtr { CustomPtr(T* p) : p_(p) {} operator T*() { return p_; } bool operator!=(std::nullptr_t) const { return p_ != nullptr; } T* p_ = nullptr; }; template std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) == reinterpret_cast(rhs.p_) ? "true" : "false"; } template std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) != reinterpret_cast(rhs.p_) ? "true" : "false"; } template std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) < reinterpret_cast(rhs.p_) ? "true" : "false"; } template std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) > reinterpret_cast(rhs.p_) ? "true" : "false"; } template std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) <= reinterpret_cast(rhs.p_) ? "true" : "false"; } template std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) >= reinterpret_cast(rhs.p_) ? "true" : "false"; } struct NonCopyableNonMovable { NonCopyableNonMovable() = default; NonCopyableNonMovable(const NonCopyableNonMovable&) = delete; NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete; NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper(not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper_const(not_null p) { return *p == 12; } int* return_pointer() { return nullptr; } const int* return_pointer_const() { return nullptr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullConstructors") { { #ifdef CONFIRM_COMPILATION_ERRORS not_null p = nullptr; // yay...does not compile! not_null*> p1 = 0; // yay...does not compile! not_null p2; // yay...does not compile! std::unique_ptr up = std::make_unique(120); not_null p3 = up; // Forbid non-nullptr assignable types not_null> f(std::vector{1}); not_null z(10); not_null> y({1, 2}); #endif } { // from shared pointer int i = 12; auto rp = RefCounted(&i); not_null p(rp); CHECK(p.get() == &i); not_null> x( std::make_shared(10)); // shared_ptr is nullptr assignable int* pi = nullptr; CHECK_THROWS_AS(not_null(pi), fail_fast); } { // from pointer to local int t = 42; not_null x = &t; helper(&t); helper_const(&t); CHECK(*x == 42); } { // from raw pointer // from not_null pointer int t = 42; int* p = &t; not_null x = p; helper(p); helper_const(p); helper(x); helper_const(x); CHECK(*x == 42); } { // from raw const pointer // from not_null const pointer int t = 42; const int* cp = &t; not_null x = cp; helper_const(cp); helper_const(x); CHECK(*x == 42); } { // from not_null const pointer, using auto int t = 42; const int* cp = &t; auto x = not_null{cp}; CHECK(*x == 42); } { // from returned pointer CHECK_THROWS_AS(helper(return_pointer()), fail_fast); CHECK_THROWS_AS(helper_const(return_pointer()), fail_fast); } } template GSL_SUPPRESS(con.4) // NO-FORMAT: attribute void ostream_helper(T v) { not_null p(&v); { std::ostringstream os; std::ostringstream ref; os << static_cast(p); ref << static_cast(&v); CHECK(os.str() == ref.str()); } { std::ostringstream os; std::ostringstream ref; os << *p; ref << v; CHECK(os.str() == ref.str()); } } TEST_CASE("TestNotNullostream") { ostream_helper(17); ostream_helper(21.5f); ostream_helper(3.4566e-7); ostream_helper('c'); ostream_helper(0x0123u); ostream_helper("cstring"); ostream_helper("string"); } GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullCasting") { MyBase base; MyDerived derived; Unrelated unrelated; not_null u{&unrelated}; (void) u; not_null p{&derived}; not_null q(&base); q = p; // allowed with heterogeneous copy ctor CHECK(q == p); #ifdef CONFIRM_COMPILATION_ERRORS q = u; // no viable conversion possible between MyBase* and Unrelated* p = q; // not possible to implicitly convert MyBase* to MyDerived* not_null r = p; not_null s = reinterpret_cast(p); #endif not_null t(reinterpret_cast(p.get())); CHECK(reinterpret_cast(p.get()) == reinterpret_cast(t.get())); } TEST_CASE("TestNotNullAssignment") { int i = 12; not_null p(&i); CHECK(helper(p)); int* q = nullptr; CHECK_THROWS_AS(p = not_null(q), fail_fast); } TEST_CASE("TestNotNullRawPointerComparison") { int ints[2] = {42, 43}; int* p1 = &ints[0]; const int* p2 = &ints[1]; using NotNull1 = not_null; using NotNull2 = not_null; CHECK((NotNull1(p1) == NotNull1(p1)) == true); CHECK((NotNull1(p1) == NotNull2(p2)) == false); CHECK((NotNull1(p1) != NotNull1(p1)) == false); CHECK((NotNull1(p1) != NotNull2(p2)) == true); CHECK((NotNull1(p1) < NotNull1(p1)) == false); CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); CHECK((NotNull1(p1) > NotNull1(p1)) == false); CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); CHECK((NotNull1(p1) <= NotNull1(p1)) == true); CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullDereferenceOperator") { { auto sp1 = std::make_shared(); using NotNullSp1 = not_null; CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); } { int ints[1] = {42}; CustomPtr p1(&ints[0]); using NotNull1 = not_null; CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); CHECK(*NotNull1(p1) == 42); *NotNull1(p1) = 43; CHECK(ints[0] == 43); } { int v = 42; gsl::not_null p(&v); CHECK(typeid(*p) == typeid(*(&v))); *p = 43; CHECK(v == 43); } } TEST_CASE("TestNotNullSharedPtrComparison") { auto sp1 = std::make_shared(42); auto sp2 = std::make_shared(43); using NotNullSp1 = not_null; using NotNullSp2 = not_null; CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullCustomPtrComparison") { int ints[2] = {42, 43}; CustomPtr p1(&ints[0]); CustomPtr p2(&ints[1]); using NotNull1 = not_null; using NotNull2 = not_null; CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); } #if defined(__cplusplus) && (__cplusplus >= 201703L) GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullConstructorTypeDeduction") { { int i = 42; not_null x{&i}; helper(not_null{&i}); helper_const(not_null{&i}); CHECK(*x == 42); } { int i = 42; int* p = &i; not_null x{p}; helper(not_null{p}); helper_const(not_null{p}); CHECK(*x == 42); } { auto workaround_macro = []() { int* p1 = nullptr; const not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { auto workaround_macro = []() { const int* p1 = nullptr; const not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; CHECK_THROWS_AS(helper(not_null{p}), fail_fast); CHECK_THROWS_AS(helper_const(not_null{p}), fail_fast); } #ifdef CONFIRM_COMPILATION_ERRORS { not_null x{nullptr}; helper(not_null{nullptr}); helper_const(not_null{nullptr}); } #endif } #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) TEST_CASE("TestMakeNotNull") { { int i = 42; const auto x = make_not_null(&i); helper(make_not_null(&i)); helper_const(make_not_null(&i)); CHECK(*x == 42); } { int i = 42; int* p = &i; const auto x = make_not_null(p); helper(make_not_null(p)); helper_const(make_not_null(p)); CHECK(*x == 42); } { const auto workaround_macro = []() { int* p1 = nullptr; const auto x = make_not_null(p1); CHECK(*x == 42); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { const auto workaround_macro = []() { const int* p1 = nullptr; const auto x = make_not_null(p1); CHECK(*x == 42); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; CHECK_THROWS_AS(helper(make_not_null(p)), fail_fast); CHECK_THROWS_AS(helper_const(make_not_null(p)), fail_fast); } #ifdef CONFIRM_COMPILATION_ERRORS { CHECK_THROWS_AS(make_not_null(nullptr), fail_fast); CHECK_THROWS_AS(helper(make_not_null(nullptr)), fail_fast); CHECK_THROWS_AS(helper_const(make_not_null(nullptr)), fail_fast); } #endif } static_assert(std::is_nothrow_move_constructible>::value, "not_null must be no-throw move constructible"); GSL-2.1.0/tests/owner_tests.cpp000066400000000000000000000032041356460337500163740ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for owner using namespace gsl; GSL_SUPPRESS(f.23) // NO-FORMAT: attribute void f(int* i) { *i += 1; } GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute // TODO: false positive GSL_SUPPRESS(r.5) // NO-FORMAT: attribute TEST_CASE("basic_test") { owner p = new int(120); CHECK(*p == 120); f(p); CHECK(*p == 121); delete p; } TEST_CASE("check_pointer_constraint") { #ifdef CONFIRM_COMPILATION_ERRORS { owner integerTest = 10; owner> sharedPtrTest(new int(10)); } #endif } GSL-2.1.0/tests/span_tests.cpp000066400000000000000000001141401356460337500162050ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426 26497) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for byte #include // for narrow_cast, at #include // for span, span_iterator, operator==, operator!= #include // for array #include // for ptrdiff_t #include // for reverse_iterator, operator-, operator== #include // for unique_ptr, shared_ptr, make_unique, allo... #include // for match_results, sub_match, match_results<>... #include // for ptrdiff_t #include // for string #include // for integral_constant<>::value, is_default_co... #include // for vector namespace gsl { struct fail_fast; } // namespace gsl using namespace std; using namespace gsl; namespace { struct BaseClass { }; struct DerivedClass : BaseClass { }; struct AddressOverloaded { #if (__cplusplus > 201402L) [[maybe_unused]] #endif AddressOverloaded operator&() const { return {}; } }; } // namespace GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("default_constructor") { { span s; CHECK((s.size() == 0 && s.data() == nullptr)); span cs; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { span s; CHECK((s.size() == 0 && s.data() == nullptr)); span cs; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { #ifdef CONFIRM_COMPILATION_ERRORS span s; CHECK((s.size() == 1 && s.data() == nullptr)); // explains why it can't compile #endif } { span s{}; CHECK((s.size() == 0 && s.data() == nullptr)); span cs{}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("size_optimization") { { span s; CHECK(sizeof(s) == sizeof(int*) + sizeof(ptrdiff_t)); } { span s; CHECK(sizeof(s) == sizeof(int*)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_nullptr_size_constructor") { { span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { auto workaround_macro = []() { const span s{nullptr, narrow_cast::index_type>(0)}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { auto workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); auto const_workaround_macro = []() { const span cs{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { auto workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); auto const_workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("from_pointer_length_constructor") { int arr[4] = {1, 2, 3, 4}; { for(int i = 0; i<4 ; ++i) { { span s = { &arr[0], i }; CHECK(s.size() == i); CHECK(s.data() == &arr[0]); CHECK(s.empty() == (i == 0)); for (int j = 0; j < i; ++j) { CHECK(arr[j] == s[j]); CHECK(arr[j] == s.at(j)); CHECK(arr[j] == s(j)); } } { span s = { &arr[i], 4-narrow_cast(i) }; CHECK(s.size() == 4-i); CHECK(s.data() == &arr[i]); CHECK(s.empty() == (4-i == 0)); for (int j = 0; j < 4-i; ++j) { CHECK(arr[j+i] == s[j]); CHECK(arr[j+i] == s.at(j)); CHECK(arr[j+i] == s(j)); } } } } { span s{&arr[0], 2}; CHECK((s.size() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { int* p = nullptr; span s{p, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); } { int* p = nullptr; auto workaround_macro = [=]() { const span s{p, 2}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { auto s = make_span(&arr[0], 2); CHECK((s.size() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { int* p = nullptr; auto s = make_span(p, narrow_cast::index_type>(0)); CHECK((s.size() == 0 && s.data() == nullptr)); } { int* p = nullptr; auto workaround_macro = [=]() { make_span(p, 2); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_pointer_constructor") { int arr[4] = {1, 2, 3, 4}; { span s{&arr[0], &arr[2]}; CHECK((s.size() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { span s{&arr[0], &arr[2]}; CHECK((s.size() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { span s{&arr[0], &arr[0]}; CHECK((s.size() == 0 && s.data() == &arr[0])); } { span s{&arr[0], &arr[0]}; CHECK((s.size() == 0 && s.data() == &arr[0])); } // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // auto workaround_macro = [&]() { span s{&arr[1], &arr[0]}; }; // CHECK_THROWS_AS(workaround_macro(), fail_fast); //} // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // int* p = nullptr; // auto workaround_macro = [&]() { span s{&arr[0], p}; }; // CHECK_THROWS_AS(workaround_macro(), fail_fast); //} { int* p = nullptr; span s{p, p}; CHECK((s.size() == 0 && s.data() == nullptr)); } { int* p = nullptr; span s{p, p}; CHECK((s.size() == 0 && s.data() == nullptr)); } // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // int* p = nullptr; // auto workaround_macro = [&]() { span s{&arr[0], p}; }; // CHECK_THROWS_AS(workaround_macro(), fail_fast); //} { auto s = make_span(&arr[0], &arr[2]); CHECK((s.size() == 2 && s.data() == &arr[0])); CHECK((s[0] == 1 && s[1] == 2)); } { auto s = make_span(&arr[0], &arr[0]); CHECK((s.size() == 0 && s.data() == &arr[0])); } { int* p = nullptr; auto s = make_span(p, p); CHECK((s.size() == 0 && s.data() == nullptr)); } } TEST_CASE("from_array_constructor") { int arr[5] = {1, 2, 3, 4, 5}; { const span s{arr}; CHECK((s.size() == 5 && s.data() == &arr[0])); } { const span s{arr}; CHECK((s.size() == 5 && s.data() == &arr[0])); } int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr}; } { span s{arr}; CHECK((s.size() == 0 && s.data() == &arr[0])); } { span s{arr2d}; CHECK((s.size() == 6 && s.data() == &arr2d[0][0])); CHECK((s[0] == 1 && s[5] == 6)); } { span s{arr2d}; CHECK((s.size() == 0 && s.data() == &arr2d[0][0])); } { span s{arr2d}; } #endif { const span s{std::addressof(arr2d[0]), 1}; CHECK((s.size() == 1 && s.data() == std::addressof(arr2d[0]))); } int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr3d}; CHECK((s.size() == 12 && s.data() == &arr3d[0][0][0])); CHECK((s[0] == 1 && s[11] == 12)); } { span s{arr3d}; CHECK((s.size() == 0 && s.data() == &arr3d[0][0][0])); } { span s{arr3d}; } { span s{arr3d}; CHECK((s.size() == 12 && s.data() == &arr3d[0][0][0])); CHECK((s[0] == 1 && s[5] == 6)); } #endif { const span s{std::addressof(arr3d[0]), 1}; CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0]))); } { const auto s = make_span(arr); CHECK((s.size() == 5 && s.data() == std::addressof(arr[0]))); } { const auto s = make_span(std::addressof(arr2d[0]), 1); CHECK((s.size() == 1 && s.data() == std::addressof(arr2d[0]))); } { const auto s = make_span(std::addressof(arr3d[0]), 1); CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0]))); } AddressOverloaded ao_arr[5] = {}; { const span s{ao_arr}; CHECK((s.size() == 5 && s.data() == std::addressof(ao_arr[0]))); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(i.11) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("from_dynamic_array_constructor") { double(*arr)[3][4] = new double[100][3][4]; { span s(&arr[0][0][0], 10); CHECK((s.size() == 10 && s.data() == &arr[0][0][0])); } { auto s = make_span(&arr[0][0][0], 10); CHECK((s.size() == 10 && s.data() == &arr[0][0][0])); } delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_std_array_constructor") { std::array arr = {1, 2, 3, 4}; { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); span cs{arr}; CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); span cs{arr}; CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } { std::array empty_arr{}; span s{empty_arr}; CHECK((s.size() == 0 && s.empty())); } std::array ao_arr{}; { span fs{ao_arr}; CHECK((fs.size() == narrow_cast(ao_arr.size()) && ao_arr.data() == fs.data())); } #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr}; CHECK((s.size() == 2 && s.data() == arr.data())); span cs{arr}; CHECK((cs.size() == 2 && cs.data() == arr.data())); } { span s{arr}; CHECK((s.size() == 0 && s.data() == arr.data())); span cs{arr}; CHECK((cs.size() == 0 && cs.data() == arr.data())); } { span s{arr}; } { auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; auto take_a_span = [](span s) { static_cast(s); }; // try to take a temporary std::array take_a_span(get_an_array()); } #endif { auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; auto take_a_span = [](span s) { static_cast(s); }; // try to take a temporary std::array take_a_span(get_an_array()); } { auto s = make_span(arr); CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 { span s1 = make_span(arr); static span s2; s2 = s1; #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) // Known to be broken in gcc 6.4 and 6.5 with optimizations // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 CHECK(s1.size() == 4); CHECK(s2.size() == 0); #else CHECK(s1.size() == s2.size()); #endif } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_const_std_array_constructor") { const std::array arr = {1, 2, 3, 4}; { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } const std::array ao_arr{}; { span s{ao_arr}; CHECK((s.size() == narrow_cast(ao_arr.size()) && s.data() == ao_arr.data())); } #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr}; CHECK((s.size() == 2 && s.data() == arr.data())); } { span s{arr}; CHECK((s.size() == 0 && s.data() == arr.data())); } { span s{arr}; } #endif { auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; auto take_a_span = [](span s) { static_cast(s); }; // try to take a temporary std::array take_a_span(get_an_array()); } { auto s = make_span(arr); CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_std_array_const_constructor") { std::array arr = {1, 2, 3, 4}; { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } { span s{arr}; CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr}; CHECK((s.size() == 2 && s.data() == arr.data())); } { span s{arr}; CHECK((s.size() == 0 && s.data() == arr.data())); } { span s{arr}; } { span s{arr}; } #endif { auto s = make_span(arr); CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_container_constructor") { std::vector v = {1, 2, 3}; const std::vector cv = v; { span s{v}; CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); span cs{v}; CHECK((cs.size() == narrow_cast(v.size()) && cs.data() == v.data())); } std::string str = "hello"; const std::string cstr = "hello"; { #ifdef CONFIRM_COMPILATION_ERRORS span s{str}; CHECK((s.size() == narrow_cast(str.size()) && s.data() == str.data())); #endif span cs{str}; CHECK((cs.size() == narrow_cast(str.size()) && cs.data() == str.data())); } { #ifdef CONFIRM_COMPILATION_ERRORS span s{cstr}; #endif span cs{cstr}; CHECK((cs.size() == narrow_cast(cstr.size()) && cs.data() == cstr.data())); } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_vector = []() -> std::vector { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_vector()); #endif } { auto get_temp_vector = []() -> std::vector { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_vector()); } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_string = []() -> std::string { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_string()); #endif } { auto get_temp_string = []() -> std::string { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_string()); } { #ifdef CONFIRM_COMPILATION_ERRORS auto get_temp_vector = []() -> const std::vector { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_vector()); #endif } { auto get_temp_string = []() -> const std::string { return {}; }; auto use_span = [](span s) { static_cast(s); }; use_span(get_temp_string()); } { #ifdef CONFIRM_COMPILATION_ERRORS std::map m; span s{m}; #endif } { auto s = make_span(v); CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); auto cs = make_span(cv); CHECK((cs.size() == narrow_cast(cv.size()) && cs.data() == cv.data())); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_convertible_span_constructor") { { span avd; span avcd = avd; static_cast(avcd); } { #ifdef CONFIRM_COMPILATION_ERRORS span avd; span avb = avd; static_cast(avb); #endif } #ifdef CONFIRM_COMPILATION_ERRORS { span s; span s2 = s; static_cast(s2); } { span s; span s2 = s; static_cast(s2); } { span s; span s2 = s; static_cast(s2); } #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("copy_move_and_assignment") { span s1; CHECK(s1.empty()); int arr[] = {3, 4, 5}; span s2 = arr; CHECK((s2.size() == 3 && s2.data() == &arr[0])); s2 = s1; CHECK(s2.empty()); auto get_temp_span = [&]() -> span { return {&arr[1], 2}; }; auto use_span = [&](span s) { CHECK((s.size() == 2 && s.data() == &arr[1])); }; use_span(get_temp_span()); s1 = get_temp_span(); CHECK((s1.size() == 2 && s1.data() == &arr[1])); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("first") { int arr[5] = {1, 2, 3, 4, 5}; { span av = arr; CHECK(av.first<2>().size() == 2); CHECK(av.first(2).size() == 2); } { span av = arr; CHECK(av.first<0>().size() == 0); CHECK(av.first(0).size() == 0); } { span av = arr; CHECK(av.first<5>().size() == 5); CHECK(av.first(5).size() == 5); } { span av = arr; #ifdef CONFIRM_COMPILATION_ERRORS CHECK(av.first<6>().size() == 6); CHECK(av.first<-1>().size() == -1); #endif CHECK_THROWS_AS(av.first(6).size(), fail_fast); } { span av; CHECK(av.first<0>().size() == 0); CHECK(av.first(0).size() == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("last") { int arr[5] = {1, 2, 3, 4, 5}; { span av = arr; CHECK(av.last<2>().size() == 2); CHECK(av.last(2).size() == 2); } { span av = arr; CHECK(av.last<0>().size() == 0); CHECK(av.last(0).size() == 0); } { span av = arr; CHECK(av.last<5>().size() == 5); CHECK(av.last(5).size() == 5); } { span av = arr; #ifdef CONFIRM_COMPILATION_ERRORS CHECK(av.last<6>().size() == 6); #endif CHECK_THROWS_AS(av.last(6).size(), fail_fast); } { span av; CHECK(av.last<0>().size() == 0); CHECK(av.last(0).size() == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("subspan") { int arr[5] = {1, 2, 3, 4, 5}; { span av = arr; CHECK((av.subspan<2, 2>().size() == 2)); CHECK(decltype(av.subspan<2, 2>())::extent == 2); CHECK(av.subspan(2, 2).size() == 2); CHECK(av.subspan(2, 3).size() == 3); } { span av = arr; CHECK((av.subspan<0, 0>().size() == 0)); CHECK(decltype(av.subspan<0,0>())::extent == 0); CHECK(av.subspan(0, 0).size() == 0); } { span av = arr; CHECK((av.subspan<0, 5>().size() == 5)); CHECK(decltype(av.subspan<0, 5>())::extent == 5); CHECK(av.subspan(0, 5).size() == 5); CHECK_THROWS_AS(av.subspan(0, 6).size(), fail_fast); CHECK_THROWS_AS(av.subspan(1, 5).size(), fail_fast); } { span av = arr; CHECK((av.subspan<4, 0>().size() == 0)); CHECK(decltype(av.subspan<4, 0>())::extent == 0); CHECK(av.subspan(4, 0).size() == 0); CHECK(av.subspan(5, 0).size() == 0); CHECK_THROWS_AS(av.subspan(6, 0).size(), fail_fast); } { span av = arr; CHECK((av.subspan<1>().size() == 4)); CHECK(decltype(av.subspan<1>())::extent == 4); } { span av; CHECK((av.subspan<0, 0>().size() == 0)); CHECK((decltype(av.subspan<0, 0>())::extent == 0)); CHECK(av.subspan(0, 0).size() == 0); CHECK_THROWS_AS((av.subspan<1, 0>().size()), fail_fast); } { span av; CHECK(av.subspan(0).size() == 0); CHECK_THROWS_AS(av.subspan(1).size(), fail_fast); } { span av = arr; CHECK(av.subspan(0).size() == 5); CHECK(av.subspan(1).size() == 4); CHECK(av.subspan(4).size() == 1); CHECK(av.subspan(5).size() == 0); CHECK_THROWS_AS(av.subspan(6).size(), fail_fast); const auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } { span av = arr; CHECK(av.subspan(0).size() == 5); CHECK(av.subspan(1).size() == 4); CHECK(av.subspan(4).size() == 1); CHECK(av.subspan(5).size() == 0); CHECK_THROWS_AS(av.subspan(6).size(), fail_fast); const auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("at_call") { int arr[4] = {1, 2, 3, 4}; { span s = arr; CHECK(s.at(0) == 1); CHECK_THROWS_AS(s.at(5), fail_fast); } { int arr2d[2] = {1, 6}; span s = arr2d; CHECK(s.at(0) == 1); CHECK(s.at(1) == 6); CHECK_THROWS_AS(s.at(2), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("operator_function_call") { int arr[4] = {1, 2, 3, 4}; { span s = arr; CHECK(s(0) == 1); CHECK_THROWS_AS(s(5), fail_fast); } { int arr2d[2] = {1, 6}; span s = arr2d; CHECK(s(0) == 1); CHECK(s(1) == 6); CHECK_THROWS_AS(s(2), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_default_init") { span::iterator it1; span::iterator it2; CHECK(it1 == it2); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("const_iterator_default_init") { span::const_iterator it1; span::const_iterator it2; CHECK(it1 == it2); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_conversions") { span::iterator badIt; span::const_iterator badConstIt; CHECK(badIt == badConstIt); int a[] = {1, 2, 3, 4}; span s = a; auto it = s.begin(); auto cit = s.cbegin(); CHECK(it == cit); CHECK(cit == it); span::const_iterator cit2 = it; CHECK(cit2 == cit); span::const_iterator cit3 = it + 4; CHECK(cit3 == s.cend()); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_comparisons") { int a[] = {1, 2, 3, 4}; { span s = a; span::iterator it = s.begin(); auto it2 = it + 1; span::const_iterator cit = s.cbegin(); CHECK(it == cit); CHECK(cit == it); CHECK(it == it); CHECK(cit == cit); CHECK(cit == s.begin()); CHECK(s.begin() == cit); CHECK(s.cbegin() == cit); CHECK(it == s.begin()); CHECK(s.begin() == it); CHECK(it != it2); CHECK(it2 != it); CHECK(it != s.end()); CHECK(it2 != s.end()); CHECK(s.end() != it); CHECK(it2 != cit); CHECK(cit != it2); CHECK(it < it2); CHECK(it <= it2); CHECK(it2 <= s.end()); CHECK(it < s.end()); CHECK(it <= cit); CHECK(cit <= it); CHECK(cit < it2); CHECK(cit <= it2); CHECK(cit < s.end()); CHECK(cit <= s.end()); CHECK(it2 > it); CHECK(it2 >= it); CHECK(s.end() > it2); CHECK(s.end() >= it2); CHECK(it2 > cit); CHECK(it2 >= cit); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("begin_end") { { int a[] = {1, 2, 3, 4}; span s = a; span::iterator it = s.begin(); span::iterator it2 = std::begin(s); CHECK(it == it2); it = s.end(); it2 = std::end(s); CHECK(it == it2); } { int a[] = {1, 2, 3, 4}; span s = a; auto it = s.begin(); auto first = it; CHECK(it == first); CHECK(*it == 1); auto beyond = s.end(); CHECK(it != beyond); CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); CHECK(beyond - beyond == 0); ++it; CHECK(it - first == 1); CHECK(*it == 2); *it = 22; CHECK(*it == 22); CHECK(beyond - it == 3); it = first; CHECK(it == first); while (it != s.end()) { *it = 5; ++it; } CHECK(it == beyond); CHECK(it - beyond == 0); for (const auto& n : s) { CHECK(n == 5); } } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("cbegin_cend") { { int a[] = {1, 2, 3, 4}; span s = a; span::const_iterator cit = s.cbegin(); span::const_iterator cit2 = std::cbegin(s); CHECK(cit == cit2); cit = s.cend(); cit2 = std::cend(s); CHECK(cit == cit2); } { int a[] = {1, 2, 3, 4}; span s = a; auto it = s.cbegin(); auto first = it; CHECK(it == first); CHECK(*it == 1); auto beyond = s.cend(); CHECK(it != beyond); CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); CHECK(beyond - beyond == 0); ++it; CHECK(it - first == 1); CHECK(*it == 2); CHECK(beyond - it == 3); int last = 0; it = first; CHECK(it == first); while (it != s.cend()) { CHECK(*it == last + 1); last = *it; ++it; } CHECK(it == beyond); CHECK(it - beyond == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("rbegin_rend") { { int a[] = {1, 2, 3, 4}; span s = a; auto it = s.rbegin(); auto first = it; CHECK(it == first); CHECK(*it == 4); auto beyond = s.rend(); CHECK(it != beyond); CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); CHECK(beyond - beyond == 0); ++it; CHECK(it - first == 1); CHECK(*it == 3); *it = 22; CHECK(*it == 22); CHECK(beyond - it == 3); it = first; CHECK(it == first); while (it != s.rend()) { *it = 5; ++it; } CHECK(it == beyond); CHECK(it - beyond == 0); for (const auto& n : s) { CHECK(n == 5); } } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("crbegin_crend") { { int a[] = {1, 2, 3, 4}; span s = a; auto it = s.crbegin(); auto first = it; CHECK(it == first); CHECK(*it == 4); auto beyond = s.crend(); CHECK(it != beyond); CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); CHECK(beyond - beyond == 0); ++it; CHECK(it - first == 1); CHECK(*it == 3); CHECK(beyond - it == 3); it = first; CHECK(it == first); int last = 5; while (it != s.crend()) { CHECK(*it == last - 1); last = *it; ++it; } CHECK(it == beyond); CHECK(it - beyond == 0); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("comparison_operators") { { span s1; span s2; CHECK(s1 == s2); CHECK(!(s1 != s2)); CHECK(!(s1 < s2)); CHECK(s1 <= s2); CHECK(!(s1 > s2)); CHECK(s1 >= s2); CHECK(s2 == s1); CHECK(!(s2 != s1)); CHECK(!(s2 < s1)); CHECK(s2 <= s1); CHECK(!(s2 > s1)); CHECK(s2 >= s1); } { int arr[] = {2, 1}; span s1 = arr; span s2 = arr; CHECK(s1 == s2); CHECK(!(s1 != s2)); CHECK(!(s1 < s2)); CHECK(s1 <= s2); CHECK(!(s1 > s2)); CHECK(s1 >= s2); CHECK(s2 == s1); CHECK(!(s2 != s1)); CHECK(!(s2 < s1)); CHECK(s2 <= s1); CHECK(!(s2 > s1)); CHECK(s2 >= s1); } { int arr[] = {2, 1}; // bigger span s1; span s2 = arr; CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } { int arr1[] = {1, 2}; int arr2[] = {1, 2}; span s1 = arr1; span s2 = arr2; CHECK(s1 == s2); CHECK(!(s1 != s2)); CHECK(!(s1 < s2)); CHECK(s1 <= s2); CHECK(!(s1 > s2)); CHECK(s1 >= s2); CHECK(s2 == s1); CHECK(!(s2 != s1)); CHECK(!(s2 < s1)); CHECK(s2 <= s1); CHECK(!(s2 > s1)); CHECK(s2 >= s1); } { int arr[] = {1, 2, 3}; span s1 = {&arr[0], 2}; // shorter span s2 = arr; // longer CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } { int arr1[] = {1, 2}; // smaller int arr2[] = {2, 1}; // bigger span s1 = arr1; span s2 = arr2; CHECK(s1 != s2); CHECK(s2 != s1); CHECK(!(s1 == s2)); CHECK(!(s2 == s1)); CHECK(s1 < s2); CHECK(!(s2 < s1)); CHECK(s1 <= s2); CHECK(!(s2 <= s1)); CHECK(s2 > s1); CHECK(!(s1 > s2)); CHECK(s2 >= s1); CHECK(!(s1 >= s2)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_bytes") { int a[] = {1, 2, 3, 4}; { const span s = a; CHECK(s.size() == 4); const span bs = as_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); } { span s; const auto bs = as_bytes(s); CHECK(bs.size() == s.size()); CHECK(bs.size() == 0); CHECK(bs.size_bytes() == 0); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.data() == nullptr); } { span s = a; const auto bs = as_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; { #ifdef CONFIRM_COMPILATION_ERRORS // you should not be able to get writeable bytes for const objects span s = a; CHECK(s.size() == 4); span bs = as_writeable_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); #endif } { span s; const auto bs = as_writeable_bytes(s); CHECK(bs.size() == s.size()); CHECK(bs.size() == 0); CHECK(bs.size_bytes() == 0); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.data() == nullptr); } { span s = a; const auto bs = as_writeable_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; // converting to an span from an equal size array is ok span s4 = arr; CHECK(s4.size() == 4); // converting to dynamic_range is always ok { span s = s4; CHECK(s.size() == s4.size()); static_cast(s); } // initialization or assignment to static span that REDUCES size is NOT ok #ifdef CONFIRM_COMPILATION_ERRORS { span s = arr; } { span s2 = s4; static_cast(s2); } #endif // even when done dynamically { span s = arr; auto f = [&]() { const span s2 = s; static_cast(s2); }; CHECK_THROWS_AS(f(), fail_fast); } // but doing so explicitly is ok // you can convert statically { const span s2 = {&arr[0], 2}; static_cast(s2); } { const span s1 = s4.first<1>(); static_cast(s1); } // ...or dynamically { // NB: implicit conversion to span from span span s1 = s4.first(1); static_cast(s1); } // initialization or assignment to static span that requires size INCREASE is not ok. int arr2[2] = {1, 2}; #ifdef CONFIRM_COMPILATION_ERRORS { span s3 = arr2; } { span s2 = arr2; span s4a = s2; } #endif { auto f = [&]() { const span _s4 = {arr2, 2}; static_cast(_s4); }; CHECK_THROWS_AS(f(), fail_fast); } // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one span av = arr2; auto f = [&]() { const span _s4 = av; static_cast(_s4); }; CHECK_THROWS_AS(f(), fail_fast); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("interop_with_std_regex") { char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; span s = lat; const auto f_it = s.begin() + 7; std::match_results::iterator> match; std::regex_match(s.begin(), s.end(), match, std::regex(".*")); CHECK(match.ready()); CHECK(!match.empty()); CHECK(match[0].matched); CHECK(match[0].first == s.begin()); CHECK(match[0].second == s.end()); std::regex_search(s.begin(), s.end(), match, std::regex("F")); CHECK(match.ready()); CHECK(!match.empty()); CHECK(match[0].matched); CHECK(match[0].first == f_it); CHECK(match[0].second == (f_it + 1)); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("interop_with_gsl_at") { int arr[5] = {1, 2, 3, 4, 5}; span s{arr}; CHECK((at(s, 0) == 1 && at(s, 1) == 2)); } TEST_CASE("default_constructible") { CHECK((std::is_default_constructible>::value)); CHECK((std::is_default_constructible>::value)); CHECK((!std::is_default_constructible>::value)); } GSL-2.1.0/tests/strict_notnull_tests.cpp000066400000000000000000000117501356460337500203320ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch // Fix VS2015 build breaks in Release #pragma warning(disable : 4702) // unreachable code #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for not_null, operator<, operator<=, operator> namespace gsl { struct fail_fast; } // namespace gsl using namespace gsl; GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper(not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper_const(not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool strict_helper(strict_not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool strict_helper_const(strict_not_null p) { return *p == 12; } int* return_pointer() { return nullptr; } const int* return_pointer_const() { return nullptr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestStrictNotNull") { { // raw ptr <-> strict_not_null int x = 42; #ifdef CONFIRM_COMPILATION_ERRORS strict_not_null snn = &x; strict_helper(&x); strict_helper_const(&x); strict_helper(return_pointer()); strict_helper_const(return_pointer_const()); #endif const strict_not_null snn1{&x}; helper(snn1); helper_const(snn1); CHECK(*snn1 == 42); } { // strict_not_null -> strict_not_null int x = 42; strict_not_null snn1{&x}; const strict_not_null snn2{&x}; strict_helper(snn1); strict_helper_const(snn1); strict_helper_const(snn2); CHECK(snn1 == snn2); } { // strict_not_null -> not_null int x = 42; strict_not_null snn{&x}; const not_null nn1 = snn; const not_null nn2{snn}; helper(snn); helper_const(snn); CHECK(snn == nn1); CHECK(snn == nn2); } { // not_null -> strict_not_null int x = 42; not_null nn{&x}; const strict_not_null snn1{nn}; const strict_not_null snn2{nn}; strict_helper(nn); strict_helper_const(nn); CHECK(snn1 == nn); CHECK(snn2 == nn); std::hash> hash_snn; std::hash> hash_nn; CHECK(hash_nn(snn1) == hash_nn(nn)); CHECK(hash_snn(snn1) == hash_nn(nn)); CHECK(hash_nn(snn1) == hash_nn(snn2)); CHECK(hash_snn(snn1) == hash_snn(nn)); } #ifdef CONFIRM_COMPILATION_ERRORS { strict_not_null p{nullptr}; } #endif } #if defined(__cplusplus) && (__cplusplus >= 201703L) GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestStrictNotNullConstructorTypeDeduction") { { int i = 42; strict_not_null x{&i}; helper(strict_not_null{&i}); helper_const(strict_not_null{&i}); CHECK(*x == 42); } { int i = 42; int* p = &i; strict_not_null x{p}; helper(strict_not_null{p}); helper_const(strict_not_null{p}); CHECK(*x == 42); } { auto workaround_macro = []() { int* p1 = nullptr; const strict_not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { auto workaround_macro = []() { const int* p1 = nullptr; const strict_not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; CHECK_THROWS_AS(helper(strict_not_null{p}), fail_fast); CHECK_THROWS_AS(helper_const(strict_not_null{p}), fail_fast); } #ifdef CONFIRM_COMPILATION_ERRORS { strict_not_null x{nullptr}; helper(strict_not_null{nullptr}); helper_const(strict_not_null{nullptr}); } #endif } #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) static_assert(std::is_nothrow_move_constructible>::value, "strict_not_null must be no-throw move constructible"); GSL-2.1.0/tests/strided_span_tests.cpp000066400000000000000000000666571356460337500177460ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch deprecated #pragma warning(disable : 4996) // strided_span is in the process of being deprecated. // Suppressing warnings until it is completely removed #endif #if __clang__ || __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for byte #include // for narrow_cast #include // for strided_span, index, multi_span, strided_... #include // for size_t #include // for begin, end #include // for iota #include // for integral_constant<>::value, is_convertible #include // for vector namespace gsl { struct fail_fast; } // namespace gsl using namespace std; using namespace gsl; namespace { struct BaseClass { }; struct DerivedClass : BaseClass { }; } TEST_CASE("span_section_test") { int a[30][4][5]; const auto av = as_multi_span(a); const auto sub = av.section({15, 0, 0}, gsl::multi_span_index<3>{2, 2, 2}); const auto subsub = sub.section({1, 0, 0}, gsl::multi_span_index<3>{1, 1, 1}); (void) subsub; } TEST_CASE("span_section") { std::vector data(5 * 10); std::iota(begin(data), end(data), 0); const multi_span av = as_multi_span(multi_span{data}, dim<5>(), dim<10>()); const strided_span av_section_1 = av.section({1, 2}, {3, 4}); CHECK(!av_section_1.empty()); CHECK((av_section_1[{0, 0}] == 12)); CHECK((av_section_1[{0, 1}] == 13)); CHECK((av_section_1[{1, 0}] == 22)); CHECK((av_section_1[{2, 3}] == 35)); const strided_span av_section_2 = av_section_1.section({1, 2}, {2, 2}); CHECK(!av_section_2.empty()); CHECK((av_section_2[{0, 0}] == 24)); CHECK((av_section_2[{0, 1}] == 25)); CHECK((av_section_2[{1, 0}] == 34)); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_constructors") { // Check stride constructor { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; strided_span sav1{arr, {{9}, {1}}}; // T -> T CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{9}); CHECK(sav1.bounds().stride() == 1); CHECK((sav1[0] == 1 && sav1[8] == 9)); strided_span sav2{carr, {{4}, {2}}}; // const T -> const T CHECK(sav2.bounds().index_bounds() == multi_span_index<1>{4}); CHECK(sav2.bounds().strides() == multi_span_index<1>{2}); CHECK((sav2[0] == 1 && sav2[3] == 7)); strided_span sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T CHECK((sav3.bounds().index_bounds() == multi_span_index<2>{2, 2})); CHECK((sav3.bounds().strides() == multi_span_index<2>{6, 2})); CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7)); } // Check multi_span constructor { int arr[] = {1, 2}; // From non-cv-qualified source { const multi_span src = arr; strided_span sav{src, {2, 1}}; CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav.bounds().strides() == multi_span_index<1>{1}); CHECK(sav[1] == 2); #if defined(_MSC_VER) && _MSC_VER > 1800 // strided_span sav_c{ {src}, {2, 1} }; strided_span sav_c{multi_span{src}, strided_bounds<1>{2, 1}}; #else strided_span sav_c{multi_span{src}, strided_bounds<1>{2, 1}}; #endif CHECK(sav_c.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_c.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_c[1] == 2); #if defined(_MSC_VER) && _MSC_VER > 1800 strided_span sav_v{src, {2, 1}}; #else strided_span sav_v{multi_span{src}, strided_bounds<1>{2, 1}}; #endif CHECK(sav_v.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_v.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_v[1] == 2); #if defined(_MSC_VER) && _MSC_VER > 1800 strided_span sav_cv{src, {2, 1}}; #else strided_span sav_cv{multi_span{src}, strided_bounds<1>{2, 1}}; #endif CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_cv[1] == 2); } // From const-qualified source { const multi_span src{arr}; strided_span sav_c{src, {2, 1}}; CHECK(sav_c.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_c.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_c[1] == 2); #if defined(_MSC_VER) && _MSC_VER > 1800 strided_span sav_cv{src, {2, 1}}; #else strided_span sav_cv{multi_span{src}, strided_bounds<1>{2, 1}}; #endif CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_cv[1] == 2); } // From volatile-qualified source { const multi_span src{arr}; strided_span sav_v{src, {2, 1}}; CHECK(sav_v.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_v.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_v[1] == 2); #if defined(_MSC_VER) && _MSC_VER > 1800 strided_span sav_cv{src, {2, 1}}; #else strided_span sav_cv{multi_span{src}, strided_bounds<1>{2, 1}}; #endif CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_cv[1] == 2); } // From cv-qualified source { const multi_span src{arr}; strided_span sav_cv{src, {2, 1}}; CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); CHECK(sav_cv[1] == 2); } } // Check const-casting constructor { int arr[2] = {4, 5}; const multi_span av(arr, 2); multi_span av2{av}; CHECK(av2[1] == 5); static_assert( std::is_convertible, multi_span>::value, "ctor is not implicit!"); const strided_span src{arr, {2, 1}}; strided_span sav{src}; CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav.bounds().stride() == 1); CHECK(sav[1] == 5); static_assert( std::is_convertible, strided_span>::value, "ctor is not implicit!"); } // Check copy constructor { int arr1[2] = {3, 4}; const strided_span src1{arr1, {2, 1}}; strided_span sav1{src1}; CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav1.bounds().stride() == 1); CHECK(sav1[0] == 3); int arr2[6] = {1, 2, 3, 4, 5, 6}; const strided_span src2{arr2, {{3, 2}, {2, 1}}}; strided_span sav2{src2}; CHECK((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2})); CHECK((sav2.bounds().strides() == multi_span_index<2>{2, 1})); CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); } // Check const-casting assignment operator { int arr1[2] = {1, 2}; int arr2[6] = {3, 4, 5, 6, 7, 8}; const strided_span src{arr1, {{2}, {1}}}; strided_span sav{arr2, {{3}, {2}}}; strided_span& sav_ref = (sav = src); CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav.bounds().strides() == multi_span_index<1>{1}); CHECK(sav[0] == 1); CHECK(&sav_ref == &sav); } // Check copy assignment operator { int arr1[2] = {3, 4}; int arr1b[1] = {0}; const strided_span src1{arr1, {2, 1}}; strided_span sav1{arr1b, {1, 1}}; strided_span& sav1_ref = (sav1 = src1); CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav1.bounds().strides() == multi_span_index<1>{1}); CHECK(sav1[0] == 3); CHECK(&sav1_ref == &sav1); const int arr2[6] = {1, 2, 3, 4, 5, 6}; const int arr2b[1] = {0}; const strided_span src2{arr2, {{3, 2}, {2, 1}}}; strided_span sav2{arr2b, {{1, 1}, {1, 1}}}; strided_span& sav2_ref = (sav2 = src2); CHECK((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2})); CHECK((sav2.bounds().strides() == multi_span_index<2>{2, 1})); CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); CHECK(&sav2_ref == &sav2); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_slice") { std::vector data(5 * 10); std::iota(begin(data), end(data), 0); const multi_span src = as_multi_span(multi_span{data}, dim<5>(), dim<10>()); const strided_span sav{src, {{5, 10}, {10, 1}}}; #ifdef CONFIRM_COMPILATION_ERRORS const strided_span csav{{src}, {{5, 10}, {10, 1}}}; #endif const strided_span csav{multi_span{src}, {{5, 10}, {10, 1}}}; strided_span sav_sl = sav[2]; CHECK(sav_sl[0] == 20); CHECK(sav_sl[9] == 29); strided_span csav_sl = sav[3]; CHECK(csav_sl[0] == 30); CHECK(csav_sl[9] == 39); CHECK(sav[4][0] == 40); CHECK(sav[4][9] == 49); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_column_major") { // strided_span may be used to accommodate more peculiar // use cases, such as column-major multidimensional array // (aka. "FORTRAN" layout). int cm_array[3 * 5] = {1, 4, 7, 10, 13, 2, 5, 8, 11, 14, 3, 6, 9, 12, 15}; strided_span cm_sav{cm_array, {{5, 3}, {1, 5}}}; // Accessing elements CHECK((cm_sav[{0, 0}] == 1)); CHECK((cm_sav[{0, 1}] == 2)); CHECK((cm_sav[{1, 0}] == 4)); CHECK((cm_sav[{4, 2}] == 15)); // Slice strided_span cm_sl = cm_sav[3]; CHECK(cm_sl[0] == 10); CHECK(cm_sl[1] == 11); CHECK(cm_sl[2] == 12); // Section strided_span cm_sec = cm_sav.section({2, 1}, {3, 2}); CHECK((cm_sec.bounds().index_bounds() == multi_span_index<2>{3, 2})); CHECK((cm_sec[{0, 0}] == 8)); CHECK((cm_sec[{0, 1}] == 9)); CHECK((cm_sec[{1, 0}] == 11)); CHECK((cm_sec[{2, 1}] == 15)); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_bounds") { int arr[] = {0, 1, 2, 3}; multi_span av(arr); { // incorrect sections CHECK_THROWS_AS(av.section(0, 0)[0], fail_fast); CHECK_THROWS_AS(av.section(1, 0)[0], fail_fast); CHECK_THROWS_AS(av.section(1, 1)[1], fail_fast); CHECK_THROWS_AS(av.section(2, 5), fail_fast); CHECK_THROWS_AS(av.section(5, 2), fail_fast); CHECK_THROWS_AS(av.section(5, 0), fail_fast); CHECK_THROWS_AS(av.section(0, 5), fail_fast); CHECK_THROWS_AS(av.section(5, 5), fail_fast); } { // zero stride strided_span sav{av, {{4}, {}}}; CHECK(sav[0] == 0); CHECK(sav[3] == 0); CHECK_THROWS_AS(sav[4], fail_fast); } { // zero extent strided_span sav{av, {{}, {1}}}; CHECK_THROWS_AS(sav[0], fail_fast); } { // zero extent and stride strided_span sav{av, {{}, {}}}; CHECK_THROWS_AS(sav[0], fail_fast); } { // strided array ctor with matching strided bounds strided_span sav{arr, {4, 1}}; CHECK(sav.bounds().index_bounds() == multi_span_index<1>{4}); CHECK(sav[3] == 3); CHECK_THROWS_AS(sav[4], fail_fast); } { // strided array ctor with smaller strided bounds strided_span sav{arr, {2, 1}}; CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav[1] == 1); CHECK_THROWS_AS(sav[2], fail_fast); } { // strided array ctor with fitting irregular bounds strided_span sav{arr, {2, 3}}; CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); CHECK(sav[0] == 0); CHECK(sav[1] == 3); CHECK_THROWS_AS(sav[2], fail_fast); } { // bounds cross data boundaries - from static arrays CHECK_THROWS_AS((strided_span{arr, {3, 2}}), fail_fast); CHECK_THROWS_AS((strided_span{arr, {3, 3}}), fail_fast); CHECK_THROWS_AS((strided_span{arr, {4, 5}}), fail_fast); CHECK_THROWS_AS((strided_span{arr, {5, 1}}), fail_fast); CHECK_THROWS_AS((strided_span{arr, {5, 5}}), fail_fast); } { // bounds cross data boundaries - from array view CHECK_THROWS_AS((strided_span{av, {3, 2}}), fail_fast); CHECK_THROWS_AS((strided_span{av, {3, 3}}), fail_fast); CHECK_THROWS_AS((strided_span{av, {4, 5}}), fail_fast); CHECK_THROWS_AS((strided_span{av, {5, 1}}), fail_fast); CHECK_THROWS_AS((strided_span{av, {5, 5}}), fail_fast); } { // bounds cross data boundaries - from dynamic arrays CHECK_THROWS_AS((strided_span{av.data(), 4, {3, 2}}), fail_fast); CHECK_THROWS_AS((strided_span{av.data(), 4, {3, 3}}), fail_fast); CHECK_THROWS_AS((strided_span{av.data(), 4, {4, 5}}), fail_fast); CHECK_THROWS_AS((strided_span{av.data(), 4, {5, 1}}), fail_fast); CHECK_THROWS_AS((strided_span{av.data(), 4, {5, 5}}), fail_fast); CHECK_THROWS_AS((strided_span{av.data(), 2, {2, 2}}), fail_fast); } #ifdef CONFIRM_COMPILATION_ERRORS { strided_span sav0{av.data(), {3, 2}}; strided_span sav1{arr, {1}}; strided_span sav2{arr, {1, 1, 1}}; strided_span sav3{av, {1}}; strided_span sav4{av, {1, 1, 1}}; strided_span sav5{av.as_multi_span(dim<2>(), dim<2>()), {1}}; strided_span sav6{av.as_multi_span(dim<2>(), dim<2>()), {1, 1, 1}}; strided_span sav7{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1}, {1, 1}, {1, 1}}}; multi_span_index<1> index{0, 1}; strided_span sav8{arr, {1, {1, 1}}}; strided_span sav9{arr, {{1, 1}, {1, 1}}}; strided_span sav10{av, {1, {1, 1}}}; strided_span sav11{av, {{1, 1}, {1, 1}}}; strided_span sav12{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1}}}; strided_span sav13{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1, 1, 1}}}; strided_span sav14{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1, 1}, {1}}}; } #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_type_conversion") { int arr[] = {0, 1, 2, 3}; multi_span av(arr); { strided_span sav{av.data(), av.size(), {av.size() / 2, 2}}; #ifdef CONFIRM_COMPILATION_ERRORS strided_span lsav1 = sav.as_strided_span(); #endif } { strided_span sav{av, {av.size() / 2, 2}}; #ifdef CONFIRM_COMPILATION_ERRORS strided_span lsav1 = sav.as_strided_span(); #endif } multi_span bytes = as_bytes(av); // retype strided array with regular strides - from raw data { strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; strided_span sav2{bytes.data(), bytes.size(), bounds}; strided_span sav3 = sav2.as_strided_span(); CHECK(sav3[0][0] == 0); CHECK(sav3[1][0] == 2); CHECK_THROWS_AS(sav3[1][1], fail_fast); CHECK_THROWS_AS(sav3[0][1], fail_fast); } // retype strided array with regular strides - from multi_span { strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; multi_span bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); strided_span sav2{bytes2, bounds}; strided_span sav3 = sav2.as_strided_span(); CHECK(sav3[0][0] == 0); CHECK(sav3[1][0] == 2); CHECK_THROWS_AS(sav3[1][1], fail_fast); CHECK_THROWS_AS(sav3[0][1], fail_fast); } // retype strided array with not enough elements - last dimension of the array is too small { strided_bounds<2> bounds{{4, 2}, {4, 1}}; multi_span bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); strided_span sav2{bytes2, bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } // retype strided array with not enough elements - strides are too small { strided_bounds<2> bounds{{4, 2}, {2, 1}}; multi_span bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); strided_span sav2{bytes2, bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } // retype strided array with not enough elements - last dimension does not divide by the new // typesize { strided_bounds<2> bounds{{2, 6}, {4, 1}}; multi_span bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); strided_span sav2{bytes2, bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } // retype strided array with not enough elements - strides does not divide by the new // typesize { strided_bounds<2> bounds{{2, 1}, {6, 1}}; multi_span bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); strided_span sav2{bytes2, bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } // retype strided array with irregular strides - from raw data { strided_bounds<1> bounds{bytes.size() / 2, 2}; strided_span sav2{bytes.data(), bytes.size(), bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } // retype strided array with irregular strides - from multi_span { strided_bounds<1> bounds{bytes.size() / 2, 2}; strided_span sav2{bytes, bounds}; CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("empty_strided_spans") { { multi_span empty_av(nullptr); strided_span empty_sav{empty_av, {0, 1}}; CHECK(empty_sav.bounds().index_bounds() == multi_span_index<1>{0}); CHECK(empty_sav.empty()); CHECK_THROWS_AS(empty_sav[0], fail_fast); CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); for (const auto& v : empty_sav) { (void) v; CHECK(false); } } { strided_span empty_sav{nullptr, 0, {0, 1}}; CHECK(empty_sav.bounds().index_bounds() == multi_span_index<1>{0}); CHECK_THROWS_AS(empty_sav[0], fail_fast); CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); for (const auto& v : empty_sav) { (void) v; CHECK(false); } } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute void iterate_every_other_element(multi_span av) { // pick every other element auto length = av.size() / 2; #if defined(_MSC_VER) && _MSC_VER > 1800 auto bounds = strided_bounds<1>({length}, {2}); #else auto bounds = strided_bounds<1>(multi_span_index<1>{length}, multi_span_index<1>{2}); #endif strided_span strided(&av.data()[1], av.size() - 1, bounds); CHECK(strided.size() == length); CHECK(strided.bounds().index_bounds()[0] == length); for (auto i = 0; i < strided.size(); ++i) { CHECK(strided[i] == av[2 * i + 1]); } int idx = 0; for (auto num : strided) { CHECK(num == av[2 * idx + 1]); idx++; } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_section_iteration") { int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; // static bounds { multi_span av(arr, 8); iterate_every_other_element(av); } // dynamic bounds { multi_span av(arr, 8); iterate_every_other_element(av); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("dynamic_strided_span_section_iteration") { auto arr = new int[8]; for (int i = 0; i < 4; ++i) { arr[2 * i] = 4 + i; arr[2 * i + 1] = i; } auto av = as_multi_span(arr, 8); iterate_every_other_element(av); delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute // TODO: does not work void iterate_second_slice(multi_span av) { const int expected[6] = {2, 3, 10, 11, 18, 19}; auto section = av.section({0, 1, 0}, {3, 1, 2}); for (auto i = 0; i < section.extent<0>(); ++i) { for (auto j = 0; j < section.extent<1>(); ++j) for (auto k = 0; k < section.extent<2>(); ++k) { auto idx = multi_span_index<3>{i, j, k}; // avoid braces in the CHECK macro CHECK(section[idx] == expected[2 * i + 2 * j + k]); } } for (auto i = 0; i < section.extent<0>(); ++i) { for (auto j = 0; j < section.extent<1>(); ++j) for (auto k = 0; k < section.extent<2>(); ++k) CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]); } int i = 0; for (const auto num : section) { CHECK(num == expected[i]); i++; } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("strided_span_section_iteration_3d") { int arr[3][4][2]{}; for (auto i = 0; i < 3; ++i) { for (auto j = 0; j < 4; ++j) for (auto k = 0; k < 2; ++k) arr[i][j][k] = 8 * i + 2 * j + k; } { multi_span av = arr; iterate_second_slice(av); } } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("dynamic_strided_span_section_iteration_3d") { const auto height = 12, width = 2; const auto size = height * width; auto arr = new int[static_cast(size)]; for (auto i = 0; i < size; ++i) { arr[i] = i; } { auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>()); iterate_second_slice(av); } { auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>()); iterate_second_slice(av); } { auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>()); iterate_second_slice(av); } { auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2)); iterate_second_slice(av); } delete[] arr; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("strided_span_conversion") { // get an multi_span of 'c' values from the list of X's struct X { int a; int b; int c; }; X arr[4] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}}; int s = sizeof(int) / sizeof(byte); auto d2 = 3 * s; auto d1 = narrow_cast(sizeof(int)) * 12 / d2; // convert to 4x12 array of bytes auto av = as_multi_span(as_bytes(as_multi_span(&arr[0], 4)), dim(d1), dim(d2)); CHECK(av.bounds().index_bounds()[0] == 4); CHECK(av.bounds().index_bounds()[1] == 12); // get the last 4 columns auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], // arr[0].c[3] } , { arr[1].c[0], ... } , ... // } // convert to array 4x1 array of integers auto cs = section.as_strided_span(); // { { arr[0].c }, {arr[1].c } , ... } CHECK(cs.bounds().index_bounds()[0] == 4); CHECK(cs.bounds().index_bounds()[1] == 1); // transpose to 1x4 array strided_bounds<2> reverse_bounds{ {cs.bounds().index_bounds()[1], cs.bounds().index_bounds()[0]}, {cs.bounds().strides()[1], cs.bounds().strides()[0]}}; strided_span transposed{cs.data(), cs.bounds().total_size(), reverse_bounds}; // slice to get a one-dimensional array of c's strided_span result = transposed[0]; CHECK(result.bounds().index_bounds()[0] == 4); CHECK_THROWS_AS(result.bounds().index_bounds()[1], fail_fast); int i = 0; for (auto& num : result) { CHECK(num == arr[i].c); i++; } } #if __clang__ || __GNUC__ #pragma GCC diagnostic pop #endif GSL-2.1.0/tests/string_span_tests.cpp000066400000000000000000000753761356460337500176140ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for Expects, fail_fast (ptr only) #include // for owner #include // for span, dynamic_extent #include // for basic_string_span, operator==, ensure_z #include // for move, find #include // for size_t #include // for map #include // for basic_string, string, char_traits, operat... #include // for remove_reference<>::type #include // for vector, allocator using namespace std; using namespace gsl; // Generic string functions namespace generic { template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(f.23) // NO-FORMAT: attribute auto strlen(const CharT* s) { auto p = s; while (*p) ++p; return p - s; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute auto strnlen(const CharT* s, std::size_t n) { return std::find(s, s + n, CharT{0}) - s; } } // namespace generic GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestLiteralConstruction") { cwstring_span<> v = ensure_z(L"Hello"); CHECK(5 == v.length()); #ifdef CONFIRM_COMPILATION_ERRORS wstring_span<> v2 = ensure0(L"Hello"); #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromStdString") { std::string s = "Hello there world"; cstring_span<> v = s; CHECK(v.length() == static_cast::index_type>(s.length())); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromStdVector") { std::vector vec(5, 'h'); string_span<> v{vec}; CHECK(v.length() == static_cast::index_type>(vec.size())); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestStackArrayConstruction") { wchar_t stack_string[] = L"Hello"; { cwstring_span<> v = ensure_z(stack_string); CHECK(v.length() == 5); } { cwstring_span<> v = stack_string; CHECK(v.length() == 5); } { wstring_span<> v = ensure_z(stack_string); CHECK(v.length() == 5); } { wstring_span<> v = stack_string; CHECK(v.length() == 5); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromConstCharPointer") { const char* s = "Hello"; cstring_span<> v = ensure_z(s); CHECK(v.length() == 5); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConversionToConst") { char stack_string[] = "Hello"; string_span<> v = ensure_z(stack_string); cstring_span<> v2 = v; CHECK(v.length() == v2.length()); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConversionFromConst") { char stack_string[] = "Hello"; cstring_span<> v = ensure_z(stack_string); (void) v; #ifdef CONFIRM_COMPILATION_ERRORS string_span<> v2 = v; string_span<> v3 = "Hello"; #endif } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestToString") { auto s = gsl::to_string(cstring_span<>{}); CHECK(s.length() == 0); char stack_string[] = "Hello"; cstring_span<> v = ensure_z(stack_string); auto s2 = gsl::to_string(v); CHECK(static_cast::index_type>(s2.length()) == v.length()); CHECK(s2.length() == 5); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestToBasicString") { auto s = gsl::to_basic_string, ::std::allocator>( cstring_span<>{}); CHECK(s.length() == 0); char stack_string[] = "Hello"; cstring_span<> v = ensure_z(stack_string); auto s2 = gsl::to_basic_string, ::std::allocator>(v); CHECK(static_cast::index_type>(s2.length()) == v.length()); CHECK(s2.length() == 5); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("EqualityAndImplicitConstructors") { { cstring_span<> span = "Hello"; cstring_span<> span1; // comparison to empty span CHECK(span1 != span); CHECK(span != span1); } { cstring_span<> span = "Hello"; cstring_span<> span1 = "Hello1"; // comparison to different span CHECK(span1 != span); CHECK(span != span1); } { cstring_span<> span = "Hello"; const char ar[] = {'H', 'e', 'l', 'l', 'o'}; const char ar1[] = "Hello"; const char ar2[10] = "Hello"; const char* ptr = "Hello"; const std::string str = "Hello"; const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; gsl::span sp = ensure_z("Hello"); // comparison to literal CHECK(span == cstring_span<>("Hello")); // comparison to static array with no null termination CHECK(span == cstring_span<>(ar)); // comparison to static array with null at the end CHECK(span == cstring_span<>(ar1)); // comparison to static array with null in the middle CHECK(span == cstring_span<>(ar2)); // comparison to null-terminated c string CHECK(span == cstring_span<>(ptr, 5)); // comparison to string CHECK(span == cstring_span<>(str)); // comparison to vector of charaters with no null termination CHECK(span == cstring_span<>(vec)); // comparison to span CHECK(span == cstring_span<>(sp)); // comparison to string_span CHECK(span == span); } { char ar[] = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = ar; char ar1[] = "Hello"; char ar2[10] = "Hello"; char* ptr = ar; std::string str = "Hello"; std::vector vec = {'H', 'e', 'l', 'l', 'o'}; gsl::span sp = ensure_z(ar1); // comparison to static array with no null termination CHECK(span == string_span<>(ar)); // comparison to static array with null at the end CHECK(span == string_span<>(ar1)); // comparison to static array with null in the middle CHECK(span == string_span<>(ar2)); // comparison to null-terminated c string CHECK(span == string_span<>(ptr, 5)); // comparison to string CHECK(span == string_span<>(str)); // comparison to vector of charaters with no null termination CHECK(span == string_span<>(vec)); // comparison to span CHECK(span == string_span<>(sp)); // comparison to string_span CHECK(span == span); } { const char ar[] = {'H', 'e', 'l', 'l', 'o'}; const char ar1[] = "Hello"; const char ar2[10] = "Hello"; const std::string str = "Hello"; const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const gsl::span sp = ensure_z("Hello"); cstring_span<> span = "Hello"; // const span, const other type CHECK(span == "Hello"); CHECK(span == ar); CHECK(span == ar1); CHECK(span == ar2); #ifdef CONFIRM_COMPILATION_ERRORS const char* ptr = "Hello"; CHECK(span == ptr); #endif CHECK(span == str); CHECK(span == vec); CHECK(span == sp); CHECK("Hello" == span); CHECK(ar == span); CHECK(ar1 == span); CHECK(ar2 == span); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(ptr == span); #endif CHECK(str == span); CHECK(vec == span); CHECK(sp == span); // const span, non-const other type char _ar[] = {'H', 'e', 'l', 'l', 'o'}; char _ar1[] = "Hello"; char _ar2[10] = "Hello"; char* _ptr = _ar; std::string _str = "Hello"; std::vector _vec = {'H', 'e', 'l', 'l', 'o'}; gsl::span _sp{_ar, 5}; CHECK(span == _ar); CHECK(span == _ar1); CHECK(span == _ar2); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(span == _ptr); #endif CHECK(span == _str); CHECK(span == _vec); CHECK(span == _sp); CHECK(_ar == span); CHECK(_ar1 == span); CHECK(_ar2 == span); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(_ptr == span); #endif CHECK(_str == span); CHECK(_vec == span); CHECK(_sp == span); string_span<> _span{_ptr, 5}; // non-const span, non-const other type CHECK(_span == _ar); CHECK(_span == _ar1); CHECK(_span == _ar2); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(_span == _ptr); #endif CHECK(_span == _str); CHECK(_span == _vec); CHECK(_span == _sp); CHECK(_ar == _span); CHECK(_ar1 == _span); CHECK(_ar2 == _span); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(_ptr == _span); #endif CHECK(_str == _span); CHECK(_vec == _span); CHECK(_sp == _span); // non-const span, const other type CHECK(_span == "Hello"); CHECK(_span == ar); CHECK(_span == ar1); CHECK(_span == ar2); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(_span == ptr); #endif CHECK(_span == str); CHECK(_span == vec); CHECK(_span == sp); CHECK("Hello" == _span); CHECK(ar == _span); CHECK(ar1 == _span); CHECK(ar2 == _span); #ifdef CONFIRM_COMPILATION_ERRORS CHECK(ptr == _span); #endif CHECK(str == _span); CHECK(vec == _span); CHECK(sp == _span); // two spans CHECK(_span == span); CHECK(span == _span); } { std::vector str1 = {'H', 'e', 'l', 'l', 'o'}; cstring_span<> span1 = str1; std::vector str2 = std::move(str1); cstring_span<> span2 = str2; // comparison of spans from the same vector before and after move (ok) CHECK(span1 == span2); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("ComparisonAndImplicitConstructors") { { cstring_span<> span = "Hello"; const char ar[] = {'H', 'e', 'l', 'l', 'o'}; const char ar1[] = "Hello"; const char ar2[10] = "Hello"; const char* ptr = "Hello"; const std::string str = "Hello"; const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; // comparison to literal CHECK(span < cstring_span<>("Helloo")); CHECK(span > cstring_span<>("Hell")); // comparison to static array with no null termination CHECK(span >= cstring_span<>(ar)); // comparison to static array with null at the end CHECK(span <= cstring_span<>(ar1)); // comparison to static array with null in the middle CHECK(span >= cstring_span<>(ar2)); // comparison to null-terminated c string CHECK(span <= cstring_span<>(ptr, 5)); // comparison to string CHECK(span >= cstring_span<>(str)); // comparison to vector of charaters with no null termination CHECK(span <= cstring_span<>(vec)); } { char ar[] = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = ar; char larr[] = "Hell"; char rarr[] = "Helloo"; char ar1[] = "Hello"; char ar2[10] = "Hello"; char* ptr = ar; std::string str = "Hello"; std::vector vec = {'H', 'e', 'l', 'l', 'o'}; // comparison to static array with no null termination CHECK(span <= string_span<>(ar)); CHECK(span < string_span<>(rarr)); CHECK(span > string_span<>(larr)); // comparison to static array with null at the end CHECK(span >= string_span<>(ar1)); // comparison to static array with null in the middle CHECK(span <= string_span<>(ar2)); // comparison to null-terminated c string CHECK(span >= string_span<>(ptr, 5)); // comparison to string CHECK(span <= string_span<>(str)); // comparison to vector of charaters with no null termination CHECK(span >= string_span<>(vec)); } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(r.11) // NO-FORMAT: attribute GSL_SUPPRESS(r.3) // NO-FORMAT: attribute GSL_SUPPRESS(r.5) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("ConstrutorsEnsureZ") { // remove z from literals { cstring_span<> sp = "hello"; CHECK((sp.length() == 5)); } // take the string as is { auto str = std::string("hello"); cstring_span<> sp = str; CHECK((sp.length() == 5)); } // ensure z on c strings { gsl::owner ptr = new char[3]; ptr[0] = 'a'; ptr[1] = 'b'; ptr[2] = '\0'; string_span<> span = ensure_z(ptr); CHECK(span.length() == 2); delete[] ptr; } } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("Constructors") { // creating cstring_span // from span of a final extent { span sp = "Hello"; cstring_span<> span = sp; CHECK(span.length() == 6); } // from const span of a final extent to non-const string_span #ifdef CONFIRM_COMPILATION_ERRORS { span sp = "Hello"; string_span<> span = sp; CHECK(span.length() == 6); } #endif // from string temporary #ifdef CONFIRM_COMPILATION_ERRORS { cstring_span<> span = std::string("Hello"); } #endif // default { cstring_span<> span; CHECK(span.length() == 0); } // from string literal { cstring_span<> span = "Hello"; CHECK(span.length() == 5); } // from const static array { const char ar[] = {'H', 'e', 'l', 'l', 'o'}; cstring_span<> span = ar; CHECK(span.length() == 5); } // from non-const static array { char ar[] = {'H', 'e', 'l', 'l', 'o'}; cstring_span<> span = ar; CHECK(span.length() == 5); } // from const ptr and length { const char* ptr = "Hello"; cstring_span<> span{ptr, 5}; CHECK(span.length() == 5); } // from const ptr and length, include 0 { const char* ptr = "Hello"; cstring_span<> span{ptr, 6}; CHECK(span.length() == 6); } // from const ptr and length, 0 inside { const char* ptr = "He\0lo"; cstring_span<> span{ptr, 5}; CHECK(span.length() == 5); } // from non-const ptr and length { char ar[] = {'H', 'e', 'l', 'l', 'o'}; char* ptr = ar; cstring_span<> span{ptr, 5}; CHECK(span.length() == 5); } // from non-const ptr and length, 0 inside { char ar[] = {'H', 'e', '\0', 'l', 'o'}; char* ptr = ar; cstring_span<> span{ptr, 5}; CHECK(span.length() == 5); } // from const string { const std::string str = "Hello"; const cstring_span<> span = str; CHECK(span.length() == 5); } // from non-const string { std::string str = "Hello"; const cstring_span<> span = str; CHECK(span.length() == 5); } // from const vector { const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const cstring_span<> span = vec; CHECK(span.length() == 5); } // from non-const vector { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const cstring_span<> span = vec; CHECK(span.length() == 5); } // from const span { const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const span inner = vec; const cstring_span<> span = inner; CHECK(span.length() == 5); } // from non-const span { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const span inner = vec; const cstring_span<> span = inner; CHECK(span.length() == 5); } // from const string_span { const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const cstring_span<> tmp = vec; const cstring_span<> span = tmp; CHECK(span.length() == 5); } // from non-const string_span { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> tmp = vec; cstring_span<> span = tmp; CHECK(span.length() == 5); } // creating string_span // from string literal { #ifdef CONFIRM_COMPILATION_ERRORS string_span<> span = "Hello"; #endif } // from const static array { #ifdef CONFIRM_COMPILATION_ERRORS const char ar[] = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = ar; CHECK(span.length() == 5); #endif } // from non-const static array { char ar[] = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = ar; CHECK(span.length() == 5); } // from const ptr and length { #ifdef CONFIRM_COMPILATION_ERRORS const char* ptr = "Hello"; string_span<> span{ptr, 5}; CHECK(span.length() == 5); #endif } // from non-const ptr and length { char ar[] = {'H', 'e', 'l', 'l', 'o'}; char* ptr = ar; string_span<> span{ptr, 5}; CHECK(span.length() == 5); } // from const string { #ifdef CONFIRM_COMPILATION_ERRORS const std::string str = "Hello"; string_span<> span = str; CHECK(span.length() == 5); #endif } // from non-const string { std::string str = "Hello"; string_span<> span = str; CHECK(span.length() == 5); } // from const vector { #ifdef CONFIRM_COMPILATION_ERRORS const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = vec; CHECK(span.length() == 5); #endif } // from non-const vector { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = vec; CHECK(span.length() == 5); } // from const span { #ifdef CONFIRM_COMPILATION_ERRORS std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const span inner = vec; string_span<> span = inner; CHECK(span.length() == 5); #endif } // from non-const span { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; span inner = vec; string_span<> span = inner; CHECK(span.length() == 5); } // from non-const span of non-const data from const vector { #ifdef CONFIRM_COMPILATION_ERRORS const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const span inner = vec; string_span<> span = inner; CHECK(span.length() == 5); #endif } // from const string_span { #ifdef CONFIRM_COMPILATION_ERRORS std::vector vec = {'H', 'e', 'l', 'l', 'o'}; cstring_span<> tmp = vec; string_span<> span = tmp; CHECK(span.length() == 5); #endif } // from non-const string_span { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const string_span<> tmp = vec; const string_span<> span = tmp; CHECK(span.length() == 5); } // from non-const string_span from const vector { #ifdef CONFIRM_COMPILATION_ERRORS const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> tmp = vec; string_span<> span = tmp; CHECK(span.length() == 5); #endif } // from const string_span of non-const data { std::vector vec = {'H', 'e', 'l', 'l', 'o'}; const string_span<> tmp = vec; const string_span<> span = tmp; CHECK(span.length() == 5); } } template T move_wrapper(T&& t) { return std::move(t); } template T create() { return T{}; } template void use(basic_string_span) { } TEST_CASE("MoveConstructors") { // move string_span { cstring_span<> span = "Hello"; const auto span1 = std::move(span); CHECK(span1.length() == 5); } { cstring_span<> span = "Hello"; const auto span1 = move_wrapper(std::move(span)); CHECK(span1.length() == 5); } { cstring_span<> span = "Hello"; const auto span1 = move_wrapper(std::move(span)); CHECK(span1.length() == 5); } // move span { span span = ensure_z("Hello"); const cstring_span<> span1 = std::move(span); CHECK(span1.length() == 5); } { span span = ensure_z("Hello"); const cstring_span<> span2 = move_wrapper(std::move(span)); CHECK(span2.length() == 5); } // move string { #ifdef CONFIRM_COMPILATION_ERRORS std::string str = "Hello"; string_span<> span = std::move(str); CHECK(span.length() == 5); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS std::string str = "Hello"; string_span<> span = move_wrapper(std::move(str)); CHECK(span.length() == 5); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS use(create()); #endif } // move container { #ifdef CONFIRM_COMPILATION_ERRORS std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = std::move(vec); CHECK(span.length() == 5); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS std::vector vec = {'H', 'e', 'l', 'l', 'o'}; string_span<> span = move_wrapper>(std::move(vec)); CHECK(span.length() == 5); #endif } { #ifdef CONFIRM_COMPILATION_ERRORS use(create>()); #endif } } TEST_CASE("Conversion") { #ifdef CONFIRM_COMPILATION_ERRORS cstring_span<> span = "Hello"; cwstring_span<> wspan{span}; CHECK(wspan.length() == 5); #endif } czstring_span<> CreateTempName(string_span<> span) { Expects(span.size() > 1); int last = 0; if (span.size() > 4) { span[0] = 't'; span[1] = 'm'; span[2] = 'p'; last = 3; } span[last] = '\0'; auto ret = span.subspan(0, 4); return {ret}; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("zstring") { // create zspan from zero terminated string { char buf[1]; buf[0] = '\0'; zstring_span<> zspan({buf, 1}); CHECK(generic::strlen(zspan.assume_z()) == 0); CHECK(zspan.as_string_span().size() == 0); CHECK(zspan.ensure_z().size() == 0); } // create zspan from non-zero terminated string { char buf[1]; buf[0] = 'a'; auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } // usage scenario: create zero-terminated temp file name and pass to a legacy API { char buf[10]; auto name = CreateTempName({buf, 10}); if (!name.empty()) { czstring<> str = name.assume_z(); CHECK(generic::strlen(str) == 3); CHECK(*(str + 3) == '\0'); } } } cwzstring_span<> CreateTempNameW(wstring_span<> span) { Expects(span.size() > 1); int last = 0; if (span.size() > 4) { span[0] = L't'; span[1] = L'm'; span[2] = L'p'; last = 3; } span[last] = L'\0'; auto ret = span.subspan(0, 4); return {ret}; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("wzstring") { // create zspan from zero terminated string { wchar_t buf[1]; buf[0] = L'\0'; wzstring_span<> zspan({buf, 1}); CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); CHECK(zspan.as_string_span().size() == 0); CHECK(zspan.ensure_z().size() == 0); } // create zspan from non-zero terminated string { wchar_t buf[1]; buf[0] = L'a'; const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } // usage scenario: create zero-terminated temp file name and pass to a legacy API { wchar_t buf[10]; const auto name = CreateTempNameW({buf, 10}); if (!name.empty()) { cwzstring<> str = name.assume_z(); CHECK(generic::strnlen(str, 10) == 3); CHECK(*(str + 3) == L'\0'); } } } cu16zstring_span<> CreateTempNameU16(u16string_span<> span) { Expects(span.size() > 1); int last = 0; if (span.size() > 4) { span[0] = u't'; span[1] = u'm'; span[2] = u'p'; last = 3; } span[last] = u'\0'; auto ret = span.subspan(0, 4); return {ret}; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("u16zstring") { // create zspan from zero terminated string { char16_t buf[1]; buf[0] = L'\0'; u16zstring_span<> zspan({buf, 1}); CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); CHECK(zspan.as_string_span().size() == 0); CHECK(zspan.ensure_z().size() == 0); } // create zspan from non-zero terminated string { char16_t buf[1]; buf[0] = u'a'; const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } // usage scenario: create zero-terminated temp file name and pass to a legacy API { char16_t buf[10]; const auto name = CreateTempNameU16({buf, 10}); if (!name.empty()) { cu16zstring<> str = name.assume_z(); CHECK(generic::strnlen(str, 10) == 3); CHECK(*(str + 3) == L'\0'); } } } cu32zstring_span<> CreateTempNameU32(u32string_span<> span) { Expects(span.size() > 1); int last = 0; if (span.size() > 4) { span[0] = U't'; span[1] = U'm'; span[2] = U'p'; last = 3; } span[last] = U'\0'; auto ret = span.subspan(0, 4); return {ret}; } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("u32zstring") { // create zspan from zero terminated string { char32_t buf[1]; buf[0] = L'\0'; u32zstring_span<> zspan({buf, 1}); CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); CHECK(zspan.as_string_span().size() == 0); CHECK(zspan.ensure_z().size() == 0); } // create zspan from non-zero terminated string { char32_t buf[1]; buf[0] = u'a'; const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } // usage scenario: create zero-terminated temp file name and pass to a legacy API { char32_t buf[10]; const auto name = CreateTempNameU32({buf, 10}); if (!name.empty()) { cu32zstring<> str = name.assume_z(); CHECK(generic::strnlen(str, 10) == 3); CHECK(*(str + 3) == L'\0'); } } } TEST_CASE("Issue305") { std::map, int> foo = {{"foo", 0}, {"bar", 1}}; CHECK(foo["foo"] == 0); CHECK(foo["bar"] == 1); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("char16_t type") { gsl::cu16string_span<> ss1 = gsl::ensure_z(u"abc"); CHECK(ss1.size() == 3); CHECK(ss1.size_bytes() == 6); std::u16string s1 = gsl::to_string(ss1); CHECK(s1 == u"abc"); std::u16string s2 = u"abc"; gsl::u16string_span<> ss2 = s2; CHECK(ss2.size() == 3); gsl::u16string_span<> ss3 = ss2.subspan(1, 1); CHECK(ss3.size() == 1); CHECK(ss3[0] == u'b'); char16_t buf[4]{u'a', u'b', u'c', u'\0'}; gsl::u16string_span<> ss4{buf, 4}; CHECK(ss4[3] == u'\0'); gsl::cu16zstring_span<> ss5(u"abc"); CHECK(ss5.as_string_span().size() == 3); gsl::cu16string_span<> ss6 = ss5.as_string_span(); CHECK(ss6 == ss1); std::vector v7 = {u'a', u'b', u'c'}; gsl::cu16string_span<> ss7{v7}; CHECK(ss7 == ss1); gsl::cu16string_span<> ss8 = gsl::ensure_z(u"abc"); gsl::cu16string_span<> ss9 = gsl::ensure_z(u"abc"); CHECK(ss8 == ss9); ss9 = gsl::ensure_z(u"abd"); CHECK(ss8 < ss9); CHECK(ss8 <= ss9); CHECK(ss8 != ss9); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("char32_t type") { gsl::cu32string_span<> ss1 = gsl::ensure_z(U"abc"); CHECK(ss1.size() == 3); CHECK(ss1.size_bytes() == 12); std::u32string s1 = gsl::to_string(ss1); CHECK(s1 == U"abc"); std::u32string s2 = U"abc"; gsl::u32string_span<> ss2 = s2; CHECK(ss2.size() == 3); gsl::u32string_span<> ss3 = ss2.subspan(1, 1); CHECK(ss3.size() == 1); CHECK(ss3[0] == U'b'); char32_t buf[4]{U'a', U'b', U'c', U'\0'}; gsl::u32string_span<> ss4{buf, 4}; CHECK(ss4[3] == u'\0'); gsl::cu32zstring_span<> ss5(U"abc"); CHECK(ss5.as_string_span().size() == 3); gsl::cu32string_span<> ss6 = ss5.as_string_span(); CHECK(ss6 == ss1); gsl::cu32string_span<> ss8 = gsl::ensure_z(U"abc"); gsl::cu32string_span<> ss9 = gsl::ensure_z(U"abc"); CHECK(ss8 == ss9); ss9 = gsl::ensure_z(U"abd"); CHECK(ss8 < ss9); CHECK(ss8 <= ss9); CHECK(ss8 != ss9); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_bytes") { cwzstring_span<> v(L"qwerty"); const auto s = v.as_string_span(); const auto bs = as_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { wchar_t buf[]{L"qwerty"}; wzstring_span<> v(buf); const auto s = v.as_string_span(); const auto bs = as_writeable_bytes(s); CHECK(static_cast(bs.data()) == static_cast(s.data())); CHECK(bs.size() == s.size_bytes()); } GSL-2.1.0/tests/test.cpp000066400000000000000000000020761356460337500150050ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #define CATCH_CONFIG_MAIN #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #include #pragma warning(disable : ALL_CODE_ANALYSIS_WARNINGS) // from catch #endif // _MSC_VER #include GSL-2.1.0/tests/utils_tests.cpp000066400000000000000000000066421356460337500164130ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER // blanket turn off warnings from CppCoreCheck from catch // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for narrow, finally, narrow_cast, narrowing_e... #include // for move #include // for reference_wrapper, _Bind_helper<>::type #include // for numeric_limits #include // for uint32_t, int32_t #include // for is_same using namespace gsl; TEST_CASE("sanity check for gsl::index typedef") { static_assert(std::is_same::value, "gsl::index represents wrong arithmetic type"); } void f(int& i) { i += 1; } TEST_CASE("finally_lambda") { int i = 0; { auto _ = finally([&]() { f(i); }); CHECK(i == 0); } CHECK(i == 1); } TEST_CASE("finally_lambda_move") { int i = 0; { auto _1 = finally([&]() { f(i); }); { auto _2 = std::move(_1); CHECK(i == 0); } CHECK(i == 1); { auto _2 = std::move(_1); CHECK(i == 1); } CHECK(i == 1); } CHECK(i == 1); } TEST_CASE("finally_function_with_bind") { int i = 0; { auto _ = finally(std::bind(&f, std::ref(i))); CHECK(i == 0); } CHECK(i == 1); } static int j = 0; void g() { j += 1; } TEST_CASE("finally_function_ptr") { j = 0; { auto _ = finally(&g); CHECK(j == 0); } CHECK(j == 1); } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("narrow_cast") { int n = 120; char c = narrow_cast(n); CHECK(c == 120); n = 300; unsigned char uc = narrow_cast(n); CHECK(uc == 44); } GSL_SUPPRESS(con.5) // NO-FORMAT: attribute TEST_CASE("narrow") { int n = 120; const char c = narrow(n); CHECK(c == 120); n = 300; CHECK_THROWS_AS(narrow(n), narrowing_error); const auto int32_max = std::numeric_limits::max(); const auto int32_min = std::numeric_limits::min(); CHECK(narrow(int32_t(0)) == 0); CHECK(narrow(int32_t(1)) == 1); CHECK(narrow(int32_max) == static_cast(int32_max)); CHECK_THROWS_AS(narrow(int32_t(-1)), narrowing_error); CHECK_THROWS_AS(narrow(int32_min), narrowing_error); n = -42; CHECK_THROWS_AS(narrow(n), narrowing_error); #if GSL_CONSTEXPR_NARROW static_assert(narrow(120) == 120, "Fix GSL_CONSTEXPR_NARROW"); #endif }