Compare commits

...

60 Commits

Author SHA1 Message Date
Carson Radtke 87f9d76886 GSL v4.1.0 (#1163)
Fixes: #1161

Update version strings in README and CMakeLists.txt.
2024-10-21 10:19:37 -05:00
Heiko Kröger 82ba6c77ce Added the IWYU pragma export (#1154)
* Added the IWYU pragma export

clang-tidy has added the check misc-include-cleaner with version 17. This check respects the IWYU pragmas.
2024-10-15 17:26:45 -05:00
mq白 32511b8de4 Delete the useless 'noexcept(false)' (#1152) 2024-10-14 15:30:40 -05:00
Konstantin Akimov 84b2ca1352 Remove unused headers from gsl/pointers (#1153)
* Remove unused headers from gsl/pointers

forward is already declared in utility, no need to include algorithm which is relativaly heavy
hash is already declared in memory, no need to bring brand-new header system_error for hash only

* Fix: add missing header <functional> to gsl/pointers due to using less/greater
2024-10-14 15:15:46 -05:00
Carson Radtke ce2a959e02 [ci]: add testing pipelines to github actions (#1159)
move pipeline testing from AzDO to GitHub Actions.

* update clang versions to 13-15
* update gcc versions to 10-12
* update xcode versions to 14.3.1 and 15.4
* test against C++23 (where supported)
2024-10-14 15:05:13 -05:00
Brian Kroth 11fe02d1ac Add a MS GSL disambiguation note (#1156) 2024-10-14 09:43:43 -05:00
Werner Henze 3275f9ccb9 Fix gcc build problem (#1149)
Closes issue #1148 by fixing problems introduced in PR #1140.

Co-authored-by: Werner Henze <w.henze@avm.de>
2024-10-11 19:46:21 -05:00
Carson Radtke b206bd163b [ci]: fix android job (#1158)
Job has been failing for months and is preventing other PRs from getting
merged. This PR fixes the pipeline - it changed the following:
 - runs on macos-latest-large (which is a non-arm image)
 - starts the emulator under java8 (see
   https://learn.microsoft.com/en-us/java/openjdk/transition-from-java-8-to-java-11)
 - runs emulator with -no-audio

The above were requirements to get the pipeline running. Other changes
include the following:
 - The job will auto-cancel when a newer commit is pushed to the
 PR.
 - The 'Wait for emulator ready' step now has a 2 minute timeout. This
   is necessary because we get no indication on whether or not the
   command that started the emulator suceeded. I believe there is room
   for improvement here, but it is outside the scope of the PR.
2024-10-11 16:05:20 -07:00
Werner Henze b39e7e4b09 Add documentation for to_integer(byte) (#1144)
Co-authored-by: Werner Henze <w.henze@avm.de>
2024-02-26 13:23:45 -08:00
Stephan T. Lavavej 2e0d1ba48c Test only __cpp_lib_byte, drop _HAS_STD_BYTE. (#1145) 2024-02-26 13:22:20 -08:00
d-winsor 1b4d42ca2e Fix initialization in test (#1140)
* Suppress unsafe-buffer-usage
2024-02-26 13:17:12 -08:00
Bruce Mitchener caae4dd0f8 Fix some typos. (#1146) 2024-02-21 15:06:29 -08:00
Bruce Mitchener f1a494cfd2 ci: Update to actions/checkout@v4. (#1142)
This fixes annotations on task runs like the following:

    The following actions uses node12 which is deprecated and will be forced
    to run on node16: actions/checkout@v2. For more info:
    https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
2024-01-17 15:25:32 -08:00
Bruce Mitchener 77b2f4f3b8 Fix some typos. (#1143) 2024-01-17 15:25:07 -08:00
Nicholas Guriev e64c97fc2c Mark not_null constructors as noexcept when underlying type can be moved with no exception (#1135)
This enables possible optimisations for trivial types. This also avoids a bug
in std::variant::emplace from GNU's libstdc++.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106547
2023-10-18 15:15:26 -07:00
Edward Chen 52212c2d76 Update Clang GSL_SUPPRESS to stringize parameter instead of using fixed string literal. (#1133)
Fix #1130.
2023-09-11 10:52:30 -07:00
Dmitry Kobets 2940006b5c Suppress some noisy / buggy warnings (#1136)
Two warnings were being emitted in the MSVC+LLVM tests. 

The warning `-Wunsafe-buffer-usage` is initially introduced in some capacity here https://reviews.llvm.org/D137346 pointing to documentation at https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734. The warning is a stylistic checker whose goal is to "emit a warning every time an unsafe operation is performed on a raw pointer". This type of programming model is not useful for library implementations of types such as `span`, where direct manipulation of raw pointers is inevitable, so disable the warning altogether.

There is also a false-positive warning https://github.com/llvm/llvm-project/issues/65689 that I've disabled inline.
2023-09-11 10:06:40 -07:00
Werner Henze 9695da9b38 fix and optimize documentation (#1131)
- Add anchor for `finally` in `headers.md` so that the link in `README.md` can work
- In `README.md` add code formatting for the character types of the `zstring` and `string_span` types
- In `README.md` change code formatting to links for GSL types
- Vertical alignment
2023-09-05 16:08:36 -07:00
Dmitry Kobets 4300304ef2 Remove unused macros (#1128)
This macro is a relic of the old implementation of GSL's header. It is unused and can be removed.
2023-07-26 15:07:28 -07:00
Werner Henze b34f7350fe get back gcc 8.4 compatibility (#1127)
Before my PR #1122 `gsl/pointers` was gcc 8.4 compatible. Now it is not. This commit makes it compatible with gcc 8.4 again.
2023-07-06 12:51:48 -07:00
Werner Henze 167c77d28e add missing include (#1126)
The header file uses `std::declval`, so it needs to `#include <utility>`.
2023-07-03 17:20:50 -07:00
Werner Henze 87e21400dc remove gcc noexcept warning (#1122)
Without this change a `gsl::not_null<class_type>` triggers these `noexcept` warnings:
```
.../gsl/include/gsl/pointers:162:50: warning: noexcept-expression evaluates to ‘false’ because of a call to ‘constexpr gsl::details::value_or_reference_return_t<T> gsl::not_null<T>::get() const [with T = class_type*; gsl::details::value_or_reference_return_t<T> = class_type* const]’ [-Wnoexcept]
  162 |                 const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
      |                                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../gsl/include/gsl/pointers:119:55: note: but ‘constexpr gsl::details::value_or_reference_return_t<T> gsl::not_null<T>::get() const [with T = class_type*; gsl::details::value_or_reference_return_t<T> = class_type* const]’ does not throw; perhaps it should be declared ‘noexcept’
  119 |     constexpr details::value_or_reference_return_t<T> get() const
      |                                                       ^~~
```

Co-authored-by: Werner Henze <w.henze@avm.de>
2023-06-28 15:17:12 -07:00
Dmitry Kobets 3549e31ba4 Deprecate <gsl/string_span> and replace with <gsl/zstring> (#1125)
With `string_span` having been deprecated (https://github.com/microsoft/GSL/pull/931, https://github.com/microsoft/GSL/pull/945) and removed (https://github.com/microsoft/GSL/pull/1074), the header `<gsl/string_span>` now only contains the definitions for the `zstring` family. Update the name accordingly from `<gsl/string_span>` to `<gsl/zstring>`. The old header is now deprecated and should no longer be used and will be removed in some future release.
2023-06-28 10:48:23 -07:00
Dmitry Kobets 65a5995035 Remove deprecated headers (#1124)
Headers that were previously prefixed with `gsl_` were renamed to drop the `gsl_` prefix in https://github.com/microsoft/GSL/pull/946, and the original version deprecated.
The deprecation happened a long time ago, so it is now time to remove these headers entirely.
2023-06-28 10:48:04 -07:00
Dmitry Kobets 303d964a24 Deprecate the Ptr make_span overloads (#1113)
These overloads don't seem to be in a usable state, and their original purpose is no longer clear. Deprecate them.
Resolves #1092
2023-05-22 10:48:41 -07:00
jpr42 afaaa71bce Install GSL.natvis (#1112)
Turns out supporting GSL.natvis perfectly is quite difficult.

There is no universal way to consume .natvis files that would satisfy everyone.

I thought the solution was to use the /NATVIS linker option. But it turns out that actually embeds information into the PDB. So I'm not sure how to properly support the Ninja generator...

That's not even accounting for the fact target_link_options doesn't play nicely with /NATVIS

When you just add the file via target_sources the visual studio solution will just pick it up and recognize it without adding it to the PDB file. Which won't affect the binary and is what most devs want.

This all comes down to the fact that /NATVIS files have native integration with visual studio that makes it difficult to use with non-visual studio solutions. /NATVIS almost works but embeds itself into the PDB which not everyone wants, and not everyone generates PDBs either.

Docs for natvis files and /NATVIS
- https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022
- https://learn.microsoft.com/en-us/cpp/build/reference/natvis-add-natvis-to-pdb?view=msvc-170

So my current solution is to just simplify the existing CMake code, and install the natvis so the user can decide.

closes #1084
2023-05-10 17:02:44 -07:00
Dmitry Kobets 4b5b5a1ed5 Disable std::hash<gsl::not_null<T>> if std::hash<T> is not enabled. (#1109)
Resolves #914
2023-05-10 11:25:04 -07:00
Dmitry Kobets 5dc7fae119 Use the implementation-defined strict total order for pointer comparisons with not_null (#1106)
Using `<`,`<=`,`>`,`>=` to compare unrelated pointers gives an unspecified result according to the standard.
This PR replaces the usage of these operators in `gsl::not_null` with the STL counterparts, which would leverage any implementation-defined strict total ordering for pointers.

Resolves #880
2023-05-09 09:06:53 -07:00
Dmitry Kobets 9face82309 Remove unnecessary check from size_bytes() (#1105)
`size_bytes()` returns the span's size in bytes. 
Assuming the span was constructed with an accurate size parameter, the check `size() < dynamic_extent / sizeof(element_type)` isn't required, since `size_t(-1)` (which is `dynamic_extent`) represents the size of the address space, so the number of bytes will never exceed it and in practice won't even come close.
Otherwise, it is not actually feasible to detect cases when the size parameter does not correspond to the dimensions of the underlying data pointer. In these cases, the relationship `size() < dynamic_extent / sizeof(element_type)` is simply one of many ways in which the `size()` could be incorrect, and serves no necessary purpose.

Resolves #1012
2023-05-09 09:05:26 -07:00
Dmitry Kobets 1d036585cc Add testcase for #1100 (#1101) 2023-03-30 11:10:15 -07:00
Werner Henze 43d60c5e38 Suppress warning C26481 (#1099)
Suppress "warning C26481: Don't use pointer arithmetic. Use span instead (bounds.1)." in the code that impements `span`.
2023-03-14 16:57:46 -07:00
Stephan T. Lavavej 50d6eef541 Add span_iterator::_Prevent_inheriting_unwrap. (#1100) 2023-03-14 13:50:34 -07:00
dmitrykobets-msft b080081c9c Add missing link to documentation 2023-02-27 15:49:09 -08:00
Werner Henze 9f85e4e088 minor docs improvements (#1097)
- Capitalize inital letter (make both tables consistent)
- Add links to docs/headers.md
- Latest cmake requirement is 3.14
- Mark text as code
2023-02-23 11:10:19 -08:00
dmitrykobets-msft 78eb6ca145 Document span_ext (#1098)
`<gsl/span>` is intended to mirror `<span>` in the STL. `<span_ext>` provides convenience features that aren't part of `<span>`.
Address #1095
2023-02-23 10:22:02 -08:00
Werner Henze 7f7108a076 Better links to CoreGuidelines (#1094)
The `#i13-do-not-pass-an-array-as-a-single-pointer` anchor seems to be auto generated based on the title of the section. The `#Ri-array` anchor is explicitely written in the source, so this should be a better link.
2023-02-21 17:11:30 -08:00
Werner Henze 7a297d4283 Extend docs and tests for span ctor (#1096) 2023-02-21 15:46:40 -08:00
Werner Henze 9851b94d7e add some span test for constructor from other span (#1093)
More combinations with dynamic_extent or fixed extent for higher coverage.
2023-02-17 13:05:40 -08:00
Werner Henze 743939744c Documentation (#1086)
Add documentation for #1071.
2023-02-17 10:38:34 -08:00
Werner Henze 3ba80d5dd4 simplify to_byte (#1090)
- to_byte_impl is not necessary, the same can be achieved with shorter code
- add test code for things that should not compile
2023-02-14 14:10:56 -08:00
Werner Henze 49c88f27bd add not_null and strict_not_null tests for const (#1085) 2023-02-06 13:16:06 -08:00
jpr42 f7da2e41f0 Raise CMake min to 3.14 (#1083)
- Explicitly test package manager support with CMake 3.14 and Ninja
- Remove gsl_install.cmake
- Simplify installation code
2023-02-06 11:16:37 -08:00
dmitrykobets-msft cbf5e664fc Fix max macro collision (#1081)
PR https://github.com/microsoft/GSL/pull/1076 introduced a usage of `numeric_limits::max()` function, which seems to have [issues interacting with some Windows headers](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions#warning-c4003-the-min-the-max-and-the-macro). This PR implements [a simple fix](https://stackoverflow.com/questions/1394132/macro-and-member-function-conflict), which is to wrap the invocations in parentheses. This offloads the fix from the users of the library.
2023-01-19 13:17:39 -08:00
Werner Henze a381a3759f 1075 Wrong Expects in gsl::at? (#1076)
https://github.com/microsoft/GSL/issues/1075
- Add `static_assert` because we only support C style array `at` for up to half of the address space.
- Add `std::` before `size_t`.
- tests:
  - Add `#include <exception>`
  - Implement `span_tests` `interop_with_gsl_at` like `at_tests` `std_span`
2023-01-18 13:33:20 -08:00
Gabriel Gerlero 0822838a7c Add Linguist language override for include files (#1079)
Add a `linguist-language` Git attribute that matches the files at `include/gsl` and sets their language to C++. Without this override, these files are not detected as C++ code by [GitHub's Linguist](https://github.com/github/linguist) (likely due to lacking any file extensions).

This will cause GitHub.com to count these files correctly as C++ code and do syntax highlighting when browsing the repo.

**Linguist breakdown results**

Before:

<details>


```
$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) -t linguist github-linguist --breakdown
91.57%  152148     C++
8.43%   14011      CMake

CMake:
CMakeLists.txt
cmake/gsl_functions.cmake
cmake/gsl_install.cmake
include/CMakeLists.txt
tests/CMakeLists.txt

C++:
tests/algorithm_tests.cpp
tests/assertion_tests.cpp
tests/at_tests.cpp
tests/byte_tests.cpp
tests/deathTestCommon.h
tests/no_exception_ensure_tests.cpp
tests/notnull_tests.cpp
tests/owner_tests.cpp
tests/span_compatibility_tests.cpp
tests/span_ext_tests.cpp
tests/span_tests.cpp
tests/strict_notnull_tests.cpp
tests/utils_tests.cpp
```

</details>

After:

<details>

```
$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) -t linguist github-linguist --breakdown
94.16%  225699     C++
5.84%   14011      CMake

CMake:
CMakeLists.txt
cmake/gsl_functions.cmake
cmake/gsl_install.cmake
include/CMakeLists.txt
tests/CMakeLists.txt

C++:
include/gsl/algorithm
include/gsl/assert
include/gsl/byte
include/gsl/gsl
include/gsl/gsl_algorithm
include/gsl/gsl_assert
include/gsl/gsl_byte
include/gsl/gsl_narrow
include/gsl/gsl_util
include/gsl/narrow
include/gsl/pointers
include/gsl/span
include/gsl/span_ext
include/gsl/string_span
include/gsl/util
tests/algorithm_tests.cpp
tests/assertion_tests.cpp
tests/at_tests.cpp
tests/byte_tests.cpp
tests/deathTestCommon.h
tests/no_exception_ensure_tests.cpp
tests/notnull_tests.cpp
tests/owner_tests.cpp
tests/span_compatibility_tests.cpp
tests/span_ext_tests.cpp
tests/span_tests.cpp
tests/strict_notnull_tests.cpp
tests/utils_tests.cpp
```
</details>
2023-01-06 08:11:06 -08:00
Werner Henze f94c1f6f2b use code spans in README.md (#1078) 2022-12-29 10:23:30 -08:00
Werner Henze ac26d7bc71 cleanup natvis (#1077)
- `fail_fast`,`basic_string_span` and `basic_zstring_span` are not declared in the headers any more.
- Name the exporting header file for all types in `GSL.natvis`.
2022-12-29 10:21:11 -08:00
Werner Henze c016bdc77f remove all deprecated string_span stuff (#1074)
This solves issue #1070 and removes the class `string_span`. The only content remaining in the header file `gsl/string_span` is the `*zstring` types.
This also removes the `string_span_tests.cpp` unit tests as these were only for the deprecated `string_span` class.

Co-authored-by: Werner Henze <werner.henze+gitcommits@posteo.de>
2022-12-27 07:22:26 -08:00
dmitrykobets-msft 46c72713f2 Document potentially confusing behavior in gsl::narrow (#1073)
NaN != Nan, so the comparisons used in gsl::narrow will always throw when attempting to cast a NaN value. This may be surprising, so document it.
2022-12-24 11:49:26 -08:00
dmitrykobets-msft 6c6111acb7 Remove null check inside not_null::get (#1067)
Guidelines issue 2006 removes the null check inside not_null::get, since the contained pointer is already guaranteed to be not-null upon construction.

Resolves #1051
2022-12-14 18:16:52 -08:00
dmitrykobets-msft f3620bb009 Suppress false postive warning (#1068)
The Clang compiler for MSVC in Visual Studio 2022 17.4.33122.133 used by the test runner has a bug which raises -Wdeprecated "out-of-line definition of constexpr static data member is redundant in C++17 and is deprecated" in gsl/span, when compiling with C++14. Temporarily suppress this warning for MSVC Clang with C++14.
2022-12-14 15:39:34 -08:00
Changming Sun 517ed29228 Fix GSL_SUPPRESS definition when nvcc is in-use (#1064) 2022-11-07 14:00:32 -08:00
jpr42 d69e578519 clang-tidy: performance-noexcept-move-constructor (#1063)
I ran GSL through clang-tidy with the performance-* checks

https://releases.llvm.org/15.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.html
2022-11-01 10:07:47 -07:00
jpr42 9c4212aca4 Raise CMake min to 3.8 (#1061)
This avoids propagating -std=c++14 as a compile option

Currently if you use less than CMake 3.8 and you install the project
`-std=c++14` gets added to the INTERFACE_COMPILE_OPTIONS. This forces
users to use C++ 14 or remove the property from the imported target.

The solution is to raise the minimum and use `cxx_std_14`
2022-10-29 12:31:23 -07:00
Eli Boyarski 1e0d0446dd README.md: fixed a typo (#1062) 2022-10-24 13:34:44 -07:00
jpr42 c52bad36aa CMake cleanup (#1060)
- Move all install logic inside gsl_install.cmake
  - This makes reading the logic easier, and avoids the enable language
    issue with `GNUInstallDirs` by having it included after the project
    call
- Have all functions inside gsl_functions.cmake
- Use CMake idiom PROJECT_IS_TOP_LEVEL
- Update README.md
2022-10-18 11:05:09 -07:00
dmitrykobets-msft 991fa6682e Prevent inefficient copying when using not_null::get (#1059)
Closes issue #550, which highlighted overhead in not_null::get for larger types such as shared_ptr. Every call to get would return a copy of the contained value.
This PR implements Herb's suggestion for changing the return type of not_null::get. The not_null's value will now only be copied if it is "trivially copyable"; otherwise, it will be returned by const reference.
Note: this change also forces the returned copy to be const.
2022-10-11 16:49:16 -07:00
Herb Sutter 7d49d4b45d Clean up final_act and finally, closes #846 (#977)
Somewhere along the way, GSL's implementation of final_act and finally seems to have become way overthought. This PR is to re-simplify these facilities back to what C++ Core Guidelines C.30 said which is simple and clear and works. It just copies the invocable thing, and doesn't bother trying to optimize the copy. This should be fine, because we're typically passing something that's cheap to copy, often a stateless lambda.

The problem in #846 appears to be because finally looks like was originally written as a const&/&& overload (its state at the time that issue was opened)... to eliminate a copy when you invoke it with a temporary. If so, then the && was probably never intended to be a forwarder, but an rvalue reference that tripped over the horrid C++ syntax collision where a && parameter magically instead means a forwarding reference because the type happens to be a template parameter type here. So I suspect the original author was just trying to write an rvalue overload, and the forwarder that's there now was never intended at all.
2022-10-10 16:09:21 -07:00
Rose 849f7ceaf7 Fix Clang-tidy 15 warnings (#1058)
These warnings were found by running clang-tidy 15.
2022-10-06 09:44:39 -07:00
dmitrykobets-msft 1683d87a3f Fix NDK version in Android CI (#1054)
This PR future-proofs the fix made in #1053, which is now outdated due to further updates to the NDK version in the Azure VMs used as part of the CI.
2022-09-27 17:04:21 -07:00
44 changed files with 1753 additions and 2622 deletions
+1
View File
@@ -0,0 +1 @@
include/gsl/* linguist-language=C++
+18 -9
View File
@@ -1,4 +1,9 @@
name: CI_Android
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches: [ main ]
@@ -7,39 +12,43 @@ on:
jobs:
Android:
runs-on: macos-latest
runs-on: macos-latest-large
defaults:
run:
working-directory: build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Create build directory
run: mkdir -p build
working-directory: .
- name: Start emulator
- uses: actions/setup-java@v4
with:
java-version: 8
distribution: zulu
- name: Start Emulator
run: |
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-24;default;x86_64'
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-24;default;x86_64' --force
$ANDROID_HOME/emulator/emulator -list-avds
echo "Starting emulator"
# Start emulator in background
nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot > /dev/null 2>&1 &
echo "Emulator starting"
echo "Starting emulator..."
nohup $ANDROID_HOME/emulator/emulator -no-audio -no-snapshot -avd xamarin_android_emulator &> /dev/null &
echo "Emulator starting in background"
- name: Configure
run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/25.0.8775105/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
- name: Build
run: cmake --build . --parallel
- name: Wait for emulator ready
timeout-minutes: 2
run: |
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 10; done; input keyevent 82'
$ANDROID_HOME/platform-tools/adb devices
$ANDROID_HOME/platform-tools/adb shell getprop ro.product.cpu.abi
echo "Emulator started"
- name: Deploy tests
run: |
+56
View File
@@ -0,0 +1,56 @@
name: Composite CMake
inputs:
cmake_generator:
required: false
type: string
default: 'Unix Makefiles'
cmake_build_type:
required: true
type: string
default: ''
cmake_cxx_compiler:
required: false
type: string
gsl_cxx_standard:
required: true
type: number
extra_cmake_args:
required: false
type: string
default: ''
build_cmd:
required: true
type: string
default: 'make'
test_cmd:
required: false
type: string
default: 'make test'
shell:
required: false
type: string
default: 'bash'
runs:
using: composite
steps:
- name: Create build directory
run: mkdir build
shell: ${{ inputs.shell }}
- name: Configure CMake
working-directory: build
run: cmake -G "${{ inputs.cmake_generator }}" -DCMAKE_BUILD_TYPE=${{ inputs.cmake_build_type }} -DCMAKE_CXX_COMPILER=${{ inputs.cmake_cxx_compiler }} -DGSL_CXX_STANDARD=${{ inputs.gsl_cxx_standard }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ inputs.extra_cmake_args }} ..
shell: ${{ inputs.shell }}
- name: Build
working-directory: build
run: ${{ inputs.build_cmd }}
shell: ${{ inputs.shell }}
- name: Test
working-directory: build
run: ${{ inputs.test_cmd }}
shell: ${{ inputs.shell }}
+25
View File
@@ -0,0 +1,25 @@
name: cmake_find_package
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
cmake-find-package:
name: Build ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest ]
steps:
- uses: actions/checkout@v4
- uses: lukka/get-cmake@latest
with:
cmakeVersion: 3.14.0
- name: Configure GSL
run: cmake -S . -B build -G "Ninja" -D GSL_TEST=OFF -D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/build/install
- name: Install GSL
run: cmake --build build --target install
- name: Test GSL find_package support
run: cmake -S tests/ -B build/tests_find_package -G "Ninja" -D CMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/build/install -D CMAKE_BUILD_TYPE=Release
+104
View File
@@ -0,0 +1,104 @@
name: Compiler Integration Tests
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# These jobs are correlated with the officially supported compilers
# and toolsets. If you change any versions, please update README.md.
jobs:
gcc:
strategy:
matrix:
gcc_version: [ 10, 11, 12 ]
build_type: [ Debug, Release ]
cxx_version: [ 14, 17, 20, 23 ]
exclude:
- gcc_version: 10
cxx_version: 23
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_build_type: ${{ matrix.build_type }}
cmake_cxx_compiler: g++-${{ matrix.gcc_version }}
gsl_cxx_standard: ${{ matrix.cxx_version }}
clang:
strategy:
matrix:
clang_version: [ 13, 14, 15 ]
build_type: [ Debug, Release ]
cxx_version: [ 14, 17, 20, 23 ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_build_type: ${{ matrix.build_type }}
cmake_cxx_compiler: clang++-${{ matrix.clang_version }}
gsl_cxx_standard: ${{ matrix.cxx_version }}
xcode:
strategy:
matrix:
xcode_version: [ '14.3.1', '15.4' ]
build_type: [ Debug, Release ]
cxx_version: [ 14, 17, 20, 23 ]
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: select xcode version
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode_version }}.app
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_build_type: ${{ matrix.build_type }}
cmake_cxx_compiler: clang++
gsl_cxx_standard: ${{ matrix.cxx_version }}
VisualStudio:
strategy:
matrix:
generator: [ 'Visual Studio 16 2019', 'Visual Studio 17 2022' ]
image: [ windows-2019, windows-2022 ]
build_type: [ Debug, Release ]
extra_args: [ '', '-T ClangCL' ]
cxx_version: [ 14, 17, 20, 23 ]
exclude:
- generator: 'Visual Studio 17 2022'
image: windows-2019
- generator: 'Visual Studio 16 2019'
image: windows-2022
- generator: 'Visual Studio 16 2019'
cxx_version: 23
runs-on: ${{ matrix.image }}
steps:
- uses: actions/checkout@v4
- uses: microsoft/setup-msbuild@v2
- name: Run CMake (configure, build, test)
uses: ./.github/workflows/cmake
with:
cmake_generator: ${{ matrix.generator }}
cmake_build_type: ${{ matrix.build_type }}
gsl_cxx_standard: ${{ matrix.cxx_version }}
extra_cmake_args: ${{ matrix.extra_args }}
build_cmd: msbuild GSL.sln
test_cmd: ctest . --output-on-failure --no-compress-output
shell: pwsh
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
run:
working-directory: build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Create build directory
run: mkdir -p build
+32 -45
View File
@@ -1,61 +1,48 @@
cmake_minimum_required(VERSION 3.1.3...3.16)
cmake_minimum_required(VERSION 3.14...3.16)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(guidelineSupportLibrary)
project(GSL VERSION 4.1.0 LANGUAGES CXX)
project(GSL
VERSION 4.0.0
LANGUAGES CXX
)
# Must include after the project call due to GNUInstallDirs requiring a language be enabled (IE. CXX)
include(GNUInstallDirs)
# Creates a library GSL which is an interface (header files only)
add_library(GSL INTERFACE)
# NOTE: If you want to use GSL prefer to link against GSL using this alias target
# EX:
# target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
#
# Add Microsoft.GSL::GSL alias for GSL so that dependents can be agnostic about
# whether GSL was added via `add_subdirectory` or `find_package`
add_library(Microsoft.GSL::GSL ALIAS GSL)
# 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()
# https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL)
### Project options
option(GSL_INSTALL "Generate and install GSL target" ${GSL_STANDALONE_PROJECT})
option(GSL_TEST "Build and perform GSL tests" ${GSL_STANDALONE_PROJECT})
option(GSL_INSTALL "Generate and install GSL target" ${PROJECT_IS_TOP_LEVEL})
option(GSL_TEST "Build and perform GSL tests" ${PROJECT_IS_TOP_LEVEL})
# This GSL implementation generally assumes a platform that implements C++14 support.
set(gsl_min_cxx_standard "14")
if (GSL_STANDALONE_PROJECT)
gsl_set_default_cxx_standard(${gsl_min_cxx_standard})
else()
gsl_client_set_cxx_standard(${gsl_min_cxx_standard})
endif()
# The implementation generally assumes a platform that implements C++14 support
target_compile_features(GSL INTERFACE "cxx_std_14")
# Setup include directory
add_subdirectory(include)
# Add natvis file
gsl_add_native_visualizer_support()
# Add packaging support
gsl_create_packaging_file()
if (GSL_INSTALL)
# Setup install/export logic
gsl_install_logic()
endif()
target_sources(GSL INTERFACE $<BUILD_INTERFACE:${GSL_SOURCE_DIR}/GSL.natvis>)
if (GSL_TEST)
enable_testing()
add_subdirectory(tests)
endif()
if (GSL_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/gsl" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
set(export_name "Microsoft.GSLConfig")
set(namespace "Microsoft.GSL::")
set(cmake_files_install_dir ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
install(TARGETS GSL EXPORT ${export_name} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(EXPORT ${export_name} NAMESPACE ${namespace} DESTINATION ${cmake_files_install_dir})
export(TARGETS GSL NAMESPACE ${namespace} FILE ${export_name}.cmake)
set(gls_config_version "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake")
write_basic_package_version_file(${gls_config_version} COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT)
install(FILES ${gls_config_version} DESTINATION ${cmake_files_install_dir})
install(FILES GSL.natvis DESTINATION ${cmake_files_install_dir})
endif()
+4 -31
View File
@@ -4,13 +4,7 @@
vim: syntax=xml
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- These types are from the gsl_assert header. -->
<Type Name="gsl::fail_fast">
<!-- na hides the address, otherwise it would appear as 0x.... "Message" -->
<DisplayString>{_Data._What,nasb}</DisplayString>
</Type>
<!-- These types are from the gsl_util header. -->
<!-- These types are from the util header. -->
<Type Name="gsl::final_action&lt;*&gt;">
<DisplayString>{{ invoke = {invoke_}, action = {f_} }}</DisplayString>
<Expand>
@@ -19,7 +13,8 @@
</Expand>
</Type>
<Type Name="gsl::span&lt;*, *&gt;">
<!-- These types are from the span header. -->
<Type Name="gsl::span&lt;*, *&gt;">
<DisplayString>{{ extent = {storage_.size_} }}</DisplayString>
<Expand>
<ArrayItems>
@@ -29,29 +24,7 @@
</Expand>
</Type>
<Type Name="gsl::basic_string_span&lt;*, *&gt;">
<DisplayString>{span_.storage_.data_,[span_.storage_.size_]na}</DisplayString>
<Expand>
<Item Name="[size]">span_.storage_.size_</Item>
<ArrayItems>
<Size>span_.storage_.size_</Size>
<ValuePointer>span_.storage_.data_</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="gsl::basic_zstring_span&lt;*, *&gt;">
<DisplayString>{span_.storage_.data_,[span_.storage_.size_]na}</DisplayString>
<Expand>
<Item Name="[size]">span_.storage_.size_</Item>
<ArrayItems>
<Size>span_.storage_.size_</Size>
<ValuePointer>span_.storage_.data_</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- These types are from the gsl header. -->
<!-- These types are from the pointers header. -->
<Type Name="gsl::not_null&lt;*&gt;">
<!-- We can always dereference this since it's an invariant. -->
<DisplayString>value = {*ptr_}</DisplayString>
+72 -78
View File
@@ -22,59 +22,59 @@ This project makes use of the [Google Test](https://github.com/google/googletest
# Supported features
## Microsoft GSL implements the following from the C++ Core Guidelines:
Feature | Supported? | Description
-----------------------------------|:----------:|-------------
[**1. Views**][cg-views] | |
owner | &#x2611; | an alias for a raw pointer
not_null | &#x2611; | restricts a pointer / smart pointer to hold non-null values
span | &#x2611; | a view over a contiguous sequence of memory. Based on the standardized verison of `std::span`, however `gsl::span` enforces bounds checking. See the [wiki](https://github.com/microsoft/GSL/wiki/gsl::span-and-std::span) for additional information.
span_p | &#x2610; | spans a range starting from a pointer to the first place for which the predicate is true
basic_zstring | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type
zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char
czstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char
wzstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of wchar_t
cwzstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const wchar_t
u16zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char16_t
cu16zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char16_t
u32zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of char32_t
cu32zstring | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of const char32_t
[**2. Owners**][cg-owners] | |
unique_ptr | &#x2611; | an alias to `std::unique_ptr`
shared_ptr | &#x2611; | an alias to `std::shared_ptr`
stack_array | &#x2610; | a stack-allocated array
dyn_array | &#x2610; | a heap-allocated array
[**3. Assertions**][cg-assertions] | |
Expects | &#x2611; | a precondition assertion; on failure it terminates
Ensures | &#x2611; | a postcondition assertion; on failure it terminates
[**4. Utilities**][cg-utilities] | |
move_owner | &#x2610; | a helper function that moves one `owner` to the other
byte | &#x2611; | either an alias to std::byte or a byte type
final_action | &#x2611; | a RAII style class that invokes a functor on its destruction
finally | &#x2611; | a helper function instantiating `final_action`
GSL_SUPPRESS | &#x2611; | a macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
[[implicit]] | &#x2610; | a "marker" to put on single-argument constructors to explicitly make them non-explicit
index | &#x2611; | a type to use for all container and array indexing (currently an alias for std::ptrdiff_t)
joining_thread | &#x2610; | a RAII style version of `std::thread` that joins
narrow | &#x2611; | a checked version of narrow_cast; it can throw `narrowing_error`
narrow_cast | &#x2611; | a narrowing cast for values and a synonym for static_cast
narrowing_error | &#x2611; | a custom exception type thrown by `narrow()`
[**5. Concepts**][cg-concepts] | &#x2610; |
Feature | Supported? | Description
-------------------------------------------------------------------------|:----------:|-------------
[**1. Views**][cg-views] | |
[owner](docs/headers.md#user-content-H-pointers-owner) | &#x2611; | An alias for a raw pointer
[not_null](docs/headers.md#user-content-H-pointers-not_null) | &#x2611; | Restricts a pointer/smart pointer to hold non-null values
[span](docs/headers.md#user-content-H-span-span) | &#x2611; | A view over a contiguous sequence of memory. Based on the standardized version of `std::span`, however `gsl::span` enforces bounds checking.
span_p | &#x2610; | Spans a range starting from a pointer to the first place for which the predicate is true
[basic_zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | A pointer to a C-string (zero-terminated array) with a templated char type
[zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char`
[czstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char`
[wzstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `wchar_t`
[cwzstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const wchar_t`
[u16zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char16_t`
[cu16zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char16_t`
[u32zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t`
[cu32zstring](docs/headers.md#user-content-H-zstring) | &#x2611; | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t`
[**2. Owners**][cg-owners] | |
[unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | &#x2611; | An alias to `std::unique_ptr`
[shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | &#x2611; | An alias to `std::shared_ptr`
stack_array | &#x2610; | A stack-allocated array
dyn_array | &#x2610; | A heap-allocated array
[**3. Assertions**][cg-assertions] | |
[Expects](docs/headers.md#user-content-H-assert-expects) | &#x2611; | A precondition assertion; on failure it terminates
[Ensures](docs/headers.md#user-content-H-assert-ensures) | &#x2611; | A postcondition assertion; on failure it terminates
[**4. Utilities**][cg-utilities] | |
move_owner | &#x2610; | A helper function that moves one `owner` to the other
[byte](docs/headers.md#user-content-H-byte-byte) | &#x2611; | Either an alias to `std::byte` or a byte type
[final_action](docs/headers.md#user-content-H-util-final_action) | &#x2611; | A RAII style class that invokes a functor on its destruction
[finally](docs/headers.md#user-content-H-util-finally) | &#x2611; | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action)
[GSL_SUPPRESS](docs/headers.md#user-content-H-assert-gsl_suppress) | &#x2611; | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
[[implicit]] | &#x2610; | A "marker" to put on single-argument constructors to explicitly make them non-explicit
[index](docs/headers.md#user-content-H-util-index) | &#x2611; | A type to use for all container and array indexing (currently an alias for `std::ptrdiff_t`)
joining_thread | &#x2610; | A RAII style version of `std::thread` that joins
[narrow](docs/headers.md#user-content-H-narrow-narrow) | &#x2611; | A checked version of `narrow_cast`; it can throw [narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error)
[narrow_cast](docs/headers.md#user-content-H-util-narrow_cast) | &#x2611; | A narrowing cast for values and a synonym for `static_cast`
[narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error) | &#x2611; | A custom exception type thrown by [narrow](docs/headers.md#user-content-H-narrow-narrow)
[**5. Concepts**][cg-concepts] | &#x2610; |
## The following features do not exist in or have been removed from the C++ Core Guidelines:
Feature | Supported? | Description
-----------------------------------|:----------:|-------------
strict_not_null | &#x2611; | A stricter version of `not_null` with explicit constructors
[strict_not_null](docs/headers.md#user-content-H-pointers-strict_not_null) | &#x2611; | A stricter version of [not_null](docs/headers.md#user-content-H-pointers-not_null) with explicit constructors
multi_span | &#x2610; | Deprecated. Multi-dimensional span.
strided_span | &#x2610; | Deprecated. Support for this type has been discontinued.
basic_string_span | &#x2610; | Deprecated. Like `span` but for strings with a templated char type
string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char
cstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char
wstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of wchar_t
cwstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const wchar_t
u16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char16_t
cu16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char16_t
u32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of char32_t
cu32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of const char32_t
string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char`
cstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const char`
wstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `wchar_t`
cwstring_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const wchar_t`
u16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char16_t`
cu16string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const char16_t`
u32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `char32_t`
cu32string_span | &#x2610; | Deprecated. An alias to `basic_string_span` with a char type of `const char32_t`
This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library).
@@ -86,24 +86,17 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp
# Quick Start
## Supported Compilers / Toolsets
The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang.
Within these two major versions, we try to target the latest minor updates / revisions (although this may be affected by
delays between a toolchain's release and when it becomes widely available for use).
Below is a table showing the versions currently being tested.
The GSL officially supports recent major versions of Visual Studio with both MSVC and LLVM, GCC, Clang, and XCode with Apple-Clang.
For each of these major versions, the GSL officially supports C++14, C++17, C++20, and C++23 (when supported by the compiler).
Below is a table showing the versions currently being tested (also see [.github/workflows/compilers.yml](the workflow).)
Compiler |Toolset Versions Currently Tested
:------- |--:
XCode | 13.2.1 & 12.5.1
GCC | 11[^1] & 10[^2]
Clang | 12[^2] & 11[^2]
Visual Studio with MSVC | VS2022[^3] & VS2019[^4]
Visual Studio with LLVM | VS2022[^3] & VS2019[^4]
[^1]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26).
[^2]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#language-and-runtime).
[^3]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022).
[^4]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019).
GCC | 10, 11, 12
XCode | 14.3.1, 15.4
Clang | 13, 14, 15
Visual Studio with MSVC | VS2019, VS2022
Visual Studio with LLVM | VS2019, VS2022
---
If you successfully port GSL to another platform, we would love to hear from you!
@@ -121,11 +114,11 @@ Note: These CI/CD steps are run with each pull request, however failures in them
## Building the tests
To build the tests, you will require the following:
* [CMake](http://cmake.org), version 3.1.3 (3.2.3 for AppleClang) or later to be installed and in your PATH.
* [CMake](http://cmake.org), version 3.14 or later to be installed and in your PATH.
These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`.
1. Create a directory to contain the build outputs for a particular architecture (we name it c:\GSL\build-x86 in this example).
1. Create a directory to contain the build outputs for a particular architecture (we name it `c:\GSL\build-x86` in this example).
cd GSL
md build-x86
@@ -179,43 +172,44 @@ Include the library using:
## Usage in CMake
The library provides a Config file for CMake, once installed it can be found via
find_package(Microsoft.GSL CONFIG)
The library provides a Config file for CMake, once installed it can be found via `find_package`.
Which, when successful, will add library target called `Microsoft.GSL::GSL` which you can use via the usual
`target_link_libraries` mechanism.
```cmake
find_package(Microsoft.GSL CONFIG REQUIRED)
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
```
### FetchContent
If you are using cmake version 3.11+ you can use the offical FetchContent module.
If you are using CMake version 3.11+ you can use the official [FetchContent module](https://cmake.org/cmake/help/latest/module/FetchContent.html).
This allows you to easily incorporate GSL into your project.
```cmake
# NOTE: This example uses cmake version 3.14 (FetchContent_MakeAvailable).
# NOTE: This example uses CMake version 3.14 (FetchContent_MakeAvailable).
# Since it streamlines the FetchContent process
cmake_minimum_required(VERSION 3.14)
include(FetchContent)
# In this example we are picking a specific tag.
# You can also pick a specific commit, if you need to.
FetchContent_Declare(GSL
GIT_REPOSITORY "https://github.com/microsoft/GSL"
GIT_TAG "v3.1.0"
GIT_TAG "v4.1.0"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(GSL)
# Now you can link against the GSL interface library
add_executable(foobar)
# Link against the interface library (IE header only library)
target_link_libraries(foobar PRIVATE GSL)
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
```
## Debugging visualization support
For Visual Studio users, the file [GSL.natvis](./GSL.natvis) in the root directory of the repository can be added to your project if you would like more helpful visualization of GSL types in the Visual Studio debugger than would be offered by default.
If you are using cmake this will be done automatically for you.
See 'GSL_VS_ADD_NATIVE_VISUALIZERS'
## See Also
For information on [Microsoft Gray Systems Lab (GSL)](https://aka.ms/gsl) of applied data management and system research see <https://aka.ms/gsl>.
-66
View File
@@ -1,66 +0,0 @@
trigger:
- main
pr:
autoCancel: true
stages:
- stage: GCC
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: gcc
image: ubuntu-20.04
compilerVersions: [ 11, 10 ]
setupfile: 'setup_gcc.yml'
- stage: Clang
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: clang
image: ubuntu-20.04
compilerVersions: [ 12, 11 ]
setupfile: 'setup_clang.yml'
- stage: Xcode
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: 'Xcode'
image: macOS-11
compilerVersions: [ '12.5.1', '13.2.1' ]
setupfile: 'setup_apple.yml'
- stage: VS_MSVC
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2019 (MSVC)'
compilerVersions: [ 'default' ]
image: windows-2019
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2022 (MSVC)'
compilerVersions: [ 'default' ]
image: windows-2022
- stage: VS_LLVM
dependsOn: []
jobs:
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2019 (LLVM)'
compilerVersions: [ 'default' ]
image: windows-2019
extraCmakeArgs: '-T ClangCL'
- template: ./pipelines/jobs.yml
parameters:
compiler: 'VS2022 (LLVM)'
compilerVersions: [ 'default' ]
image: windows-2022
extraCmakeArgs: '-T ClangCL'
-116
View File
@@ -1,116 +0,0 @@
# This cmake module is meant to hold helper functions/macros
# that make maintaining the cmake build system much easier.
# This is especially helpful since gsl needs to provide coverage
# for multiple versions of cmake.
#
# Any functions/macros should have a gsl_* prefix to avoid problems
if (CMAKE_VERSION VERSION_GREATER 3.10 OR CMAKE_VERSION VERSION_EQUAL 3.10)
include_guard()
else()
if (DEFINED guideline_support_library_include_guard)
return()
endif()
set(guideline_support_library_include_guard ON)
endif()
# Necessary for 'write_basic_package_version_file'
include(CMakePackageConfigHelpers)
function(gsl_set_default_cxx_standard min_cxx_standard)
set(GSL_CXX_STANDARD "${min_cxx_standard}" CACHE STRING "Use c++ standard")
set(GSL_CXX_STD "cxx_std_${GSL_CXX_STANDARD}")
if (MSVC)
set(GSL_CXX_STD_OPT "-std:c++${GSL_CXX_STANDARD}")
else()
set(GSL_CXX_STD_OPT "-std=c++${GSL_CXX_STANDARD}")
endif()
# when minimum version required is 3.8.0 remove if below
# both branches do exactly the same thing
if (CMAKE_VERSION VERSION_LESS 3.7.9)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("${GSL_CXX_STD_OPT}" COMPILER_SUPPORTS_CXX_STANDARD)
if(COMPILER_SUPPORTS_CXX_STANDARD)
target_compile_options(GSL INTERFACE "${GSL_CXX_STD_OPT}")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no c++${GSL_CXX_STANDARD} support. Please use a different C++ compiler.")
endif()
else()
target_compile_features(GSL INTERFACE "${GSL_CXX_STD}")
# on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
endfunction()
# The best way for a project to specify the GSL's C++ standard is by the client specifying
# the CMAKE_CXX_STANDARD. However, this isn't always ideal. Since the CMAKE_CXX_STANDARD is
# tied to the cmake version. And many projects have low cmake minimums.
#
# So provide an alternative approach in case that doesn't work.
function(gsl_client_set_cxx_standard min_cxx_standard)
if (DEFINED CMAKE_CXX_STANDARD)
if (${CMAKE_CXX_STANDARD} VERSION_LESS ${min_cxx_standard})
message(FATAL_ERROR "GSL: Requires at least CXX standard ${min_cxx_standard}, user provided ${CMAKE_CXX_STANDARD}")
endif()
# Set the GSL standard to what the client desires
set(GSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
# Exit out early to avoid extra unneccessary work
return()
endif()
# Otherwise pick a reasonable default
gsl_set_default_cxx_standard(${min_cxx_standard})
endfunction()
# Adding the GSL.natvis files improves the debugging experience for users of this library.
function(gsl_add_native_visualizer_support)
if (CMAKE_VERSION VERSION_GREATER 3.7.8)
if (MSVC_IDE)
option(GSL_VS_ADD_NATIVE_VISUALIZERS "Configure project to use Visual Studio native visualizers" TRUE)
else()
set(GSL_VS_ADD_NATIVE_VISUALIZERS FALSE CACHE INTERNAL "Native visualizers are Visual Studio extension" FORCE)
endif()
# add natvis file to the library so it will automatically be loaded into Visual Studio
if(GSL_VS_ADD_NATIVE_VISUALIZERS)
target_sources(GSL INTERFACE $<BUILD_INTERFACE:${GSL_SOURCE_DIR}/GSL.natvis>)
endif()
endif()
endfunction()
function(gsl_install_logic)
install(TARGETS GSL EXPORT Microsoft.GSLConfig)
install(
DIRECTORY include/gsl
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
# Make library importable by other projects
install(EXPORT Microsoft.GSLConfig NAMESPACE Microsoft.GSL:: DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
export(TARGETS GSL NAMESPACE Microsoft.GSL:: FILE Microsoft.GSLConfig.cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
endfunction()
# Add find_package() versioning support. The version for
# generated Microsoft.GSLConfigVersion.cmake will be used from
# last project() command. The version's compatibility is set between all
# minor versions (as it was in prev. GSL releases).
function(gsl_create_packaging_file)
if(${CMAKE_VERSION} VERSION_LESS "3.14.0")
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake
COMPATIBILITY SameMajorVersion
)
else()
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake
COMPATIBILITY SameMajorVersion
ARCH_INDEPENDENT
)
endif()
endfunction()
+860
View File
@@ -0,0 +1,860 @@
The Guidelines Support Library (GSL) interface is very lightweight and exposed via a header-only library. This document attempts to document all of the headers and their exposed classes and functions.
Types and functions are exported in the namespace `gsl`.
See [GSL: Guidelines support library](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl)
# <a name="H" />Headers
- [`<algorithms>`](#user-content-H-algorithms)
- [`<assert>`](#user-content-H-assert)
- [`<byte>`](#user-content-H-byte)
- [`<gsl>`](#user-content-H-gsl)
- [`<narrow>`](#user-content-H-narrow)
- [`<pointers>`](#user-content-H-pointers)
- [`<span>`](#user-content-H-span)
- [`<span_ext>`](#user-content-H-span_ext)
- [`<zstring>`](#user-content-H-zstring)
- [`<util>`](#user-content-H-util)
## <a name="H-algorithms" />`<algorithms>`
This header contains some common algorithms that have been wrapped in GSL safety features.
- [`gsl::copy`](#user-content-H-algorithms-copy)
### <a name="H-algorithms-copy" />`gsl::copy`
```cpp
template <class SrcElementType, std::size_t SrcExtent, class DestElementType,
std::size_t DestExtent>
void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent> dest);
```
This function copies the content from the `src` [`span`](#user-content-H-span-span) to the `dest` [`span`](#user-content-H-span-span). It [`Expects`](#user-content-H-assert-expects)
that the destination `span` is at least as large as the source `span`.
## <a name="H-assert" />`<assert>`
This header contains some macros used for contract checking and suppressing code analysis warnings.
See [GSL.assert: Assertions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions)
- [`GSL_SUPPRESS`](#user-content-H-assert-gsl_suppress)
- [`Expects`](#user-content-H-assert-expects)
- [`Ensures`](#user-content-H-assert-ensures)
### <a name="H-assert-gsl_suppress" />`GSL_SUPPRESS`
This macro can be used to suppress a code analysis warning.
The core guidelines request tools that check for the rules to respect suppressing a rule by writing
`[[gsl::suppress(tag)]]` or `[[gsl::suppress(tag, justification: "message")]]`.
Clang does not use exactly that syntax, but requires `tag` to be put in double quotes `[[gsl::suppress("tag")]]`.
For portable code you can use `GSL_SUPPRESS(tag)`.
See [In.force: Enforcement](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#inforce-enforcement).
### <a name="H-assert-expects" />`Expects`
This macro can be used for expressing a precondition. If the precondition is not held, then `std::terminate` will be called.
See [I.6: Prefer `Expects()` for expressing preconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i6-prefer-expects-for-expressing-preconditions)
### <a name="H-assert-ensures" />`Ensures`
This macro can be used for expressing a postcondition. If the postcondition is not held, then `std::terminate` will be called.
See [I.8: Prefer `Ensures()` for expressing postconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i8-prefer-ensures-for-expressing-postconditions)
## <a name="H-byte" />`<byte>`
This header contains the definition of a byte type, implementing `std::byte` before it was standardized into C++17.
- [`gsl::byte`](#user-content-H-byte-byte)
### <a name="H-byte-byte" />`gsl::byte`
If `GSL_USE_STD_BYTE` is defined to be `1`, then `gsl::byte` will be an alias to `std::byte`.
If `GSL_USE_STD_BYTE` is defined to be `0`, then `gsl::byte` will be a distinct type that implements the concept of byte.
If `GSL_USE_STD_BYTE` is not defined, then the header file will check if `std::byte` is available (C\+\+17 or higher). If yes,
`gsl::byte` will be an alias to `std::byte`, otherwise `gsl::byte` will be a distinct type that implements the concept of byte.
&#x26a0; Take care when linking projects that were compiled with different language standards (before C\+\+17 and C\+\+17 or higher).
If you do so, you might want to `#define GSL_USE_STD_BYTE 0` to a fixed value to be sure that both projects use exactly
the same type. Otherwise you might get linker errors.
See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily represent characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-byte)
### Non-member functions
```cpp
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator<<(byte b, IntegerType shift) noexcept;
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
```
Left or right shift a `byte` by a given number of bits.
```cpp
constexpr byte& operator|=(byte& l, byte r) noexcept;
constexpr byte operator|(byte l, byte r) noexcept;
```
Bitwise "or" of two `byte`s.
```cpp
constexpr byte& operator&=(byte& l, byte r) noexcept;
constexpr byte operator&(byte l, byte r) noexcept;
```
Bitwise "and" of two `byte`s.
```cpp
constexpr byte& operator^=(byte& l, byte r) noexcept;
constexpr byte operator^(byte l, byte r) noexcept;
```
Bitwise xor of two `byte`s.
```cpp
constexpr byte operator~(byte b) noexcept;
```
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.
```cpp
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr IntegerType to_integer(byte b) noexcept;
```
Convert the given `byte` value to an integral type.
```cpp
template <typename T>
constexpr byte to_byte(T t) noexcept;
```
Convert the given value to a `byte`. The template requires `T` to be an `unsigned char` so that no data loss can occur.
If you want to convert an integer constant to a `byte` you probably want to call `to_byte<integer constant>()`.
```cpp
template <int I>
constexpr byte to_byte() noexcept;
```
Convert the given value `I` to a `byte`. The template requires `I` to be in the valid range 0..255 for a `gsl::byte`.
## <a name="H-gsl" />`<gsl>`
This header is a convenience header that includes all other [GSL headers](#user-content-H).
Since `<narrow>` requires exceptions, it will only be included if exceptions are enabled.
## <a name="H-narrow" />`<narrow>`
This header contains utility functions and classes, for narrowing casts, which require exceptions. The narrowing-related utilities that don't require exceptions are found inside [util](#user-content-H-util).
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
- [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error)
- [`gsl::narrow`](#user-content-H-narrow-narrow)
### <a name="H-narrow-narrowing_error" />`gsl::narrowing_error`
`gsl::narrowing_error` is the exception thrown by [`gsl::narrow`](#user-content-H-narrow-narrow) when a narrowing conversion fails. It is derived from `std::exception`.
### <a name="H-narrow-narrow" />`gsl::narrow`
`gsl::narrow<T>(x)` is a named cast that does a `static_cast<T>(x)` for narrowing conversions with no signedness promotions.
If the argument `x` cannot be represented in the target type `T`, then the function throws a [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error) (e.g., `narrow<unsigned>(-42)` and `narrow<char>(300)` throw).
Note: compare [`gsl::narrow_cast`](#user-content-H-util-narrow_cast) in header [util](#user-content-H-util).
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
## <a name="H-pointers" />`<pointers>`
This header contains some pointer types.
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views)
- [`gsl::unique_ptr`](#user-content-H-pointers-unique_ptr)
- [`gsl::shared_ptr`](#user-content-H-pointers-shared_ptr)
- [`gsl::owner`](#user-content-H-pointers-owner)
- [`gsl::not_null`](#user-content-H-pointers-not_null)
- [`gsl::strict_not_null`](#user-content-H-pointers-strict_not_null)
### <a name="H-pointers-unique_ptr" />`gsl::unique_ptr`
`gsl::unique_ptr` is an alias to `std::unique_ptr`.
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
### <a name="H-pointers-shared_ptr" />`gsl::shared_ptr`
`gsl::shared_ptr` is an alias to `std::shared_ptr`.
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
### <a name="H-pointers-owner" />`gsl::owner`
`gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory. Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used as a stepping point in converting legacy code to use more modern RAII constructs such as smart pointers.
`T` must be a pointer type (`std::is_pointer<T>`).
A `gsl::owner<T>` is a typedef to `T`. It adds no runtime overhead whatsoever, as it is purely syntactic and does not add any runtime checks. Instead, it serves as an annotation for static analysis tools which check for memory safety, and as a code comprehension guide for human readers.
See Enforcement section of [C.31: All resources acquired by a class must be released by the classs destructor](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-dtor-release).
### <a name="H-pointers-not_null" />`gsl::not_null`
`gsl::not_null<T>` restricts a pointer or smart pointer to only hold non-null values. It has no size overhead over `T`.
The checks for ensuring that the pointer is not null are done in the constructor. There is no overhead when retrieving or dereferencing the checked pointer.
When a nullptr check fails, `std::terminate` is called.
See [F.23: Use a `not_null<T>` to indicate that “null” is not a valid value](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr)
#### Member functions
##### Construct/Copy
```cpp
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u);
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u);
```
Constructs a `gsl_owner<T>` from a pointer that is convertible to `T` or that is a `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
```cpp
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other);
```
Constructs a `gsl_owner<T>` from another `gsl_owner` where the other pointer is convertible to `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
```cpp
not_null(const not_null& other) = default;
not_null& operator=(const not_null& other) = default;
```
Copy construction and assignment.
```cpp
not_null(std::nullptr_t) = delete;
not_null& operator=(std::nullptr_t) = delete;
```
Construction from `std::nullptr_t` and assignment of `std::nullptr_t` are explicitly deleted.
##### Modifiers
```cpp
not_null& operator++() = delete;
not_null& operator--() = delete;
not_null operator++(int) = delete;
not_null operator--(int) = delete;
not_null& operator+=(std::ptrdiff_t) = delete;
not_null& operator-=(std::ptrdiff_t) = delete;
```
Explicitly deleted operators. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
##### Observers
```cpp
constexpr details::value_or_reference_return_t<T> get() const;
constexpr operator T() const { return get(); }
```
Get the underlying pointer.
```cpp
constexpr decltype(auto) operator->() const { return get(); }
constexpr decltype(auto) operator*() const { return *get(); }
```
Dereference the underlying pointer.
```cpp
void operator[](std::ptrdiff_t) const = delete;
```
Array index operator is explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow treating them as an array.
#### Non-member functions
```cpp
template <class T>
auto make_not_null(T&& t) noexcept;
```
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
```cpp
template <class T, class U>
auto operator==(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
-> decltype(lhs.get() == rhs.get());
template <class T, class U>
auto operator!=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
-> decltype(lhs.get() != rhs.get());
template <class T, class U>
auto operator<(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
-> decltype(lhs.get() < rhs.get());
template <class T, class U>
auto operator<=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
-> decltype(lhs.get() <= rhs.get());
template <class T, class U>
auto operator>(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
-> decltype(lhs.get() > rhs.get());
template <class T, class U>
auto operator>=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
-> decltype(lhs.get() >= rhs.get());
```
Comparison of pointers that are convertible to each other.
##### Input/Output
```cpp
template <class T>
std::ostream& operator<<(std::ostream& os, const not_null<T>& val);
```
Performs stream output on a `not_null` pointer, invoking `os << val.get()`. This function is only available when `GSL_NO_IOSTREAMS` is not defined.
##### Modifiers
```cpp
template <class T, class U>
std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
template <class T>
not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
template <class T>
not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
template <class T>
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
```
Addition and subtraction are explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
##### STL integration
```cpp
template <class T>
struct std::hash<gsl::not_null<T>> { ... };
```
Specialization of `std::hash` for `gsl::not_null`.
### <a name="H-pointers-strict_not_null" />`gsl::strict_not_null`
`strict_not_null` is the same as [`not_null`](#user-content-H-pointers-not_null) except that the constructors are `explicit`.
The free function that deduces the target type from the type of the argument and creates a `gsl::strict_not_null` object is `gsl::make_strict_not_null`.
## <a name="H-span" />`<span>`
This header file exports the class `gsl::span`, a bounds-checked implementation of `std::span`.
- [`gsl::span`](#user-content-H-span-span)
### <a name="H-span-span" />`gsl::span`
```cpp
template <class ElementType, std::size_t Extent>
class span;
```
`gsl::span` is a view over memory. It does not own the memory and is only a way to access contiguous sequences of objects.
The extent can be either a fixed size or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
The `gsl::span` is based on the standardized version of `std::span` which was added to C++20. Originally, the plan was to
deprecate `gsl::span` when `std::span` finished standardization, however that plan changed when the runtime bounds checking
was removed from `std::span`'s design.
The only difference between `gsl::span` and `std::span` is that `gsl::span` strictly enforces runtime bounds checking.
Any violations of the bounds check results in termination of the program.
Like `gsl::span`, `gsl::span`'s iterators also differ from `std::span`'s iterator in that all access operations are bounds checked.
#### Which version of span should I use?
##### Use `gsl::span` if
- you want to guarantee bounds safety in your project.
- All data accessing operations use bounds checking to ensure you are only accessing valid memory.
- your project uses C++14 or C++17.
- `std::span` is not available as it was not introduced into the STL until C++20.
##### Use `std::span` if
- your project is C++20 and you need the performance offered by `std::span`.
#### Types
```cpp
using element_type = ElementType;
using value_type = std::remove_cv_t<ElementType>;
using size_type = std::size_t;
using pointer = element_type*;
using const_pointer = const element_type*;
using reference = element_type&;
using const_reference = const element_type&;
using difference_type = std::ptrdiff_t;
using iterator = details::span_iterator<ElementType>;
using reverse_iterator = std::reverse_iterator<iterator>;
```
#### Member functions
```cpp
constexpr span() noexcept;
```
Constructs an empty `span`. This constructor is only available if `Extent` is 0 or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
`span::data()` will return `nullptr`.
```cpp
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer ptr, size_type count) noexcept;
```
Constructs a `span` from a pointer and a size. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
then the constructor [`Expects`](#user-content-H-assert-expects) that `count == Extent`.
```cpp
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer firstElem, pointer lastElem) noexcept;
```
Constructs a `span` from a pointer to the begin and the end of the data. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
then the constructor [`Expects`](#user-content-H-assert-expects) that `lastElem - firstElem == Extent`.
```cpp
template <std::size_t N>
constexpr span(element_type (&arr)[N]) noexcept;
```
Constructs a `span` from a C style array. This overload is available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
or `N == Extent`.
```cpp
template <class T, std::size_t N>
constexpr span(std::array<T, N>& arr) noexcept;
template <class T, std::size_t N>
constexpr span(const std::array<T, N>& arr) noexcept;
```
Constructs a `span` from a `std::array`. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
or `N == Extent`, and if the array can be interpreted as a `ElementType` array.
```cpp
template <class Container>
constexpr explicit(Extent != gsl::dynamic_extent) span(Container& cont) noexcept;
template <class Container>
constexpr explicit(Extent != gsl::dynamic_extent) span(const Container& cont) noexcept;
```
Constructs a `span` from a container. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
or `N == Extent`, and if the container can be interpreted as a contiguous `ElementType` array.
```cpp
constexpr span(const span& other) noexcept = default;
```
Copy constructor.
```cpp
template <class OtherElementType, std::size_t OtherExtent>
explicit(Extent != gsl::dynamic_extent && OtherExtent == dynamic_extent)
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept;
```
Constructs a `span` from another `span`. This constructor is available if `OtherExtent == Extent || Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)` || OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
and if `ElementType` and `OtherElementType` are compatible.
If `Extent !=`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) and `OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
then the constructor [`Expects`](#user-content-H-assert-expects) that `other.size() == Extent`.
```cpp
constexpr span& operator=(const span& other) noexcept = default;
```
Copy assignment
```cpp
template <std::size_t Count>
constexpr span<element_type, Count> first() const noexcept;
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept;
template <std::size_t Count>
constexpr span<element_type, Count> last() const noexcept;
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept;
```
Return a subspan of the first/last `Count` elements. [`Expects`](#user-content-H-assert-expects) that `Count` does not exceed the `span`'s size.
```cpp
template <std::size_t offset, std::size_t count = dynamic_extent>
constexpr auto subspan() const noexcept;
constexpr span<element_type, dynamic_extent>
subspan(size_type offset, size_type count = dynamic_extent) const noexcept;
```
Return a subspan starting at `offset` and having size `count`. [`Expects`](#user-content-H-assert-expects) that `offset` does not exceed the `span`'s size,
and that `offset == `[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) or `offset + count` does not exceed the `span`'s size.
If `count` is `gsl::dynamic_extent`, the number of elements in the subspan is `size() - offset`.
```cpp
constexpr size_type size() const noexcept;
constexpr size_type size_bytes() const noexcept;
```
Returns the size respective the size in bytes of the `span`.
```cpp
constexpr bool empty() const noexcept;
```
Is the `span` empty?
```cpp
constexpr reference operator[](size_type idx) const noexcept;
```
Returns a reference to the element at the given index. [`Expects`](#user-content-H-assert-expects) that `idx` is less than the `span`'s size.
```cpp
constexpr reference front() const noexcept;
constexpr reference back() const noexcept;
```
Returns a reference to the first/last element in the `span`. [`Expects`](#user-content-H-assert-expects) that the `span` is not empty.
```cpp
constexpr pointer data() const noexcept;
```
Returns a pointer to the beginning of the contained data.
```cpp
constexpr iterator begin() const noexcept;
constexpr iterator end() const noexcept;
constexpr reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() const noexcept;
```
Returns an iterator to the first/last normal/reverse iterator.
```cpp
template <class Type, std::size_t Extent>
span(Type (&)[Extent]) -> span<Type, Extent>;
template <class Type, std::size_t Size>
span(std::array<Type, Size>&) -> span<Type, Size>;
template <class Type, std::size_t Size>
span(const std::array<Type, Size>&) -> span<const Type, Size>;
template <class Container,
class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
span(Container&) -> span<Element>;
template <class Container,
class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
span(const Container&) -> span<Element>;
```
Deduction guides.
```cpp
template <class ElementType, std::size_t Extent>
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(span<ElementType, Extent> s) noexcept;
template <class ElementType, std::size_t Extent>
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writable_bytes(span<ElementType, Extent> s) noexcept;
```
Converts a `span` into a `span` of `byte`s.
`as_writable_bytes` will only be available for non-const `ElementType`s.
## <a name="H-span_ext" />`<span_ext>`
This file is a companion for and included by [`<gsl/span>`](#user-content-H-span), and should not be used on its own. It contains useful features that aren't part of the `std::span` API as found inside the STL `<span>` header (with the exception of [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent), which is included here due to implementation constraints).
- [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
- [`gsl::span`](#user-content-H-span_ext-span)
- [`gsl::span` comparison operators](#user-content-H-span_ext-span_comparison_operators)
- [`gsl::make_span`](#user-content-H-span_ext-make_span)
- [`gsl::at`](#user-content-H-span_ext-at)
- [`gsl::ssize`](#user-content-H-span_ext-ssize)
- [`gsl::span` iterator functions](#user-content-H-span_ext-span_iterator_functions)
### <a name="H-span_ext-dynamic_extent" />`gsl::dynamic_extent`
Defines the extent value to be used by all `gsl::span` with dynamic extent.
Note: `std::dynamic_extent` is exposed by the STL `<span>` header and so ideally `gsl::dynamic_extent` would be under [`<gsl/span>`](#user-content-H-span), but to avoid cyclic dependency issues it is under `<span_ext>` instead.
### <a name="H-span_ext-span" />`gsl::span`
```cpp
template <class ElementType, std::size_t Extent = dynamic_extent>
class span;
```
Forward declaration of `gsl::span`.
### <a name="H-span_ext-span_comparison_operators" />`gsl::span` comparison operators
```cpp
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator!=(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
template <class ElementType, std::size_t Extent>
constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r);
template <class ElementType, std::size_t Extent>
constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r);
template <class ElementType, std::size_t Extent>
constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r);
template <class ElementType, std::size_t Extent>
constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r);
```
The comparison operators for two `span`s lexicographically compare the elements in the `span`s.
### <a name="H-span_ext-make_span" />`gsl::make_span`
```cpp
template <class ElementType>
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::size_type count);
template <class ElementType>
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem);
template <class ElementType, std::size_t N>
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept;
template <class Container>
constexpr span<typename Container::value_type> make_span(Container& cont);
template <class Container>
constexpr span<const typename Container::value_type> make_span(const Container& cont);
template <class Ptr>
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count);
template <class Ptr>
constexpr span<typename Ptr::element_type> make_span(Ptr& cont);
```
Utility function for creating a `span` with [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) from
- pointer and length,
- pointer to start and pointer to end,
- a C style array, or
- a container.
### <a name="H-span_ext-at" />`gsl::at`
```cpp
template <class ElementType, std::size_t Extent>
constexpr ElementType& at(span<ElementType, Extent> s, index i);
```
The function `gsl::at` offers a safe way to access data with index bounds checking.
This is the specialization of [`gsl::at`](#user-content-H-util-at) for [`span`](#user-content-H-span-span). It returns a reference to the `i`th element and
[`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the `span`.
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
### <a name="H-span_ext-ssize" />`gsl::ssize`
```cpp
template <class ElementType, std::size_t Extent>
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept;
```
Return the size of a [`span`](#user-content-H-span-span) as a `ptrdiff_t`.
### <a name="H-span_ext-span_iterator_functions" />`gsl::span` iterator functions
```cpp
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::iterator
begin(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent = dynamic_extent>
constexpr typename span<ElementType, Extent>::iterator
end(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::reverse_iterator
rbegin(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::reverse_iterator
rend(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::iterator
cbegin(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent = dynamic_extent>
constexpr typename span<ElementType, Extent>::iterator
cend(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::reverse_iterator
crbegin(const span<ElementType, Extent>& s) noexcept;
template <class ElementType, std::size_t Extent>
constexpr typename span<ElementType, Extent>::reverse_iterator
crend(const span<ElementType, Extent>& s) noexcept;
```
Free functions for getting a non-const/const begin/end normal/reverse iterator for a [`span`](#user-content-H-span-span).
## <a name="H-zstring" />`<zstring>`
This header exports a family of `*zstring` types.
A `gsl::XXzstring<T>` is a typedef to `T`. It adds no checks whatsoever, it is just for having a syntax to describe
that a pointer points to a zero terminated C style string. This helps static code analysis, and it helps human readers.
`basic_zstring` is a pointer to a C-string (zero-terminated array) with a templated char type. Used to implement the rest of the `*zstring` family.
`zstring` is a zero terminated `char` string.
`czstring` is a const zero terminated `char` string.
`wzstring` is a zero terminated `wchar_t` string.
`cwzstring` is a const zero terminated `wchar_t` string.
`u16zstring` is a zero terminated `char16_t` string.
`cu16zstring` is a const zero terminated `char16_t` string.
`u32zstring` is a zero terminated `char32_t` string.
`cu32zstring` is a const zero terminated `char32_t` string.
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views) and [SL.str.3: Use zstring or czstring to refer to a C-style, zero-terminated, sequence of characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-zstring).
## <a name="H-util" />`<util>`
This header contains utility functions and classes. This header works without exceptions being available. The parts that require
exceptions being available are in their own header file [narrow](#user-content-H-narrow).
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
- [`gsl::narrow_cast`](#user-content-H-util-narrow_cast)
- [`gsl::final_action`](#user-content-H-util-final_action)
- [`gsl::at`](#user-content-H-util-at)
### <a name="H-util-index" />`gsl::index`
An alias to `std::ptrdiff_t`. It serves as the index type for all container indexes/subscripts/sizes.
### <a name="H-util-narrow_cast" />`gsl::narrow_cast`
`gsl::narrow_cast<T>(x)` is a named cast that is identical to a `static_cast<T>(x)`. It exists to make clear to static code analysis tools and to human readers that a lossy conversion is acceptable.
Note: compare the throwing version [`gsl::narrow`](#user-content-H-narrow-narrow) in header [narrow](#user-content-H-narrow).
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
### <a name="H-util-final_action" />`gsl::final_action`
```cpp
template <class F>
class final_action { ... };
```
`final_action` allows you to ensure something gets run at the end of a scope.
See [E.19: Use a final_action object to express cleanup if no suitable resource handle is available](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-finally)
#### Member functions
```cpp
explicit final_action(const F& ff) noexcept;
explicit final_action(F&& ff) noexcept;
```
Construct an object with the action to invoke in the destructor.
```cpp
~final_action() noexcept;
```
The destructor will call the action that was passed in the constructor.
```cpp
final_action(final_action&& other) noexcept;
final_action(const final_action&) = delete;
void operator=(const final_action&) = delete;
void operator=(final_action&&) = delete;
```
Move construction is allowed. Copy construction is deleted. Copy and move assignment are also explicitly deleted.
#### <a name="H-util-finally" />Non-member functions
```cpp
template <class F>
auto finally(F&& f) noexcept;
```
Creates a `gsl::final_action` object, deducing the template argument type from the type of the argument.
### <a name="H-util-at" />`gsl::at`
The function `gsl::at` offers a safe way to access data with index bounds checking.
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
See [ES.42: Keep use of pointers simple and straightforward](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-ptr)
```cpp
template <class T, std::size_t N>
constexpr T& at(T (&arr)[N], const index i);
```
This overload returns a reference to the `i`s element of a C style array `arr`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
```cpp
template <class Cont>
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]);
```
This overload returns a reference to the `i`s element of the container `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
```cpp
template <class T>
constexpr T at(const std::initializer_list<T> cont, const index i);
```
This overload returns a reference to the `i`s element of the initializer list `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
```cpp
template <class T, std::size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()]);
```
This overload returns a reference to the `i`s element of the `std::span` `sp`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
For [`gsl::at`](#user-content-H-span_ext-at) for [`gsl::span`](#user-content-H-span-span) see header [`span_ext`](#user-content-H-span_ext).
+3 -10
View File
@@ -1,4 +1,3 @@
# Add include folders to the library and targets that consume it
# the SYSTEM keyword suppresses warnings for users of the library
#
@@ -7,14 +6,8 @@
#
# IE:
# #include <gsl/gsl>
if(GSL_STANDALONE_PROJECT)
target_include_directories(GSL INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if(PROJECT_IS_TOP_LEVEL)
target_include_directories(GSL INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
else()
target_include_directories(GSL SYSTEM INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_include_directories(GSL SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
endif()
+5 -8
View File
@@ -14,8 +14,8 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef GSL_CONTRACTS_H
#define GSL_CONTRACTS_H
#ifndef GSL_ASSERT_H
#define GSL_ASSERT_H
//
// Temporary until MSVC STL supports no-exceptions mode.
@@ -46,18 +46,15 @@
// Hopefully temporary until suppression standardization occurs
//
#if defined(__clang__)
#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]]
#else
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__)
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
#else
#define GSL_SUPPRESS(x)
#endif // _MSC_VER
#endif // __clang__
#define GSL_STRINGIFY_DETAIL(x) #x
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
#if defined(__clang__) || defined(__GNUC__)
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
@@ -133,4 +130,4 @@ namespace details
#pragma clang diagnostic pop
#endif
#endif // GSL_CONTRACTS_H
#endif // GSL_ASSERT_H
+8 -38
View File
@@ -17,24 +17,8 @@
#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) && !defined(__INTEL_COMPILER)
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
#else
#define GSL_SUPPRESS(x)
#endif // _MSC_VER
#endif // __clang__
#include <type_traits>
// VS2017 15.8 added support for the __cpp_lib_byte definition
// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires
#ifdef _MSC_VER
#pragma warning(push)
@@ -45,18 +29,15 @@
#ifndef GSL_USE_STD_BYTE
// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \
(defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#define GSL_USE_STD_BYTE 1
#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
// 201603)
#else // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#define GSL_USE_STD_BYTE 0
#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
// 201603)
#endif // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
#endif // GSL_USE_STD_BYTE
#else // _MSC_VER
@@ -174,26 +155,15 @@ constexpr IntegerType to_integer(byte b) noexcept
#endif // GSL_USE_STD_BYTE
template <bool E, typename T>
constexpr byte to_byte_impl(T t) noexcept
{
static_assert(
E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
"If you are calling to_byte with an integer contant use: gsl::to_byte<t>() version.");
return static_cast<byte>(t);
}
template <>
template <typename T>
// NOTE: need suppression since c++14 does not allow "return {t}"
// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
constexpr byte to_byte_impl<true, unsigned char>(unsigned char t) noexcept
{
return byte(t);
}
template <typename T>
constexpr byte to_byte(T t) noexcept
{
return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
static_assert(std::is_same<T, unsigned char>::value,
"gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
"If you are calling to_byte with an integer constant use: gsl::to_byte<t>() version.");
return byte(t);
}
template <int I>
+3 -1
View File
@@ -17,16 +17,18 @@
#ifndef GSL_GSL_H
#define GSL_GSL_H
// IWYU pragma: begin_exports
#include "algorithm" // copy
#include "assert" // Ensures/Expects
#include "byte" // byte
#include "pointers" // owner, not_null
#include "span" // span
#include "string_span" // zstring, string_span, zstring_builder...
#include "zstring" // zstring
#include "util" // finally()/narrow_cast()...
#ifdef __cpp_exceptions
#include "narrow" // narrow()
#endif
// IWYU pragma: end_exports
#endif // GSL_GSL_H
-4
View File
@@ -1,4 +0,0 @@
#pragma once
#pragma message( \
"This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
#include "algorithm"
-3
View File
@@ -1,3 +0,0 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/assert> instead of <gsl/gsl_assert>")
#include "assert"
-3
View File
@@ -1,3 +0,0 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/byte> instead of <gsl/gsl_byte>")
#include "byte"
-3
View File
@@ -1,3 +0,0 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/narrow> instead of <gsl/gsl_narrow>")
#include "narrow"
-3
View File
@@ -1,3 +0,0 @@
#pragma once
#pragma message("This header will soon be removed. Use <gsl/util> instead of <gsl/gsl_util>")
#include "util"
+3 -4
View File
@@ -30,13 +30,12 @@ struct narrowing_error : public std::exception
template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
// in the static_cast below, and that gsl::narrow should be used instead.
// Suppress this warning, since gsl::narrow is defined in terms of
// static_cast
// clang-format on
constexpr T narrow(U u) noexcept(false)
constexpr T narrow(U u)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
@@ -52,6 +51,7 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
// Note: NaN will always throw, since NaN != NaN
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
{
throw narrowing_error{};
@@ -66,9 +66,8 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
template <class T, class U, typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
// clang-format on
constexpr T narrow(U u) noexcept(false)
constexpr T narrow(U u)
{
const T t = narrow_cast<T>(u);
+54 -30
View File
@@ -19,11 +19,11 @@
#include "assert" // for Ensures, Expects
#include <algorithm> // for forward
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t
#include <memory> // for shared_ptr, unique_ptr
#include <system_error> // for hash
#include <functional> // for less, greater
#include <memory> // for shared_ptr, unique_ptr, hash
#include <type_traits> // for enable_if_t, is_convertible, is_assignable
#include <utility> // for declval, forward
#if !defined(GSL_NO_IOSTREAMS)
#include <iosfwd> // for ostream
@@ -46,6 +46,17 @@ namespace details
: std::true_type
{
};
// Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value
// of type T.
//
// Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-in)
template<typename T>
using value_or_reference_return_t = std::conditional_t<
sizeof(T) < 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
const T,
const T&>;
} // namespace details
//
@@ -57,8 +68,9 @@ using std::unique_ptr;
//
// owner
//
// owner<T> is designed as a bridge for code that must deal directly with owning pointers for some
// reason
// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory.
// Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used
// as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers.
//
// T must be a pointer type
// - disallow construction from any type other than pointer type
@@ -87,26 +99,26 @@ public:
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u) : ptr_(std::forward<U>(u))
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
{
Expects(ptr_ != nullptr);
}
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u) : ptr_(std::move(u))
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
{
Expects(ptr_ != nullptr);
}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other) : not_null(other.get())
constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
{}
not_null(const not_null& other) = default;
not_null& operator=(const not_null& other) = default;
constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const
constexpr details::value_or_reference_return_t<T> get() const
noexcept(noexcept(details::value_or_reference_return_t<T>{std::declval<T&>()}))
{
Ensures(ptr_ != nullptr);
return ptr_;
}
@@ -164,34 +176,34 @@ auto operator!=(const not_null<T>& lhs,
template <class T, class U>
auto operator<(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
-> decltype(lhs.get() < rhs.get())
const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
-> decltype(std::less<>{}(lhs.get(), rhs.get()))
{
return lhs.get() < rhs.get();
return std::less<>{}(lhs.get(), rhs.get());
}
template <class T, class U>
auto operator<=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
-> decltype(lhs.get() <= rhs.get())
const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
-> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
{
return lhs.get() <= rhs.get();
return std::less_equal<>{}(lhs.get(), rhs.get());
}
template <class T, class U>
auto operator>(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
-> decltype(lhs.get() > rhs.get())
const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
-> decltype(std::greater<>{}(lhs.get(), rhs.get()))
{
return lhs.get() > rhs.get();
return std::greater<>{}(lhs.get(), rhs.get());
}
template <class T, class U>
auto operator>=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
-> decltype(lhs.get() >= rhs.get())
const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
-> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
{
return lhs.get() >= rhs.get();
return std::greater_equal<>{}(lhs.get(), rhs.get());
}
// more unwanted operators
@@ -204,14 +216,28 @@ not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
template <class T>
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
template <class T, class U = decltype(std::declval<const T&>().get()), bool = std::is_default_constructible<std::hash<U>>::value>
struct not_null_hash
{
std::size_t operator()(const T& value) const { return std::hash<U>{}(value.get()); }
};
template <class T, class U>
struct not_null_hash<T, U, false>
{
not_null_hash() = delete;
not_null_hash(const not_null_hash&) = delete;
not_null_hash& operator=(const not_null_hash&) = delete;
};
} // namespace gsl
namespace std
{
template <class T>
struct hash<gsl::not_null<T>>
struct hash<gsl::not_null<T>> : gsl::not_null_hash<gsl::not_null<T>>
{
std::size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value.get()); }
};
} // namespace std
@@ -256,7 +282,9 @@ public:
constexpr strict_not_null(const strict_not_null<U>& other) : not_null<T>(other)
{}
strict_not_null(strict_not_null&& other) = default;
// To avoid invalidating the "not null" invariant, the contained pointer is actually copied
// instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions.
strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
strict_not_null(const strict_not_null& other) = default;
strict_not_null& operator=(const strict_not_null& other) = default;
strict_not_null& operator=(const not_null<T>& other)
@@ -310,12 +338,8 @@ strict_not_null(T) -> strict_not_null<T>;
namespace std
{
template <class T>
struct hash<gsl::strict_not_null<T>>
struct hash<gsl::strict_not_null<T>> : gsl::not_null_hash<gsl::strict_not_null<T>>
{
std::size_t operator()(const gsl::strict_not_null<T>& value) const
{
return hash<T>{}(value.get());
}
};
} // namespace std
+26 -7
View File
@@ -42,7 +42,7 @@
#pragma warning(disable : 4702) // unreachable code
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
#pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
#endif // _MSC_VER
@@ -53,7 +53,7 @@
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
// GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
// While there is a conversion from signed to unsigned, it happens at
// compiletime, so the compiler wouldn't have to warn indiscriminately, but
// could check if the source value actually doesn't fit into the target type
@@ -63,6 +63,14 @@
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
// Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks
#if defined(__clang__)
#if __has_warning("-Wunsafe-buffer-usage")
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif // __has_warning("-Wunsafe-buffer-usage")
#endif // defined(__clang__)
namespace gsl
{
@@ -126,6 +134,7 @@ namespace details
#ifdef _MSC_VER
using _Unchecked_type = pointer;
using _Prevent_inheriting_unwrap = span_iterator;
#endif // _MSC_VER
constexpr span_iterator() = default;
@@ -214,6 +223,7 @@ namespace details
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(current_ - begin_ >= n);
if (n < 0) Expects(end_ - current_ >= -n);
GSL_SUPPRESS(bounds .1)
current_ -= n;
return *this;
}
@@ -622,11 +632,7 @@ public:
// [span.obs], span observers
constexpr size_type size() const noexcept { return storage_.size(); }
constexpr size_type size_bytes() const noexcept
{
Expects(size() < dynamic_extent / sizeof(element_type));
return size() * sizeof(element_type);
}
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
constexpr bool empty() const noexcept { return size() == 0; }
@@ -779,8 +785,15 @@ span(const Container&) -> span<Element>;
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this static constexpr workaround in C++14 mode.
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
template <class ElementType, std::size_t Extent>
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
#pragma clang diagnostic pop
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
#endif
namespace details
@@ -841,4 +854,10 @@ as_writable_bytes(span<ElementType, Extent> s) noexcept
#pragma GCC diagnostic pop
#endif // __GNUC__ > 6
#if defined(__clang__)
#if __has_warning("-Wunsafe-buffer-usage")
#pragma clang diagnostic pop
#endif // __has_warning("-Wunsafe-buffer-usage")
#endif // defined(__clang__)
#endif // GSL_SPAN_H
+2
View File
@@ -123,12 +123,14 @@ constexpr span<const typename Container::value_type> make_span(const Container&
}
template <class Ptr>
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count)
{
return span<typename Ptr::element_type>(cont, count);
}
template <class Ptr>
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
{
return span<typename Ptr::element_type>(cont);
+4 -759
View File
@@ -1,759 +1,4 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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 "assert" // for Ensures, Expects
#include "span_ext" // for operator!=, operator==, dynamic_extent
#include "util" // for narrow_cast
#include <algorithm> // for equal, lexicographical_compare
#include <array> // for array
#include <cstddef> // for size_t, nullptr_t
#include <cstdint> // for PTRDIFF_MAX
#include <cstring>
#include <string> // for basic_string, allocator, char_traits
#include <type_traits> // for declval, is_convertible, enable_if_t, add_...
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates
#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes
#pragma warning(disable : 4996) // use of functions & classes marked [[deprecated]]
#endif // _MSC_VER
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace gsl
{
//
// czstring and wzstring
//
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//
template <typename CharT, std::size_t Extent = dynamic_extent>
using basic_zstring = CharT*;
using czstring = basic_zstring<const char, dynamic_extent>;
using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
using zstring = basic_zstring<char, dynamic_extent>;
using wzstring = basic_zstring<wchar_t, dynamic_extent>;
using u16zstring = basic_zstring<char16_t, dynamic_extent>;
using u32zstring = basic_zstring<char32_t, dynamic_extent>;
namespace details
{
template <class CharT>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr std::size_t
string_length(const CharT* str, std::size_t n)
{
if (str == nullptr || n == dynamic_extent) return 0;
const span<const CharT> str_span{str, n};
std::size_t len = 0;
while (len < n && str_span[len]) len++;
return len;
}
} // namespace details
//
// ensure_sentinel()
//
// Provides a way to obtain an span from a contiguous sequence
// that ends with a (non-inclusive) sentinel value.
//
// Will fail-fast if sentinel cannot be found before max elements are examined.
//
template <typename T, const T Sentinel>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<T, dynamic_extent>
ensure_sentinel(T* seq, std::size_t max = static_cast<std::size_t>(-1))
{
Ensures(seq != nullptr);
// clang-format off
GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work
// clang-format on
auto cur = seq;
Ensures(cur != nullptr); // workaround for removing the warning
// clang-format off
GSL_SUPPRESS(bounds.1) // TODO: suppress does not work
// clang-format on
while (static_cast<std::size_t>(cur - seq) < max && *cur != Sentinel) ++cur;
Ensures(*cur == Sentinel);
return {seq, static_cast<std::size_t>(cur - seq)};
}
//
// ensure_z - creates a span for a zero terminated strings. The span will not contain the zero
// termination. Will fail fast if a null-terminator cannot be found before the limit of size_type.
//
template <typename CharT>
[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<CharT, dynamic_extent>
ensure_z(CharT* const& sz, std::size_t max = static_cast<std::size_t>(-1))
{
return ensure_sentinel<CharT, CharT(0)>(sz, max);
}
template <typename CharT, std::size_t N>
constexpr span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
{
return ensure_z(&sz[0], N);
}
template <class Cont>
[[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<typename std::
remove_pointer<
typename Cont::pointer>::type,
dynamic_extent>
ensure_z(Cont& cont)
{
return ensure_z(cont.data(), cont.size());
}
template <typename CharT, std::size_t>
class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span;
namespace details
{
template <typename T>
struct [[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle : std::false_type{};
template <typename CharT, std::size_t Extent>
struct [[deprecated(
"string_span was removed from the C++ Core Guidelines. For more information, see "
"isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle<basic_string_span<CharT,
Extent>>
: std::true_type{};
template <typename T>
struct [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span
: is_basic_string_span_oracle<std::remove_cv_t<T>>{};
} // namespace details
//
// string_span and relatives
//
template <typename CharT, std::size_t Extent = dynamic_extent>
class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span
{
public:
using element_type = CharT;
using value_type = std::remove_cv_t<element_type>;
using pointer = std::add_pointer_t<element_type>;
using reference = std::add_lvalue_reference_t<element_type>;
using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>;
using impl_type = span<element_type, Extent>;
using size_type = typename impl_type::size_type;
using iterator = typename impl_type::iterator;
using reverse_iterator = typename impl_type::reverse_iterator;
// default (empty)
constexpr basic_string_span() noexcept = default;
// copy
constexpr basic_string_span(const basic_string_span& other) noexcept = default;
// assign
constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default;
constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {}
constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {}
// From static arrays - if 0-terminated, remove 0 from the view
// All other containers allow 0s within the length, so we do not remove them
template <std::size_t N>
constexpr basic_string_span(element_type(&arr)[N]) : span_(remove_z(arr))
{}
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
constexpr basic_string_span(std::array<ArrayElementType, N> & arr) noexcept : span_(arr)
{}
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) noexcept : span_(arr)
{}
// Container signature should work for basic_string after C++17 version exists
template <class Traits, class Allocator>
// GSL_SUPPRESS(bounds.4) // TODO: parser bug
constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator> & str)
: span_(&str[0], str.length())
{}
template <class Traits, class Allocator>
constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str)
: span_(&str[0], str.length())
{}
// from containers. Containers must have a pointer type and data() function signatures
template <class Container,
class = std::enable_if_t<
!details::is_basic_string_span<Container>::value &&
std::is_convertible<typename Container::pointer, pointer>::value &&
std::is_convertible<typename Container::pointer,
decltype(std::declval<Container>().data())>::value>>
constexpr basic_string_span(Container & cont) : span_(cont)
{}
template <class Container,
class = std::enable_if_t<
!details::is_basic_string_span<Container>::value &&
std::is_convertible<typename Container::pointer, pointer>::value &&
std::is_convertible<typename Container::pointer,
decltype(std::declval<Container>().data())>::value>>
constexpr basic_string_span(const Container& cont) : span_(cont)
{}
// from string_span
template <
class OtherValueType, std::size_t OtherExtent,
class = std::enable_if_t<std::is_convertible<
typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>>
constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other)
: span_(other.data(), other.length())
{}
template <size_type Count>
constexpr basic_string_span<element_type, Count> first() const
{
return {span_.template first<Count>()};
}
constexpr basic_string_span<element_type, dynamic_extent> first(size_type count) const
{
return {span_.first(count)};
}
template <size_type Count>
constexpr basic_string_span<element_type, Count> last() const
{
return {span_.template last<Count>()};
}
constexpr basic_string_span<element_type, dynamic_extent> last(size_type count) const
{
return {span_.last(count)};
}
template <size_type Offset, size_type Count>
constexpr basic_string_span<element_type, Count> subspan() const
{
return {span_.template subspan<Offset, Count>()};
}
constexpr basic_string_span<element_type, dynamic_extent> subspan(
size_type offset, size_type count = dynamic_extent) const
{
return {span_.subspan(offset, count)};
}
constexpr reference operator[](size_type idx) const { return span_[idx]; }
constexpr reference operator()(size_type idx) const { return span_[idx]; }
constexpr pointer data() const { return span_.data(); }
constexpr size_type length() const noexcept { return span_.size(); }
constexpr size_type size() const noexcept { return span_.size(); }
constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); }
constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); }
constexpr bool empty() const noexcept { return size() == 0; }
constexpr iterator begin() const noexcept { return span_.begin(); }
constexpr iterator end() const noexcept { return span_.end(); }
constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); }
constexpr reverse_iterator rend() const noexcept { return span_.rend(); }
private:
static constexpr impl_type remove_z(pointer const& sz, std::size_t max)
{
return impl_type(sz, details::string_length(sz, max));
}
template <std::size_t N>
static constexpr impl_type remove_z(element_type(&sz)[N])
{
return remove_z(&sz[0], N);
}
impl_type span_;
};
template <std::size_t Extent = dynamic_extent>
using string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char, Extent>;
template <std::size_t Extent = dynamic_extent>
using cstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char, Extent>;
template <std::size_t Extent = dynamic_extent>
using wstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cwstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const wchar_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using u16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char16_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cu16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char16_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using u32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<char32_t, Extent>;
template <std::size_t Extent = dynamic_extent>
using cu32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_string_span<const char32_t, Extent>;
//
// to_string() allow (explicit) conversions from string_span to string
//
template <typename CharT, std::size_t Extent>
constexpr std::basic_string<typename std::remove_const<CharT>::type>
to_string(basic_string_span<CharT, Extent> view)
{
return {view.data(), narrow_cast<std::size_t>(view.length())};
}
template <typename CharT, typename Traits = typename std::char_traits<CharT>,
typename Allocator = std::allocator<CharT>, typename gCharT, std::size_t Extent>
constexpr std::basic_string<CharT, Traits, Allocator>
to_basic_string(basic_string_span<gCharT, Extent> view)
{
return {view.data(), narrow_cast<std::size_t>(view.length())};
}
template <class ElementType, std::size_t Extent>
constexpr basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(basic_string_span<ElementType, Extent> s) noexcept
{
// clang-format off
GSL_SUPPRESS(type.1)
// clang-format on
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
}
template <class ElementType, std::size_t Extent,
class = std::enable_if_t<!std::is_const<ElementType>::value>>
constexpr basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writable_bytes(basic_string_span<ElementType, Extent> s) noexcept
{
// clang-format off
GSL_SUPPRESS(type.1)
// clang-format on
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
}
// zero-terminated string span, used to convert
// zero-terminated spans to legacy strings
template <typename CharT, std::size_t Extent = dynamic_extent>
class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, "
"see isocpp/CppCoreGuidelines PR#1680")]] basic_zstring_span
{
public:
using value_type = CharT;
using const_value_type = std::add_const_t<CharT>;
using pointer = std::add_pointer_t<value_type>;
using const_pointer = std::add_pointer_t<const_value_type>;
using zstring_type = basic_zstring<value_type, Extent>;
using const_zstring_type = basic_zstring<const_value_type, Extent>;
using impl_type = span<value_type, Extent>;
using string_span_type = basic_string_span<value_type, Extent>;
constexpr basic_zstring_span(impl_type s) : span_(s)
{
// expects a zero-terminated span
Expects(s.size() > 0);
Expects(s[s.size() - 1] == value_type{});
}
// copy
constexpr basic_zstring_span(const basic_zstring_span& other) = default;
// move
constexpr basic_zstring_span(basic_zstring_span && other) = default;
// assign
constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;
// move assign
constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;
constexpr bool empty() const noexcept { return false; }
constexpr string_span_type as_string_span() const noexcept
{
return {span_.data(), span_.size() - 1};
}
constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); }
constexpr const_zstring_type assume_z() const noexcept { return span_.data(); }
private:
impl_type span_;
};
template <std::size_t Max = dynamic_extent>
using zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char, Max>;
template <std::size_t Max = dynamic_extent>
using wzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<wchar_t, Max>;
template <std::size_t Max = dynamic_extent>
using u16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char16_t, Max>;
template <std::size_t Max = dynamic_extent>
using u32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<char32_t, Max>;
template <std::size_t Max = dynamic_extent>
using czstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const char, Max>;
template <std::size_t Max = dynamic_extent>
using cwzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more "
"information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const wchar_t, Max>;
template <std::size_t Max = dynamic_extent>
using cu16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For "
"more information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const char16_t, Max>;
template <std::size_t Max = dynamic_extent>
using cu32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For "
"more information, see isocpp/CppCoreGuidelines PR#1680")]] =
basic_zstring_span<const char32_t, Max>;
// operator ==
template <class CharT, std::size_t Extent, class T,
class = std::enable_if_t<
details::is_basic_string_span<T>::value ||
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other)
{
const gsl::basic_string_span<std::add_const_t<CharT>> tmp(other);
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
}
template <class CharT, std::size_t Extent, class T,
class = std::enable_if_t<
!details::is_basic_string_span<T>::value &&
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other)
{
const gsl::basic_string_span<std::add_const_t<CharT>> tmp(one);
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
}
// operator !=
template <typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<std::is_convertible<
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return !(one == other);
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
!gsl::details::is_basic_string_span<T>::value>>
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return !(one == other);
}
// operator<
template <typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<std::is_convertible<
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
const gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
!gsl::details::is_basic_string_span<T>::value>>
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
}
#ifndef _MSC_VER
// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
}
#endif
// operator <=
template <typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<std::is_convertible<
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return !(other < one);
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
!gsl::details::is_basic_string_span<T>::value>>
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return !(other < one);
}
#ifndef _MSC_VER
// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return !(other < one);
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return !(other < one);
}
#endif
// operator>
template <typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<std::is_convertible<
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return other < one;
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
!gsl::details::is_basic_string_span<T>::value>>
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return other < one;
}
#ifndef _MSC_VER
// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return other < one;
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return other < one;
}
#endif
// operator >=
template <typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<std::is_convertible<
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return !(one < other);
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename = std::enable_if_t<
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
!gsl::details::is_basic_string_span<T>::value>>
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return !(one < other);
}
#ifndef _MSC_VER
// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
return !(one < other);
}
template <
typename CharT, std::size_t Extent = dynamic_extent, typename T,
typename DataType = typename T::value_type,
typename = std::enable_if_t<
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
std::is_convertible<DataType*, CharT*>::value &&
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
DataType>::value>>
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
return !(one < other);
}
#endif
} // namespace gsl
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif // _MSC_VER
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif // GSL_STRING_SPAN_H
#pragma once
#pragma message( \
"This header will soon be removed. Use <gsl/zstring> instead of <gsl/string_span>")
#include "zstring"
+30 -25
View File
@@ -21,6 +21,7 @@
#include <array>
#include <cstddef> // for ptrdiff_t, size_t
#include <limits> // for numeric_limits
#include <initializer_list> // for initializer_list
#include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward
@@ -39,6 +40,14 @@
#endif // _MSC_VER
// Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks
#if defined(__clang__)
#if __has_warning("-Wunsafe-buffer-usage")
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif // __has_warning("-Wunsafe-buffer-usage")
#endif // defined(__clang__)
#if defined(__cplusplus) && (__cplusplus >= 201703L)
#define GSL_NODISCARD [[nodiscard]]
#else
@@ -65,40 +74,29 @@ template <class F>
class final_action
{
public:
static_assert(!std::is_reference<F>::value && !std::is_const<F>::value &&
!std::is_volatile<F>::value,
"Final_action should store its callable by value");
explicit final_action(const F& ff) noexcept : f{ff} { }
explicit final_action(F&& ff) noexcept : f{std::move(ff)} { }
explicit final_action(F f) noexcept : f_(std::move(f)) {}
~final_action() noexcept { if (invoke) f(); }
final_action(final_action&& other) noexcept
: f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false))
{}
: f(std::move(other.f)), invoke(std::exchange(other.invoke, false))
{ }
final_action(const final_action&) = delete;
final_action& operator=(const final_action&) = delete;
final_action& operator=(final_action&&) = delete;
// clang-format off
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
// clang-format on
~final_action() noexcept
{
if (invoke_) f_();
}
final_action(const final_action&) = delete;
void operator=(const final_action&) = delete;
void operator=(final_action&&) = delete;
private:
F f_;
bool invoke_{true};
F f;
bool invoke = true;
};
// finally() - convenience function to generate a final_action
template <class F>
GSL_NODISCARD final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>
finally(F&& f) noexcept
GSL_NODISCARD auto finally(F&& f) noexcept
{
return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(
std::forward<F>(f));
return final_action<std::decay_t<F>>{std::forward<F>(f)};
}
// narrow_cast(): a searchable way to do narrowing casts of values
@@ -121,6 +119,7 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on
constexpr T& at(T (&arr)[N], const index i)
{
static_assert(N <= static_cast<std::size_t>((std::numeric_limits<std::ptrdiff_t>::max)()), "We only support arrays up to PTRDIFF_MAX bytes.");
Expects(i >= 0 && i < narrow_cast<index>(N));
return arr[narrow_cast<std::size_t>(i)];
}
@@ -148,11 +147,11 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
}
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
template <class T, size_t extent = std::dynamic_extent>
template <class T, std::size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()])
{
Expects(i >= 0 && i < narrow_cast<index>(sp.size()));
return sp[gsl::narrow_cast<size_t>(i)];
return sp[gsl::narrow_cast<std::size_t>(i)];
}
#endif // __cpp_lib_span >= 202002L
} // namespace gsl
@@ -163,4 +162,10 @@ constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size
#endif // _MSC_VER
#if defined(__clang__)
#if __has_warning("-Wunsafe-buffer-usage")
#pragma clang diagnostic pop
#endif // __has_warning("-Wunsafe-buffer-usage")
#endif // defined(__clang__)
#endif // GSL_UTIL_H
+58
View File
@@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef GSL_ZSTRING_H
#define GSL_ZSTRING_H
#include "span_ext" // for dynamic_extent
#include <cstddef> // for size_t, nullptr_t
namespace gsl
{
//
// czstring and wzstring
//
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//
template <typename CharT, std::size_t Extent = dynamic_extent>
using basic_zstring = CharT*;
using czstring = basic_zstring<const char, dynamic_extent>;
using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
using zstring = basic_zstring<char, dynamic_extent>;
using wzstring = basic_zstring<wchar_t, dynamic_extent>;
using u16zstring = basic_zstring<char16_t, dynamic_extent>;
using u32zstring = basic_zstring<char32_t, dynamic_extent>;
} // namespace gsl
#endif // GSL_ZSTRING_H
-43
View File
@@ -1,43 +0,0 @@
parameters:
CXXVersions: [ 14, 17, 20 ]
buildTypes: [ 'Debug', 'Release' ]
image: ''
compiler: ''
compilerVersions: ["default"] # if default value, simply uses whatever version is on the machine.
# the text of this default value doesn't actually matter.
setupfile: ''
extraCmakeArgs: ''
jobs:
- ${{ each compilerVersion in parameters.compilerVersions }}:
- ${{ each CXXVersion in parameters.CXXVersions }}:
- ${{ each buildType in parameters.buildTypes }}:
- job:
displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }}
pool:
vmImage: ${{ parameters.image }}
continueOnError: false
steps:
- ${{ if not(eq(parameters.setupfile, '')) }}:
- template: ${{ parameters.setupfile }}
parameters:
version: ${{ compilerVersion }}
- task: CMake@1
name: Configure
inputs:
workingDirectory: build
cmakeArgs: '-DGSL_CXX_STANDARD=${{ CXXVersion }} -DCMAKE_BUILD_TYPE=${{ buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ parameters.extraCmakeArgs }} .. '
- task: CMake@1
name: Build
inputs:
workingDirectory: build
cmakeArgs: '--build . '
- script: ctest . --output-on-failure --no-compress-output
name: CTest
workingDirectory: build
failOnStderr: true
-9
View File
@@ -1,9 +0,0 @@
parameters:
version: 0
steps:
- script: |
if [ "${{ parameters.version }}" != "default" ]; then sudo xcode-select -switch /Applications/Xcode_${{ parameters.version }}.app; fi
displayName: "Setup Xcode Version"
failOnStderr: true
-13
View File
@@ -1,13 +0,0 @@
parameters:
version: 0
steps:
- script: |
echo "##vso[task.setvariable variable=CXX;]${CXX}"
echo "##vso[task.setvariable variable=CC;]${CC}"
displayName: "Setup Clang Version"
failOnStderr: true
env:
CC: clang-${{ parameters.version }}
CXX: clang++-${{ parameters.version }}
-14
View File
@@ -1,14 +0,0 @@
parameters:
version: 0
steps:
- script: |
echo "##vso[task.setvariable variable=CXX;]${CXX}"
echo "##vso[task.setvariable variable=CC;]${CC}"
if [ "${{ parameters.version }}" = "11" ]; then sudo apt-get install $CXX; fi
displayName: "Setup GCC Version"
failOnStderr: true
env:
CC: gcc-${{ parameters.version }}
CXX: g++-${{ parameters.version }}
View File
+38 -10
View File
@@ -1,7 +1,12 @@
cmake_minimum_required(VERSION 3.0.2)
cmake_minimum_required(VERSION 3.14...3.16)
project(GSLTests CXX)
enable_testing() # again, for support standalone testing
project(GSLTests LANGUAGES CXX)
set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard")
set(CMAKE_CXX_STANDARD ${GSL_CXX_STANDARD})
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FindPkgConfig)
include(ExternalProject)
@@ -52,10 +57,14 @@ if (NOT GTestMain_FOUND)
endif()
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
# CMake has been started independently in this directory with tests. Do
# import the globally installed Guidelines Support Library and test it
# instead of the current version from the include/ folder.
find_package(Microsoft.GSL REQUIRED)
find_package(Microsoft.GSL CONFIG REQUIRED)
enable_testing()
if (NOT DEFINED Microsoft.GSL_VERSION)
message(FATAL_ERROR "Microsoft.GSL_VERSION not defined!")
endif()
message(STATUS "Microsoft.GSL_VERSION = ${Microsoft.GSL_VERSION}")
endif()
if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17))
@@ -104,12 +113,15 @@ if(MSVC) # MSVC or simulating MSVC
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-member-function
-Wno-unused-variable
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
>
>
>
)
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
if (WARN_RESERVED_ID)
target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier")
target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier")
endif()
else()
target_compile_options(gsl_tests_config INTERFACE
@@ -134,6 +146,7 @@ else()
-Wno-global-constructors # GTest
-Wno-missing-prototypes
-Wno-padded
-Wno-switch-default
-Wno-unknown-attributes
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
-Wno-weak-vtables
@@ -174,6 +187,11 @@ else()
>
)
endif(MSVC)
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
if (WARN_UNSAFE_BUFFER)
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
target_compile_options(gsl_tests_config INTERFACE "-Wno-unsafe-buffer-usage")
endif()
# for tests to find the gtest header
target_include_directories(gsl_tests_config SYSTEM INTERFACE
@@ -191,7 +209,7 @@ add_executable(gsl_tests
span_ext_tests.cpp
span_tests.cpp
strict_notnull_tests.cpp
string_span_tests.cpp
utils_tests.cpp
)
@@ -234,11 +252,16 @@ if(MSVC) # MSVC or simulating MSVC
-Wno-c++98-compat-pedantic
-Wno-missing-prototypes
-Wno-unknown-attributes
$<$<EQUAL:${GSL_CXX_STANDARD},14>:
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
>
>
>
)
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
if (WARN_RESERVED_ID)
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier")
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier")
endif()
else()
target_compile_options(gsl_tests_config_noexcept INTERFACE
@@ -280,6 +303,11 @@ else()
>
)
endif(MSVC)
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
if (WARN_UNSAFE_BUFFER)
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-unsafe-buffer-usage")
endif()
add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp)
target_link_libraries(gsl_noexcept_tests
+1 -1
View File
@@ -15,7 +15,7 @@
///////////////////////////////////////////////////////////////////////////////
#include "deathTestCommon.h"
#include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects
#include <gsl/assert> // for Ensures, Expects
#include <gtest/gtest.h>
using namespace gsl;
+1
View File
@@ -20,6 +20,7 @@
#include <array> // for array
#include <cstddef> // for size_t
#include <exception> // for terminate
#include <initializer_list> // for initializer_list
#include <vector> // for vector
#if defined(__cplusplus) && __cplusplus >= 202002L
+6 -3
View File
@@ -37,9 +37,6 @@ TEST(byte_tests, construction)
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
}
// clang-format off
GSL_SUPPRESS(es.49)
// clang-format on
{
const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
@@ -61,6 +58,12 @@ TEST(byte_tests, construction)
EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
}
#endif
#ifdef CONFIRM_COMPILATION_ERRORS
to_byte(char{});
to_byte(3);
to_byte(3u);
#endif
}
TEST(byte_tests, bitwise_operations)
+89 -11
View File
@@ -19,11 +19,12 @@
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <algorithm> // for addressof
#include <cstdint> // for uint16_t
#include <memory> // for shared_ptr, make_shared, operator<, opera...
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
#include <stdint.h> // for uint16_t
#include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info
#include <variant> // for variant, monostate, get
#include "deathTestCommon.h"
using namespace gsl;
@@ -52,7 +53,7 @@ template <typename T>
struct CustomPtr
{
CustomPtr(T* p) : p_(p) {}
operator T*() { return p_; }
operator T*() const { return p_; }
bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
T* p_ = nullptr;
};
@@ -441,6 +442,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
not_null x{&i};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(not_null{&i});
#endif
helper_const(not_null{&i});
EXPECT_TRUE(*x == 42);
}
{
int i = 42;
int* p = &i;
@@ -452,6 +465,19 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
const int* p = &i;
not_null x{p};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(not_null{p});
#endif
helper_const(not_null{p});
EXPECT_TRUE(*x == 42);
}
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
std::abort();
@@ -489,6 +515,17 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
}
#endif
}
TEST(notnull_tests, TestVariantEmplace)
{
int i = 0;
std::variant<std::monostate, not_null<int*>> v;
v.emplace<not_null<int*>>(&i);
EXPECT_FALSE(v.valueless_by_exception());
EXPECT_TRUE(v.index() == 1);
EXPECT_TRUE(std::get<not_null<int*>>(v) == &i);
}
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
TEST(notnull_tests, TestMakeNotNull)
@@ -503,6 +540,18 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
const auto x = make_not_null(&i);
#ifdef CONFIRM_COMPILATION_ERRORS
helper(make_not_null(&i));
#endif
helper_const(make_not_null(&i));
EXPECT_TRUE(*x == 42);
}
{
int i = 42;
int* p = &i;
@@ -514,6 +563,19 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
const int* p = &i;
const auto x = make_not_null(p);
#ifdef CONFIRM_COMPILATION_ERRORS
helper(make_not_null(p));
#endif
helper_const(make_not_null(p));
EXPECT_TRUE(*x == 42);
}
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull";
std::abort();
@@ -556,15 +618,31 @@ TEST(notnull_tests, TestMakeNotNull)
TEST(notnull_tests, TestStdHash)
{
int x = 42;
int y = 99;
not_null<int*> nn{&x};
const not_null<int*> cnn{&x};
{
int x = 42;
int y = 99;
not_null<int*> nn{&x};
const not_null<int*> cnn{&x};
std::hash<not_null<int*>> hash_nn;
std::hash<int*> hash_intptr;
std::hash<not_null<int*>> hash_nn;
std::hash<int*> hash_intptr;
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
}
{
const int x = 42;
const int y = 99;
not_null<const int*> nn{&x};
const not_null<const int*> cnn{&x};
std::hash<not_null<const int*>> hash_nn;
std::hash<const int*> hash_intptr;
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
}
}
+1 -1
View File
@@ -519,7 +519,7 @@ TEST(span_compatibility_tests, assertion_tests)
// assertions for span's definition
static_assert(std::is_same<decltype(gsl::dynamic_extent), const std::size_t>::value,
"gsl::dynamic_extent must be respresented as std::size_t");
"gsl::dynamic_extent must be represented as std::size_t");
static_assert(gsl::dynamic_extent == static_cast<std::size_t>(-1),
"gsl::dynamic_extent must be defined as the max value of std::size_t");
+26 -7
View File
@@ -19,9 +19,10 @@
#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at
#include <array> // for array
#include <iostream> // for cerr
#include <vector> // for vector
#include <array> // for array
#include <exception> // for terminate
#include <iostream> // for cerr
#include <vector> // for vector
using namespace std;
using namespace gsl;
@@ -193,10 +194,28 @@ TEST(span_ext_test, make_span_from_container_constructor)
TEST(span_test, interop_with_gsl_at)
{
int arr[5] = {1, 2, 3, 4, 5};
gsl::span<int> s{arr};
EXPECT_TRUE(at(s, 0) == 1);
EXPECT_TRUE(at(s, 1) == 2);
std::vector<int> vec{1, 2, 3, 4, 5};
gsl::span<int> sp{vec};
std::vector<int> cvec{1, 2, 3, 4, 5};
gsl::span<int> csp{cvec};
for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i)
{
EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]);
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]);
}
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. interop_with_gsl_at";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(sp, -1), expected);
EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
EXPECT_DEATH(gsl::at(csp, -1), expected);
EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
}
TEST(span_ext_test, iterator_free_functions)
+103 -39
View File
@@ -333,7 +333,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
}
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int arr3d[2][3][2] = { { {1, 2}, {3, 4}, {5, 6} }, { {7, 8}, {9, 10}, {11, 12} } };
#ifdef CONFIRM_COMPILATION_ERRORS
{
@@ -646,37 +646,100 @@ TEST(span_test, from_container_constructor)
}
}
TEST(span_test, from_convertible_span_constructor){{span<DerivedClass> avd;
span<const DerivedClass> avcd = avd;
static_cast<void>(avcd);
}
TEST(span_test, from_convertible_span_constructor)
{
#ifdef CONFIRM_COMPILATION_ERRORS
span<DerivedClass> avd;
span<BaseClass> avb = avd;
static_cast<void>(avb);
#endif
}
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. from_convertible_span_constructor";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
{
span<DerivedClass> avd;
span<const DerivedClass> avcd = avd;
static_cast<void>(avcd);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass, 2> avd{arr};
span<const DerivedClass, 2> avcd = avd;
static_cast<void>(avcd);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass, 2> avd{arr};
span<const DerivedClass> avcd = avd;
static_cast<void>(avcd);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass> avd{arr};
span<const DerivedClass, 2> avcd{avd};
static_cast<void>(avcd);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass> avd{arr};
using T = span<const DerivedClass, 1>;
EXPECT_DEATH(T{avd}, expected);
}
{
std::array<DerivedClass, 1> arr{};
span<DerivedClass> avd{arr};
using T = span<const DerivedClass, 2>;
EXPECT_DEATH(T{avd}, expected);
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
span<int> s;
span<unsigned int> s2 = s;
static_cast<void>(s2);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass> avd{arr};
span<const DerivedClass, 2> avcd = avd;
static_cast<void>(avcd);
}
{
span<int> s;
span<const unsigned int> s2 = s;
static_cast<void>(s2);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass, 2> avd{arr};
span<const DerivedClass, 1> avcd = avd;
static_cast<void>(avcd);
}
{
span<int> s;
span<short> s2 = s;
static_cast<void>(s2);
}
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass, 2> avd{arr};
span<const DerivedClass, 3> avcd = avd;
static_cast<void>(avcd);
}
{
span<DerivedClass> avd;
span<BaseClass> avb = avd;
static_cast<void>(avb);
}
{
span<int> s;
span<unsigned int> s2 = s;
static_cast<void>(s2);
}
{
span<int> s;
span<const unsigned int> s2 = s;
static_cast<void>(s2);
}
{
span<int> s;
span<short> s2 = s;
static_cast<void>(s2);
}
#endif
}
@@ -1053,12 +1116,6 @@ TEST(span_test, rbegin_rend)
TEST(span_test, as_bytes)
{
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. as_bytes";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
int a[] = {1, 2, 3, 4};
{
const span<const int> s = a;
@@ -1084,12 +1141,6 @@ TEST(span_test, as_bytes)
EXPECT_TRUE(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data()));
EXPECT_TRUE(bs.size() == s.size_bytes());
}
int b[5] = {1, 2, 3, 4, 5};
{
span<int> sp(std::begin(b), static_cast<size_t>(-2));
EXPECT_DEATH((void) sp.size_bytes(), expected);
}
}
TEST(span_test, as_writable_bytes)
@@ -1317,3 +1368,16 @@ TEST(span_test, std_span)
EXPECT_TRUE(std_span.size() == gsl_span.size());
}
#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
#if defined(__cpp_lib_span) && defined(__cpp_lib_ranges)
// This test covers the changes in PR #1100
TEST(span_test, msvc_compile_error_PR1100)
{
int arr[]{1, 7, 2, 9};
gsl::span sp{arr, std::size(arr)};
std::ranges::sort(sp);
for (const auto& e : sp) {
(void)e;
}
}
#endif // defined(__cpp_lib_span) && defined(__cpp_lib_ranges)
+107
View File
@@ -71,6 +71,28 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(*snn1 == 42);
}
{
// raw ptr <-> strict_not_null
const int x = 42;
#ifdef CONFIRM_COMPILATION_ERRORS
strict_not_null<int*> snn = &x;
strict_helper(&x);
strict_helper_const(&x);
strict_helper(return_pointer());
strict_helper_const(return_pointer_const());
#endif
const strict_not_null<const int*> snn1{&x};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(snn1);
#endif
helper_const(snn1);
EXPECT_TRUE(*snn1 == 42);
}
{
// strict_not_null -> strict_not_null
int x = 42;
@@ -85,6 +107,22 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(snn1 == snn2);
}
{
// strict_not_null -> strict_not_null
const int x = 42;
strict_not_null<const int*> snn1{&x};
const strict_not_null<const int*> snn2{&x};
#ifdef CONFIRM_COMPILATION_ERRORS
strict_helper(snn1);
#endif
strict_helper_const(snn1);
strict_helper_const(snn2);
EXPECT_TRUE(snn1 == snn2);
}
{
// strict_not_null -> not_null
int x = 42;
@@ -101,6 +139,24 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(snn == nn2);
}
{
// strict_not_null -> not_null
const int x = 42;
strict_not_null<const int*> snn{&x};
const not_null<const int*> nn1 = snn;
const not_null<const int*> nn2{snn};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(snn);
#endif
helper_const(snn);
EXPECT_TRUE(snn == nn1);
EXPECT_TRUE(snn == nn2);
}
{
// not_null -> strict_not_null
int x = 42;
@@ -125,6 +181,32 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
}
{
// not_null -> strict_not_null
const int x = 42;
not_null<const int*> nn{&x};
const strict_not_null<const int*> snn1{nn};
const strict_not_null<const int*> snn2{nn};
#ifdef CONFIRM_COMPILATION_ERRORS
strict_helper(nn);
#endif
strict_helper_const(nn);
EXPECT_TRUE(snn1 == nn);
EXPECT_TRUE(snn2 == nn);
std::hash<strict_not_null<const int*>> hash_snn;
std::hash<not_null<const int*>> hash_nn;
EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn));
EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn));
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
strict_not_null<int*> p{nullptr};
@@ -152,6 +234,18 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
strict_not_null x{&i};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(strict_not_null{&i});
#endif
helper_const(strict_not_null{&i});
EXPECT_TRUE(*x == 42);
}
{
int i = 42;
int* p = &i;
@@ -163,6 +257,19 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42);
}
{
const int i = 42;
const int* p = &i;
strict_not_null x{p};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(strict_not_null{p});
#endif
helper_const(strict_not_null{p});
EXPECT_TRUE(*x == 42);
}
{
auto workaround_macro = []() {
int* p1 = nullptr;
File diff suppressed because it is too large Load Diff
+12 -2
View File
@@ -19,11 +19,11 @@
#include <algorithm> // for move
#include <complex>
#include <cstddef> // for std::ptrdiff_t
#include <cstdint> // for uint32_t, int32_t
#include <functional> // for reference_wrapper, _Bind_helper<>::type
#include <gsl/narrow> // for narrow, narrowing_error
#include <gsl/util> // finally, narrow_cast
#include <limits> // for numeric_limits
#include <stdint.h> // for uint32_t, int32_t
#include <type_traits> // for is_same
using namespace gsl;
@@ -96,7 +96,7 @@ TEST(utils_tests, finally_function_with_bind)
{
int i = 0;
{
auto _ = finally(std::bind(&f, std::ref(i)));
auto _ = finally([&i] { return f(i); });
EXPECT_TRUE(i == 0);
}
EXPECT_TRUE(i == 1);
@@ -112,6 +112,16 @@ TEST(utils_tests, finally_function_ptr)
EXPECT_TRUE(j == 1);
}
TEST(utils_tests, finally_function)
{
j = 0;
{
auto _ = finally(g);
EXPECT_TRUE(j == 0);
}
EXPECT_TRUE(j == 1);
}
TEST(utils_tests, narrow_cast)
{
int n = 120;